Debuger updates:

* Improved behaviour of bottom line in Qt and win32 debugger views.
* Ported memory tracking feature from Qt to win32 module.
This commit is contained in:
Vas Crabb 2021-01-30 22:46:43 +11:00
parent fd3ca4668a
commit 8d04ca7d7d
6 changed files with 242 additions and 77 deletions

View File

@ -66,11 +66,13 @@ void DebuggerView::paintEvent(QPaintEvent *event)
// Handle the scroll bars
int const horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x;
horizontalScrollBar()->setRange(0, (std::max)(0, horizontalScrollCharDiff));
horizontalScrollBar()->setPageStep(lineWidth - 1);
int const verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y;
int const verticalScrollSize = (std::max)(0, verticalScrollCharDiff);
bool const atEnd = verticalScrollBar()->value() == verticalScrollBar()->maximum();
verticalScrollBar()->setRange(0, verticalScrollSize);
verticalScrollBar()->setPageStep((contentHeight / fontHeight) - 1);
if (m_preferBottom && atEnd)
verticalScrollBar()->setValue(verticalScrollSize);
@ -147,9 +149,24 @@ void DebuggerView::paintEvent(QPaintEvent *event)
x * fontWidth,
y * fontHeight,
((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
((y + 1) < visibleCharDims.y) ? fontHeight : (contentHeight - (y * fontHeight)),
fontHeight,
bgBrush);
if (((y + 1) == visibleCharDims.y) && (contentHeight > (visibleCharDims.y * fontHeight)))
{
if (textAttr & DCA_ANCILLARY)
bgColor.setRgb(0xe0, 0xe0, 0xe0);
else
bgColor.setRgb(0xff, 0xff, 0xff);
bgBrush.setColor(bgColor);
painter.fillRect(
x * fontWidth,
visibleCharDims.y * fontHeight,
((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
contentHeight - (visibleCharDims.y * fontHeight),
bgBrush);
}
// There is a touchy interplay between font height, drawing difference, visible position, etc
// Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed.
painter.drawText(x * fontWidth, (y * fontHeight + (fontHeight * 0.80)), text);

View File

@ -326,7 +326,7 @@ void DebuggerMemView::addItemsToContextMenu(QMenu *menu)
if (addressSpace)
{
// get the last known PC to write to this memory location
debug_view_xy const pos = view()->cursor_position();
debug_view_xy const pos = memView.cursor_position();
offs_t const address = memView.addressAtCursorPosition(pos);
offs_t a = address & addressSpace->logaddrmask();
bool good = false;

View File

@ -21,12 +21,10 @@ debugbase_info::debugbase_info(debugger_windows_interface &debugger) :
void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &bounds)
{
RECT curbounds;
int flags = 0;
// first get the current bounds, relative to the parent
RECT curbounds;
GetWindowRect(wnd, &curbounds);
if (parent != nullptr)
if (parent)
{
RECT parentbounds;
GetWindowRect(parent, &parentbounds);
@ -37,6 +35,7 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &
}
// if the position matches, don't change it
int flags = 0;
if (curbounds.top == bounds.top && curbounds.left == bounds.left)
flags |= SWP_NOMOVE;
if ((curbounds.bottom - curbounds.top) == (bounds.bottom - bounds.top) &&
@ -45,17 +44,19 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &
// if we need to, reposition the window
if (flags != (SWP_NOMOVE | SWP_NOSIZE))
SetWindowPos(wnd, nullptr,
bounds.left, bounds.top,
bounds.right - bounds.left, bounds.bottom - bounds.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags);
{
SetWindowPos(
wnd, nullptr,
bounds.left, bounds.top,
bounds.right - bounds.left, bounds.bottom - bounds.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags);
}
}
void debugbase_info::smart_show_window(HWND wnd, bool show)
{
BOOL const visible = IsWindowVisible(wnd);
if ((visible && !show) || (!visible && show))
bool const visible = bool(IsWindowVisible(wnd));
if (visible != show)
ShowWindow(wnd, show ? SW_SHOW : SW_HIDE);
}

View File

@ -401,6 +401,7 @@ void debugview_info::draw_contents(HDC windc)
// get the client rect
RECT client;
GetClientRect(m_wnd, &client);
bool const need_filldown = client.bottom > (metrics().debug_font_height() * visarea.y);
// create a compatible DC and an offscreen bitmap
HDC const dc = CreateCompatibleDC(windc);
@ -413,6 +414,9 @@ void debugview_info::draw_contents(HDC windc)
return;
}
HGDIOBJ const oldbitmap = SelectObject(dc, bitmap);
bool const show_hscroll = m_hscroll && IsWindowVisible(m_hscroll);
if (show_hscroll)
client.bottom -= metrics().hscroll_height();
// set the font
HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font());
@ -423,6 +427,8 @@ void debugview_info::draw_contents(HDC windc)
// iterate over rows and columns
for (uint32_t row = 0; row < visarea.y; row++)
{
bool do_filldown = (row == (visarea.y - 1)) && need_filldown;
// loop twice; once to fill the background and once to draw the text
for (int iter = 0; iter < 2; iter++)
{
@ -451,16 +457,16 @@ void debugview_info::draw_contents(HDC windc)
{
COLORREF oldbg = bgcolor;
// reset to standard colors
fgcolor = RGB(0x00,0x00,0x00);
// pick new background color
bgcolor = RGB(0xff,0xff,0xff);
// pick new fg/bg colors
if (viewdata[col].attrib & DCA_VISITED) bgcolor = RGB(0xc6, 0xe2, 0xff);
if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0);
if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80);
if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00);
if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80);
// pick new foreground color
fgcolor = RGB(0x00,0x00,0x00);
if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00);
if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff);
if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2);
@ -471,21 +477,41 @@ void debugview_info::draw_contents(HDC windc)
{
bounds.right = bounds.left + (count * metrics().debug_font_width());
if (iter == 0)
{
FillRect(dc, &bounds, bgbrush);
if (do_filldown)
{
COLORREF const filldown = (last_attrib & DCA_ANCILLARY) ? RGB(0xe0,0xe0,0xe0) : RGB(0xff,0xff,0xff);
if (oldbg != filldown)
{
DeleteObject(bgbrush);
bgbrush = CreateSolidBrush(filldown);
oldbg = filldown;
}
RECT padding = bounds;
padding.top = padding.bottom;
padding.bottom = client.bottom;
FillRect(dc, &padding, bgbrush);
}
}
else
{
ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
}
bounds.left = bounds.right;
count = 0;
}
// set the new colors
if (iter == 0 && oldbg != bgcolor)
if (iter == 1)
{
SetTextColor(dc, fgcolor);
}
else if (oldbg != bgcolor)
{
DeleteObject(bgbrush);
bgbrush = CreateSolidBrush(bgcolor);
}
else if (iter == 1)
SetTextColor(dc, fgcolor);
last_attrib = viewdata[col].attrib;
}
@ -494,33 +520,43 @@ void debugview_info::draw_contents(HDC windc)
}
// flush any remaining stuff
if (count > 0)
{
bounds.right = bounds.left + (count * metrics().debug_font_width());
if (iter == 0)
FillRect(dc, &bounds, bgbrush);
else
ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
}
// erase to the end of the line
bounds.right = bounds.left + (count * metrics().debug_font_width());
if (iter == 0)
{
bounds.left = bounds.right;
// erase to the end of the line
bounds.right = client.right;
FillRect(dc, &bounds, bgbrush);
if (do_filldown)
{
COLORREF const filldown = (last_attrib & DCA_ANCILLARY) ? RGB(0xe0,0xe0,0xe0) : RGB(0xff,0xff,0xff);
if (bgcolor != filldown)
{
DeleteObject(bgbrush);
bgbrush = CreateSolidBrush(filldown);
}
bounds.top = bounds.bottom;
bounds.bottom = client.bottom;
FillRect(dc, &bounds, bgbrush);
}
DeleteObject(bgbrush);
}
else if (count > 0)
{
ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
}
}
// advance viewdata
viewdata += visarea.x;
}
// erase anything beyond the bottom with white
GetClientRect(m_wnd, &client);
client.top = visarea.y * metrics().debug_font_height();
FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
// prevent garbage from showing in the corner
if (show_hscroll)
{
client.top = client.bottom;
client.bottom = client.top + metrics().hscroll_height();
FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
// reset the font
SetBkMode(dc, oldbkmode);
@ -539,47 +575,48 @@ void debugview_info::draw_contents(HDC windc)
void debugview_info::update()
{
RECT bounds, vscroll_bounds, hscroll_bounds;
debug_view_xy totalsize, visiblesize, topleft;
bool show_vscroll, show_hscroll;
SCROLLINFO scrollinfo;
// get the updated total rows/cols and left row/col
debug_view_xy const totalsize = m_view->total_size();
debug_view_xy topleft = m_view->visible_position();
// get the view window bounds
RECT bounds;
GetClientRect(m_wnd, &bounds);
debug_view_xy visiblesize;
visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
// get the updated total rows/cols and left row/col
totalsize = m_view->total_size();
topleft = m_view->visible_position();
// determine if we need to show the scrollbars
show_vscroll = show_hscroll = false;
if (totalsize.x > visiblesize.x && bounds.bottom >= metrics().hscroll_height())
bool const fit_hscroll = (bounds.bottom - bounds.top) > metrics().hscroll_height();
bool show_hscroll = fit_hscroll && (totalsize.x > visiblesize.x);
if (show_hscroll)
{
bounds.bottom -= metrics().hscroll_height();
visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
show_hscroll = true;
}
if (totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
bool const fit_vscroll = (bounds.right - bounds.left) > metrics().vscroll_width();
bool const show_vscroll = fit_vscroll && (totalsize.y > visiblesize.y);
if (show_vscroll)
{
bounds.right -= metrics().vscroll_width();
visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
show_vscroll = true;
}
if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
{
bounds.right -= metrics().vscroll_width();
visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
show_vscroll = true;
if (fit_hscroll && !show_hscroll && (totalsize.x > visiblesize.x))
{
bounds.bottom -= metrics().hscroll_height();
visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
show_hscroll = true;
}
}
// compute the bounds of the scrollbars
RECT vscroll_bounds;
GetClientRect(m_wnd, &vscroll_bounds);
vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width();
if (show_hscroll)
vscroll_bounds.bottom -= metrics().hscroll_height();
RECT hscroll_bounds;
GetClientRect(m_wnd, &hscroll_bounds);
hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height();
if (show_vscroll)
@ -592,26 +629,34 @@ void debugview_info::update()
topleft.x = std::max(totalsize.x - visiblesize.x, 0);
// fill out the scroll info struct for the vertical scrollbar
scrollinfo.cbSize = sizeof(scrollinfo);
scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
scrollinfo.nMin = 0;
scrollinfo.nMax = totalsize.y - 1;
scrollinfo.nPage = visiblesize.y;
scrollinfo.nPos = topleft.y;
SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE);
if (m_vscroll)
{
scrollinfo.cbSize = sizeof(scrollinfo);
scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
scrollinfo.nMin = 0;
scrollinfo.nMax = totalsize.y - 1;
scrollinfo.nPage = visiblesize.y;
scrollinfo.nPos = topleft.y;
SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE);
}
// fill out the scroll info struct for the horizontal scrollbar
scrollinfo.cbSize = sizeof(scrollinfo);
scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
scrollinfo.nMin = 0;
scrollinfo.nMax = totalsize.x - 1;
scrollinfo.nPage = visiblesize.x;
scrollinfo.nPos = topleft.x;
SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE);
if (m_hscroll)
{
scrollinfo.cbSize = sizeof(scrollinfo);
scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
scrollinfo.nMin = 0;
scrollinfo.nMax = totalsize.x - 1;
scrollinfo.nPage = visiblesize.x;
scrollinfo.nPos = topleft.x;
SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE);
}
// update window info
visiblesize.y++;
visiblesize.x++;
if (((bounds.right - bounds.left) > (visiblesize.x * metrics().debug_font_width())) && ((topleft.x + visiblesize.x) < totalsize.x))
visiblesize.x++;
if (((bounds.bottom - bounds.top) > (visiblesize.y * metrics().debug_font_height())) && ((topleft.y + visiblesize.y) < totalsize.y))
visiblesize.y++;
m_view->set_visible_size(visiblesize);
m_view->set_visible_position(topleft);
@ -691,7 +736,7 @@ uint32_t debugview_info::process_scroll(WORD type, HWND wnd)
scrollinfo.nPos = result;
SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE);
return (uint32_t)result;
return uint32_t(result);
}
@ -864,10 +909,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
{
debug_view_xy topleft = m_view->visible_position();
debug_view_xy const topleft = m_view->visible_position();
debug_view_xy const visiblesize = m_view->visible_size();
debug_view_xy newpos;
newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width();
newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height();
newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0);
newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0);
m_view->process_click((message == WM_LBUTTONDOWN) ? DCK_LEFT_CLICK : DCK_MIDDLE_CLICK, newpos);
SetFocus(m_wnd);
break;
@ -877,10 +923,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
case WM_RBUTTONDOWN:
if (m_view->cursor_supported())
{
debug_view_xy topleft = m_view->visible_position();
debug_view_xy const topleft = m_view->visible_position();
debug_view_xy const visiblesize = m_view->visible_size();
debug_view_xy newpos;
newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width();
newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height();
newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0);
newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0);
m_view->set_cursor_position(newpos);
m_view->set_cursor_visible(true);
}

View File

@ -11,6 +11,8 @@
#include "debug/dvmemory.h"
#include "strconv.h"
memoryview_info::memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) :
debugview_info(debugger, owner, parent, DVT_MEMORY)
@ -71,3 +73,86 @@ void memoryview_info::set_physical(bool physical)
{
view<debug_view_memory>()->set_physical(physical);
}
void memoryview_info::add_items_to_context_menu(HMENU menu)
{
debugview_info::add_items_to_context_menu(menu);
AppendMenu(menu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
AppendMenu(menu, MF_GRAYED, ID_CONTEXT_LAST_PC, TEXT("Last PC"));
}
void memoryview_info::update_context_menu(HMENU menu)
{
debugview_info::update_context_menu(menu);
bool enable = false;
debug_view_memory &memview(*view<debug_view_memory>());
debug_view_memory_source const &source = downcast<debug_view_memory_source const &>(*memview.source());
address_space *const space = source.space();
if (space)
{
if (memview.cursor_visible())
{
// get the last known PC to write to this memory location
debug_view_xy const pos = memview.cursor_position();
offs_t const address = memview.addressAtCursorPosition(pos);
offs_t a = address & space->logaddrmask();
if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a))
{
m_lastpc = "Bad address";
}
else
{
uint64_t memval = space->unmap();
auto dis = space->device().machine().disable_side_effects();
switch (space->data_width())
{
case 8: memval = space->read_byte(a); break;
case 16: memval = space->read_word_unaligned(a); break;
case 32: memval = space->read_dword_unaligned(a); break;
case 64: memval = space->read_qword_unaligned(a); break;
}
offs_t const pc = source.device()->debug()->track_mem_pc_from_space_address_data(
space->spacenum(),
address,
memval);
if (pc != offs_t(-1))
{
m_lastpc = util::string_format("Address %x written at PC=%x", address, pc);
enable = true;
}
else
{
m_lastpc = "Unknown PC";
}
}
}
else
{
m_lastpc = "No address";
}
}
else
{
m_lastpc = "Not an address space";
}
ModifyMenuW(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND, ID_CONTEXT_LAST_PC, osd::text::to_wstring(m_lastpc).c_str());
EnableMenuItem(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED));
}
void memoryview_info::handle_context_menu(unsigned command)
{
switch (command)
{
case ID_CONTEXT_LAST_PC:
// TODO: copy to clipboard
return;
default:
debugview_info::handle_context_menu(command);
};
}

View File

@ -14,6 +14,8 @@
#include "debugviewinfo.h"
#include <string>
class memoryview_info : public debugview_info
{
@ -31,6 +33,19 @@ public:
void set_chunks_per_row(uint32_t rowchunks);
void set_reverse(bool reverse);
void set_physical(bool physical);
protected:
enum
{
ID_CONTEXT_LAST_PC = 101
};
virtual void add_items_to_context_menu(HMENU menu) override;
virtual void update_context_menu(HMENU menu) override;
virtual void handle_context_menu(unsigned command) override;
private:
std::string m_lastpc;
};
#endif // MAME_DEBUGGER_WIN_MEMORYVIEWINFO_H