From 7e45ccc99b18ba7448e2f3833c6abefb81a251f3 Mon Sep 17 00:00:00 2001 From: Michael Kopp Date: Tue, 20 Nov 2018 22:31:27 +0100 Subject: [PATCH] determine gdb target ABI by parsing 'gdb --configuration' Currently, the gdb target ABI is determined by running `gdb -version`, which for recent gdb's does not reproduce the target ABI string -- yet this string is searched in the output. This obviously fails, and qtcreator uses a fallback behavior, that is not suitable when using gdb for debugging on targets (like avr microcontrollers). With this change, QtCreator calls `gdb --configuration` if that is supported by gdb and extracts ` from `--target=` in the output. For older versions of gdb (which do not support the `--configuration` flag, but still have the target information in the output of `--version`, the output of `--version` is parsed. If both methods fail, no ABI is set for gdb. Change-Id: Ib406f6700b63e2cedb46bd4ec8cc0d215677ecdc Reviewed-by: Michael Kopp Reviewed-by: hjk Reviewed-by: Orgad Shaneh --- src/plugins/debugger/debuggeritem.cpp | 73 ++++++++++++++++++----- src/plugins/debugger/debuggerprotocol.cpp | 5 ++ src/plugins/projectexplorer/abi.cpp | 1 + 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index a46908923f0..2c889a016b7 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -31,6 +31,7 @@ #include +#include #include #include #include @@ -61,6 +62,35 @@ const char DEBUGGER_INFORMATION_ABIS[] = "Abis"; const char DEBUGGER_INFORMATION_LASTMODIFIED[] = "LastModified"; const char DEBUGGER_INFORMATION_WORKINGDIRECTORY[] = "WorkingDirectory"; + +//! Return the configuration of gdb as a list of --key=value +//! \note That the list will also contain some output not in this format. +static QString getConfigurationOfGdbCommand(const QString &command) +{ + // run gdb with the --configuration opion + Utils::SynchronousProcess gdbConfigurationCall; + Utils::SynchronousProcessResponse output = + gdbConfigurationCall.runBlocking(command, {QString("--configuration")}); + return output.allOutput(); +} + +//! Extract the target ABI identifier from GDB output +//! \return QString() (aka Null) if unable to find something +static QString extractGdbTargetAbiStringFromGdbOutput(const QString &gdbOutput) +{ + const auto outputLines = gdbOutput.split('\n'); + const auto whitespaceSeparatedTokens = outputLines.join(' ').split(' ', QString::SkipEmptyParts); + + const QString targetKey{"--target="}; + const QString targetValue = Utils::findOrDefault(whitespaceSeparatedTokens, + [&targetKey](const QString &token) { return token.startsWith(targetKey); }); + if (!targetValue.isEmpty()) + return targetValue.mid(targetKey.size()); + + return {}; +} + + namespace Debugger { // -------------------------------------------------------------------------- @@ -130,22 +160,6 @@ void DebuggerItem::reinitializeFromFile() const QString output = response.allOutput().trimmed(); if (output.contains("gdb")) { m_engineType = GdbEngineType; - const char needle[] = "This GDB was configured as \""; - // E.g. "--host=i686-pc-linux-gnu --target=arm-unknown-nto-qnx6.5.0". - // or "i686-linux-gnu" - int pos1 = output.indexOf(needle); - if (pos1 != -1) { - pos1 += int(strlen(needle)); - int pos2 = output.indexOf('"', pos1 + 1); - QString target = output.mid(pos1, pos2 - pos1); - int pos3 = target.indexOf("--target="); - if (pos3 >= 0) - target = target.mid(pos3 + 9); - m_abis.append(Abi::abiFromTargetTriplet(target)); - } else { - // Fallback. - m_abis = Abi::abisOfBinary(m_command); // FIXME: Wrong. - } // Version bool isMacGdb, isQnxGdb; @@ -155,6 +169,33 @@ void DebuggerItem::reinitializeFromFile() if (version) m_version = QString::fromLatin1("%1.%2.%3") .arg(version / 10000).arg((version / 100) % 100).arg(version % 100); + + // ABI + const bool unableToFindAVersion = (0 == version); + const bool gdbSupportsConfigurationFlag = (version >= 70700); + if (gdbSupportsConfigurationFlag || unableToFindAVersion) { + const auto gdbConfiguration = getConfigurationOfGdbCommand(m_command.toString()); + const auto gdbTargetAbiString = + extractGdbTargetAbiStringFromGdbOutput(gdbConfiguration); + if (!gdbTargetAbiString.isEmpty()) { + m_abis.append(Abi::abiFromTargetTriplet(gdbTargetAbiString)); + return; + } + } + + // ABI: legacy: the target was removed from the output of --version with + // https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=c61b06a19a34baab66e3809c7b41b0c31009ed9f + auto legacyGdbTargetAbiString = extractGdbTargetAbiStringFromGdbOutput(output); + if (!legacyGdbTargetAbiString.isEmpty()) { + // remove trailing " + legacyGdbTargetAbiString = + legacyGdbTargetAbiString.left(legacyGdbTargetAbiString.length() - 1); + m_abis.append(Abi::abiFromTargetTriplet(legacyGdbTargetAbiString)); + return; + } + + qWarning() << "Unable to determine gdb target ABI"; + //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here. return; } if (output.startsWith("lldb") || output.startsWith("LLDB")) { diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index ac4fad40bbb..69dce9a7b89 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -436,6 +436,11 @@ QString DebuggerResponse::toString() const // Tested in tests/auto/debugger/tst_gdb.cpp +//! Extract the GDB version number from the output of 'gdb --version'. +//! \param[out] gdbVersion GDB version "hash" with major*10000 + minor*100 + patch +//! e.g. version GDB 3.7.14 will set this to 30714 +//! \param[out] gdbBuildVersion distribution dependent value +//! \note See the file tests/auto/debugger/tst_gdb.cpp for example conversions. void extractGdbVersion(const QString &msg, int *gdbVersion, int *gdbBuildVersion, bool *isMacGdb, bool *isQnxGdb) { diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 69d87fd1b09..131fbb33b41 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -958,6 +958,7 @@ Abi Abi::hostAbi() return result; } +//! Extract available ABIs from a binary using heuristics. QList Abi::abisOfBinary(const Utils::FileName &path) { QList tmp;