You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/languages/cpp/debugger/gdbcontroller.h

359 lines
12 KiB

/***************************************************************************
gdbcontroller.h - description
-------------------
begin : Sun Aug 8 1999
copyright : (C) 1999 by John Birch
email : jbb@kdevelop.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef _GDBCONTROLLER_H_
#define _GDBCONTROLLER_H_
#include "dbgcontroller.h"
#include "mi/gdbmi.h"
#include "mi/miparser.h"
#include <qcstring.h>
#include <qdom.h>
#include <qobject.h>
#include <qptrlist.h>
#include <qstring.h>
#include <qmap.h>
#include <qdatetime.h>
#include <memory>
#include <set>
class KProcess;
namespace GDBDebugger
{
class Breakpoint;
class DbgCommand;
class GDBCommand;
class VarItem;
class STTY;
/**
* A front end implementation to the gdb command line debugger
* @author jbb
*/
class GDBController : public DbgController
{
Q_OBJECT
public:
GDBController(QDomDocument &projectDom);
~GDBController();
enum event_t { program_state_changed = 1, program_exited, debugger_exited,
thread_or_frame_changed, debugger_busy, debugger_ready,
shared_library_loaded,
// Raised when debugger believe that program start running.
// Can be used to hide current line indicator.
// Don't count on this being raise in all cases where
// program is running.
program_running,
connected_to_program
};
/** Adds a command to the end of queue of commands to be executed
by gdb. The command will be actually sent to gdb only when
replies from all previous commands are received and full processed.
The literal command sent to gdb is obtained by calling
cmd->cmdToSend. The call is made immediately before sending the
command, so it's possible to use results of prior commands when
computing the exact command to send.
*/
void addCommand(GDBCommand* cmd);
/** Same as above, but internally constructs new GDBCommand
instance from the string. */
void addCommand(const QString& cmd);
/** Adds command to the front of the commands queue. It will be executed
next.
This is usefull to implement 'atomic' command sequences. For example,
if one wants to switch to each thread in turn, asking gdb where that
thread stand, this should never be interrupted by other command, since
other commands might not expect that thread magically changes.
In this specific case, first -thread-list-ids commands is issued. The
handler for reply will add a number of command to front, and it will
guarantee that no other command will get in between.
Note that if you call:
addCommandToFront(cmd1);
addCommandToFront(cmd2);
The execution order will be 'cmd2', then 'cmd1'.
FIXME: is not used for now, maybe remove.
*/
void addCommandToFront(GDBCommand* cmd);
/* If current command queue has any command
for which isRun is true, inserts 'cmd'
before the first such command. Otherwise,
works the same as addCommand. */
void addCommandBeforeRun(GDBCommand* cmd);
/** Selects the specified thread/frame. Immediately emits
thread_or_frame_changed event.
*/
void selectFrame(int frameNo, int threadNo);
/** Returns the numerical identfier of the current thread,
or -1 if the program is not threaded (i.e. there's just
one thread.
*/
int currentThread() const;
int currentFrame() const;
bool start(const QString& shell,
const DomUtil::PairList& run_envvars,
const QString& run_directory,
const QString &application,
const QString& run_arguments);
int qtVersion() const;
/**
* Call this when something very interesting happens that the user
* might be unaware of. It will make KDevelop's taskbar entry flash
* if the application doesn't already have focus.
* Typical use case: The debugger has stopped on a breakpoint.
*/
void demandAttention() const;
void pauseApp();
bool miPendingBreakpoints() const;
protected:
enum queue_where { queue_at_end, queue_at_front, queue_before_run };
void queueCmd(GDBCommand *cmd, enum queue_where queue_where = queue_at_end);
private:
void parseLocals (char type, char *buf);
/** Parses the CLI output line, and catches interesting messages
like "Program exited". This is intended to allow using console
commands in the gdb window despite the fact that GDB does not
produce right MI notification for CLI commands. I.e. if you
run "continue" there will be no MI message if the application has
exited.
*/
void parseCliLine (const QString&);
/** Handles a result response from a MI command -- that is
all MI responses except for Stream and Prompt responses.
Uses currentCmd to decide what to do with response and
calls appropriate method.
*/
void processMICommandResponse(const GDBMI::ResultRecord& r);
void handleMiFileListExecSourceFile(const GDBMI::ResultRecord& r);
/** Handles reply from -stack-info-frame command issues
after switching the stack frame.
*/
void handleMiFrameSwitch(const GDBMI::ResultRecord& r);
void executeCmd ();
void destroyCmds();
void removeInfoRequests();
void actOnProgramPauseMI(const GDBMI::ResultRecord& mi_record);
/** Called when there are no pending commands and 'state_reload_needed'
is true.
Issues commands to completely reload all program state shown
to the user.
*/
void reloadProgramState();
void programNoApp(const QString &msg, bool msgBox);
void setStateOn(int stateOn);
void setStateOff(int stateOff);
void setState(int newState);
void debugStateChange(int oldState, int newState);
void commandDone();
void destroyCurrentCommand();
/** Removes all 'stateReloading' commands from the queue.
*/
void removeStateReloadingCommands();
/** Raises the specified event. Should be used instead of
emitting 'event' directly, since this method can perform
additional book-keeping for events.
*/
void raiseEvent(event_t e);
void maybeAnnounceWatchpointHit();
void handleListFeatures(const GDBMI::ResultRecord& result);
void startDone();
/** Default handler for errors.
Tries to guess is the error message is telling that target is
gone, if so, informs the user.
Otherwise, shows a dialog box and reloads view state. */
void defaultErrorHandler(const GDBMI::ResultRecord& result);
public:
bool stateIsOn(int state);
public slots:
void configure();
//void slotStart(const QString& shell, const QString &application);
void slotCoreFile(const QString &coreFile);
void slotAttachTo(int pid);
void slotStopDebugger();
void slotRun();
void slotKill();
void slotRunUntil(const QString &filename, int lineNum);
void slotJumpTo(const QString &filename, int lineNum);
void slotStepInto();
void slotStepOver();
void slotStepIntoIns();
void slotStepOverIns();
void slotStepOutOff();
void slotBreakInto();
void slotUserGDBCmd(const QString&);
// Pops up a dialog box with some hopefully
// detailed information about which state debugger
// is in, which commands were sent and so on.
void explainDebuggerStatus();
protected slots:
void slotDbgStdout(KProcess *proc, char *buf, int buflen);
void slotDbgStderr(KProcess *proc, char *buf, int buflen);
void slotDbgWroteStdin(KProcess *proc);
void slotDbgProcessExited(KProcess *proc);
signals:
/** This signal is emitted whenever the given event in a program
happens. See DESIGN.txt for expected handled of each event.
NOTE: this signal should never be emitted directly. Instead,
use raiseEvent.
*/
void event(GDBController::event_t e);
void debuggerAbnormalExit();
/** Emitted immediately after breakpoint is hit, before any commands
are sent and before current line indicator is shown. */
void breakpointHit(int id);
/** Emitted for watchpoint hit, after line indicator is shown. */
void watchpointHit(int id,
const QString& oldValue, const QString& newValue);
private:
int currentFrame_;
int viewedThread_;
// The output from gdb that was not parsed yet
QCString gdbOutput_;
// The output from gdb that arrived where we was
// parsing the previous output. To avoid messing
// things up, it's not directly added to
// gdbOutput_ but stored for future use.
// VP: It's not clear why the previous code was doing
// this, and holdingZone_ won't be processed until
// next output arrives, so probably should be just removed.
QCString holdingZone_;
QPtrList<GDBCommand> cmdList_;
GDBCommand* currentCmd_;
STTY* tty_;
QString badCore_;
QString application_;
// Gdb command that should be issued when we stop on breakpoint
// with the given gdb breakpoint id.
QMap<int, const Breakpoint*> tracedBreakpoints_;
// Some state variables
int state_;
bool programHasExited_;
// Configuration values
QDomDocument &dom;
bool config_breakOnLoadingLibrary_;
bool config_forceBPSet_;
bool config_displayStaticMembers_;
bool config_asmDemangle_;
bool config_dbgTerminal_;
QString config_gdbPath_;
QString config_dbgShell_;
QCString config_configGdbScript_;
QCString config_runShellScript_;
QCString config_runGdbScript_;
int config_outputRadix_;
MIParser mi_parser_;
// As of gdb 6.3, the *stopped packet does not contain
// full file name. So we need to send another command to
// fetch that, to highlight current line.
// After highting current line we need to do something more,
// like announcing write watchpoints, and so need to have
// access to the stop packet. So store it here.
std::auto_ptr<GDBMI::ResultRecord> last_stop_result;
// Gdb 6.4 (and 6.3) does not support "character" format with MI,
// so the only way it can work is via the "print" command. As gdb
// outputs things, we'll grep for lines that look like output from
// print, and store such lines in this variable, so later use.
QCString print_command_result;
bool state_reload_needed;
QTime commandExecutionTime;
bool stateReloadInProgress_;
/** Commands issues as result of the 'program_state_changed'
event. */
std::set<GDBCommand*> stateReloadingCommands_;
bool saw_gdb_prompt_;
/** Does the used GDB supports pending breakpoints in MI? */
bool mi_pending_breakpoints_;
};
}
#endif