From 41d35df1532cc1a4caea25300683340ae58d0962 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 6 May 2003 20:09:22 +0000 Subject: [PATCH] Implemented orphaned breakpoints to simplify debuggin of dynamic modules. --- ChangeLog | 4 ++ kdbg/brkpt.cpp | 22 ++++++--- kdbg/dbgdriver.h | 1 + kdbg/dbgmainwnd.cpp | 1 + kdbg/debugger.cpp | 127 +++++++++++++++++++++++++++++++++++++++++--------- kdbg/debugger.h | 7 ++- kdbg/pics/Makefile.am | 1 + kdbg/pics/brkorph.xpm | 19 ++++++++ kdbg/sourcewnd.cpp | 9 ++++ kdbg/sourcewnd.h | 5 +- 10 files changed, 164 insertions(+), 32 deletions(-) create mode 100644 kdbg/pics/brkorph.xpm diff --git a/ChangeLog b/ChangeLog index 99b0e14..e7be4d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ Version 1.9.0 Improved register formating by Daniel Kristjansson. + "Orphaned breakpoints", i.e. breakpoints that gdb cannot set + immediately, can be set. This helps debug shared libraries and + dynamically loaded modules. + Version 1.2.7 Fixed parsing of stack frames for recent gdbs. diff --git a/kdbg/brkpt.cpp b/kdbg/brkpt.cpp index 017276b..00c1ae7 100644 --- a/kdbg/brkpt.cpp +++ b/kdbg/brkpt.cpp @@ -170,7 +170,7 @@ void BreakpointTable::addBP() Breakpoint* bp = new Breakpoint; bp->text = bpText; - m_debugger->setBreakpoint(bp); + m_debugger->setBreakpoint(bp, false); } } @@ -184,7 +184,7 @@ void BreakpointTable::addWP() bp->type = Breakpoint::watchpoint; bp->text = wpExpr; - m_debugger->setBreakpoint(bp); + m_debugger->setBreakpoint(bp, false); } } @@ -197,6 +197,8 @@ void BreakpointTable::removeBP() Breakpoint* brk = m_debugger->breakpointById(bp->id); if (brk != 0) { m_debugger->deleteBreakpoint(brk); + // note that both brk and bp may be deleted by now + // (if bp was an orphaned breakpoint) } } @@ -345,16 +347,18 @@ void BreakpointTable::initListAndIcons() QPixmap watchdis = BarIcon("watchdis.xpm"); QPixmap brktmp = BarIcon("brktmp.xpm"); QPixmap brkcond = BarIcon("brkcond.xpm"); + QPixmap brkorph = BarIcon("brkorph.xpm"); /* - * There are 16 different pixmaps: The basic enabled or disabled + * There are 32 different pixmaps: The basic enabled or disabled * breakpoint, plus an optional overlaid brktmp icon plus an optional - * overlaid brkcond icon. Then the same sequence for watchpoints. + * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then + * the same sequence for watchpoints. */ - m_icons.setSize(16); + m_icons.setSize(32); QPixmap canvas(16,16); - for (int i = 0; i < 16; i++) { + for (int i = 0; i < 32; i++) { { QPainter p(&canvas); // clear canvas @@ -373,6 +377,10 @@ void BreakpointTable::initListAndIcons() if (i & 4) { p.drawPixmap(1,1, brkcond); } + // orphan overlay + if (i & 16) { + p.drawPixmap(1,1, brkorph); + } } canvas.setMask(canvas.createHeuristicMask()); m_icons[i] = canvas; @@ -391,6 +399,8 @@ void BreakpointItem::display() code += 4; if (type == watchpoint) code += 8; + if (isOrphaned()) + code += 16; setPixmap(0, lb->m_icons[code]); // more breakpoint info diff --git a/kdbg/dbgdriver.h b/kdbg/dbgdriver.h index 89a4c09..040b0e0 100644 --- a/kdbg/dbgdriver.h +++ b/kdbg/dbgdriver.h @@ -184,6 +184,7 @@ struct Breakpoint QString fileName; int lineNo; /* zero-based line number */ Breakpoint(); + bool isOrphaned() const { return id < 0; } }; /** diff --git a/kdbg/dbgmainwnd.cpp b/kdbg/dbgmainwnd.cpp index 119289e..c96ac34 100644 --- a/kdbg/dbgmainwnd.cpp +++ b/kdbg/dbgmainwnd.cpp @@ -129,6 +129,7 @@ DebuggerMainWnd::DebuggerMainWnd(const char* name) : m_filesWindow, SLOT(activate(const QString&,int,const DbgAddr&))); connect(m_debugger, SIGNAL(updateUI()), m_bpTable, SLOT(updateUI())); connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateBreakList())); + connect(m_debugger, SIGNAL(breakpointsChanged()), m_bpTable, SLOT(updateUI())); connect(m_debugger, SIGNAL(registersChanged(QList&)), m_registers, SLOT(updateRegisters(QList&))); diff --git a/kdbg/debugger.cpp b/kdbg/debugger.cpp index b403969..3b91dee 100644 --- a/kdbg/debugger.cpp +++ b/kdbg/debugger.cpp @@ -360,7 +360,7 @@ bool KDebugger::setBreakpoint(QString file, int lineNo, { bp->address = address; } - setBreakpoint(bp); + setBreakpoint(bp, false); } else { @@ -377,7 +377,7 @@ bool KDebugger::setBreakpoint(QString file, int lineNo, return true; } -void KDebugger::setBreakpoint(Breakpoint* bp) +void KDebugger::setBreakpoint(Breakpoint* bp, bool queueOnly) { CmdQueueItem* cmd; if (!bp->text.isEmpty()) @@ -400,13 +400,23 @@ void KDebugger::setBreakpoint(Breakpoint* bp) if (offset >= 0) { file.remove(0, offset+1); } - cmd = m_d->executeCmd(bp->temporary ? DCtbreakline : DCbreakline, - file, bp->lineNo); + if (queueOnly) { + cmd = m_d->queueCmd(bp->temporary ? DCtbreakline : DCbreakline, + file, bp->lineNo, DebuggerDriver::QMoverride); + } else { + cmd = m_d->executeCmd(bp->temporary ? DCtbreakline : DCbreakline, + file, bp->lineNo); + } } else { - cmd = m_d->executeCmd(bp->temporary ? DCtbreakaddr : DCbreakaddr, - bp->address.asString()); + if (queueOnly) { + cmd = m_d->queueCmd(bp->temporary ? DCtbreakaddr : DCbreakaddr, + bp->address.asString(), DebuggerDriver::QMoverride); + } else { + cmd = m_d->executeCmd(bp->temporary ? DCtbreakaddr : DCbreakaddr, + bp->address.asString()); + } } cmd->m_brkpt = bp; // used in newBreakpoint() } @@ -422,12 +432,20 @@ bool KDebugger::enableDisableBreakpoint(Breakpoint* bp) { /* * Toggle enabled/disabled state. + * + * The driver is not bothered if we are modifying an orphaned + * breakpoint. */ - if (canChangeBreakpoints()) { + if (!bp->isOrphaned()) { + if (!canChangeBreakpoints()) { + return false; + } m_d->executeCmd(bp->enabled ? DCdisable : DCenable, bp->id); - return true; + } else { + bp->enabled = !bp->enabled; + emit breakpointsChanged(); } - return false; + return true; } bool KDebugger::conditionalBreakpoint(Breakpoint* bp, @@ -436,10 +454,16 @@ bool KDebugger::conditionalBreakpoint(Breakpoint* bp, { /* * Change the condition and ignore count. + * + * The driver is not bothered if we are removing an orphaned + * breakpoint. */ - if (canChangeBreakpoints()) - { + if (!bp->isOrphaned()) { + if (!canChangeBreakpoints()) { + return false; + } + bool changed = false; if (bp->condition != condition) { @@ -456,19 +480,33 @@ bool KDebugger::conditionalBreakpoint(Breakpoint* bp, // get the changes m_d->queueCmd(DCinfobreak, DebuggerDriver::QMoverride); } - return true; + } else { + bp->condition = condition; + bp->ignoreCount = ignoreCount; + emit breakpointsChanged(); } - return false; + return true; } bool KDebugger::deleteBreakpoint(Breakpoint* bp) { /* * Remove the breakpoint. + * + * The driver is not bothered if we are removing an orphaned + * breakpoint. */ - if (canChangeBreakpoints()) { + if (!bp->isOrphaned()) { + if (!canChangeBreakpoints()) { + return false; + } m_d->executeCmd(DCdelete, bp->id); - return true; + } else { + // move the last entry to bp's slot and shorten the list + int i = m_brkpts.findRef(bp); + m_brkpts.insert(i, m_brkpts.take(m_brkpts.size()-1)); + m_brkpts.resize(m_brkpts.size()-1); + emit breakpointsChanged(); } return false; } @@ -860,7 +898,7 @@ void KDebugger::restoreBreakpoints(KSimpleConfig* config) /* * Add the breakpoint. */ - setBreakpoint(bp); + setBreakpoint(bp, false); // the new breakpoint is disabled or conditionalized later // in newBreakpoint() } @@ -1052,6 +1090,19 @@ void KDebugger::handleRunCommands(const char* output) emit executableUpdated(); } + /* + * Try to set any orphaned breakpoints now. + */ + for (int i = m_brkpts.size()-1; i >= 0; i--) { + if (m_brkpts[i]->isOrphaned()) { + TRACE("re-trying brkpt loc: "+m_brkpts[i]->location+ + " file: "+m_brkpts[i]->fileName+ + QString().sprintf(" line: %d", m_brkpts[i]->lineNo)); + setBreakpoint(m_brkpts[i], true); + flags |= DebuggerDriver::SFrefreshBreak; + } + } + /* * If we stopped at a breakpoint, we must update the breakpoint list * because the hit count changes. Also, if the breakpoint was temporary @@ -1804,6 +1855,11 @@ void KDebugger::handleRegisters(const char* output) /* * The output of the DCbreak* commands has more accurate information about * the file and the line number. + * + * All newly set breakpoints are inserted in the m_brkpts, even those that + * were not set sucessfully. The unsuccessful breakpoints ("orphaned + * breakpoints") are assigned negative ids, and they are tried to set later + * when the program stops again at a breakpoint. */ void KDebugger::newBreakpoint(CmdQueueItem* cmd, const char* output) { @@ -1812,23 +1868,46 @@ void KDebugger::newBreakpoint(CmdQueueItem* cmd, const char* output) if (bp == 0) return; + // if this is a new breakpoint, put it in the list + bool isNew = !m_brkpts.contains(bp); + if (isNew) { + assert(bp->id == 0); + int n = m_brkpts.size(); + m_brkpts.resize(n+1); + m_brkpts.insert(n, bp); + } + + // parse the output to determine success or failure int id; QString file; int lineNo; QString address; if (!m_d->parseBreakpoint(output, id, file, lineNo, address)) { - delete cmd->m_brkpt; + /* + * Failure, the breakpoint could not be set. If this is a new + * breakpoint, assign it a negative id. We look for the minimal id + * of all breakpoints (that are already in the list) to get the new + * id. + */ + if (isNew) + { + assert(bp->id == 0); + for (int i = m_brkpts.size()-2; i >= 0; i--) { + if (m_brkpts[i]->id < bp->id) { + bp->id = m_brkpts[i]->id; + break; + } + } + --bp->id; + } return; } // The breakpoint was successfully set. + if (bp->id <= 0) { - // add it - int n = m_brkpts.size(); - m_brkpts.resize(n+1); - m_brkpts.insert(n, cmd->m_brkpt); - + // this is a new or orphaned breakpoint: // set the remaining properties if (!cmd->m_brkpt->enabled) { m_d->executeCmd(DCdisable, id); @@ -1856,6 +1935,10 @@ void KDebugger::updateBreakList(const char* output) for (int i = m_brkpts.size()-1; i >= 0; i--) // decrement! { + // skip orphaned breakpoints + if (m_brkpts[i]->id < 0) + continue; + for (Breakpoint* bp = brks.first(); bp != 0; bp = brks.next()) { if (bp->id == m_brkpts[i]->id) { diff --git a/kdbg/debugger.h b/kdbg/debugger.h index bfc7fc4..590e749 100644 --- a/kdbg/debugger.h +++ b/kdbg/debugger.h @@ -178,8 +178,9 @@ public: * Set a breakpoint. * * @param bp Describes the breakpoint. + * @param queueOnly If false, the breakpoint is set using a high-priority command. */ - void setBreakpoint(Breakpoint* bp); + void setBreakpoint(Breakpoint* bp, bool queueOnly); /** * Enable or disable a breakpoint at the specified location. @@ -202,7 +203,9 @@ public: bool enableDisableBreakpoint(Breakpoint* bp); /** - * Removes the specified breakpoint. + * Removes the specified breakpoint. Note that if bp is an orphaned + * breakpoint, then bp is an invalid pointer if (and only if) this + * function returns true. * * @return false if the command was not executed, e.g. because the * debuggee is running at the moment. diff --git a/kdbg/pics/Makefile.am b/kdbg/pics/Makefile.am index 32a3849..7fcaf14 100644 --- a/kdbg/pics/Makefile.am +++ b/kdbg/pics/Makefile.am @@ -19,6 +19,7 @@ PICTOGRAMS = \ brkdis.xpm \ brktmp.xpm \ brkcond.xpm \ + brkorph.xpm \ pcinner.xpm \ pcup.xpm \ regs.xpm \ diff --git a/kdbg/pics/brkorph.xpm b/kdbg/pics/brkorph.xpm new file mode 100644 index 0000000..52704af --- /dev/null +++ b/kdbg/pics/brkorph.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * brkorph_xpm[] = { +"14 14 2 1", +" c None", +". c #563131", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" .. .. ", +" ... ... ", +" ..... ", +" ... ", +" ..... ", +" ... ... ", +" .. .. "}; diff --git a/kdbg/sourcewnd.cpp b/kdbg/sourcewnd.cpp index 03d9688..9f59009 100644 --- a/kdbg/sourcewnd.cpp +++ b/kdbg/sourcewnd.cpp @@ -32,6 +32,7 @@ SourceWindow::SourceWindow(const char* fileName, QWidget* parent, const char* na m_brkdis = BarIcon("brkdis"); m_brktmp = BarIcon("brktmp"); m_brkcond = BarIcon("brkcond"); + m_brkorph = BarIcon("brkorph"); setFont(KGlobalSettings::fixedFont()); } @@ -229,6 +230,12 @@ void SourceWindow::paintCell(QPainter* p, int row, int col) if (y < 0) y = 0; p->drawPixmap(0,y,m_brkcond); } + if (item & liBPorphan) { + // orphaned breakpoint marker + int y = (h - m_brkcond.height())/2; + if (y < 0) y = 0; + p->drawPixmap(0,y,m_brkorph); + } if (item & liPC) { // program counter in innermost frame int y = (h - m_pcinner.height())/2; @@ -298,6 +305,8 @@ void SourceWindow::updateLineItems(const KDebugger* dbg) flags |= liBPtemporary; if (!bp->condition.isEmpty() || bp->ignoreCount != 0) flags |= liBPconditional; + if (bp->isOrphaned()) + flags |= liBPorphan; // update if changed int row = lineToRow(i, bp->address); if ((m_lineItems[row] & liBPany) != flags) { diff --git a/kdbg/sourcewnd.h b/kdbg/sourcewnd.h index c814da7..300f1b8 100644 --- a/kdbg/sourcewnd.h +++ b/kdbg/sourcewnd.h @@ -78,8 +78,8 @@ protected: QString m_fileName; enum LineItem { liPC = 1, liPCup = 2, liBP = 4, liBPdisabled = 8, liBPtemporary = 16, - liBPconditional = 32, - liBPany = liBP|liBPdisabled|liBPtemporary|liBPconditional + liBPconditional = 32, liBPorphan = 64, + liBPany = liBP|liBPdisabled|liBPtemporary|liBPconditional|liBPorphan }; struct SourceLine { @@ -100,6 +100,7 @@ protected: QPixmap m_brkdis; /* disabled breakpoint */ QPixmap m_brktmp; /* temporary breakpoint marker */ QPixmap m_brkcond; /* conditional breakpoint marker */ + QPixmap m_brkorph; /* orphaned breakpoint marker */ }; #endif // SOURCEWND_H -- 2.11.4.GIT