Commit 62137283 authored by Peifeng Yu's avatar Peifeng Yu
Browse files

Merge branch 'master' into peifeng/lldb-plugin

parents 17b7b0dc 72388379
......@@ -79,11 +79,17 @@ add_definitions(
# Turn off missing-field-initializers warning to avoid noise from false positives with empty {}
# See discussion: http://mail.kde.org/pipermail/kdevelop-devel/2014-February/046910.html
if (CMAKE_COMPILER_IS_GNUCXX)
check_cxx_compiler_flag(-Wno-missing-field-initializers HAVE_MFI_FLAG)
check_cxx_compiler_flag(-Werror=undefined-bool-conversion HAVE_UBC_FLAG)
check_cxx_compiler_flag(-Werror=tautological-undefined-compare HAVE_TUC_FLAG)
if (HAVE_MFI_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=undefined-bool-conversion -Werror=tautological-undefined-compare")
if (HAVE_UBC_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=undefined-bool-conversion")
endif()
if (HAVE_TUC_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=tautological-undefined-compare")
endif()
include_directories(${KDevelop_SOURCE_DIR} ${KDevelop_BINARY_DIR} )
......
......@@ -14,6 +14,7 @@
***************************************************************************/
#include "micommand.h"
#include <QDateTime>
using namespace KDevMI::MI;
......@@ -604,3 +605,33 @@ bool MICommand::stateReloading() const
{
return stateReloading_;
}
void MICommand::markAsEnqueued()
{
m_enqueueTimestamp = QDateTime::currentMSecsSinceEpoch();
}
void MICommand::markAsSubmitted()
{
m_submitTimestamp = QDateTime::currentMSecsSinceEpoch();
}
void MICommand::markAsCompleted()
{
m_completeTimestamp = QDateTime::currentMSecsSinceEpoch();
}
qint64 MICommand::gdbProcessingTime() const
{
return m_completeTimestamp - m_submitTimestamp;
}
qint64 MICommand::queueTime() const
{
return m_submitTimestamp - m_enqueueTimestamp;
}
qint64 MICommand::totalProcessingTime() const
{
return m_completeTimestamp - m_enqueueTimestamp;
}
......@@ -195,6 +195,26 @@ public:
bool stateReloading() const;
/// Called when the command has been enqueued in the debug session
/// and the command is wait for being submitted to GDB.
void markAsEnqueued();
/// Called when the command has been submitted to GDB and the command
/// waits for completion by GDB.
void markAsSubmitted();
/// Called when the command has been completed and the response has arrived.
void markAsCompleted();
/// returns the amount of time (in ms) passed between submission and completion.
qint64 gdbProcessingTime() const;
/// returns the amount of time (in ms) passed between enqueuing and submission.
qint64 queueTime() const;
/// returns the amount of time (in ms) passed between enqueuing and completion.
qint64 totalProcessingTime() const;
protected:
CommandType type_;
CommandFlags flags_;
......@@ -206,6 +226,13 @@ protected:
int m_thread;
int m_frame;
// remember the timestamps (in ms since start of the epoch) when this command
// - was added to the command queue (enqueued)
// - was submitted to GDB
// - was completed; response from GDB arrived
qint64 m_enqueueTimestamp;
qint64 m_submitTimestamp;
qint64 m_completeTimestamp;
};
class UserCommand : public MICommand
......
......@@ -19,6 +19,7 @@
#include "mi.h"
#include "micommand.h"
#include "debuglog.h"
using namespace KDevMI::MI;
......@@ -39,19 +40,38 @@ void CommandQueue::enqueue(MICommand* command)
m_tokenCounter = 1;
command->setToken(m_tokenCounter);
// take the time when this command was added to the command queue
command->markAsEnqueued();
m_commandList.append(command);
if (command->flags() & (CmdImmediately | CmdInterrupt))
++m_immediatelyCounter;
rationalizeQueue(command);
dumpQueue();
}
void CommandQueue::dumpQueue()
{
qCDebug(DEBUGGERCOMMON) << "Pending commands" << m_commandList.count();
unsigned commandNum = 0;
foreach(const MICommand* command, m_commandList) {
qCDebug(DEBUGGERCOMMON) << "Command" << commandNum << command->initialString();
++commandNum;
}
}
void CommandQueue::rationalizeQueue(MICommand * command)
void CommandQueue::rationalizeQueue(MICommand* command)
{
if (command->type() >= ExecAbort && command->type() <= ExecUntil)
// Changing execution location, abort any variable updates
removeVariableUpdates();
if ((command->type() >= ExecAbort && command->type() <= ExecUntil) &&
command->type() != ExecArguments &&
command->type() != ExecShowArguments ) {
// Changing execution location, abort any variable updates
removeVariableUpdates();
// ... and stack list updates
removeStackListUpdates();
}
}
void CommandQueue::removeVariableUpdates()
......@@ -70,6 +90,22 @@ void CommandQueue::removeVariableUpdates()
}
}
void CommandQueue::removeStackListUpdates()
{
QMutableListIterator<MICommand*> it = m_commandList;
while (it.hasNext()) {
MICommand* command = it.next();
CommandType type = command->type();
if (type >= StackListArguments && type <= StackListLocals) {
if (command->flags() & (CmdImmediately | CmdInterrupt))
--m_immediatelyCounter;
it.remove();
delete command;
}
}
}
void CommandQueue::clear()
{
qDeleteAll(m_commandList);
......
......@@ -49,6 +49,8 @@ public:
private:
void rationalizeQueue(MICommand* command);
void removeVariableUpdates();
void removeStackListUpdates();
void dumpQueue();
QList<MICommand*> m_commandList;
int m_immediatelyCounter = 0;
......
......@@ -81,6 +81,7 @@ void MIDebugger::execute(MICommand* command)
QByteArray commandUtf8 = commandText.toUtf8();
process_->write(commandUtf8, commandUtf8.length());
command->markAsSubmitted();
QString prettyCmd = currentCmd_->cmdToSend();
prettyCmd.remove( QRegExp("set prompt \032.\n") );
......@@ -183,12 +184,22 @@ void MIDebugger::processLine(const QByteArray& line)
} else {
qCDebug(DEBUGGERCOMMON) << "Result token is" << result.token;
Q_ASSERT(currentCmd_->token() == result.token);
currentCmd_->markAsCompleted();
qCDebug(DEBUGGERCOMMON) << "Command successful, times "
<< currentCmd_->totalProcessingTime()
<< currentCmd_->queueTime()
<< currentCmd_->gdbProcessingTime();
currentCmd_->invokeHandler(result);
}
}
else if (result.reason == "error")
{
qCDebug(DEBUGGERCOMMON) << "Handling error";
currentCmd_->markAsCompleted();
qCDebug(DEBUGGERCOMMON) << "Command error, times"
<< currentCmd_->totalProcessingTime()
<< currentCmd_->queueTime()
<< currentCmd_->gdbProcessingTime();
// Some commands want to handle errors themself.
if (currentCmd_->handlesError() &&
currentCmd_->invokeHandler(result))
......
......@@ -798,7 +798,8 @@ void MIDebugSession::queueCmd(MICommand *cmd)
m_commandQueue->enqueue(cmd);
qCDebug(DEBUGGERCOMMON) << "QUEUE: " << cmd->initialString()
<< (m_stateReloadInProgress ? "(state reloading)" : "");
<< (m_stateReloadInProgress ? "(state reloading)" : "")
<< m_commandQueue->count() << "pending";
bool varCommandWithContext= (cmd->type() >= MI::VarAssign
&& cmd->type() <= MI::VarUpdate
......
......@@ -162,10 +162,10 @@ int STTY::findTTY()
#ifdef __sgi__
ptyfd = open("/dev/ptmx",O_RDWR);
#elif defined(Q_OS_MAC)
#elif defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
ptyfd = posix_openpt(O_RDWR);
#endif
#if defined(__sgi__) || defined(Q_OS_MAC)
#if defined(__sgi__) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
if (ptyfd == -1) {
perror("Can't open a pseudo teletype");
return(-1);
......@@ -178,7 +178,7 @@ int STTY::findTTY()
#endif
// first we try UNIX PTY's
#ifdef TIOCGPTN
#if defined(TIOCGPTN) && !defined(Q_OS_FREEBSD)
strcpy(pty_master,"/dev/ptmx");
strcpy(tty_slave,"/dev/pts/");
ptyfd = open(pty_master,O_RDWR);
......
......@@ -258,7 +258,7 @@ void DebugSession::handleVersion(const QStringList& s)
}
}
void DebugSession::handleFileExecAndSymbols(const MI::ResultRecord& r)
void DebugSession::handleFileExecAndSymbols(const ResultRecord& r)
{
if (r.reason == "error") {
KMessageBox::error(
......
......@@ -113,6 +113,42 @@ DisassembleWindow::DisassembleWindow(QWidget *parent, DisassembleWidget* widget)
m_runUntilCursor = new QAction(QIcon::fromTheme("debug-run-cursor"), i18n("&Run to Cursor"), this);
m_runUntilCursor->setWhatsThis(i18n("Continues execution until the cursor position is reached."));
connect(m_runUntilCursor,&QAction::triggered, widget, &DisassembleWidget::runToCursor);
m_disassemblyFlavorAtt = new QAction(i18n("&AT&&T"), this);
m_disassemblyFlavorAtt->setToolTip(i18n("GDB will use the AT&T disassembly flavor (e.g. mov 0xc(%ebp),%eax)."));
m_disassemblyFlavorAtt->setData(DisassemblyFlavorATT);
m_disassemblyFlavorAtt->setCheckable(true);
m_disassemblyFlavorIntel = new QAction(i18n("&Intel"), this);
m_disassemblyFlavorIntel->setToolTip(i18n("GDB will use the Intel disassembly flavor (e.g. mov eax, DWORD PTR [ebp+0xc])."));
m_disassemblyFlavorIntel->setData(DisassemblyFlavorIntel);
m_disassemblyFlavorIntel->setCheckable(true);
m_disassemblyFlavorActionGroup = new QActionGroup(this);
m_disassemblyFlavorActionGroup->setExclusive(true);
m_disassemblyFlavorActionGroup->addAction(m_disassemblyFlavorAtt);
m_disassemblyFlavorActionGroup->addAction(m_disassemblyFlavorIntel);
connect(m_disassemblyFlavorActionGroup, &QActionGroup::triggered, widget, &DisassembleWidget::setDisassemblyFlavor);
}
}
void DisassembleWindow::setDisassemblyFlavor(DisassemblyFlavor flavor)
{
switch(flavor)
{
default:
case DisassemblyFlavorUnknown:
m_disassemblyFlavorAtt->setChecked(false);
m_disassemblyFlavorIntel->setChecked(false);
break;
case DisassemblyFlavorATT:
m_disassemblyFlavorAtt->setChecked(true);
m_disassemblyFlavorIntel->setChecked(false);
break;
case DisassemblyFlavorIntel:
m_disassemblyFlavorAtt->setChecked(false);
m_disassemblyFlavorIntel->setChecked(true);
break;
}
}
......@@ -122,6 +158,9 @@ void DisassembleWindow::contextMenuEvent(QContextMenuEvent *e)
popup.addAction(m_selectAddrAction);
popup.addAction(m_jumpToLocation);
popup.addAction(m_runUntilCursor);
QMenu* disassemblyFlavorMenu = popup.addMenu(i18n("Disassembly flavor"));
disassemblyFlavorMenu->addAction(m_disassemblyFlavorAtt);
disassemblyFlavorMenu->addAction(m_disassemblyFlavorIntel);
popup.exec(e->globalPos());
}
/***************************************************************************/
......@@ -282,6 +321,7 @@ void DisassembleWidget::slotActivate(bool activate)
active_ = activate;
if (active_)
{
updateDisassemblyFlavor();
m_registersManager->updateRegisters();
if (!displayCurrent())
disassembleMemoryRegion();
......@@ -435,3 +475,64 @@ void DisassembleWidget::update(const QString &address)
}
m_registersManager->updateRegisters();
}
void DisassembleWidget::setDisassemblyFlavor(QAction* action)
{
DebugSession* s = qobject_cast<DebugSession*>(KDevelop::ICore::
self()->debugController()->currentSession());
if(!s || !s->isRunning()) {
return;
}
DisassemblyFlavor disassemblyFlavor = static_cast<DisassemblyFlavor>(action->data().toInt());
QString cmd;
switch(disassemblyFlavor)
{
default:
// unknown flavor, do not build a GDB command
break;
case DisassemblyFlavorATT:
cmd = QStringLiteral("disassembly-flavor att");
break;
case DisassemblyFlavorIntel:
cmd = QStringLiteral("disassembly-flavor intel");
break;
}
qCDebug(DEBUGGERGDB) << "Disassemble widget set " << cmd;
if (!cmd.isEmpty()) {
s->addCommand(GdbSet, cmd, this, &DisassembleWidget::setDisassemblyFlavorHandler);
}
}
void DisassembleWidget::setDisassemblyFlavorHandler(const ResultRecord& r)
{
if (r.reason == "done" && active_) {
disassembleMemoryRegion();
}
}
void DisassembleWidget::updateDisassemblyFlavor()
{
DebugSession* s = qobject_cast<DebugSession*>(KDevelop::ICore::
self()->debugController()->currentSession());
if(!s || !s->isRunning()) {
return;
}
s->addCommand(GdbShow, QStringLiteral("disassembly-flavor"), this, &DisassembleWidget::showDisassemblyFlavorHandler);
}
void DisassembleWidget::showDisassemblyFlavorHandler(const ResultRecord& r)
{
const Value& value = r["value"];
qCDebug(DEBUGGERGDB) << "Disassemble widget disassembly flavor" << value.literal();
DisassemblyFlavor disassemblyFlavor = DisassemblyFlavorUnknown;
if (value.literal() == "att") {
disassemblyFlavor = DisassemblyFlavorATT;
} else if (value.literal() == "intel") {
disassemblyFlavor = DisassemblyFlavorIntel;
}
m_disassembleWindow->setDisassemblyFlavor(disassemblyFlavor);
}
......@@ -52,27 +52,35 @@ class SelectAddressDialog : public QDialog
Q_OBJECT
public:
SelectAddressDialog(QWidget *parent = 0);
QString address() const;
void setAddress(const QString& address);
bool hasValidAddress() const;
void updateOkState();
private Q_SLOTS:
void validateInput();
void itemSelected();
private:
Ui::SelectAddressDialog m_ui;
};
class DisassembleWidget;
enum DisassemblyFlavor {
DisassemblyFlavorUnknown = -1,
DisassemblyFlavorATT = 0,
DisassemblyFlavorIntel,
};
class DisassembleWindow : public QTreeWidget
{
public:
DisassembleWindow(QWidget *parent, DisassembleWidget* widget);
void setDisassemblyFlavor(DisassemblyFlavor flavor);
protected:
void contextMenuEvent(QContextMenuEvent *e) override;
......@@ -80,6 +88,9 @@ private:
QAction* m_selectAddrAction;
QAction* m_jumpToLocation;
QAction* m_runUntilCursor;
QAction* m_disassemblyFlavorAtt;
QAction* m_disassemblyFlavorIntel;
QActionGroup* m_disassemblyFlavorActionGroup;
};
class Breakpoint;
......@@ -115,6 +126,7 @@ public Q_SLOTS:
void update(const QString &address);
void jumpToCursor();
void runToCursor();
void setDisassemblyFlavor(QAction* action);
private Q_SLOTS:
void currentSessionChanged(KDevelop::IDebugSession* session);
......@@ -126,7 +138,8 @@ protected:
private:
bool displayCurrent();
void updateDisassemblyFlavor();
/// Disassembles memory region from..to
/// if from is empty current execution position is used
/// if to is empty, 256 bytes range is taken
......@@ -136,6 +149,8 @@ private:
/// callbacks for GDBCommands
void disassembleMemoryHandler(const MI::ResultRecord& r);
void updateExecutionAddressHandler(const MI::ResultRecord& r);
void setDisassemblyFlavorHandler(const MI::ResultRecord& r);
void showDisassemblyFlavorHandler(const MI::ResultRecord& r);
//for str to uint conversion.
bool ok;
......
......@@ -326,7 +326,7 @@ void GDBOutputWidget::flushPending()
/***************************************************************************/
void GDBOutputWidget::slotStateChanged(DBGStateFlags oldStatus, DBGStateFlags newStatus)
void GDBOutputWidget::slotStateChanged(KDevMI::DBGStateFlags oldStatus, KDevMI::DBGStateFlags newStatus)
{
Q_UNUSED(oldStatus)
if (newStatus & s_dbgNotStarted)
......
......@@ -147,6 +147,7 @@ void MemoryView::slotStateChanged(DBGStateFlags oldState, DBGStateFlags newState
void MemoryView::initWidget()
{
QVBoxLayout *l = new QVBoxLayout(this);
l->setContentsMargins(0, 0, 0, 0);
khexedit2_widget = KHE::createBytesEditWidget(this);
if (!khexedit2_widget)
......@@ -230,9 +231,11 @@ void MemoryView::slotChangeMemoryRange()
KDevelop::ICore::self()->debugController()->currentSession());
if (!session) return;
session->addCommand(new ExpressionValueCommand(
rangeSelector_->amountLineEdit->text(),
this, &MemoryView::sizeComputed));
QString amount = rangeSelector_->amountLineEdit->text();
if(amount.isEmpty())
amount = QString("sizeof(%1)").arg(rangeSelector_->startAddressLineEdit->text());
session->addCommand(new ExpressionValueCommand(amount, this, &MemoryView::sizeComputed));
}
void MemoryView::sizeComputed(const QString& size)
......@@ -457,9 +460,7 @@ void MemoryView::slotEnableOrDisable()
{
bool app_started = !(debuggerState_ & s_appNotStarted);
bool enabled_ = app_started &&
!rangeSelector_->startAddressLineEdit->text().isEmpty() &&
!rangeSelector_->amountLineEdit->text().isEmpty();
bool enabled_ = app_started && !rangeSelector_->startAddressLineEdit->text().isEmpty();
rangeSelector_->okButton->setEnabled(enabled_);
}
......@@ -480,10 +481,14 @@ MemoryViewerWidget::MemoryViewerWidget(CppDebuggerPlugin* /*plugin*/, QWidget* p
addAction(newMemoryViewerAction);
QVBoxLayout *l = new QVBoxLayout(this);
l->setContentsMargins(0, 0, 0, 0);
toolBox_ = new QToolBox(this);
toolBox_->setContentsMargins(0, 0, 0, 0);
l->addWidget(toolBox_);
setLayout(l);
// Start with one empty memory view.
slotAddMemoryView();
}
......
......@@ -204,7 +204,20 @@ public:
if(m_declaration->isFunctionDeclaration()) {
auto doc = view->document();
if (doc->characterAt(word.end()) != QLatin1Char('(')) {
// Function pointer?
bool funcptr = false;
const auto line = doc->line(word.start().line());
auto pos = word.end().column() - 1;
while ( pos > 0 && (line.at(pos).isLetterOrNumber() || line.at(pos) == QLatin1Char(':')) ) {
pos--;
if ( line.at(pos) == QLatin1Char('&') ) {
funcptr = true;
break;
}
}
if ( !funcptr && doc->characterAt(word.end()) != QLatin1Char('(') ) {
repl += QLatin1String("()");
}
view->document()->replaceText(word, repl);
......
......@@ -134,20 +134,22 @@ bool NoProjectIncludePathsManager::writeIncludePaths(const QString& storageDirec
void NoProjectIncludePathsManager::openConfigurationDialog(const QString& path)
{
NoProjectCustomIncludePaths cip;
auto cip = new NoProjectCustomIncludePaths;
cip->setAttribute(Qt::WA_DeleteOnClose);
cip->setModal(true);
QFileInfo fi(path);
auto dir = fi.absoluteDir().absolutePath();
cip.setStorageDirectory(dir);
cip->setStorageDirectory(dir);
auto paths = includesAndDefines(path).first;
cip.setCustomIncludePaths(pathListToStringList(paths));
cip->setCustomIncludePaths(pathListToStringList(paths));
if (cip.exec() == QDialog::Accepted) {
if (!writeIncludePaths(cip.storageDirectory(), cip.customIncludePaths())) {
qWarning() << i18n("Failed to save custom include paths in directory: %1", cip.storageDirectory());
QObject::connect(cip, &QDialog::accepted, [this, cip, &path]() {
if (!writeIncludePaths(cip->storageDirectory(), cip->customIncludePaths())) {
qWarning() << i18n("Failed to save custom include paths in directory: %1", cip->storageDirectory());
}
KDevelop::ICore::self()->languageController()->backgroundParser()->addDocument(KDevelop::IndexedString(path));
}
});
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment