diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 14:32:30 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 14:32:30 +0000 |
commit | 027f1c9655391dcb2b0117f931f720211ac933db (patch) | |
tree | 94980f450aa3daec3e1fec217374704ad62cfe45 /source | |
parent | 5e95aa85bb660d45e9905ef1d7180b2678280660 (diff) | |
download | src-test2-027f1c9655391dcb2b0117f931f720211ac933db.tar.gz src-test2-027f1c9655391dcb2b0117f931f720211ac933db.zip |
Notes
Diffstat (limited to 'source')
106 files changed, 3557 insertions, 1625 deletions
diff --git a/source/API/SBBlock.cpp b/source/API/SBBlock.cpp index c8a665f7d6fb..fdbbbc045279 100644 --- a/source/API/SBBlock.cpp +++ b/source/API/SBBlock.cpp @@ -75,7 +75,15 @@ SBBlock::GetInlinedName () const { const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo (); if (inlined_info) - return inlined_info->GetName().AsCString (NULL); + { + Function *function = m_opaque_ptr->CalculateSymbolContextFunction(); + LanguageType language; + if (function) + language = function->GetLanguage(); + else + language = lldb::eLanguageTypeUnknown; + return inlined_info->GetName(language).AsCString (NULL); + } } return NULL; } diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp index e845aef41f45..08a5822cb781 100644 --- a/source/API/SBFrame.cpp +++ b/source/API/SBFrame.cpp @@ -1571,7 +1571,7 @@ SBFrame::GetFunctionName() const if (inlined_block) { const InlineFunctionInfo* inlined_info = inlined_block->GetInlinedFunctionInfo(); - name = inlined_info->GetName().AsCString(); + name = inlined_info->GetName(sc.function->GetLanguage()).AsCString(); } } @@ -1602,3 +1602,59 @@ SBFrame::GetFunctionName() const } return name; } + +const char * +SBFrame::GetDisplayFunctionName() +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + const char *name = NULL; + ExecutionContext exe_ctx(m_opaque_sp.get()); + StackFrame *frame = NULL; + Target *target = exe_ctx.GetTargetPtr(); + Process *process = exe_ctx.GetProcessPtr(); + if (target && process) + { + Process::StopLocker stop_locker; + if (stop_locker.TryLock(&process->GetRunLock())) + { + frame = exe_ctx.GetFramePtr(); + if (frame) + { + SymbolContext sc (frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol)); + if (sc.block) + { + Block *inlined_block = sc.block->GetContainingInlinedBlock (); + if (inlined_block) + { + const InlineFunctionInfo* inlined_info = inlined_block->GetInlinedFunctionInfo(); + name = inlined_info->GetDisplayName(sc.function->GetLanguage()).AsCString(); + } + } + + if (name == NULL) + { + if (sc.function) + name = sc.function->GetDisplayName().GetCString(); + } + + if (name == NULL) + { + if (sc.symbol) + name = sc.symbol->GetDisplayName().GetCString(); + } + } + else + { + if (log) + log->Printf ("SBFrame::GetDisplayFunctionName () => error: could not reconstruct frame object for this SBFrame."); + } + } + else + { + if (log) + log->Printf ("SBFrame::GetDisplayFunctionName() => error: process is running"); + + } + } + return name; +} diff --git a/source/API/SBFunction.cpp b/source/API/SBFunction.cpp index bf5e9180a437..2ec6072b51eb 100644 --- a/source/API/SBFunction.cpp +++ b/source/API/SBFunction.cpp @@ -60,7 +60,7 @@ SBFunction::GetName() const { const char *cstr = NULL; if (m_opaque_ptr) - cstr = m_opaque_ptr->GetMangled().GetName().AsCString(); + cstr = m_opaque_ptr->GetName().AsCString(); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) @@ -76,6 +76,26 @@ SBFunction::GetName() const } const char * +SBFunction::GetDisplayName() const +{ + const char *cstr = NULL; + if (m_opaque_ptr) + cstr = m_opaque_ptr->GetMangled().GetDisplayDemangledName(m_opaque_ptr->GetLanguage()).AsCString(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + { + if (cstr) + log->Printf ("SBFunction(%p)::GetDisplayName () => \"%s\"", + static_cast<void*>(m_opaque_ptr), cstr); + else + log->Printf ("SBFunction(%p)::GetDisplayName () => NULL", + static_cast<void*>(m_opaque_ptr)); + } + return cstr; +} + +const char * SBFunction::GetMangledName () const { const char *cstr = NULL; diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp index 5662f36b514d..97ffcf149750 100644 --- a/source/API/SBPlatform.cpp +++ b/source/API/SBPlatform.cpp @@ -11,6 +11,7 @@ #include "lldb/API/SBError.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBUnixSignals.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Error.h" #include "lldb/Host/File.h" @@ -638,3 +639,11 @@ SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions) } +SBUnixSignals +SBPlatform::GetUnixSignals() const +{ + if (auto platform_sp = GetSP()) + return SBUnixSignals{platform_sp}; + + return {}; +} diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp index a1dbf686da03..01bfaf9aff01 100644 --- a/source/API/SBProcess.cpp +++ b/source/API/SBProcess.cpp @@ -912,14 +912,10 @@ SBProcess::Signal (int signo) SBUnixSignals SBProcess::GetUnixSignals() { - SBUnixSignals sb_unix_signals; - ProcessSP process_sp(GetSP()); - if (process_sp) - { - sb_unix_signals.SetSP(process_sp); - } + if (auto process_sp = GetSP()) + return SBUnixSignals{process_sp}; - return sb_unix_signals; + return {}; } void diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp index 246a455d93a7..22d1e546b5ee 100644 --- a/source/API/SBSymbol.cpp +++ b/source/API/SBSymbol.cpp @@ -63,7 +63,7 @@ SBSymbol::GetName() const { const char *name = NULL; if (m_opaque_ptr) - name = m_opaque_ptr->GetMangled().GetName().AsCString(); + name = m_opaque_ptr->GetName().AsCString(); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) @@ -73,6 +73,20 @@ SBSymbol::GetName() const } const char * +SBSymbol::GetDisplayName() const +{ + const char *name = NULL; + if (m_opaque_ptr) + name = m_opaque_ptr->GetMangled().GetDisplayDemangledName(m_opaque_ptr->GetLanguage()).AsCString(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBSymbol(%p)::GetDisplayName () => \"%s\"", + static_cast<void*>(m_opaque_ptr), name ? name : ""); + return name; +} + +const char * SBSymbol::GetMangledName () const { const char *name = NULL; diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp index 923885223a5f..6597d4e77c73 100644 --- a/source/API/SBTarget.cpp +++ b/source/API/SBTarget.cpp @@ -2293,6 +2293,19 @@ SBTarget::FindSymbols (const char *name, lldb::SymbolType symbol_type) } +lldb::SBValue +SBTarget::EvaluateExpression (const char *expr) +{ + TargetSP target_sp(GetSP()); + if (!target_sp) + return SBValue(); + + SBExpressionOptions options; + lldb::DynamicValueType fetch_dynamic_value = target_sp->GetPreferDynamicValue(); + options.SetFetchDynamicValue (fetch_dynamic_value); + options.SetUnwindOnError (true); + return EvaluateExpression(expr, options); +} lldb::SBValue SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &options) diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp index dfc7ce9629f3..42b5c9affe50 100644 --- a/source/API/SBThread.cpp +++ b/source/API/SBThread.cpp @@ -392,7 +392,7 @@ SBThread::GetStopDescription (char *dst, size_t dst_len) case eStopReasonSignal: { - stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals ().GetSignalAsCString (stop_info_sp->GetValue()); + stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals()->GetSignalAsCString(stop_info_sp->GetValue()); if (stop_desc == NULL || stop_desc[0] == '\0') { static char signal_desc[] = "signal"; diff --git a/source/API/SBUnixSignals.cpp b/source/API/SBUnixSignals.cpp index ca321d82fd60..531c9782973d 100644 --- a/source/API/SBUnixSignals.cpp +++ b/source/API/SBUnixSignals.cpp @@ -9,6 +9,7 @@ #include "lldb/lldb-defines.h" #include "lldb/Target/Process.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Core/Log.h" @@ -25,8 +26,13 @@ SBUnixSignals::SBUnixSignals (const SBUnixSignals &rhs) : { } -SBUnixSignals::SBUnixSignals (ProcessSP &process_sp) : - m_opaque_wp(process_sp) +SBUnixSignals::SBUnixSignals(ProcessSP &process_sp) : + m_opaque_wp(process_sp ? process_sp->GetUnixSignals() : nullptr) +{ +} + +SBUnixSignals::SBUnixSignals(PlatformSP &platform_sp) : + m_opaque_wp(platform_sp ? platform_sp->GetUnixSignals() : nullptr) { } @@ -42,16 +48,16 @@ SBUnixSignals::~SBUnixSignals() { } -ProcessSP +UnixSignalsSP SBUnixSignals::GetSP() const { return m_opaque_wp.lock(); } void -SBUnixSignals::SetSP (const ProcessSP &process_sp) +SBUnixSignals::SetSP(const UnixSignalsSP &signals_sp) { - m_opaque_wp = process_sp; + m_opaque_wp = signals_sp; } void @@ -63,30 +69,33 @@ SBUnixSignals::Clear () bool SBUnixSignals::IsValid() const { - return (bool) GetSP(); + return static_cast<bool>(GetSP()); } const char * SBUnixSignals::GetSignalAsCString (int32_t signo) const { - ProcessSP process_sp(GetSP()); - if (process_sp) return process_sp->GetUnixSignals().GetSignalAsCString(signo); - return NULL; + if (auto signals_sp = GetSP()) + return signals_sp->GetSignalAsCString(signo); + + return nullptr; } int32_t SBUnixSignals::GetSignalNumberFromName (const char *name) const { - ProcessSP process_sp(GetSP()); - if (process_sp) return process_sp->GetUnixSignals().GetSignalNumberFromName(name); - return -1; + if (auto signals_sp = GetSP()) + return signals_sp->GetSignalNumberFromName(name); + + return LLDB_INVALID_SIGNAL_NUMBER; } bool SBUnixSignals::GetShouldSuppress (int32_t signo) const { - ProcessSP process_sp(GetSP()); - if (process_sp) return process_sp->GetUnixSignals().GetShouldSuppress(signo); + if (auto signals_sp = GetSP()) + return signals_sp->GetShouldSuppress(signo); + return false; } @@ -94,25 +103,28 @@ bool SBUnixSignals::SetShouldSuppress (int32_t signo, bool value) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - ProcessSP process_sp(GetSP()); + auto signals_sp = GetSP(); if (log) { log->Printf ("SBUnixSignals(%p)::SetShouldSuppress (signo=%d, value=%d)", - static_cast<void*>(process_sp.get()), + static_cast<void*>(signals_sp.get()), signo, value); } - if (process_sp) return process_sp->GetUnixSignals().SetShouldSuppress(signo, value); + if (signals_sp) + return signals_sp->SetShouldSuppress(signo, value); + return false; } bool SBUnixSignals::GetShouldStop (int32_t signo) const { - ProcessSP process_sp(GetSP()); - if (process_sp) return process_sp->GetUnixSignals().GetShouldStop(signo); + if (auto signals_sp = GetSP()) + return signals_sp->GetShouldStop(signo); + return false; } @@ -120,25 +132,28 @@ bool SBUnixSignals::SetShouldStop (int32_t signo, bool value) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - ProcessSP process_sp(GetSP()); + auto signals_sp = GetSP(); if (log) { log->Printf ("SBUnixSignals(%p)::SetShouldStop (signo=%d, value=%d)", - static_cast<void*>(process_sp.get()), + static_cast<void*>(signals_sp.get()), signo, value); } - if (process_sp) return process_sp->GetUnixSignals().SetShouldStop(signo, value); + if (signals_sp) + return signals_sp->SetShouldStop(signo, value); + return false; } bool SBUnixSignals::GetShouldNotify (int32_t signo) const { - ProcessSP process_sp(GetSP()); - if (process_sp) return process_sp->GetUnixSignals().GetShouldNotify(signo); + if (auto signals_sp = GetSP()) + return signals_sp->GetShouldNotify(signo); + return false; } @@ -146,54 +161,36 @@ bool SBUnixSignals::SetShouldNotify (int32_t signo, bool value) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - ProcessSP process_sp(GetSP()); + auto signals_sp = GetSP(); if (log) { log->Printf ("SBUnixSignals(%p)::SetShouldNotify (signo=%d, value=%d)", - static_cast<void*>(process_sp.get()), + static_cast<void*>(signals_sp.get()), signo, value); } - if (process_sp) return process_sp->GetUnixSignals().SetShouldNotify(signo, value); + if (signals_sp) + return signals_sp->SetShouldNotify(signo, value); + return false; } int32_t SBUnixSignals::GetNumSignals () const { - if (auto process_sp = GetSP()) - { - // only valid while we hold process_sp - UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals(); - int32_t num_signals = 0; - for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber(); - signo != LLDB_INVALID_SIGNAL_NUMBER; - signo = unix_signals_ptr->GetNextSignalNumber(signo)) - { - num_signals++; - } - return num_signals; - } - return LLDB_INVALID_SIGNAL_NUMBER; + if (auto signals_sp = GetSP()) + return signals_sp->GetNumSignals(); + + return -1; } int32_t SBUnixSignals::GetSignalAtIndex (int32_t index) const { - if (auto process_sp = GetSP()) - { - // only valid while we hold process_sp - UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals(); - int32_t idx = 0; - for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber(); - signo != LLDB_INVALID_SIGNAL_NUMBER; - signo = unix_signals_ptr->GetNextSignalNumber(signo)) - { - if (index == idx) return signo; - idx++; - } - } + if (auto signals_sp = GetSP()) + return signals_sp->GetSignalAtIndex(index); + return LLDB_INVALID_SIGNAL_NUMBER; } diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp index 731d38a37bee..01ad8157646e 100644 --- a/source/API/SystemInitializerFull.cpp +++ b/source/API/SystemInitializerFull.cpp @@ -58,7 +58,6 @@ #if defined(_MSC_VER) #include "lldb/Host/windows/windows.h" -#include "Plugins/Process/Windows/DynamicLoaderWindows.h" #include "Plugins/Process/Windows/ProcessWindows.h" #endif @@ -264,7 +263,6 @@ SystemInitializerFull::Initialize() RenderScriptRuntime::Initialize(); #if defined(_MSC_VER) - DynamicLoaderWindows::Initialize(); ProcessWindows::Initialize(); #endif #if defined(__FreeBSD__) @@ -369,9 +367,6 @@ SystemInitializerFull::Terminate() ProcessKDP::Terminate(); SymbolVendorMacOSX::Terminate(); #endif -#if defined(_MSC_VER) - DynamicLoaderWindows::Terminate(); -#endif #if defined(__FreeBSD__) ProcessFreeBSD::Terminate(); diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp index ef9144778df0..a199d390803b 100644 --- a/source/Breakpoint/BreakpointLocation.cpp +++ b/source/Breakpoint/BreakpointLocation.cpp @@ -611,7 +611,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) { s->EOL(); s->Indent("function = "); - s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>")); + s->PutCString (sc.function->GetName().AsCString("<unknown>")); } if (sc.line_entry.line > 0) @@ -632,7 +632,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) s->Indent ("re-exported target = "); else s->Indent("symbol = "); - s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>")); + s->PutCString(sc.symbol->GetName().AsCString("<unknown>")); } } } diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp index 4cbcb70d5fd2..162bfb4b5a76 100644 --- a/source/Commands/CommandObjectBreakpoint.cpp +++ b/source/Commands/CommandObjectBreakpoint.cpp @@ -1249,27 +1249,27 @@ public: CommandObjectBreakpointDisable (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "breakpoint disable", - "Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all.", + "Disable the specified breakpoint(s) without removing them. If none are specified, disable all breakpoints.", NULL) { SetHelpLong( -"Disable the specified breakpoint(s) without removing it/them. \n\ -If no breakpoints are specified, disable them all.\n\ -\n\ -Note: disabling a breakpoint will cause none of its locations to be hit\n\ -regardless of whether they are enabled or disabled. So the sequence: \n\ -\n\ - (lldb) break disable 1\n\ - (lldb) break enable 1.1\n\ -\n\ -will NOT cause location 1.1 to get hit. To achieve that, do:\n\ -\n\ - (lldb) break disable 1.*\n\ - (lldb) break enable 1.1\n\ -\n\ -The first command disables all the locations of breakpoint 1, \n\ +"Disable the specified breakpoint(s) without removing them. \ +If none are specified, disable all breakpoints." R"( + +)" "Note: disabling a breakpoint will cause none of its locations to be hit \ +regardless of whether they are enabled or disabled. After the sequence:" R"( + + (lldb) break disable 1 + (lldb) break enable 1.1 + +execution will NOT stop at location 1.1. To achieve that, type: + + (lldb) break disable 1.* + (lldb) break enable 1.1 + +)" "The first command disables all the locations of breakpoint 1, \ the second re-enables the first location." - ); + ); CommandArgumentEntry arg; CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp index 180ab600a50e..ac9c9a64188c 100644 --- a/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/source/Commands/CommandObjectBreakpointCommand.cpp @@ -49,143 +49,120 @@ public: m_options (interpreter) { SetHelpLong ( -"\nGeneral information about entering breakpoint commands\n\ -------------------------------------------------------\n\ -\n\ -This command will cause you to be prompted to enter the command or set of\n\ -commands you wish to be executed when the specified breakpoint is hit. You\n\ -will be told to enter your command(s), and will see a '> 'prompt. Because\n\ -you can enter one or many commands to be executed when a breakpoint is hit,\n\ -you will continue to be prompted after each new-line that you enter, until you\n\ -enter the word 'DONE', which will cause the commands you have entered to be\n\ -stored with the breakpoint and executed when the breakpoint is hit.\n\ -\n\ -Syntax checking is not necessarily done when breakpoint commands are entered.\n\ -An improperly written breakpoint command will attempt to get executed when the\n\ -breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\ -not appear to be getting executed, go back and check your syntax.\n\ -\n\ -Special information about PYTHON breakpoint commands\n\ -----------------------------------------------------\n\ -\n\ -You may enter either one line of Python, multiple lines of Python (including\n\ -function definitions), or specify a Python function in a module that has already,\n\ -or will be imported. If you enter a single line of Python, that will be passed\n\ -to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\ -function definitions, they will be passed to the Python interpreter as soon as\n\ -you finish entering the breakpoint command, and they can be called later (don't\n\ -forget to add calls to them, if you want them called when the breakpoint is\n\ -hit). If you enter multiple lines of Python that are not function definitions,\n\ -they will be collected into a new, automatically generated Python function, and\n\ -a call to the newly generated function will be attached to the breakpoint.\n\ -\n\ -\n\ -This auto-generated function is passed in three arguments:\n\ -\n\ - frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\ - bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\ - location that was hit.\n\ - dict: the python session dictionary hit.\n\ -\n\ -When specifying a python function with the --python-function option, you need\n\ -to supply the function name prepended by the module name. So if you import a\n\ -module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\ -specify the option as:\n\ -\n\ - --python-function myutils.breakpoint_callback\n\ -\n\ -The function itself must have the following prototype:\n\ -\n\ -def breakpoint_callback(frame, bp_loc, dict):\n\ - # Your code goes here\n\ -\n\ -The arguments are the same as the 3 auto generation function arguments listed\n\ -above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\ -function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\ -can get you to the thread (frame.GetThread()), the thread can get you to the\n\ -process (thread.GetProcess()), and the process can get you back to the target\n\ -(process.GetTarget()).\n\ -\n\ -Important Note: Because loose Python code gets collected into functions, if you\n\ -want to access global variables in the 'loose' code, you need to specify that\n\ -they are global, using the 'global' keyword. Be sure to use correct Python\n\ -syntax, including indentation, when entering Python breakpoint commands.\n\ -\n\ -As a third option, you can pass the name of an already existing Python function\n\ -and that function will be attached to the breakpoint. It will get passed the\n\ -frame and bp_loc arguments mentioned above.\n\ -\n\ -Example Python one-line breakpoint command:\n\ -\n\ -(lldb) breakpoint command add -s python 1\n\ -Enter your Python command(s). Type 'DONE' to end.\n\ -> print \"Hit this breakpoint!\"\n\ -> DONE\n\ -\n\ -As a convenience, this also works for a short Python one-liner:\n\ -(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\ -(lldb) run\n\ -Launching '.../a.out' (x86_64)\n\ -(lldb) Fri Sep 10 12:17:45 2010\n\ -Process 21778 Stopped\n\ -* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\ - 36 \n\ - 37 int c(int val)\n\ - 38 {\n\ - 39 -> return val + 3;\n\ - 40 }\n\ - 41 \n\ - 42 int main (int argc, char const *argv[])\n\ -(lldb)\n\ -\n\ -Example multiple line Python breakpoint command, using function definition:\n\ -\n\ -(lldb) breakpoint command add -s python 1\n\ -Enter your Python command(s). Type 'DONE' to end.\n\ -> def breakpoint_output (bp_no):\n\ -> out_string = \"Hit breakpoint number \" + repr (bp_no)\n\ -> print out_string\n\ -> return True\n\ -> breakpoint_output (1)\n\ -> DONE\n\ -\n\ -\n\ -Example multiple line Python breakpoint command, using 'loose' Python:\n\ -\n\ -(lldb) breakpoint command add -s p 1\n\ -Enter your Python command(s). Type 'DONE' to end.\n\ -> global bp_count\n\ -> bp_count = bp_count + 1\n\ -> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\ -> DONE\n\ -\n\ -In this case, since there is a reference to a global variable,\n\ -'bp_count', you will also need to make sure 'bp_count' exists and is\n\ -initialized:\n\ -\n\ -(lldb) script\n\ ->>> bp_count = 0\n\ ->>> quit()\n\ -\n\ -(lldb)\n\ -\n\ -\n\ -Your Python code, however organized, can optionally return a value.\n\ -If the returned value is False, that tells LLDB not to stop at the breakpoint\n\ -to which the code is associated. Returning anything other than False, or even\n\ -returning None, or even omitting a return statement entirely, will cause\n\ -LLDB to stop.\n\ -\n\ -Final Note: If you get a warning that no breakpoint command was generated, but\n\ -you did not get any syntax errors, you probably forgot to add a call to your\n\ -functions.\n\ -\n\ -Special information about debugger command breakpoint commands\n\ ---------------------------------------------------------------\n\ -\n\ -You may enter any debugger command, exactly as you would at the debugger prompt.\n\ -You may enter as many debugger commands as you like, but do NOT enter more than\n\ -one command per line.\n" ); +R"( +General information about entering breakpoint commands +------------------------------------------------------ + +)" "This command will prompt for commands to be executed when the specified \ +breakpoint is hit. Each command is typed on its own line following the '> ' \ +prompt until 'DONE' is entered." R"( + +)" "Syntactic errors may not be detected when initially entered, and many \ +malformed commands can silently fail when executed. If your breakpoint commands \ +do not appear to be executing, double-check the command syntax." R"( + +)" "Note: You may enter any debugger command exactly as you would at the debugger \ +prompt. There is no limit to the number of commands supplied, but do NOT enter \ +more than one command per line." R"( + +Special information about PYTHON breakpoint commands +---------------------------------------------------- + +)" "You may enter either one or more lines of Python, including function \ +definitions or calls to functions that will have been imported by the time \ +the code executes. Single line breakpoint commands will be interpreted 'as is' \ +when the breakpoint is hit. Multiple lines of Python will be wrapped in a \ +generated function, and a call to the function will be attached to the breakpoint." R"( + +This auto-generated function is passed in three arguments: + + frame: an lldb.SBFrame object for the frame which hit breakpoint. + + bp_loc: an lldb.SBBreakpointLocation object that represents the breakpoint location that was hit. + + dict: the python session dictionary hit. + +)" "When specifying a python function with the --python-function option, you need \ +to supply the function name prepended by the module name:" R"( + + --python-function myutils.breakpoint_callback + +The function itself must have the following prototype: + +def breakpoint_callback(frame, bp_loc, dict): + # Your code goes here + +)" "The arguments are the same as the arguments passed to generated functions as \ +described above. Note that the global variable 'lldb.frame' will NOT be updated when \ +this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ +can get you to the thread via frame.GetThread(), the thread can get you to the \ +process via thread.GetProcess(), and the process can get you back to the target \ +via process.GetTarget()." R"( + +)" "Important Note: As Python code gets collected into functions, access to global \ +variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ +Python syntax, including indentation, when entering Python breakpoint commands." R"( + +Example Python one-line breakpoint command: + +(lldb) breakpoint command add -s python 1 +Enter your Python command(s). Type 'DONE' to end. +> print "Hit this breakpoint!" +> DONE + +As a convenience, this also works for a short Python one-liner: + +(lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()' +(lldb) run +Launching '.../a.out' (x86_64) +(lldb) Fri Sep 10 12:17:45 2010 +Process 21778 Stopped +* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread + 36 + 37 int c(int val) + 38 { + 39 -> return val + 3; + 40 } + 41 + 42 int main (int argc, char const *argv[]) + +Example multiple line Python breakpoint command: + +(lldb) breakpoint command add -s p 1 +Enter your Python command(s). Type 'DONE' to end. +> global bp_count +> bp_count = bp_count + 1 +> print "Hit this breakpoint " + repr(bp_count) + " times!" +> DONE + +Example multiple line Python breakpoint command, using function definition: + +(lldb) breakpoint command add -s python 1 +Enter your Python command(s). Type 'DONE' to end. +> def breakpoint_output (bp_no): +> out_string = "Hit breakpoint number " + repr (bp_no) +> print out_string +> return True +> breakpoint_output (1) +> DONE + +)" "In this case, since there is a reference to a global variable, \ +'bp_count', you will also need to make sure 'bp_count' exists and is \ +initialized:" R"( + +(lldb) script +>>> bp_count = 0 +>>> quit() + +)" "Your Python code, however organized, can optionally return a value. \ +If the returned value is False, that tells LLDB not to stop at the breakpoint \ +to which the code is associated. Returning anything other than False, or even \ +returning None, or even omitting a return statement entirely, will cause \ +LLDB to stop." R"( + +)" "Final Note: A warning that no breakpoint command was generated when there \ +are no syntax errors may indicate that a function was declared but never called." + ); CommandArgumentEntry arg; CommandArgumentData bp_id_arg; diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp index 5fd99cfdabf4..f56d089877de 100644 --- a/source/Commands/CommandObjectCommands.cpp +++ b/source/Commands/CommandObjectCommands.cpp @@ -450,60 +450,74 @@ public: NULL) { SetHelpLong( - "'alias' allows the user to create a short-cut or abbreviation for long \n\ - commands, multi-word commands, and commands that take particular options. \n\ - Below are some simple examples of how one might use the 'alias' command: \n\ - \n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ - // command. \n\ - 'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ - // command. Since breakpoint commands are two-word \n\ - // commands, the user will still need to enter the \n\ - // second word after 'bp', e.g. 'bp enable' or \n\ - // 'bp delete'. \n\ - 'command alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\ - // two-word command 'breakpoint list'. \n\ - \nAn alias can include some options for the command, with the values either \n\ - filled in at the time the alias is created, or specified as positional \n\ - arguments, to be filled in when the alias is invoked. The following example \n\ - shows how to create aliases with options: \n\ - \n\ - 'command alias bfl breakpoint set -f %1 -l %2' \n\ - \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ - options already part of the alias. So if the user wants to set a breakpoint \n\ - by file and line without explicitly having to use the -f and -l options, the \n\ - user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ - for the actual arguments that will be passed when the alias command is used. \n\ - The number in the placeholder refers to the position/order the actual value \n\ - occupies when the alias is used. All the occurrences of '%1' in the alias \n\ - will be replaced with the first argument, all the occurrences of '%2' in the \n\ - alias will be replaced with the second argument, and so on. This also allows \n\ - actual arguments to be used multiple times within an alias (see 'process \n\ - launch' example below). \n\ - Note: the positional arguments must substitute as whole words in the resultant\n\ - command, so you can't at present do something like:\n\ - \n\ - command alias bcppfl breakpoint set -f %1.cpp -l %2\n\ - \n\ - to get the file extension \".cpp\" automatically appended. For more complex\n\ - aliasing, use the \"command regex\" command instead.\n\ - \nSo in the 'bfl' case, the actual file value will be \n\ - filled in with the first argument following 'bfl' and the actual line number \n\ - value will be filled in with the second argument. The user would use this \n\ - alias as follows: \n\ - \n (lldb) command alias bfl breakpoint set -f %1 -l %2 \n\ - <... some time later ...> \n\ - (lldb) bfl my-file.c 137 \n\ - \nThis would be the same as if the user had entered \n\ - 'breakpoint set -f my-file.c -l 137'. \n\ - \nAnother example: \n\ - \n (lldb) command alias pltty process launch -s -o %1 -e %1 \n\ - (lldb) pltty /dev/tty0 \n\ - // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ - \nIf the user always wanted to pass the same value to a particular option, the \n\ - alias could be defined with that value directly in the alias as a constant, \n\ - rather than using a positional placeholder: \n\ - \n command alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ - // 3 of whatever file is indicated. \n"); +"'alias' allows the user to create a short-cut or abbreviation for long \ +commands, multi-word commands, and commands that take particular options. \ +Below are some simple examples of how one might use the 'alias' command:" R"( + +(lldb) command alias sc script + + Creates the abbreviation 'sc' for the 'script' command. + +(lldb) command alias bp breakpoint + +)" " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ +breakpoint commands are two-word commands, the user would still need to \ +enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." R"( + +(lldb) command alias bpl breakpoint list + + Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. + +)" "An alias can include some options for the command, with the values either \ +filled in at the time the alias is created, or specified as positional \ +arguments, to be filled in when the alias is invoked. The following example \ +shows how to create aliases with options:" R"( + +(lldb) command alias bfl breakpoint set -f %1 -l %2 + +)" " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ +options already part of the alias. So if the user wants to set a breakpoint \ +by file and line without explicitly having to use the -f and -l options, the \ +user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ +for the actual arguments that will be passed when the alias command is used. \ +The number in the placeholder refers to the position/order the actual value \ +occupies when the alias is used. All the occurrences of '%1' in the alias \ +will be replaced with the first argument, all the occurrences of '%2' in the \ +alias will be replaced with the second argument, and so on. This also allows \ +actual arguments to be used multiple times within an alias (see 'process \ +launch' example below)." R"( + +)" "Note: the positional arguments must substitute as whole words in the resultant \ +command, so you can't at present do something like this to append the file extension \ +\".cpp\":" R"( + +(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 + +)" "For more complex aliasing, use the \"command regex\" command instead. In the \ +'bfl' case above, the actual file value will be filled in with the first argument \ +following 'bfl' and the actual line number value will be filled in with the second \ +argument. The user would use this alias as follows:" R"( + +(lldb) command alias bfl breakpoint set -f %1 -l %2 +(lldb) bfl my-file.c 137 + +This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. + +Another example: + +(lldb) command alias pltty process launch -s -o %1 -e %1 +(lldb) pltty /dev/tty0 + + Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' + +)" "If the user always wanted to pass the same value to a particular option, the \ +alias could be defined with that value directly in the alias as a constant, \ +rather than using a positional placeholder:" R"( + +(lldb) command alias bl3 breakpoint set -f %1 -l 3 + + Always sets a breakpoint on line 3 of whatever file is indicated.)" + ); CommandArgumentEntry arg1; CommandArgumentEntry arg2; @@ -960,31 +974,30 @@ public: IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { - SetHelpLong( -"This command allows the user to create powerful regular expression commands\n" -"with substitutions. The regular expressions and substitutions are specified\n" -"using the regular expression substitution format of:\n" -"\n" -" s/<regex>/<subst>/\n" -"\n" -"<regex> is a regular expression that can use parenthesis to capture regular\n" -"expression input and substitute the captured matches in the output using %1\n" -"for the first match, %2 for the second, and so on.\n" -"\n" -"The regular expressions can all be specified on the command line if more than\n" -"one argument is provided. If just the command name is provided on the command\n" -"line, then the regular expressions and substitutions can be entered on separate\n" -" lines, followed by an empty line to terminate the command definition.\n" -"\n" -"EXAMPLES\n" -"\n" -"The following example will define a regular expression command named 'f' that\n" -"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n" -"a number follows 'f':\n" -"\n" -" (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n" -"\n" - ); + SetHelpLong(R"( +)" "This command allows the user to create powerful regular expression commands \ +with substitutions. The regular expressions and substitutions are specified \ +using the regular expression substitution format of:" R"( + + s/<regex>/<subst>/ + +)" "<regex> is a regular expression that can use parenthesis to capture regular \ +expression input and substitute the captured matches in the output using %1 \ +for the first match, %2 for the second, and so on." R"( + +)" "The regular expressions can all be specified on the command line if more than \ +one argument is provided. If just the command name is provided on the command \ +line, then the regular expressions and substitutions can be entered on separate \ +lines, followed by an empty line to terminate the command definition." R"( + +EXAMPLES + +)" "The following example will define a regular expression command named 'f' that \ +will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ +a number follows 'f':" R"( + + (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')" + ); } ~CommandObjectCommandsAddRegex() diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp index f4bb8fbac11e..1be17a0cfddc 100644 --- a/source/Commands/CommandObjectExpression.cpp +++ b/source/Commands/CommandObjectExpression.cpp @@ -202,35 +202,39 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete m_expr_line_count (0), m_expr_lines () { - SetHelpLong( -"Timeouts:\n\ - If the expression can be evaluated statically (without running code) then it will be.\n\ - Otherwise, by default the expression will run on the current thread with a short timeout:\n\ - currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\ - and resumed with all threads running. You can use the -a option to disable retrying on all\n\ - threads. You can use the -t option to set a shorter timeout.\n\ -\n\ -User defined variables:\n\ - You can define your own variables for convenience or to be used in subsequent expressions.\n\ - You define them the same way you would define variables in C. If the first character of \n\ - your user defined variable is a $, then the variable's value will be available in future\n\ - expressions, otherwise it will just be available in the current expression.\n\ -\n\ -\n\ -Continuing evaluation after a breakpoint:\n\ - If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once\n\ - you are done with your investigation, you can either remove the expression execution frames\n\ - from the stack with \"thread return -x\" or if you are still interested in the expression result\n\ - you can issue the \"continue\" command and the expression evaluation will complete and the\n\ - expression result will be available using the \"thread.completed-expression\" key in the thread\n\ - format.\n\ -\n\ -Examples: \n\ -\n\ - expr my_struct->a = my_array[3] \n\ - expr -f bin -- (index * 8) + 5 \n\ - expr unsigned int $foo = 5\n\ - expr char c[] = \"foo\"; c[0]\n"); + SetHelpLong( +R"( +Timeouts: + +)" " If the expression can be evaluated statically (without running code) then it will be. \ +Otherwise, by default the expression will run on the current thread with a short timeout: \ +currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted \ +and resumed with all threads running. You can use the -a option to disable retrying on all \ +threads. You can use the -t option to set a shorter timeout." R"( + +User defined variables: + +)" " You can define your own variables for convenience or to be used in subsequent expressions. \ +You define them the same way you would define variables in C. If the first character of \ +your user defined variable is a $, then the variable's value will be available in future \ +expressions, otherwise it will just be available in the current expression." R"( + +Continuing evaluation after a breakpoint: + +)" " If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \ +you are done with your investigation, you can either remove the expression execution frames \ +from the stack with \"thread return -x\" or if you are still interested in the expression result \ +you can issue the \"continue\" command and the expression evaluation will complete and the \ +expression result will be available using the \"thread.completed-expression\" key in the thread \ +format." R"( + +Examples: + + expr my_struct->a = my_array[3] + expr -f bin -- (index * 8) + 5 + expr unsigned int $foo = 5 + expr char c[] = \"foo\"; c[0])" + ); CommandArgumentEntry arg; CommandArgumentData expression_arg; diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp index 866587fb4ebc..a0979d059edb 100644 --- a/source/Commands/CommandObjectPlatform.cpp +++ b/source/Commands/CommandObjectPlatform.cpp @@ -1067,10 +1067,12 @@ public: 0) { SetHelpLong( -"Examples: \n\ -\n\ - platform get-file /the/remote/file/path /the/local/file/path\n\ - # Transfer a file from the remote end with file path /the/remote/file/path to the local host.\n"); +R"(Examples: + +(lldb) platform get-file /the/remote/file/path /the/local/file/path + + Transfer a file from the remote end with file path /the/remote/file/path to the local host.)" + ); CommandArgumentEntry arg1, arg2; CommandArgumentData file_arg_remote, file_arg_host; @@ -1150,10 +1152,12 @@ public: 0) { SetHelpLong( -"Examples: \n\ -\n\ - platform get-size /the/remote/file/path\n\ - # Get the file size from the remote end with path /the/remote/file/path.\n"); +R"(Examples: + +(lldb) platform get-size /the/remote/file/path + + Get the file size from the remote end with path /the/remote/file/path.)" + ); CommandArgumentEntry arg1; CommandArgumentData file_arg_remote; diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index 4414bdf2a2c8..e587eadfa3d6 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -1337,7 +1337,7 @@ protected: if (::isxdigit (signal_name[0])) signo = StringConvert::ToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0); else - signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name); + signo = process->GetUnixSignals()->GetSignalNumberFromName(signal_name); if (signo == LLDB_INVALID_SIGNAL_NUMBER) { @@ -1681,7 +1681,8 @@ public: NULL), m_options (interpreter) { - SetHelpLong ("If no signals are specified, update them all. If no update option is specified, list the current values.\n"); + SetHelpLong ("\nIf no signals are specified, update them all. If no update " + "option is specified, list the current values."); CommandArgumentEntry arg; CommandArgumentData signal_arg; @@ -1734,14 +1735,14 @@ public: } void - PrintSignal (Stream &str, int32_t signo, const char *sig_name, UnixSignals &signals) + PrintSignal(Stream &str, int32_t signo, const char *sig_name, const UnixSignalsSP &signals_sp) { bool stop; bool suppress; bool notify; str.Printf ("%-11s ", sig_name); - if (signals.GetSignalInfo (signo, suppress, stop, notify)) + if (signals_sp->GetSignalInfo(signo, suppress, stop, notify)) { bool pass = !suppress; str.Printf ("%s %s %s", @@ -1753,7 +1754,7 @@ public: } void - PrintSignalInformation (Stream &str, Args &signal_args, int num_valid_signals, UnixSignals &signals) + PrintSignalInformation(Stream &str, Args &signal_args, int num_valid_signals, const UnixSignalsSP &signals_sp) { PrintSignalHeader (str); @@ -1762,18 +1763,18 @@ public: size_t num_args = signal_args.GetArgumentCount(); for (size_t i = 0; i < num_args; ++i) { - int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i)); + int32_t signo = signals_sp->GetSignalNumberFromName(signal_args.GetArgumentAtIndex(i)); if (signo != LLDB_INVALID_SIGNAL_NUMBER) - PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals); + PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals_sp); } } else // Print info for ALL signals { - int32_t signo = signals.GetFirstSignalNumber(); + int32_t signo = signals_sp->GetFirstSignalNumber(); while (signo != LLDB_INVALID_SIGNAL_NUMBER) { - PrintSignal (str, signo, signals.GetSignalAsCString (signo), signals); - signo = signals.GetNextSignalNumber (signo); + PrintSignal(str, signo, signals_sp->GetSignalAsCString(signo), signals_sp); + signo = signals_sp->GetNextSignalNumber(signo); } } } @@ -1830,27 +1831,27 @@ protected: } size_t num_args = signal_args.GetArgumentCount(); - UnixSignals &signals = process_sp->GetUnixSignals(); + UnixSignalsSP signals_sp = process_sp->GetUnixSignals(); int num_signals_set = 0; if (num_args > 0) { for (size_t i = 0; i < num_args; ++i) { - int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i)); + int32_t signo = signals_sp->GetSignalNumberFromName(signal_args.GetArgumentAtIndex(i)); if (signo != LLDB_INVALID_SIGNAL_NUMBER) { // Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees // the value is either 0 or 1. if (stop_action != -1) - signals.SetShouldStop (signo, (bool) stop_action); + signals_sp->SetShouldStop(signo, stop_action); if (pass_action != -1) { - bool suppress = ! ((bool) pass_action); - signals.SetShouldSuppress (signo, suppress); + bool suppress = !pass_action; + signals_sp->SetShouldSuppress(signo, suppress); } if (notify_action != -1) - signals.SetShouldNotify (signo, (bool) notify_action); + signals_sp->SetShouldNotify(signo, notify_action); ++num_signals_set; } else @@ -1866,25 +1867,25 @@ protected: { if (m_interpreter.Confirm ("Do you really want to update all the signals?", false)) { - int32_t signo = signals.GetFirstSignalNumber(); + int32_t signo = signals_sp->GetFirstSignalNumber(); while (signo != LLDB_INVALID_SIGNAL_NUMBER) { if (notify_action != -1) - signals.SetShouldNotify (signo, (bool) notify_action); + signals_sp->SetShouldNotify(signo, notify_action); if (stop_action != -1) - signals.SetShouldStop (signo, (bool) stop_action); + signals_sp->SetShouldStop(signo, stop_action); if (pass_action != -1) { - bool suppress = ! ((bool) pass_action); - signals.SetShouldSuppress (signo, suppress); + bool suppress = !pass_action; + signals_sp->SetShouldSuppress(signo, suppress); } - signo = signals.GetNextSignalNumber (signo); + signo = signals_sp->GetNextSignalNumber(signo); } } } } - PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals); + PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals_sp); if (num_signals_set > 0) result.SetStatus (eReturnStatusSuccessFinishNoResult); diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp index ccbf98c767f1..8ed783b211f6 100644 --- a/source/Commands/CommandObjectSettings.cpp +++ b/source/Commands/CommandObjectSettings.cpp @@ -60,24 +60,25 @@ public: m_arguments.push_back (arg2); SetHelpLong ( -"When setting a dictionary or array variable, you can set multiple entries \n\ -at once by giving the values to the set command. For example: \n\ -\n\ -(lldb) settings set target.run-args value1 value2 value3 \n\ -(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345 \n\ -\n\ -(lldb) settings show target.run-args \n\ - [0]: 'value1' \n\ - [1]: 'value2' \n\ - [3]: 'value3' \n\ -(lldb) settings show target.env-vars \n\ - 'MYPATH=~/.:/usr/bin'\n\ - 'SOME_ENV_VAR=12345' \n\ -\n\ -Warning: The 'set' command re-sets the entire array or dictionary. If you \n\ -just want to add, remove or update individual values (or add something to \n\ -the end), use one of the other settings sub-commands: append, replace, \n\ -insert-before or insert-after.\n"); +"\nWhen setting a dictionary or array variable, you can set multiple entries \ +at once by giving the values to the set command. For example:" R"( + +(lldb) settings set target.run-args value1 value2 value3 +(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345 + +(lldb) settings show target.run-args + [0]: 'value1' + [1]: 'value2' + [3]: 'value3' +(lldb) settings show target.env-vars + 'MYPATH=~/.:/usr/bin' + 'SOME_ENV_VAR=12345' + +)" "Warning: The 'set' command re-sets the entire array or dictionary. If you \ +just want to add, remove or update individual values (or add something to \ +the end), use one of the other settings sub-commands: append, replace, \ +insert-before or insert-after." + ); } diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp index 7c8061a6ca08..584e94d0452d 100644 --- a/source/Commands/CommandObjectType.cpp +++ b/source/Commands/CommandObjectType.cpp @@ -764,31 +764,39 @@ public: m_arguments.push_back (type_arg); SetHelpLong( - "Some examples of using this command.\n" - "We use as reference the following snippet of code:\n" - "\n" - "typedef int Aint;\n" - "typedef float Afloat;\n" - "typedef Aint Bint;\n" - "typedef Afloat Bfloat;\n" - "\n" - "Aint ix = 5;\n" - "Bint iy = 5;\n" - "\n" - "Afloat fx = 3.14;\n" - "BFloat fy = 3.14;\n" - "\n" - "Typing:\n" - "type format add -f hex AInt\n" - "frame variable iy\n" - "will produce an hex display of iy, because no formatter is available for Bint and the one for Aint is used instead\n" - "To prevent this type\n" - "type format add -f hex -C no AInt\n" - "\n" - "A similar reasoning applies to\n" - "type format add -f hex -C no float -p\n" - "which now prints all floats and float&s as hexadecimal, but does not format float*s\n" - "and does not change the default display for Afloat and Bfloat objects.\n" +R"( +The following examples of 'type format add' refer to this code snippet for context: + + typedef int Aint; + typedef float Afloat; + typedef Aint Bint; + typedef Afloat Bfloat; + + Aint ix = 5; + Bint iy = 5; + + Afloat fx = 3.14; + BFloat fy = 3.14; + +Adding default formatting: + +(lldb) type format add -f hex AInt +(lldb) frame variable iy + +)" " Produces hexidecimal display of iy, because no formatter is available for Bint and \ +the one for Aint is used instead." R"( + +To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains: + + +(lldb) type format add -f hex -C no AInt + +Similar reasoning applies to this: + +(lldb) type format add -f hex -C no float -p + +)" " All float values and float references are now formatted as hexadecimal, but not \ +pointers to floats. Nor will it change the default display for Afloat and Bfloat objects." ); // Add the "--format" to all options groups @@ -1736,69 +1744,86 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &in m_arguments.push_back (type_arg); SetHelpLong( - "Some examples of using this command.\n" - "We use as reference the following snippet of code:\n" - "struct JustADemo\n" - "{\n" - "int* ptr;\n" - "float value;\n" - "JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n" - "};\n" - "JustADemo object(42,3.14);\n" - "struct AnotherDemo : public JustADemo\n" - "{\n" - "uint8_t byte;\n" - "AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n" - "};\n" - "AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n" - "\n" - "type summary add --summary-string \"the answer is ${*var.ptr}\" JustADemo\n" - "when typing frame variable object you will get \"the answer is 42\"\n" - "type summary add --summary-string \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n" - "when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n" - "\n" - "Alternatively, you could also say\n" - "type summary add --summary-string \"${var%V} -> ${*var}\" \"int *\"\n" - "and replace the above summary string with\n" - "type summary add --summary-string \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n" - "to obtain a similar result\n" - "\n" - "To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n" - "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n" - "\n" - "This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n" - "If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n" - "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n" - "A similar option -r exists for references.\n" - "\n" - "If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n" - "you can use the -c option, without giving any summary string:\n" - "type summary add -c JustADemo\n" - "frame variable object\n" - "the output being similar to (ptr=0xsomeaddress, value=3.14)\n" - "\n" - "If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n" - "type summary add -e --summary-string \"*ptr = ${*var.ptr}\" JustADemo\n" - "Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n" - "to get an output like:\n" - "\n" - "*ptr = 42 {\n" - " ptr = 0xsomeaddress\n" - " value = 3.14\n" - "}\n" - "\n" - "You can also add Python summaries, in which case you will use lldb public API to gather information from your variables" - "and elaborate them to a meaningful summary inside a script written in Python. The variable object will be passed to your" - "script as an SBValue object. The following example might help you when starting to use the Python summaries feature:\n" - "type summary add JustADemo -o \"value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();\"\n" - "If you prefer to type your scripts on multiple lines, you will use the -P option and then type your script, ending it with " - "the word DONE on a line by itself to mark you're finished editing your code:\n" - "(lldb)type summary add JustADemo -P\n" - " value = valobj.GetChildMemberWithName('value');\n" - " return 'My value is ' + value.GetValue();\n" - "DONE\n" - "(lldb) <-- type further LLDB commands here\n" - ); +R"( +The following examples of 'type summary add' refer to this code snippet for context: + + struct JustADemo + { + int* ptr; + float value; + JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {} + }; + JustADemo demo_instance(42, 3.14); + + typedef JustADemo NewDemo; + NewDemo new_demo_instance(42, 3.14); + +(lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo + + Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42" + +(lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo + + Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14" + +)" "Alternatively, you could define formatting for all pointers to integers and \ +rely on that when formatting JustADemo to obtain the same result:" R"( + +(lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *" +(lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo + +)" "Type summaries are automatically applied to derived typedefs, so the examples \ +above apply to both JustADemo and NewDemo. The cascade option can be used to \ +suppress this behavior:" R"( + +(lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no + + The summary will now be used for values of JustADemo but not NewDemo. + +)" "By default summaries are shown for pointers and references to values of the \ +specified type. To suppress formatting for pointers use the -p option, or apply \ +the corresponding -r option to suppress formatting for references:" R"( + +(lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo + +)" "One-line summaries including all fields in a type can be inferred without supplying an \ +explicit summary string by passing the -c option:" R"( + +(lldb) type summary add -c JustADemo +(lldb) frame variable demo_instance +(ptr=<address>, value=3.14) + +)" "Type summaries normally suppress the nested display of individual fields. To \ +supply a summary to supplement the default structure add the -e option:" R"( + +(lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo + +)" "Now when displaying JustADemo values the int* is displayed, followed by the \ +standard LLDB sequence of children, one per line:" R"( + +*ptr = 42 { + ptr = <address> + value = 3.14 +} + +)" "You can also add summaries written in Python. These scripts use lldb public API to \ +gather information from your variables and produce a meaningful summary. To start a \ +multi-line script use the -P option. The function declaration will be displayed along with \ +a comment describing the two arguments. End your script with the word 'DONE' on a line by \ +itself:" R"( + +(lldb) type summary add JustADemo -P +def function (valobj,internal_dict): +"""valobj: an SBValue which you want to provide a summary for +internal_dict: an LLDB support object not to be used""" + value = valobj.GetChildMemberWithName('value'); + return 'My value is ' + value.GetValue(); + DONE + +Alternatively, the -o option can be used when providing a simple one-line Python script: + +(lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")" + ); } bool @@ -4117,31 +4142,37 @@ public: m_arguments.push_back (type_arg); SetHelpLong( - "Some examples of using this command.\n" - "We use as reference the following snippet of code:\n" - "\n" - "class Foo {;\n" - " int a;\n" - " int b;\n" - " int c;\n" - " int d;\n" - " int e;\n" - " int f;\n" - " int g;\n" - " int h;\n" - " int i;\n" - "} \n" - "Typing:\n" - "type filter add --child a --child g Foo\n" - "frame variable a_foo\n" - "will produce an output where only a and g are displayed\n" - "Other children of a_foo (b,c,d,e,f,h and i) are available by asking for them, as in:\n" - "frame variable a_foo.b a_foo.c ... a_foo.i\n" - "\n" - "Use option --raw to frame variable prevails on the filter\n" - "frame variable a_foo --raw\n" - "shows all the children of a_foo (a thru i) as if no filter was defined\n" - ); +R"( +The following examples of 'type filter add' refer to this code snippet for context: + + class Foo { + int a; + int b; + int c; + int d; + int e; + int f; + int g; + int h; + int i; + } + Foo my_foo; + +Adding a simple filter: + +(lldb) type filter add --child a --child g Foo +(lldb) frame variable my_foo + +)" "Produces output where only a and g are displayed. Other children of my_foo \ +(b, c, d, e, f, h and i) are available by asking for them explicitly:" R"( + +(lldb) frame variable my_foo.b my_foo.c my_foo.i + +)" "The formatting option --raw on frame variable bypasses the filter, showing \ +all children of my_foo as if no filter was defined:" R"( + +(lldb) frame variable my_foo --raw)" + ); } ~CommandObjectTypeFilterAdd () diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp index 650fd253af02..414e78403cc8 100644 --- a/source/Commands/CommandObjectWatchpoint.cpp +++ b/source/Commands/CommandObjectWatchpoint.cpp @@ -931,10 +931,14 @@ public: m_option_watchpoint () { SetHelpLong( - "Examples: \n\ - \n\ - watchpoint set variable -w read_write my_global_var \n\ - # Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n"); +R"( +Examples: + +(lldb) watchpoint set variable -w read_write my_global_var + +)" " Watches my_global_var for read/write access, with the region to watch \ +corresponding to the byte size of the data type." + ); CommandArgumentEntry arg; CommandArgumentData var_name_arg; @@ -1138,10 +1142,13 @@ public: m_option_watchpoint () { SetHelpLong( - "Examples: \n\ - \n\ - watchpoint set expression -w write -x 1 -- foo + 32\n\ - # Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n"); +R"( +Examples: + +(lldb) watchpoint set expression -w write -x 1 -- foo + 32 + + Watches write access for the 1-byte region pointed to by the address 'foo + 32')" + ); CommandArgumentEntry arg; CommandArgumentData expression_arg; diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp index d7d064e5fed9..84342cc8ffdf 100644 --- a/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/source/Commands/CommandObjectWatchpointCommand.cpp @@ -48,121 +48,112 @@ public: m_options (interpreter) { SetHelpLong ( -"\nGeneral information about entering watchpoint commands \n\ ------------------------------------------------------- \n\ - \n\ -This command will cause you to be prompted to enter the command or set \n\ -of commands you wish to be executed when the specified watchpoint is \n\ -hit. You will be told to enter your command(s), and will see a '> ' \n\ -prompt. Because you can enter one or many commands to be executed when \n\ -a watchpoint is hit, you will continue to be prompted after each \n\ -new-line that you enter, until you enter the word 'DONE', which will \n\ -cause the commands you have entered to be stored with the watchpoint \n\ -and executed when the watchpoint is hit. \n\ - \n\ -Syntax checking is not necessarily done when watchpoint commands are \n\ -entered. An improperly written watchpoint command will attempt to get \n\ -executed when the watchpoint gets hit, and usually silently fail. If \n\ -your watchpoint command does not appear to be getting executed, go \n\ -back and check your syntax. \n\ - \n\ - \n\ -Special information about PYTHON watchpoint commands \n\ ----------------------------------------------------- \n\ - \n\ -You may enter either one line of Python or multiple lines of Python \n\ -(including defining whole functions, if desired). If you enter a \n\ -single line of Python, that will be passed to the Python interpreter \n\ -'as is' when the watchpoint gets hit. If you enter function \n\ -definitions, they will be passed to the Python interpreter as soon as \n\ -you finish entering the watchpoint command, and they can be called \n\ -later (don't forget to add calls to them, if you want them called when \n\ -the watchpoint is hit). If you enter multiple lines of Python that \n\ -are not function definitions, they will be collected into a new, \n\ -automatically generated Python function, and a call to the newly \n\ -generated function will be attached to the watchpoint. \n\ - \n\ -This auto-generated function is passed in two arguments: \n\ - \n\ - frame: an SBFrame object representing the frame which hit the watchpoint. \n\ - From the frame you can get back to the thread and process. \n\ - wp: the watchpoint that was hit. \n\ - \n\ -Important Note: Because loose Python code gets collected into functions, \n\ -if you want to access global variables in the 'loose' code, you need to \n\ -specify that they are global, using the 'global' keyword. Be sure to \n\ -use correct Python syntax, including indentation, when entering Python \n\ -watchpoint commands. \n\ - \n\ -As a third option, you can pass the name of an already existing Python function \n\ -and that function will be attached to the watchpoint. It will get passed the \n\ -frame and wp_loc arguments mentioned above. \n\ - \n\ -Example Python one-line watchpoint command: \n\ - \n\ -(lldb) watchpoint command add -s python 1 \n\ -Enter your Python command(s). Type 'DONE' to end. \n\ -> print \"Hit this watchpoint!\" \n\ -> DONE \n\ - \n\ -As a convenience, this also works for a short Python one-liner: \n\ -(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\ -(lldb) run \n\ -Launching '.../a.out' (x86_64) \n\ -(lldb) Fri Sep 10 12:17:45 2010 \n\ -Process 21778 Stopped \n\ -* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\ - 36 \n\ - 37 int c(int val)\n\ - 38 {\n\ - 39 -> return val + 3;\n\ - 40 }\n\ - 41 \n\ - 42 int main (int argc, char const *argv[])\n\ -(lldb) \n\ - \n\ -Example multiple line Python watchpoint command, using function definition: \n\ - \n\ -(lldb) watchpoint command add -s python 1 \n\ -Enter your Python command(s). Type 'DONE' to end. \n\ -> def watchpoint_output (wp_no): \n\ -> out_string = \"Hit watchpoint number \" + repr (wp_no) \n\ -> print out_string \n\ -> return True \n\ -> watchpoint_output (1) \n\ -> DONE \n\ - \n\ - \n\ -Example multiple line Python watchpoint command, using 'loose' Python: \n\ - \n\ -(lldb) watchpoint command add -s p 1 \n\ -Enter your Python command(s). Type 'DONE' to end. \n\ -> global wp_count \n\ -> wp_count = wp_count + 1 \n\ -> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\ -> DONE \n\ - \n\ -In this case, since there is a reference to a global variable, \n\ -'wp_count', you will also need to make sure 'wp_count' exists and is \n\ -initialized: \n\ - \n\ -(lldb) script \n\ ->>> wp_count = 0 \n\ ->>> quit() \n\ - \n\ -(lldb) \n\ - \n\ - \n\ -Final Note: If you get a warning that no watchpoint command was generated, \n\ -but you did not get any syntax errors, you probably forgot to add a call \n\ -to your functions. \n\ - \n\ -Special information about debugger command watchpoint commands \n\ --------------------------------------------------------------- \n\ - \n\ -You may enter any debugger command, exactly as you would at the \n\ -debugger prompt. You may enter as many debugger commands as you like, \n\ -but do NOT enter more than one command per line. \n" ); +R"( +General information about entering watchpoint commands +------------------------------------------------------ + +)" "This command will prompt for commands to be executed when the specified \ +watchpoint is hit. Each command is typed on its own line following the '> ' \ +prompt until 'DONE' is entered." R"( + +)" "Syntactic errors may not be detected when initially entered, and many \ +malformed commands can silently fail when executed. If your watchpoint commands \ +do not appear to be executing, double-check the command syntax." R"( + +)" "Note: You may enter any debugger command exactly as you would at the debugger \ +prompt. There is no limit to the number of commands supplied, but do NOT enter \ +more than one command per line." R"( + +Special information about PYTHON watchpoint commands +---------------------------------------------------- + +)" "You may enter either one or more lines of Python, including function \ +definitions or calls to functions that will have been imported by the time \ +the code executes. Single line watchpoint commands will be interpreted 'as is' \ +when the watchpoint is hit. Multiple lines of Python will be wrapped in a \ +generated function, and a call to the function will be attached to the watchpoint." R"( + +This auto-generated function is passed in three arguments: + + frame: an lldb.SBFrame object for the frame which hit the watchpoint. + + wp: the watchpoint that was hit. + +)" "When specifying a python function with the --python-function option, you need \ +to supply the function name prepended by the module name:" R"( + + --python-function myutils.watchpoint_callback + +The function itself must have the following prototype: + +def watchpoint_callback(frame, wp): + # Your code goes here + +)" "The arguments are the same as the arguments passed to generated functions as \ +described above. Note that the global variable 'lldb.frame' will NOT be updated when \ +this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ +can get you to the thread via frame.GetThread(), the thread can get you to the \ +process via thread.GetProcess(), and the process can get you back to the target \ +via process.GetTarget()." R"( + +)" "Important Note: As Python code gets collected into functions, access to global \ +variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ +Python syntax, including indentation, when entering Python watchpoint commands." R"( + +Example Python one-line watchpoint command: + +(lldb) watchpoint command add -s python 1 +Enter your Python command(s). Type 'DONE' to end. +> print "Hit this watchpoint!" +> DONE + +As a convenience, this also works for a short Python one-liner: + +(lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()' +(lldb) run +Launching '.../a.out' (x86_64) +(lldb) Fri Sep 10 12:17:45 2010 +Process 21778 Stopped +* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread + 36 + 37 int c(int val) + 38 { + 39 -> return val + 3; + 40 } + 41 + 42 int main (int argc, char const *argv[]) + +Example multiple line Python watchpoint command, using function definition: + +(lldb) watchpoint command add -s python 1 +Enter your Python command(s). Type 'DONE' to end. +> def watchpoint_output (wp_no): +> out_string = "Hit watchpoint number " + repr (wp_no) +> print out_string +> return True +> watchpoint_output (1) +> DONE + +Example multiple line Python watchpoint command, using 'loose' Python: + +(lldb) watchpoint command add -s p 1 +Enter your Python command(s). Type 'DONE' to end. +> global wp_count +> wp_count = wp_count + 1 +> print "Hit this watchpoint " + repr(wp_count) + " times!" +> DONE + +)" "In this case, since there is a reference to a global variable, \ +'wp_count', you will also need to make sure 'wp_count' exists and is \ +initialized:" R"( + +(lldb) script +>>> wp_count = 0 +>>> quit() + +)" "Final Note: A warning that no watchpoint command was generated when there \ +are no syntax errors may indicate that a function was declared but never called." + ); CommandArgumentEntry arg; CommandArgumentData wp_id_arg; diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index 33cbede9ce14..36344307743e 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -887,20 +887,15 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su } else if (arch_type == eArchTypeELF) { - llvm::Triple::OSType ostype; switch (os) { - case llvm::ELF::ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break; - case llvm::ELF::ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break; - case llvm::ELF::ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break; - case llvm::ELF::ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break; - case llvm::ELF::ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break; - case llvm::ELF::ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break; - default: - ostype = llvm::Triple::OSType::UnknownOS; + case llvm::ELF::ELFOSABI_AIX: m_triple.setOS (llvm::Triple::OSType::AIX); break; + case llvm::ELF::ELFOSABI_FREEBSD: m_triple.setOS (llvm::Triple::OSType::FreeBSD); break; + case llvm::ELF::ELFOSABI_GNU: m_triple.setOS (llvm::Triple::OSType::Linux); break; + case llvm::ELF::ELFOSABI_NETBSD: m_triple.setOS (llvm::Triple::OSType::NetBSD); break; + case llvm::ELF::ELFOSABI_OPENBSD: m_triple.setOS (llvm::Triple::OSType::OpenBSD); break; + case llvm::ELF::ELFOSABI_SOLARIS: m_triple.setOS (llvm::Triple::OSType::Solaris); break; } - m_triple.setOS (ostype); - m_triple.setVendor (llvm::Triple::UnknownVendor); } // Fall back onto setting the machine type if the arch by name failed... if (m_triple.getArch () == llvm::Triple::UnknownArch) @@ -1186,11 +1181,46 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in } break; + case ArchSpec::eCore_mips32: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last) + return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_mips32el: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last) + return true; + try_inverse = false; + } + case ArchSpec::eCore_mips64: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last) + return true; + if (core2 >= ArchSpec::kCore_mips64_first && core2 <= ArchSpec::kCore_mips64_last) + return true; + try_inverse = false; + } + + case ArchSpec::eCore_mips64el: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last) + return true; + if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= ArchSpec::kCore_mips64el_last) + return true; + try_inverse = false; + } + case ArchSpec::eCore_mips64r2: case ArchSpec::eCore_mips64r3: case ArchSpec::eCore_mips64r5: - case ArchSpec::eCore_mips64r6: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10)) @@ -1201,11 +1231,9 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in } break; - case ArchSpec::eCore_mips64el: case ArchSpec::eCore_mips64r2el: case ArchSpec::eCore_mips64r3el: case ArchSpec::eCore_mips64r5el: - case ArchSpec::eCore_mips64r6el: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10)) @@ -1216,6 +1244,63 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in } break; + case ArchSpec::eCore_mips32r2: + case ArchSpec::eCore_mips32r3: + case ArchSpec::eCore_mips32r5: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32_first && core2 <= core1) + return true; + } + break; + + case ArchSpec::eCore_mips32r2el: + case ArchSpec::eCore_mips32r3el: + case ArchSpec::eCore_mips32r5el: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= core1) + return true; + } + break; + + case ArchSpec::eCore_mips32r6: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6) + return true; + } + break; + + case ArchSpec::eCore_mips32r6el: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el) + return true; + return true; + } + break; + + case ArchSpec::eCore_mips64r6: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6) + return true; + if (core2 == ArchSpec::eCore_mips64 || core2 == ArchSpec::eCore_mips64r6) + return true; + } + break; + + case ArchSpec::eCore_mips64r6el: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el) + return true; + if (core2 == ArchSpec::eCore_mips64el || core2 == ArchSpec::eCore_mips64r6el) + return true; + } + break; + default: break; } diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp index b4b43ed97780..861bece98da9 100644 --- a/source/Core/DataExtractor.cpp +++ b/source/Core/DataExtractor.cpp @@ -1830,26 +1830,14 @@ DataExtractor::Dump (Stream *s, } else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy)) { + const auto &semantics = ast->getFloatTypeSemantics(ast->LongDoubleTy); + const auto byte_size = (llvm::APFloat::getSizeInBits(semantics) + 7) / 8; + llvm::APInt apint; - switch (target_sp->GetArchitecture().GetMachine()) + if (GetAPInt(*this, &offset, byte_size, apint)) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - // clang will assert when constructing the apfloat if we use a 16 byte integer value - if (GetAPInt (*this, &offset, 10, apint)) - { - llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint); - apfloat.toString(sv, format_precision, format_max_padding); - } - break; - - default: - if (GetAPInt (*this, &offset, item_byte_size, apint)) - { - llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint); - apfloat.toString(sv, format_precision, format_max_padding); - } - break; + llvm::APFloat apfloat(semantics, apint); + apfloat.toString(sv, format_precision, format_max_padding); } } else if (item_bit_size == ast->getTypeSize(ast->HalfTy)) diff --git a/source/Core/FormatEntity.cpp b/source/Core/FormatEntity.cpp index 2ebe95747bc0..e89d6c9cb4a9 100644 --- a/source/Core/FormatEntity.cpp +++ b/source/Core/FormatEntity.cpp @@ -1666,7 +1666,7 @@ FormatEntity::Format (const Entry &entry, if (inline_info) { s.PutCString(" [inlined] "); - inline_info->GetName().Dump(&s); + inline_info->GetName(sc->function->GetLanguage()).Dump(&s); } } } @@ -1679,9 +1679,9 @@ FormatEntity::Format (const Entry &entry, { ConstString name; if (sc->function) - name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); + name = sc->function->GetNameNoArguments(); else if (sc->symbol) - name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); + name = sc->symbol->GetNameNoArguments(); if (name) { s.PutCString(name.GetCString()); @@ -1724,7 +1724,7 @@ FormatEntity::Format (const Entry &entry, { s.PutCString (cstr); s.PutCString (" [inlined] "); - cstr = inline_info->GetName().GetCString(); + cstr = inline_info->GetName(sc->function->GetLanguage()).GetCString(); } VariableList args; diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp index 3e1a8bb89139..a1916fe913c4 100644 --- a/source/Core/Mangled.cpp +++ b/source/Core/Mangled.cpp @@ -66,7 +66,7 @@ cstring_is_mangled(const char *s) } static const ConstString & -get_demangled_name_without_arguments (const Mangled *obj) +get_demangled_name_without_arguments (ConstString mangled, ConstString demangled) { // This pair is <mangled name, demangled name without function arguments> static std::pair<ConstString, ConstString> g_most_recent_mangled_to_name_sans_args; @@ -77,9 +77,6 @@ get_demangled_name_without_arguments (const Mangled *obj) static ConstString g_last_mangled; static ConstString g_last_demangled; - ConstString mangled = obj->GetMangledName (); - ConstString demangled = obj->GetDemangledName (); - if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) { return g_most_recent_mangled_to_name_sans_args.second; @@ -197,7 +194,7 @@ Mangled::Clear () int Mangled::Compare (const Mangled& a, const Mangled& b) { - return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled)); + return ConstString::Compare(a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled), a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled)); } @@ -261,7 +258,7 @@ Mangled::SetValue (const ConstString &name) // object's lifetime. //---------------------------------------------------------------------- const ConstString& -Mangled::GetDemangledName () const +Mangled::GetDemangledName (lldb::LanguageType language) const { // Check to make sure we have a valid mangled name and that we // haven't already decoded our mangled name. @@ -339,13 +336,20 @@ Mangled::GetDemangledName () const } +ConstString +Mangled::GetDisplayDemangledName (lldb::LanguageType language) const +{ + return GetDemangledName(language); +} + bool -Mangled::NameMatches (const RegularExpression& regex) const +Mangled::NameMatches (const RegularExpression& regex, lldb::LanguageType language) const { if (m_mangled && regex.Execute (m_mangled.AsCString())) return true; - - if (GetDemangledName() && regex.Execute (m_demangled.AsCString())) + + ConstString demangled = GetDemangledName(language); + if (demangled && regex.Execute (demangled.AsCString())) return true; return false; } @@ -353,30 +357,28 @@ Mangled::NameMatches (const RegularExpression& regex) const //---------------------------------------------------------------------- // Get the demangled name if there is one, else return the mangled name. //---------------------------------------------------------------------- -const ConstString& -Mangled::GetName (Mangled::NamePreference preference) const +ConstString +Mangled::GetName (lldb::LanguageType language, Mangled::NamePreference preference) const { + ConstString demangled = GetDemangledName(language); + if (preference == ePreferDemangledWithoutArguments) { - // Call the accessor to make sure we get a demangled name in case - // it hasn't been demangled yet... - GetDemangledName(); - - return get_demangled_name_without_arguments (this); + return get_demangled_name_without_arguments (m_mangled, demangled); } if (preference == ePreferDemangled) { // Call the accessor to make sure we get a demangled name in case // it hasn't been demangled yet... - if (GetDemangledName()) - return m_demangled; + if (demangled) + return demangled; return m_mangled; } else { if (m_mangled) return m_mangled; - return GetDemangledName(); + return demangled; } } @@ -429,7 +431,7 @@ Mangled::GuessLanguage () const ConstString mangled = GetMangledName(); if (mangled) { - if (GetDemangledName()) + if (GetDemangledName(lldb::eLanguageTypeUnknown)) { if (cstring_is_mangled(mangled.GetCString())) return lldb::eLanguageTypeC_plus_plus; @@ -447,7 +449,7 @@ operator << (Stream& s, const Mangled& obj) if (obj.GetMangledName()) s << "mangled = '" << obj.GetMangledName() << "'"; - const ConstString& demangled = obj.GetDemangledName(); + const ConstString& demangled = obj.GetDemangledName(lldb::eLanguageTypeUnknown); if (demangled) s << ", demangled = '" << demangled << '\''; else diff --git a/source/Core/StructuredData.cpp b/source/Core/StructuredData.cpp index a2c440948af1..efc104f1f3e8 100644 --- a/source/Core/StructuredData.cpp +++ b/source/Core/StructuredData.cpp @@ -14,301 +14,148 @@ #include <inttypes.h> #include "lldb/Core/StreamString.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Utility/JSON.h" using namespace lldb_private; -static StructuredData::ObjectSP read_json_object (const char **ch); -static StructuredData::ObjectSP read_json_array (const char **ch); +//---------------------------------------------------------------------- +// Functions that use a JSONParser to parse JSON into StructuredData +//---------------------------------------------------------------------- +static StructuredData::ObjectSP ParseJSONValue (JSONParser &json_parser); +static StructuredData::ObjectSP ParseJSONObject (JSONParser &json_parser); +static StructuredData::ObjectSP ParseJSONArray (JSONParser &json_parser); static StructuredData::ObjectSP -read_json_number (const char **ch) +ParseJSONObject (JSONParser &json_parser) { - StructuredData::ObjectSP object_sp; - while (isspace (**ch)) - (*ch)++; - const char *start_of_number = *ch; - bool is_integer = true; - bool is_float = false; - while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E') - { - if (isdigit(**ch) == false && **ch != '-') - { - is_integer = false; - is_float = true; - } - (*ch)++; - } - while (isspace (**ch)) - (*ch)++; - if (**ch == ',' || **ch == ']' || **ch == '}') + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<StructuredData::Dictionary> dict_up(new StructuredData::Dictionary()); + + std::string value; + std::string key; + while (1) { - if (is_integer) + JSONParser::Token token = json_parser.GetToken(value); + + if (token == JSONParser::Token::String) { - errno = 0; - uint64_t val = strtoul (start_of_number, NULL, 10); - if (errno == 0) + key.swap(value); + token = json_parser.GetToken(value); + if (token == JSONParser::Token::Colon) { - object_sp.reset(new StructuredData::Integer()); - object_sp->GetAsInteger()->SetValue (val); + StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); + if (value_sp) + dict_up->AddItem(key, value_sp); + else + break; } } - if (is_float) + else if (token == JSONParser::Token::ObjectEnd) { - char *end_of_number = NULL; - errno = 0; - double val = strtod (start_of_number, &end_of_number); - if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL) - { - object_sp.reset(new StructuredData::Float()); - object_sp->GetAsFloat()->SetValue (val); - } + return StructuredData::ObjectSP(dict_up.release()); } - } - return object_sp; -} - -static std::string -read_json_string (const char **ch) -{ - std::string string; - if (**ch == '"') - { - (*ch)++; - while (**ch != '\0') + else if (token == JSONParser::Token::Comma) { - if (**ch == '"') - { - (*ch)++; - while (isspace (**ch)) - (*ch)++; - break; - } - else if (**ch == '\\') - { - switch (**ch) - { - case '"': - string.push_back('"'); - *ch += 2; - break; - case '\\': - string.push_back('\\'); - *ch += 2; - break; - case '/': - string.push_back('/'); - *ch += 2; - break; - case 'b': - string.push_back('\b'); - *ch += 2; - break; - case 'f': - string.push_back('\f'); - *ch += 2; - break; - case 'n': - string.push_back('\n'); - *ch += 2; - break; - case 'r': - string.push_back('\r'); - *ch += 2; - break; - case 't': - string.push_back('\t'); - *ch += 2; - break; - case 'u': - // FIXME handle four-hex-digits - *ch += 10; - break; - default: - *ch += 1; - } - } - else - { - string.push_back (**ch); - } - (*ch)++; + continue; + } + else + { + break; } } - return string; + return StructuredData::ObjectSP(); } static StructuredData::ObjectSP -read_json_value (const char **ch) +ParseJSONArray (JSONParser &json_parser) { - StructuredData::ObjectSP object_sp; - while (isspace (**ch)) - (*ch)++; + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array()); - if (**ch == '{') - { - object_sp = read_json_object (ch); - } - else if (**ch == '[') + std::string value; + std::string key; + while (1) { - object_sp = read_json_array (ch); - } - else if (**ch == '"') - { - std::string string = read_json_string (ch); - object_sp.reset(new StructuredData::String()); - object_sp->GetAsString()->SetValue(string); - } - else - { - if (strncmp (*ch, "true", 4) == 0) - { - object_sp.reset(new StructuredData::Boolean()); - object_sp->GetAsBoolean()->SetValue(true); - *ch += 4; - } - else if (strncmp (*ch, "false", 5) == 0) + StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); + if (value_sp) + array_up->AddItem(value_sp); + else + break; + + JSONParser::Token token = json_parser.GetToken(value); + if (token == JSONParser::Token::Comma) { - object_sp.reset(new StructuredData::Boolean()); - object_sp->GetAsBoolean()->SetValue(false); - *ch += 5; + continue; } - else if (strncmp (*ch, "null", 4) == 0) + else if (token == JSONParser::Token::ArrayEnd) { - object_sp.reset(new StructuredData::Null()); - *ch += 4; + return StructuredData::ObjectSP(array_up.release()); } else { - object_sp = read_json_number (ch); + break; } } - return object_sp; + return StructuredData::ObjectSP(); } static StructuredData::ObjectSP -read_json_array (const char **ch) +ParseJSONValue (JSONParser &json_parser) { - StructuredData::ObjectSP object_sp; - if (**ch == '[') + std::string value; + const JSONParser::Token token = json_parser.GetToken(value); + switch (token) { - (*ch)++; - while (isspace (**ch)) - (*ch)++; + case JSONParser::Token::ObjectStart: + return ParseJSONObject(json_parser); - bool first_value = true; - while (**ch != '\0' && (first_value || **ch == ',')) - { - if (**ch == ',') - (*ch)++; - first_value = false; - while (isspace (**ch)) - (*ch)++; - lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch); - if (value_sp) + case JSONParser::Token::ArrayStart: + return ParseJSONArray(json_parser); + + case JSONParser::Token::Integer: { - if (object_sp.get() == NULL) - { - object_sp.reset(new StructuredData::Array()); - } - object_sp->GetAsArray()->Push (value_sp); + bool success = false; + uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); + if (success) + return StructuredData::ObjectSP(new StructuredData::Integer(uval)); } - while (isspace (**ch)) - (*ch)++; - } - if (**ch == ']') - { - // FIXME should throw an error if we don't see a } to close out the JSON object - (*ch)++; - while (isspace (**ch)) - (*ch)++; - } - } - return object_sp; -} + break; -static StructuredData::ObjectSP -read_json_object (const char **ch) -{ - StructuredData::ObjectSP object_sp; - if (**ch == '{') - { - (*ch)++; - while (isspace (**ch)) - (*ch)++; - bool first_pair = true; - while (**ch != '\0' && (first_pair || **ch == ',')) - { - first_pair = false; - if (**ch == ',') - (*ch)++; - while (isspace (**ch)) - (*ch)++; - if (**ch != '"') - break; - std::string key_string = read_json_string (ch); - while (isspace (**ch)) - (*ch)++; - if (key_string.size() > 0 && **ch == ':') + case JSONParser::Token::Float: { - (*ch)++; - while (isspace (**ch)) - (*ch)++; - lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch); - if (value_sp.get()) - { - if (object_sp.get() == NULL) - { - object_sp.reset(new StructuredData::Dictionary()); - } - object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp); - } + bool success = false; + double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); + if (success) + return StructuredData::ObjectSP(new StructuredData::Float(val)); } - while (isspace (**ch)) - (*ch)++; - } - if (**ch == '}') - { - // FIXME should throw an error if we don't see a } to close out the JSON object - (*ch)++; - while (isspace (**ch)) - (*ch)++; - } + break; + + case JSONParser::Token::String: + return StructuredData::ObjectSP(new StructuredData::String(value)); + + case JSONParser::Token::True: + case JSONParser::Token::False: + return StructuredData::ObjectSP(new StructuredData::Boolean(token == JSONParser::Token::True)); + + case JSONParser::Token::Null: + return StructuredData::ObjectSP(new StructuredData::Null()); + + default: + break; } - return object_sp; -} + return StructuredData::ObjectSP(); +} StructuredData::ObjectSP StructuredData::ParseJSON (std::string json_text) { - StructuredData::ObjectSP object_sp; - const size_t json_text_size = json_text.size(); - if (json_text_size > 0) - { - const char *start_of_json_text = json_text.c_str(); - const char *c = json_text.c_str(); - while (*c != '\0' && - static_cast<size_t>(c - start_of_json_text) <= json_text_size) - { - while (isspace (*c) && - static_cast<size_t>(c - start_of_json_text) < json_text_size) - c++; - if (*c == '{') - { - object_sp = read_json_object (&c); - } - else if (*c == '[') - { - object_sp = read_json_array (&c); - } - else - { - // We have bad characters here, this is likely an illegal JSON string. - return object_sp; - } - } - } + JSONParser json_parser(json_text.c_str()); + StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); return object_sp; } @@ -395,7 +242,7 @@ StructuredData::Integer::Dump (Stream &s) const void StructuredData::Float::Dump (Stream &s) const { - s.Printf ("%lf", m_value); + s.Printf ("%lg", m_value); } void diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp index 47456ba5c45b..4e0fffbe6a1a 100644 --- a/source/DataFormatters/FormatManager.cpp +++ b/source/DataFormatters/FormatManager.cpp @@ -1608,6 +1608,26 @@ FormatManager::LoadHardcodedFormatters() } return nullptr; }); + m_hardcoded_summaries.push_back( + [](lldb_private::ValueObject& valobj, + lldb::DynamicValueType, + FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer { + static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags() + .SetCascades(true) + .SetDontShowChildren(true) + .SetHideItemNames(true) + .SetShowMembersOneLiner(true) + .SetSkipPointers(true) + .SetSkipReferences(false), + lldb_private::formatters::VectorTypeSummaryProvider, + "vector_type pointer summary provider")); + if (valobj.GetClangType().IsVectorType(nullptr, nullptr)) + { + if (fmt_mgr.GetCategory(fmt_mgr.m_vectortypes_category_name)->IsEnabled()) + return formatter_sp; + } + return nullptr; + }); } { // insert code to load synthetics here diff --git a/source/DataFormatters/VectorType.cpp b/source/DataFormatters/VectorType.cpp index 57bf696ba4fa..316d7b540bcd 100644 --- a/source/DataFormatters/VectorType.cpp +++ b/source/DataFormatters/VectorType.cpp @@ -7,9 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "lldb/DataFormatters/CXXFormatterFunctions.h" +#include "lldb/DataFormatters/VectorType.h" #include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/CXXFormatterFunctions.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTType.h" @@ -267,6 +268,51 @@ namespace lldb_private { } } +bool +lldb_private::formatters::VectorTypeSummaryProvider (ValueObject& valobj, + Stream& s, + const TypeSummaryOptions&) +{ + auto synthetic_children = VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP()); + if (!synthetic_children) + return false; + + synthetic_children->Update(); + + s.PutChar('('); + bool first = true; + + size_t idx = 0, len = synthetic_children->CalculateNumChildren(); + + for (; + idx < len; + idx++) + { + auto child_sp = synthetic_children->GetChildAtIndex(idx); + if (!child_sp) + continue; + child_sp = child_sp->GetQualifiedRepresentationIfAvailable(lldb::eDynamicDontRunTarget, true); + + const char* child_value = child_sp->GetValueAsCString(); + if (child_value && *child_value) + { + if (first) + { + s.Printf("%s", child_value); + first = false; + } + else + { + s.Printf(", %s", child_value); + } + } + } + + s.PutChar(')'); + + return true; +} + lldb_private::SyntheticChildrenFrontEnd* lldb_private::formatters::VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) { diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp index 1013bb540601..2c66a0aa4278 100644 --- a/source/Expression/ClangExpressionDeclMap.cpp +++ b/source/Expression/ClangExpressionDeclMap.cpp @@ -1527,6 +1527,31 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, context.m_found.function_with_type_info = true; context.m_found.function = true; } + else if (llvm::isa<clang::VarDecl>(decl_from_modules)) + { + if (log) + { + log->Printf(" CAS::FEVD[%u] Matching variable found for \"%s\" in the modules", + current_id, + name.GetCString()); + } + + clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules); + clang::VarDecl *copied_var_decl = copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) : nullptr; + + if (!copied_var_decl) + { + if (log) + log->Printf(" CAS::FEVD[%u] - Couldn't export a variable declaration from the modules", + current_id); + + break; + } + + context.AddNamedDecl(copied_var_decl); + + context.m_found.variable = true; + } } } while (0); } diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp index 3d5350d34028..2b344b0c3733 100644 --- a/source/Expression/ClangExpressionParser.cpp +++ b/source/Expression/ClangExpressionParser.cpp @@ -541,10 +541,11 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule()); Error interpret_error; + Process *process = exe_ctx.GetProcessPtr(); - can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error); + bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); + can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls); - Process *process = exe_ctx.GetProcessPtr(); if (!ir_can_run) { diff --git a/source/Expression/ClangModulesDeclVendor.cpp b/source/Expression/ClangModulesDeclVendor.cpp index 97a4d088b982..e8253630724a 100644 --- a/source/Expression/ClangModulesDeclVendor.cpp +++ b/source/Expression/ClangModulesDeclVendor.cpp @@ -18,6 +18,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" @@ -444,18 +445,18 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec } ssize_t found_priority = -1; - clang::MacroInfo *info = nullptr; + clang::MacroInfo *macro_info = nullptr; - for (clang::ModuleMacro *macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii)) + for (clang::ModuleMacro *module_macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii)) { - clang::Module *module = macro->getOwningModule(); + clang::Module *module = module_macro->getOwningModule(); { ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(module)); if (pi != module_priorities.end() && pi->second > found_priority) { - info = macro->getMacroInfo(); + macro_info = module_macro->getMacroInfo(); found_priority = pi->second; } } @@ -465,26 +466,20 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec if (top_level_module != module) { ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(top_level_module)); - + if ((pi != module_priorities.end()) && pi->second > found_priority) { - info = macro->getMacroInfo(); + macro_info = module_macro->getMacroInfo(); found_priority = pi->second; } } } - if (!info) + if (macro_info) { - continue; - } - - if (mi->second.getLatest()->getKind() == clang::MacroDirective::MD_Define) - { std::string macro_expansion = "#define "; macro_expansion.append(mi->first->getName().str().c_str()); - - if (clang::MacroInfo *macro_info = mi->second.getLatest()->getMacroInfo()) + { if (macro_info->isFunctionLike()) { @@ -560,9 +555,7 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec if (invalid) { -#ifdef LLDB_CONFIGURATION_DEBUG - assert(!"Unhandled token kind"); -#endif + lldbassert(!"Unhandled token kind"); macro_expansion.append("<unknown literal value>"); } else @@ -594,17 +587,11 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec } } } - } - else - { -#ifdef LLDB_CONFIGURATION_DEBUG - assert(!"#define with no macro info"); -#endif - } - - if (handler(macro_expansion)) - { - return; + + if (handler(macro_expansion)) + { + return; + } } } } diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp index 661bab0e4b43..0da70e2b0a70 100644 --- a/source/Expression/ClangUserExpression.cpp +++ b/source/Expression/ClangUserExpression.cpp @@ -891,7 +891,8 @@ ClangUserExpression::Execute (Stream &error_stream, *m_execution_unit_sp.get(), interpreter_error, function_stack_bottom, - function_stack_top); + function_stack_top, + exe_ctx); if (!interpreter_error.Success()) { diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp index 7232685e4f41..59c7fb6f786f 100644 --- a/source/Expression/IRExecutionUnit.cpp +++ b/source/Expression/IRExecutionUnit.cpp @@ -373,7 +373,7 @@ IRExecutionUnit::GetRunnableInfo(Error &error, ss.PutCString("\n"); emitNewLine = true; ss.PutCString(" "); - ss.PutCString(Mangled(failed_lookup).GetDemangledName().AsCString()); + ss.PutCString(Mangled(failed_lookup).GetDemangledName(lldb::eLanguageTypeObjC_plus_plus).AsCString()); } m_failed_lookups.clear(); diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp index 11bc011d6d64..cf2a93b3ea7f 100644 --- a/source/Expression/IRForTarget.cpp +++ b/source/Expression/IRForTarget.cpp @@ -267,11 +267,11 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun, { if (mangled_name.GetMangledName()) m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n", - mangled_name.GetName().GetCString(), + mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString(), mangled_name.GetMangledName().GetCString()); else m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n", - mangled_name.GetName().GetCString()); + mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString()); } return LookupResult::Fail; } diff --git a/source/Expression/IRInterpreter.cpp b/source/Expression/IRInterpreter.cpp index d11bdc1671b6..926d1f22b6aa 100644 --- a/source/Expression/IRInterpreter.cpp +++ b/source/Expression/IRInterpreter.cpp @@ -10,17 +10,28 @@ #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Module.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObject.h" #include "lldb/Expression/IRMemoryMap.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/Endian.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h" + #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" @@ -455,7 +466,8 @@ static const char *infinite_loop_error = "Interpreter ran for too m bool IRInterpreter::CanInterpret (llvm::Module &module, llvm::Function &function, - lldb_private::Error &error) + lldb_private::Error &error, + const bool support_function_calls) { lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -507,7 +519,7 @@ IRInterpreter::CanInterpret (llvm::Module &module, return false; } - if (!CanIgnoreCall(call_inst)) + if (!CanIgnoreCall(call_inst) && !support_function_calls) { if (log) log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str()); @@ -611,7 +623,8 @@ IRInterpreter::Interpret (llvm::Module &module, lldb_private::IRMemoryMap &memory_map, lldb_private::Error &error, lldb::addr_t stack_frame_bottom, - lldb::addr_t stack_frame_top) + lldb::addr_t stack_frame_top, + lldb_private::ExecutionContext &exe_ctx) { lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -668,29 +681,7 @@ IRInterpreter::Interpret (llvm::Module &module, { default: break; - case Instruction::Call: - { - const CallInst *call_inst = dyn_cast<CallInst>(inst); - - if (!call_inst) - { - if (log) - log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName()); - error.SetErrorToGenericError(); - error.SetErrorString(interpreter_internal_error); - return false; - } - if (!CanIgnoreCall(call_inst)) - { - if (log) - log->Printf("The interpreter shouldn't have accepted %s", PrintValue(call_inst).c_str()); - error.SetErrorToGenericError(); - error.SetErrorString(interpreter_internal_error); - return false; - } - } - break; case Instruction::Add: case Instruction::Sub: case Instruction::Mul: @@ -1476,6 +1467,242 @@ IRInterpreter::Interpret (llvm::Module &module, } } break; + case Instruction::Call: + { + const CallInst *call_inst = dyn_cast<CallInst>(inst); + + if (!call_inst) + { + if (log) + log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName()); + error.SetErrorToGenericError(); + error.SetErrorString(interpreter_internal_error); + return false; + } + + if (CanIgnoreCall(call_inst)) + break; + + // Get the return type + llvm::Type *returnType = call_inst->getType(); + if (returnType == nullptr) + { + error.SetErrorToGenericError(); + error.SetErrorString("unable to access return type"); + return false; + } + + // Work with void, integer and pointer return types + if (!returnType->isVoidTy() && + !returnType->isIntegerTy() && + !returnType->isPointerTy()) + { + error.SetErrorToGenericError(); + error.SetErrorString("return type is not supported"); + return false; + } + + // Check we can actually get a thread + if (exe_ctx.GetThreadPtr() == nullptr) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("unable to acquire thread"); + return false; + } + + // Make sure we have a valid process + if (!exe_ctx.GetProcessPtr()) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("unable to get the process"); + return false; + } + + // Find the address of the callee function + lldb_private::Scalar I; + const llvm::Value *val = call_inst->getCalledValue(); + + if (!frame.EvaluateValue(I, val, module)) + { + error.SetErrorToGenericError(); + error.SetErrorString("unable to get address of function"); + return false; + } + lldb_private::Address funcAddr(I.ULongLong(LLDB_INVALID_ADDRESS)); + + lldb_private::StreamString error_stream; + lldb_private::EvaluateExpressionOptions options; + + // We generally receive a function pointer which we must dereference + llvm::Type* prototype = val->getType(); + if (!prototype->isPointerTy()) + { + error.SetErrorToGenericError(); + error.SetErrorString("call need function pointer"); + return false; + } + + // Dereference the function pointer + prototype = prototype->getPointerElementType(); + if (!(prototype->isFunctionTy() || prototype->isFunctionVarArg())) + { + error.SetErrorToGenericError(); + error.SetErrorString("call need function pointer"); + return false; + } + + // Find number of arguments + const int numArgs = call_inst->getNumArgOperands(); + + // We work with a fixed array of 16 arguments which is our upper limit + static lldb_private::ABI::CallArgument rawArgs[16]; + if (numArgs >= 16) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("function takes too many arguments"); + return false; + } + + // Push all function arguments to the argument list that will + // be passed to the call function thread plan + for (int i = 0; i < numArgs; i++) + { + // Get details of this argument + llvm::Value *arg_op = call_inst->getArgOperand(i); + llvm::Type *arg_ty = arg_op->getType(); + + // Ensure that this argument is an supported type + if (!arg_ty->isIntegerTy() && !arg_ty->isPointerTy()) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("argument %d must be integer type", i); + return false; + } + + // Extract the arguments value + lldb_private::Scalar tmp_op = 0; + if (!frame.EvaluateValue(tmp_op, arg_op, module)) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("unable to evaluate argument %d", i); + return false; + } + + // Check if this is a string literal or constant string pointer + if (arg_ty->isPointerTy()) + { + // Pointer to just one type + assert(arg_ty->getNumContainedTypes() == 1); + + lldb::addr_t addr = tmp_op.ULongLong(); + size_t dataSize = 0; + + if (memory_map.GetAllocSize(addr, dataSize)) + { + // Create the required buffer + rawArgs[i].size = dataSize; + rawArgs[i].data_ap.reset(new uint8_t[dataSize + 1]); + + // Read string from host memory + memory_map.ReadMemory(rawArgs[i].data_ap.get(), addr, dataSize, error); + if (error.Fail()) + { + assert(!"we have failed to read the string from memory"); + return false; + } + // Add null terminator + rawArgs[i].data_ap[dataSize] = '\0'; + rawArgs[i].type = lldb_private::ABI::CallArgument::HostPointer; + } + else + { + assert(!"unable to locate host data for transfer to device"); + return false; + } + } + else /* if ( arg_ty->isPointerTy() ) */ + { + rawArgs[i].type = lldb_private::ABI::CallArgument::TargetValue; + // Get argument size in bytes + rawArgs[i].size = arg_ty->getIntegerBitWidth() / 8; + // Push value into argument list for thread plan + rawArgs[i].value = tmp_op.ULongLong(); + } + + } + + // Pack the arguments into an llvm::array + llvm::ArrayRef<lldb_private::ABI::CallArgument> args(rawArgs, numArgs); + + // Setup a thread plan to call the target function + lldb::ThreadPlanSP call_plan_sp + ( + new lldb_private::ThreadPlanCallFunctionUsingABI + ( + exe_ctx.GetThreadRef(), + funcAddr, + *prototype, + *returnType, + args, + options + ) + ); + + // Check if the plan is valid + if (!call_plan_sp || !call_plan_sp->ValidatePlan(&error_stream)) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("unable to make ThreadPlanCallFunctionUsingABI for 0x%llx", I.ULongLong()); + return false; + } + + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + // Execute the actual function call thread plan + lldb::ExpressionResults res = exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, error_stream); + + // Check that the thread plan completed successfully + if (res != lldb::ExpressionResults::eExpressionCompleted) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("ThreadPlanCallFunctionUsingABI failed"); + return false; + } + + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + // Void return type + if (returnType->isVoidTy()) + { + // Cant assign to void types, so we leave the frame untouched + } + else + // Integer or pointer return type + if (returnType->isIntegerTy() || returnType->isPointerTy()) + { + // Get the encapsulated return value + lldb::ValueObjectSP retVal = call_plan_sp.get()->GetReturnValueObject(); + + lldb_private::Scalar returnVal = -1; + lldb_private::ValueObject *vobj = retVal.get(); + + // Check if the return value is valid + if (vobj == nullptr || retVal.empty()) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("unable to get the return value"); + return false; + } + + // Extract the return value as a integer + lldb_private::Value & value = vobj->GetValue(); + returnVal = value.GetScalar(); + + // Push the return value as the result + frame.AssignValue(inst, returnVal, module); + } + } + break; } ++frame.m_ii; diff --git a/source/Expression/IRMemoryMap.cpp b/source/Expression/IRMemoryMap.cpp index a4fe7a968379..4733b16d5f1c 100644 --- a/source/Expression/IRMemoryMap.cpp +++ b/source/Expression/IRMemoryMap.cpp @@ -418,6 +418,32 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error) m_allocations.erase(iter); } +bool +IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size) +{ + AllocationMap::iterator iter = FindAllocation(address, size); + if (iter == m_allocations.end()) + return false; + + Allocation &al = iter->second; + + if (address > (al.m_process_start + al.m_size)) + { + size = 0; + return false; + } + + if (address > al.m_process_start) + { + int dif = address - al.m_process_start; + size = al.m_size - dif; + return true; + } + + size = al.m_size; + return true; +} + void IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error) { diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index 20d6355e6195..94c78a015651 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -1070,13 +1070,9 @@ Host::SetCrashDescription (const char *description) #endif -#if !defined (__linux__) && !defined (__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined (__NetBSD__) - -const lldb_private::UnixSignalsSP& -Host::GetUnixSignals () +const UnixSignalsSP & +Host::GetUnixSignals() { - static UnixSignalsSP s_unix_signals_sp (new UnixSignals ()); + static const auto s_unix_signals_sp = UnixSignals::Create(HostInfo::GetArchitecture()); return s_unix_signals_sp; } - -#endif diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp index 35003f5d0207..818d69bdabdc 100644 --- a/source/Host/common/NativeProcessProtocol.cpp +++ b/source/Host/common/NativeProcessProtocol.cpp @@ -441,3 +441,25 @@ NativeProcessProtocol::Terminate () { // Default implementation does nothing. } + +#ifndef __linux__ +// These need to be implemented to support lldb-gdb-server on a given platform. Stubs are +// provided to make the rest of the code link on non-supported platforms. + +Error +NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) +{ + llvm_unreachable("Platform has no NativeProcessProtocol support"); +} + +Error +NativeProcessProtocol::Attach (lldb::pid_t pid, + NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) +{ + llvm_unreachable("Platform has no NativeProcessProtocol support"); +} + +#endif diff --git a/source/Host/common/StringConvert.cpp b/source/Host/common/StringConvert.cpp index 0a8e75f4b877..c4ff67515d4e 100644 --- a/source/Host/common/StringConvert.cpp +++ b/source/Host/common/StringConvert.cpp @@ -15,79 +15,103 @@ // Project includes #include "lldb/Host/StringConvert.h" -namespace lldb_private { - -namespace StringConvert { - -int32_t -ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) +namespace lldb_private { - if (s && s[0]) + namespace StringConvert { - char *end = nullptr; - const long sval = ::strtol (s, &end, base); - if (*end == '\0') + + int32_t + ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) { + if (s && s[0]) + { + char *end = nullptr; + const long sval = ::strtol (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); + return (int32_t)sval; // All characters were used, return the result + } + } if (success_ptr) - *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); - return (int32_t)sval; // All characters were used, return the result + *success_ptr = false; + return fail_value; } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} -uint32_t -ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - const unsigned long uval = ::strtoul (s, &end, base); - if (*end == '\0') + uint32_t + ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) { + if (s && s[0]) + { + char *end = nullptr; + const unsigned long uval = ::strtoul (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = (uval <= UINT32_MAX); + return (uint32_t)uval; // All characters were used, return the result + } + } if (success_ptr) - *success_ptr = (uval <= UINT32_MAX); - return (uint32_t)uval; // All characters were used, return the result + *success_ptr = false; + return fail_value; } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} -int64_t -ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - int64_t uval = ::strtoll (s, &end, base); - if (*end == '\0') + int64_t + ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) { - if (success_ptr) *success_ptr = true; - return uval; // All characters were used, return the result + if (s && s[0]) + { + char *end = nullptr; + int64_t uval = ::strtoll (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} -uint64_t -ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - uint64_t uval = ::strtoull (s, &end, base); - if (*end == '\0') + uint64_t + ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) { - if (success_ptr) *success_ptr = true; - return uval; // All characters were used, return the result + if (s && s[0]) + { + char *end = nullptr; + uint64_t uval = ::strtoull (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} -} + double + ToDouble (const char *s, double fail_value, bool *success_ptr) + { + if (s && s[0]) + { + char *end = nullptr; + double val = strtod (s, &end); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = true; + return val; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; + } + } } diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp index 8b1c580af27d..7f8d7ae96e7a 100644 --- a/source/Host/freebsd/Host.cpp +++ b/source/Host/freebsd/Host.cpp @@ -40,8 +40,6 @@ #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/NameMatches.h" -#include "Plugins/Process/Utility/FreeBSDSignals.h" - #include "llvm/Support/Host.h" extern "C" { @@ -277,13 +275,6 @@ Host::GetAuxvData(lldb_private::Process *process) return buf_sp; } -const UnixSignalsSP& -Host::GetUnixSignals () -{ - static const lldb_private::UnixSignalsSP s_unix_signals_sp (new FreeBSDSignals ()); - return s_unix_signals_sp; -} - Error Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) { diff --git a/source/Host/posix/MainLoopPosix.cpp b/source/Host/posix/MainLoopPosix.cpp new file mode 100644 index 000000000000..cb213b9b79f1 --- /dev/null +++ b/source/Host/posix/MainLoopPosix.cpp @@ -0,0 +1,193 @@ +//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/posix/MainLoopPosix.h" + +#include <vector> + +#include "lldb/Core/Error.h" + +using namespace lldb; +using namespace lldb_private; + +static sig_atomic_t g_signal_flags[NSIG]; + +static void +SignalHandler(int signo, siginfo_t *info, void *) +{ + assert(signo < NSIG); + g_signal_flags[signo] = 1; +} + + +MainLoopPosix::~MainLoopPosix() +{ + assert(m_read_fds.size() == 0); + assert(m_signals.size() == 0); +} + +MainLoopPosix::ReadHandleUP +MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error) +{ + if (!object_sp || !object_sp->IsValid()) + { + error.SetErrorString("IO object is not valid."); + return nullptr; + } + + const bool inserted = m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; + if (! inserted) + { + error.SetErrorStringWithFormat("File descriptor %d already monitored.", + object_sp->GetWaitableHandle()); + return nullptr; + } + + return CreateReadHandle(object_sp); +} + +// We shall block the signal, then install the signal handler. The signal will be unblocked in +// the Run() function to check for signal delivery. +MainLoopPosix::SignalHandleUP +MainLoopPosix::RegisterSignal(int signo, const Callback &callback, Error &error) +{ + if (m_signals.find(signo) != m_signals.end()) + { + error.SetErrorStringWithFormat("Signal %d already monitored.", signo); + return nullptr; + } + + SignalInfo info; + info.callback = callback; + struct sigaction new_action; + new_action.sa_sigaction = &SignalHandler; + new_action.sa_flags = SA_SIGINFO; + sigemptyset(&new_action.sa_mask); + sigaddset(&new_action.sa_mask, signo); + + sigset_t old_set; + if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) + { + error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", ret); + return nullptr; + } + + info.was_blocked = sigismember(&old_set, signo); + if (sigaction(signo, &new_action, &info.old_action) == -1) + { + error.SetErrorToErrno(); + if (!info.was_blocked) + pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); + return nullptr; + } + + m_signals.insert({signo, info}); + g_signal_flags[signo] = 0; + + return SignalHandleUP(new SignalHandle(*this, signo)); +} + +void +MainLoopPosix::UnregisterReadObject(const lldb::IOObjectSP &object_sp) +{ + bool erased = m_read_fds.erase(object_sp->GetWaitableHandle()); + (void) erased; + assert(erased); +} + +void +MainLoopPosix::UnregisterSignal(int signo) +{ + // We undo the actions of RegisterSignal on a best-effort basis. + auto it = m_signals.find(signo); + assert(it != m_signals.end()); + + sigaction(signo, &it->second.old_action, nullptr); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signo); + pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, nullptr); + + m_signals.erase(it); +} + +Error +MainLoopPosix::Run() +{ + std::vector<int> signals; + sigset_t sigmask; + std::vector<int> read_fds; + fd_set read_fd_set; + m_terminate_request = false; + + // run until termination or until we run out of things to listen to + while (! m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) + { + // To avoid problems with callbacks changing the things we're supposed to listen to, we + // will store the *real* list of events separately. + signals.clear(); + read_fds.clear(); + FD_ZERO(&read_fd_set); + int nfds = 0; + + if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) + return Error("pthread_sigmask failed with error %d\n", ret); + + for (const auto &fd: m_read_fds) + { + read_fds.push_back(fd.first); + FD_SET(fd.first, &read_fd_set); + nfds = std::max(nfds, fd.first+1); + } + + for (const auto &sig: m_signals) + { + signals.push_back(sig.first); + sigdelset(&sigmask, sig.first); + } + + if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && errno != EINTR) + return Error(errno, eErrorTypePOSIX); + + for (int sig: signals) + { + if (g_signal_flags[sig] == 0) + continue; // No signal + g_signal_flags[sig] = 0; + + auto it = m_signals.find(sig); + if (it == m_signals.end()) + continue; // Signal must have gotten unregistered in the meantime + + it->second.callback(*this); // Do the work + + if (m_terminate_request) + return Error(); + } + + for (int fd: read_fds) + { + if (!FD_ISSET(fd, &read_fd_set)) + continue; // Not ready + + auto it = m_read_fds.find(fd); + if (it == m_read_fds.end()) + continue; // File descriptor must have gotten unregistered in the meantime + + it->second(*this); // Do the work + + if (m_terminate_request) + return Error(); + } + } + return Error(); +} + + diff --git a/source/Initialization/SystemInitializerCommon.cpp b/source/Initialization/SystemInitializerCommon.cpp index 35189c103f7c..51f32a2776a8 100644 --- a/source/Initialization/SystemInitializerCommon.cpp +++ b/source/Initialization/SystemInitializerCommon.cpp @@ -17,6 +17,7 @@ #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" +#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" #include "Plugins/Instruction/ARM/EmulateInstructionARM.h" #include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h" @@ -106,6 +107,7 @@ SystemInitializerCommon::Initialize() ObjectFileELF::Initialize(); ObjectFilePECOFF::Initialize(); DynamicLoaderPOSIXDYLD::Initialize(); + DynamicLoaderWindowsDYLD::Initialize(); platform_freebsd::PlatformFreeBSD::Initialize(); platform_linux::PlatformLinux::Initialize(); PlatformWindows::Initialize(); @@ -152,6 +154,7 @@ SystemInitializerCommon::Terminate() ObjectFileELF::Terminate(); ObjectFilePECOFF::Terminate(); DynamicLoaderPOSIXDYLD::Terminate(); + DynamicLoaderWindowsDYLD::Terminate(); platform_freebsd::PlatformFreeBSD::Terminate(); platform_linux::PlatformLinux::Terminate(); PlatformWindows::Terminate(); diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp index d67f76eba7b6..c0efd9e33c08 100644 --- a/source/Interpreter/CommandObject.cpp +++ b/source/Interpreter/CommandObject.cpp @@ -10,6 +10,7 @@ #include "lldb/Interpreter/CommandObject.h" #include <string> +#include <sstream> #include <map> #include <stdlib.h> @@ -921,6 +922,27 @@ ExprPathHelpTextCallback() } void +CommandObject::FormatLongHelpText (Stream &output_strm, const char *long_help) +{ + CommandInterpreter& interpreter = GetCommandInterpreter(); + std::stringstream lineStream (long_help); + std::string line; + while (std::getline (lineStream, line)) { + if (line.empty()) { + output_strm << "\n"; + continue; + } + size_t result = line.find_first_not_of (" \t"); + if (result == std::string::npos) { + result = 0; + } + std::string whitespace_prefix = line.substr (0, result); + std::string remainder = line.substr (result); + interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix.c_str(), remainder.c_str()); + } +} + +void CommandObject::GenerateHelpText (CommandReturnObject &result) { GenerateHelpText(result.GetOutputStream()); @@ -947,7 +969,7 @@ CommandObject::GenerateHelpText (Stream &output_strm) const char *long_help = GetHelpLong(); if ((long_help != nullptr) && (strlen (long_help) > 0)) - output_strm.Printf ("\n%s", long_help); + FormatLongHelpText (output_strm, long_help); if (WantsRawCommandString() && !WantsCompletion()) { // Emit the message about using ' -- ' between the end of the command options and the raw input @@ -984,7 +1006,7 @@ CommandObject::GenerateHelpText (Stream &output_strm) const char *long_help = GetHelpLong(); if ((long_help != nullptr) && (strlen (long_help) > 0)) - output_strm.Printf ("%s", long_help); + FormatLongHelpText (output_strm, long_help); else if (WantsRawCommandString()) { std::string help_text (GetHelp()); diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index 0853fe286963..4204d18769b8 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -236,7 +236,8 @@ ABISP ABIMacOSX_i386::CreateInstance (const ArchSpec &arch) { static ABISP g_abi_sp; - if (arch.GetTriple().getArch() == llvm::Triple::x86) + if ((arch.GetTriple().getArch() == llvm::Triple::x86) && + (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS())) { if (!g_abi_sp) g_abi_sp.reset (new ABIMacOSX_i386); diff --git a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp index e9e68bc0e949..69129df1f16b 100644 --- a/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp +++ b/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -257,7 +257,7 @@ ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, sp -= argSize; // write this argument onto the stack of the host process - proc.get( )->WriteMemory( sp, arg.data, arg.size, error ); + proc.get( )->WriteMemory( sp, arg.data_ap.get(), arg.size, error ); if ( error.Fail( ) ) return false; diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp index bbafcf73fa16..2308129b8cab 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -168,6 +168,9 @@ DynamicLoaderHexagonDYLD::DidAttach() // Disable JIT for hexagon targets because its not supported m_process->SetCanJIT(false); + // Enable Interpreting of function call expressions + m_process->SetCanInterpretFunctionCalls(true); + // Add the current executable to the module list ModuleList module_list; module_list.Append(executable); @@ -500,7 +503,7 @@ DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop if (sym == NULL || !sym->IsTrampoline()) return thread_plan_sp; - const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled); + const ConstString sym_name = sym->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled); if (!sym_name) return thread_plan_sp; diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 6330b42ca14a..8724fc039cb9 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -458,7 +458,7 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) if (sym == NULL || !sym->IsTrampoline()) return thread_plan_sp; - const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled); + ConstString sym_name = sym->GetName(); if (!sym_name) return thread_plan_sp; @@ -667,7 +667,9 @@ DynamicLoaderPOSIXDYLD::ResolveExecutableModule (lldb::ModuleSP &module_sp) if (module_sp && module_sp->MatchesModuleSpec (module_spec)) return; - auto error = platform_sp->ResolveExecutable (module_spec, module_sp, nullptr); + const auto executable_search_paths (Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable ( + module_spec, module_sp, !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); if (error.Fail ()) { StreamString stream; diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp new file mode 100644 index 000000000000..56b56ab3a194 --- /dev/null +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp @@ -0,0 +1,102 @@ +//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DynamicLoaderWindowsDYLD.h" + +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/Triple.h" + +using namespace lldb; +using namespace lldb_private; + +DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process) + : DynamicLoader(process) +{ + +} + +DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() +{ + +} + +void DynamicLoaderWindowsDYLD::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void DynamicLoaderWindowsDYLD::Terminate() +{ + +} + +ConstString DynamicLoaderWindowsDYLD::GetPluginNameStatic() +{ + static ConstString g_plugin_name("windows-dyld"); + return g_plugin_name; +} + +const char *DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() +{ + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Windows processes."; +} + + +DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process, bool force) +{ + bool should_create = force; + if (!should_create) + { + const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::Win32) + should_create = true; + } + + if (should_create) + return new DynamicLoaderWindowsDYLD (process); + + return nullptr; +} + +void DynamicLoaderWindowsDYLD::DidAttach() +{ + +} + +void DynamicLoaderWindowsDYLD::DidLaunch() +{ + +} + +Error DynamicLoaderWindowsDYLD::CanLoadImage() +{ + return Error(); +} + +ConstString DynamicLoaderWindowsDYLD::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t DynamicLoaderWindowsDYLD::GetPluginVersion() +{ + return 1; +} + +ThreadPlanSP +DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) +{ + return ThreadPlanSP(); +} diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h new file mode 100644 index 000000000000..d12b999f4627 --- /dev/null +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h @@ -0,0 +1,43 @@ +//===-- DynamicLoaderWindowsDYLDh ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_H_ +#define liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_H_ + +#include "lldb/lldb-forward.h" +#include "lldb/Target/DynamicLoader.h" + +namespace lldb_private +{ + +class DynamicLoaderWindowsDYLD : public DynamicLoader +{ + public: + DynamicLoaderWindowsDYLD(Process *process); + virtual ~DynamicLoaderWindowsDYLD(); + + static void Initialize(); + static void Terminate(); + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic(); + + static DynamicLoader *CreateInstance(Process *process, bool force); + + void DidAttach () override; + void DidLaunch () override; + Error CanLoadImage () override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, bool stop) override; + + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; +}; + +} + +#endif diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 7d21b779ebd2..3a3878ef09a1 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -106,7 +106,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, Symbol *symbol = sc.symbol; if (symbol != NULL) { - const char *name = symbol->GetMangled().GetDemangledName().AsCString(); + const char *name = symbol->GetMangled().GetDemangledName(lldb::eLanguageTypeC_plus_plus).AsCString(); if (name && strstr(name, vtable_demangled_prefix) == name) { Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index f9cec2415382..5fc83f06157c 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1558,7 +1558,7 @@ ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) std::string ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { - size_t pos = symbol_name.find("@"); + size_t pos = symbol_name.find('@'); return symbol_name.substr(0, pos).str(); } @@ -1795,7 +1795,16 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, static ConstString bss_section_name(".bss"); static ConstString opd_section_name(".opd"); // For ppc64 - //StreamFile strm(stdout, false); + // On Android the oatdata and the oatexec symbols in system@framework@boot.oat covers the full + // .text section what causes issues with displaying unusable symbol name to the user and very + // slow unwinding speed because the instruction emulation based unwind plans try to emulate all + // instructions in these symbols. Don't add these symbols to the symbol list as they have no + // use for the debugger and they are causing a lot of trouble. + // Filtering can't be restricted to Android because this special object file don't contain the + // note section specifying the environment to Android but the custom extension and file name + // makes it highly unlikely that this will collide with anything else. + bool skip_oatdata_oatexec = m_file.GetFilename() == ConstString("system@framework@boot.oat"); + unsigned i; for (i = 0; i < num_symbols; ++i) { @@ -1809,7 +1818,10 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, (symbol_name == NULL || symbol_name[0] == '\0')) continue; - //symbol.Dump (&strm, i, &strtab_data, section_list); + // Skipping oatdata and oatexec sections if it is requested. See details above the + // definition of skip_oatdata_oatexec for the reasons. + if (skip_oatdata_oatexec && (::strcmp(symbol_name, "oatdata") == 0 || ::strcmp(symbol_name, "oatexec") == 0)) + continue; SectionSP symbol_section_sp; SymbolType symbol_type = eSymbolTypeInvalid; @@ -2031,8 +2043,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, if (! mangled_name.empty()) mangled.SetMangledName( ConstString((mangled_name + suffix).str()) ); - llvm::StringRef demangled_name = mangled.GetDemangledName().GetStringRef(); - if (! demangled_name.empty()) + ConstString demangled = mangled.GetDemangledName(lldb::eLanguageTypeUnknown); + llvm::StringRef demangled_name = demangled.GetStringRef(); + if (!demangled_name.empty()) mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) ); } diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index fe425e02103b..b4f841a16dec 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -535,6 +535,14 @@ PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec, return false; } +const lldb::UnixSignalsSP & +PlatformPOSIX::GetRemoteUnixSignals() { + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteUnixSignals(); + return Platform::GetRemoteUnixSignals(); +} + + FileSpec PlatformPOSIX::GetRemoteWorkingDirectory() { @@ -785,9 +793,6 @@ PlatformPOSIX::Attach (ProcessAttachInfo &attach_info, if (process_sp) { - // Set UnixSignals appropriately. - process_sp->SetUnixSignals (Host::GetUnixSignals ()); - auto listener_sp = attach_info.GetHijackListener(); if (listener_sp == nullptr) { diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 19a3f0c4eef1..82686dcef6b0 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -109,6 +109,9 @@ public: lldb_private::ArchSpec GetRemoteSystemArchitecture () override; + const lldb::UnixSignalsSP & + GetRemoteUnixSignals() override; + size_t GetEnvironment (lldb_private::StringList &environment) override; diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index df0484c4e69b..b0e75d4f3457 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -32,6 +32,8 @@ #include "Utility/UriParser.h" +#include "Plugins/Process/Utility/GDBRemoteSignals.h" + using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_gdb_server; @@ -139,13 +141,14 @@ PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec, // Resolve any executable within an apk on Android? //Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); - if (resolved_module_spec.GetFileSpec().Exists()) + if (resolved_module_spec.GetFileSpec().Exists() || + module_spec.GetUUID().IsValid()) { if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid()) { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, - NULL, + module_search_paths_ptr, NULL, NULL); @@ -161,7 +164,7 @@ PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec, { error = ModuleList::GetSharedModule (resolved_module_spec, exe_module_sp, - NULL, + module_search_paths_ptr, NULL, NULL); // Did we find an executable using one of the @@ -413,6 +416,7 @@ PlatformRemoteGDBServer::DisconnectRemote () { Error error; m_gdb_client.Disconnect(&error); + m_remote_signals_sp.reset(); return error; } @@ -871,6 +875,97 @@ PlatformRemoteGDBServer::RunShellCommand(const char *command, // Shoul void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames () -{ +{ m_trap_handlers.push_back (ConstString ("_sigtramp")); } + +const UnixSignalsSP & +PlatformRemoteGDBServer::GetRemoteUnixSignals() +{ + if (!IsConnected()) + return Platform::GetRemoteUnixSignals(); + + if (m_remote_signals_sp) + return m_remote_signals_sp; + + // If packet not implemented or JSON failed to parse, + // we'll guess the signal set based on the remote architecture. + m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); + + const char packet[] = "jSignalsInfo"; + StringExtractorGDBRemote response; + auto result = m_gdb_client.SendPacketAndWaitForResponse( + packet, strlen(packet), response, false); + + if (result != decltype(result)::Success || + response.GetResponseType() != response.eResponse) + return m_remote_signals_sp; + + auto object_sp = StructuredData::ParseJSON(response.GetStringRef()); + if (!object_sp || !object_sp->IsValid()) + return m_remote_signals_sp; + + auto array_sp = object_sp->GetAsArray(); + if (!array_sp || !array_sp->IsValid()) + return m_remote_signals_sp; + + auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>(); + + bool done = array_sp->ForEach( + [&remote_signals_sp](StructuredData::Object *object) -> bool + { + if (!object || !object->IsValid()) + return false; + + auto dict = object->GetAsDictionary(); + if (!dict || !dict->IsValid()) + return false; + + // Signal number and signal name are required. + int signo; + if (!dict->GetValueForKeyAsInteger("signo", signo)) + return false; + + std::string name; + if (!dict->GetValueForKeyAsString("name", name)) + return false; + + // We can live without short_name, description, etc. + std::string short_name{""}; + auto object_sp = dict->GetValueForKey("short_name"); + if (object_sp && object_sp->IsValid()) + short_name = object_sp->GetStringValue(); + + bool suppress{false}; + object_sp = dict->GetValueForKey("suppress"); + if (object_sp && object_sp->IsValid()) + suppress = object_sp->GetBooleanValue(); + + bool stop{false}; + object_sp = dict->GetValueForKey("stop"); + if (object_sp && object_sp->IsValid()) + stop = object_sp->GetBooleanValue(); + + bool notify{false}; + object_sp = dict->GetValueForKey("notify"); + if (object_sp && object_sp->IsValid()) + notify = object_sp->GetBooleanValue(); + + std::string description{""}; + object_sp = dict->GetValueForKey("description"); + if (object_sp && object_sp->IsValid()) + description = object_sp->GetStringValue(); + + remote_signals_sp->AddSignal(signo, + name.c_str(), + short_name.c_str(), + suppress, stop, notify, + description.c_str()); + return true; + }); + + if (done) + m_remote_signals_sp = std::move(remote_signals_sp); + + return m_remote_signals_sp; +} diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 1d97b4dbc683..0bf013fdfb68 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -18,6 +18,7 @@ // Project includes #include "lldb/Target/Platform.h" #include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h" +#include "Plugins/Process/Utility/GDBRemoteSignals.h" namespace lldb_private { namespace platform_gdb_server { @@ -213,12 +214,17 @@ public: void CalculateTrapHandlerSymbolNames () override; + const lldb::UnixSignalsSP & + GetRemoteUnixSignals() override; + protected: process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to std::string m_platform_scheme; std::string m_platform_hostname; + lldb::UnixSignalsSP m_remote_signals_sp; + // Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on // failure. Subclasses should override this method if they want to do extra actions before or // after launching the lldb-gdbserver. diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index cce7a1ef28c1..5e46c836beac 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -46,7 +46,7 @@ FreeBSDThread::WillResume(lldb::StateType resume_state) ProcessSP process_sp(GetProcess()); ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); int signo = GetResumeSignal(); - bool signo_valid = process->GetUnixSignals().SignalIsValid(signo); + bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo); switch (resume_state) { diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 28bca0916148..427c66ce3e6b 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -1297,7 +1297,7 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, if (log) log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d", __FUNCTION__, - monitor->m_process->GetUnixSignals().GetSignalAsCString (signo), + monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo), "SI_USER", info->si_pid); if (info->si_pid == getpid()) @@ -1307,7 +1307,7 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, } if (log) - log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo)); + log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo)); switch (signo) { @@ -1483,7 +1483,7 @@ ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) { - const char *signame = m_process->GetUnixSignals().GetSignalAsCString (signo); + const char *signame = m_process->GetUnixSignals()->GetSignalAsCString (signo); if (signame == nullptr) signame = "<none>"; log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", diff --git a/source/Plugins/Process/FreeBSD/ProcessPOSIX.h b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h index 70694cb9b193..627017c547dc 100644 --- a/source/Plugins/Process/FreeBSD/ProcessPOSIX.h +++ b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h @@ -33,7 +33,7 @@ public: //------------------------------------------------------------------ ProcessPOSIX(lldb_private::Target& target, lldb_private::Listener &listener, - lldb_private::UnixSignalsSP &unix_signals_sp); + lldb::UnixSignalsSP &unix_signals_sp); virtual ~ProcessPOSIX(); diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp index f082e143059c..c143d36e87c7 100644 --- a/source/Plugins/Process/Utility/FreeBSDSignals.cpp +++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -13,6 +13,8 @@ // Project includes #include "FreeBSDSignals.h" +using namespace lldb_private; + FreeBSDSignals::FreeBSDSignals() : UnixSignals() { diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.h b/source/Plugins/Process/Utility/FreeBSDSignals.h index 1e14ccb9fc4d..b715c62c81e9 100644 --- a/source/Plugins/Process/Utility/FreeBSDSignals.h +++ b/source/Plugins/Process/Utility/FreeBSDSignals.h @@ -13,16 +13,19 @@ // Project includes #include "lldb/Target/UnixSignals.h" +namespace lldb_private { + /// FreeBSD specific set of Unix signals. -class FreeBSDSignals - : public lldb_private::UnixSignals +class FreeBSDSignals : public UnixSignals { public: FreeBSDSignals(); private: void - Reset(); + Reset() override; }; +} // namespace lldb_private + #endif // liblldb_FreeBSDSignals_H_ diff --git a/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/source/Plugins/Process/Utility/GDBRemoteSignals.cpp new file mode 100644 index 000000000000..4e355c63b3aa --- /dev/null +++ b/source/Plugins/Process/Utility/GDBRemoteSignals.cpp @@ -0,0 +1,32 @@ +//===-- GDBRemoteSignals.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "GDBRemoteSignals.h" + +using namespace lldb_private; + +GDBRemoteSignals::GDBRemoteSignals() + : UnixSignals() +{ + Reset(); +} + +GDBRemoteSignals::GDBRemoteSignals(const lldb::UnixSignalsSP &rhs) + : UnixSignals(*rhs) +{ +} + +void +GDBRemoteSignals::Reset() +{ + m_signals.clear(); +} diff --git a/source/Plugins/Process/Utility/GDBRemoteSignals.h b/source/Plugins/Process/Utility/GDBRemoteSignals.h new file mode 100644 index 000000000000..bbb631a14090 --- /dev/null +++ b/source/Plugins/Process/Utility/GDBRemoteSignals.h @@ -0,0 +1,36 @@ +//===-- GDBRemoteSignals.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteSignals_H_ +#define liblldb_GDBRemoteSignals_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/UnixSignals.h" + +namespace lldb_private { + +/// Empty set of Unix signals to be filled by PlatformRemoteGDBServer +class GDBRemoteSignals : public UnixSignals +{ +public: + GDBRemoteSignals(); + + GDBRemoteSignals(const lldb::UnixSignalsSP &rhs); + +private: + void + Reset() override; +}; + +} // namespace lldb_private + +#endif // liblldb_GDBRemoteSignals_H_ diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp index 0680d268233c..cd1fc8165eb9 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -12,7 +12,7 @@ // Project includes #include "LinuxSignals.h" -using namespace lldb_private::process_linux; +using namespace lldb_private; LinuxSignals::LinuxSignals() : UnixSignals() diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h index 5102bcb95e74..dd9062f040a2 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.h +++ b/source/Plugins/Process/Utility/LinuxSignals.h @@ -17,21 +17,18 @@ #include "lldb/Target/UnixSignals.h" namespace lldb_private { -namespace process_linux { - /// Linux specific set of Unix signals. - class LinuxSignals - : public lldb_private::UnixSignals - { - public: - LinuxSignals(); +/// Linux specific set of Unix signals. +class LinuxSignals : public UnixSignals +{ +public: + LinuxSignals(); - private: - void - Reset(); - }; +private: + void + Reset() override; +}; } // namespace lldb_private -} // namespace process_linux -#endif +#endif // liblldb_LinuxSignals_H_ diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index e4e654626eaa..1dc0be81c0ae 100644 --- a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -12,7 +12,7 @@ // Project includes #include "MipsLinuxSignals.h" -using namespace lldb_private::process_linux; +using namespace lldb_private; MipsLinuxSignals::MipsLinuxSignals() : UnixSignals() diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.h b/source/Plugins/Process/Utility/MipsLinuxSignals.h index 2e603fbbdf3c..a5041b50eea3 100644 --- a/source/Plugins/Process/Utility/MipsLinuxSignals.h +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.h @@ -17,21 +17,18 @@ #include "lldb/Target/UnixSignals.h" namespace lldb_private { -namespace process_linux { - /// Linux specific set of Unix signals. - class MipsLinuxSignals - : public lldb_private::UnixSignals - { - public: - MipsLinuxSignals(); +/// Linux specific set of Unix signals. +class MipsLinuxSignals : public UnixSignals +{ +public: + MipsLinuxSignals(); - private: - void - Reset(); - }; +private: + void + Reset() override; +}; } // namespace lldb_private -} // namespace process_linux -#endif +#endif // liblldb_MipsLinuxSignals_H_ diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 02d3ecd7b3c5..1cdae9011673 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -120,29 +120,28 @@ unwind_done: return false; } -// For adding a non-zero stack frame to m_frames. -bool -UnwindLLDB::AddOneMoreFrame (ABI *abi) +UnwindLLDB::CursorSP +UnwindLLDB::GetOneMoreFrame (ABI* abi) { + assert (m_frames.size() != 0 && "Get one more frame called with empty frame list"); + // If we've already gotten to the end of the stack, don't bother to try again... if (m_unwind_complete) - return false; + return nullptr; Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); - CursorSP cursor_sp(new Cursor ()); - // Frame zero is a little different - if (m_frames.size() == 0) - return false; + CursorSP prev_frame = m_frames.back(); + uint32_t cur_idx = m_frames.size(); - uint32_t cur_idx = m_frames.size (); + CursorSP cursor_sp(new Cursor ()); RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread, - m_frames[cur_idx - 1]->reg_ctx_lldb_sp, + prev_frame->reg_ctx_lldb_sp, cursor_sp->sctx, cur_idx, *this)); - // We want to detect an unwind that cycles erronously and stop backtracing. + // We want to detect an unwind that cycles erroneously and stop backtracing. // Don't want this maximum unwind limit to be too low -- if you have a backtrace // with an "infinitely recursing" bug, it will crash when the stack blows out // and the first 35,000 frames are uninteresting - it's the top most 5 frames that @@ -154,21 +153,20 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) if (log) log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - goto unwind_done; + return nullptr; } if (reg_ctx_sp.get() == NULL) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return // true. Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - goto unwind_done; + return nullptr; } if (!reg_ctx_sp->IsValid()) @@ -176,31 +174,25 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) // We failed to get a valid RegisterContext. // See if the regctx below this on the stack has a fallback unwind plan it can use. // Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) - { log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - goto unwind_done; + return nullptr; } if (!reg_ctx_sp->GetCFA (cursor_sp->cfa)) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return // true. Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) - { log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - goto unwind_done; + return nullptr; } if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { @@ -219,24 +211,19 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) || reg_ctx_sp->GetCFA (cursor_sp->cfa) == false || abi->CallFrameAddressIsValid(cursor_sp->cfa) == false) { - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) - { log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - goto unwind_done; + return nullptr; } else { if (log) - { log->Printf("%*sFrame %d had a bad CFA value but we switched the UnwindPlan being used and got one that looks more realistic.", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } } } } @@ -244,54 +231,103 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return // true. Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) - { log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - goto unwind_done; + return nullptr; } if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc)) { // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return // true. Subsequent calls to TryFallbackUnwindPlan() will return false. - if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) - { - return AddOneMoreFrame (abi); - } + if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + return GetOneMoreFrame (abi); + if (log) - { log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk", cur_idx < 100 ? cur_idx : 100, "", cur_idx); - } - goto unwind_done; + return nullptr; } - if (!m_frames.empty()) + // Infinite loop where the current cursor is the same as the previous one... + if (prev_frame->start_pc == cursor_sp->start_pc && prev_frame->cfa == cursor_sp->cfa) { - // Infinite loop where the current cursor is the same as the previous one... - if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa) - { - if (log) - log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); - goto unwind_done; - } + if (log) + log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); + return nullptr; } cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; - m_frames.push_back (cursor_sp); - return true; - -unwind_done: - if (log) + return cursor_sp; +} + +bool +UnwindLLDB::AddOneMoreFrame (ABI *abi) +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + + // Frame zero is a little different + if (m_frames.empty()) + return false; + + // If we've already gotten to the end of the stack, don't bother to try again... + if (m_unwind_complete) + return false; + + CursorSP new_frame = m_candidate_frame; + if (new_frame == nullptr) + new_frame = GetOneMoreFrame(abi); + + if (new_frame == nullptr) { - log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + if (log) + log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + m_unwind_complete = true; + return false; } - m_unwind_complete = true; - return false; + + m_frames.push_back(new_frame); + + // If we can get one more frame further then accept that we get back a correct frame. + m_candidate_frame = GetOneMoreFrame(abi); + if (m_candidate_frame) + return true; + + // We can't go further from the frame returned by GetOneMore frame. Lets try to get a + // different frame with using the fallback unwind plan. + if (!m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + // We don't have a valid fallback unwind plan. Accept the frame as it is. This is a + // valid situation when we are at the bottom of the stack. + return true; + } + + // Remove the possibly incorrect frame from the frame list and try to add a different one with + // the newly selected fallback unwind plan. + m_frames.pop_back(); + CursorSP new_frame_v2 = GetOneMoreFrame(abi); + if (new_frame_v2 == nullptr) + { + // We haven't got a new frame from the fallback unwind plan. Accept the frame from the + // original unwind plan. This is a valid situation when we are at the bottom of the stack. + m_frames.push_back(new_frame); + return true; + } + + // Push the new frame to the list and try to continue from this frame. If we can get a new frame + // then accept it as the correct one. + m_frames.push_back(new_frame_v2); + m_candidate_frame = GetOneMoreFrame(abi); + if (m_candidate_frame) + return true; + + // The new frame isn't helped in unwinding. Fall back to the original one as the default unwind + // plan is usually more reliable then the fallback one. + m_frames.pop_back(); + m_frames.push_back(new_frame); + return true; } bool diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index 35d85e2e3d26..ce897cd82423 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -65,6 +65,7 @@ protected: DoClear() { m_frames.clear(); + m_candidate_frame.reset(); m_unwind_complete = false; } @@ -126,14 +127,21 @@ private: typedef std::shared_ptr<Cursor> CursorSP; std::vector<CursorSP> m_frames; + CursorSP m_candidate_frame; bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size() // is how far we've currently gone. std::vector<ConstString> m_user_supplied_trap_handler_functions; - bool AddOneMoreFrame (ABI *abi); - bool AddFirstFrame (); + CursorSP + GetOneMoreFrame (ABI* abi); + + bool + AddOneMoreFrame (ABI *abi); + + bool + AddFirstFrame (); //------------------------------------------------------------------ // For UnwindLLDB only diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 2fff36dd4ee5..bf5cad8e39c5 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -29,8 +29,6 @@ #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" -#include "Plugins/Process/Utility/FreeBSDSignals.h" -#include "Plugins/Process/Utility/LinuxSignals.h" // Project includes #include "ProcessElfCore.h" @@ -237,23 +235,7 @@ ProcessElfCore::DoLoadCore () if (arch.IsValid()) m_target.SetArchitecture(arch); - switch (m_os) - { - case llvm::Triple::FreeBSD: - { - static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals ()); - SetUnixSignals(s_freebsd_signals_sp); - break; - } - case llvm::Triple::Linux: - { - static UnixSignalsSP s_linux_signals_sp(new process_linux::LinuxSignals ()); - SetUnixSignals(s_linux_signals_sp); - break; - } - default: - break; - } + SetUnixSignals(UnixSignals::Create(GetArchitecture())); return error; } @@ -370,7 +352,7 @@ ProcessElfCore::Clear() m_thread_list.Clear(); m_os = llvm::Triple::UnknownOS; - static UnixSignalsSP s_default_unix_signals_sp(new UnixSignals()); + static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); SetUnixSignals(s_default_unix_signals_sp); } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 1af3947a75f3..9c263c8c4087 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -564,8 +564,12 @@ GDBRemoteCommunication::DecompressPacket () return true; size_t pkt_size = m_bytes.size(); - if (pkt_size < 6) + + // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, most commonly indicating + // an unsupported packet. Anything less than 5 characters, it's definitely not a compressed packet. + if (pkt_size < 5) return true; + if (m_bytes[0] != '$' && m_bytes[0] != '%') return true; if (m_bytes[1] != 'C' && m_bytes[1] != 'N') diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index ae0a2f5e66c5..2a253c5a99e8 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -87,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : m_supports_qXfer_features_read (eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), m_supports_jThreadExtendedInfo (eLazyBoolCalculate), + m_supports_jLoadedDynamicLibrariesInfos (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -654,6 +655,24 @@ GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () } bool +GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported () +{ + if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; + } + } + } + return m_supports_jLoadedDynamicLibrariesInfos; +} + +bool GDBRemoteCommunicationClient::GetxPacketSupported () { if (m_supports_x == eLazyBoolCalculate) @@ -1037,8 +1056,8 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse // may change if we are interrupted and we continue after an async packet... std::string continue_packet(payload, packet_length); - const auto sigstop_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGSTOP"); - const auto sigint_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGINT"); + const auto sigstop_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); + const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT"); bool got_async_packet = false; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 65a2981018ea..deb41b066b45 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -550,6 +550,9 @@ public: GetThreadExtendedInfoSupported(); bool + GetLoadedDynamicLibrariesInfosSupported(); + + bool GetModuleInfo (const FileSpec& module_file_spec, const ArchSpec& arch_spec, ModuleSpec &module_spec); @@ -614,6 +617,7 @@ protected: LazyBool m_supports_qXfer_features_read; LazyBool m_supports_augmented_libraries_svr4_read; LazyBool m_supports_jThreadExtendedInfo; + LazyBool m_supports_jLoadedDynamicLibrariesInfos; bool m_supports_qProcessInfoPID:1, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 13ce9b2dc5c3..4ee66b84d474 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -132,7 +132,7 @@ GDBRemoteCommunicationServer::SendOKResponse () } bool -GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr) +GDBRemoteCommunicationServer::HandshakeWithClient() { return GetAck() == PacketResult::Success; } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 992c6dffaf54..44c0f6a32f5b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -54,7 +54,7 @@ public: // After connecting, do a little handshake with the client to make sure // we are at least communicating bool - HandshakeWithClient (Error *error_ptr); + HandshakeWithClient (); protected: std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index e8955ddbd6e4..c4523252f190 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -75,10 +75,11 @@ namespace // GDBRemoteCommunicationServerLLGS constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( - const lldb::PlatformSP& platform_sp) : + const lldb::PlatformSP& platform_sp, + MainLoop &mainloop) : GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"), m_platform_sp (platform_sp), - m_async_thread (LLDB_INVALID_HOST_THREAD), + m_mainloop (mainloop), m_current_tid (LLDB_INVALID_THREAD_ID), m_continue_tid (LLDB_INVALID_THREAD_ID), m_debugged_process_mutex (Mutex::eMutexTypeRecursive), @@ -88,7 +89,8 @@ GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( m_active_auxv_buffer_sp (), m_saved_registers_mutex (), m_saved_registers_map (), - m_next_saved_registers_id (1) + m_next_saved_registers_id (1), + m_handshake_completed (false) { assert(platform_sp); RegisterPacketHandlers(); @@ -218,7 +220,7 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () { Mutex::Locker locker (m_debugged_process_mutex); assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); - error = m_platform_sp->LaunchNativeProcess ( + error = NativeProcessProtocol::Launch( m_process_launch_info, *this, m_debugged_process_sp); @@ -306,7 +308,7 @@ GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) } // Try to attach. - error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp); + error = NativeProcessProtocol::Attach(pid, *this, m_debugged_process_sp); if (!error.Success ()) { fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); @@ -782,6 +784,58 @@ GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process) ClearProcessSpecificData (); } +void +GDBRemoteCommunicationServerLLGS::DataAvailableCallback () +{ + Log *log (GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); + + if (! m_handshake_completed) + { + if (! HandshakeWithClient()) + { + if(log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting", + __FUNCTION__); + m_read_handle_up.reset(); + m_mainloop.RequestTermination(); + return; + } + m_handshake_completed = true; + } + + bool interrupt = false; + bool done = false; + Error error; + while (true) + { + const PacketResult result = GetPacketAndSendResponse (0, error, interrupt, done); + if (result == PacketResult::ErrorReplyTimeout) + break; // No more packets in the queue + + if ((result != PacketResult::Success)) + { + if(log) + log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s", + __FUNCTION__, error.AsCString()); + m_read_handle_up.reset(); + m_mainloop.RequestTermination(); + break; + } + } +} + +Error +GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connection> &&connection) +{ + IOObjectSP read_object_sp = connection->GetReadObject(); + GDBRemoteCommunicationServer::SetConnection(connection.release()); + + Error error; + m_read_handle_up = m_mainloop.RegisterReadObject(read_object_sp, + [this] (MainLoopBase &) { DataAvailableCallback(); }, error); + return error; +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendONotification (const char *buffer, uint32_t len) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 1eda0b052bb7..29f3fdebcfb0 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -19,6 +19,7 @@ #include "lldb/Core/Communication.h" #include "lldb/Host/Mutex.h" #include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/MainLoop.h" // Project includes #include "GDBRemoteCommunicationServerCommon.h" @@ -26,6 +27,7 @@ class StringExtractorGDBRemote; namespace lldb_private { + namespace process_gdb_remote { class ProcessGDBRemote; @@ -38,7 +40,7 @@ public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp); + GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp, MainLoop &mainloop); virtual ~GDBRemoteCommunicationServerLLGS(); @@ -111,9 +113,13 @@ public: void DidExec (NativeProcessProtocol *process) override; + Error + InitializeConnection (std::unique_ptr<Connection> &&connection); + protected: lldb::PlatformSP m_platform_sp; - lldb::thread_t m_async_thread; + MainLoop &m_mainloop; + MainLoop::ReadHandleUP m_read_handle_up; lldb::tid_t m_current_tid; lldb::tid_t m_continue_tid; Mutex m_debugged_process_mutex; @@ -124,6 +130,7 @@ protected: Mutex m_saved_registers_mutex; std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; uint32_t m_next_saved_registers_id; + bool m_handshake_completed : 1; PacketResult SendONotification (const char *buffer, uint32_t len); @@ -295,6 +302,9 @@ private: void RegisterPacketHandlers (); + void + DataAvailableCallback (); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServerLLGS only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index f5e5d76f2e6f..1205049db3fb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -19,6 +19,7 @@ // Other libraries and framework includes #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Host/Config.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" @@ -26,6 +27,7 @@ #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/UnixSignals.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -54,6 +56,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() : &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, + &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, [this](StringExtractorGDBRemote packet, @@ -251,6 +255,35 @@ GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packe return SendPacketNoLock (response.GetData(), response.GetSize()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet) +{ + StructuredData::Array signal_array; + + const auto &signals = Host::GetUnixSignals(); + for (auto signo = signals->GetFirstSignalNumber(); + signo != LLDB_INVALID_SIGNAL_NUMBER; + signo = signals->GetNextSignalNumber(signo)) + { + auto dictionary = std::make_shared<StructuredData::Dictionary>(); + + dictionary->AddIntegerItem("signo", signo); + dictionary->AddStringItem("name", signals->GetSignalAsCString(signo)); + + bool suppress, stop, notify; + signals->GetSignalInfo(signo, suppress, stop, notify); + dictionary->AddBooleanItem("suppress", suppress); + dictionary->AddBooleanItem("stop", stop); + dictionary->AddBooleanItem("notify", notify); + + signal_array.Push(dictionary); + } + + StreamString response; + signal_array.Dump(response); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 4124b0424f5d..5c011371a3eb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -79,6 +79,9 @@ protected: PacketResult Handle_qC (StringExtractorGDBRemote &packet); + PacketResult + Handle_jSignalsInfo(StringExtractorGDBRemote &packet); + private: bool DebugserverProcessReaped (lldb::pid_t pid); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 5cb4da514a7f..0bcc8ca4e5e3 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -65,10 +65,8 @@ // Project includes #include "lldb/Host/Host.h" -#include "Plugins/Process/Utility/FreeBSDSignals.h" +#include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "Plugins/Process/Utility/LinuxSignals.h" -#include "Plugins/Process/Utility/MipsLinuxSignals.h" #include "Plugins/Process/Utility/StopInfoMachException.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Utility/StringExtractorGDBRemote.h" @@ -823,41 +821,8 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) if (log) log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); - // Set the Unix signals properly for the target. - // FIXME Add a gdb-remote packet to discover dynamically. - if (error.Success ()) - { - const ArchSpec arch_spec = m_gdb_comm.GetHostArchitecture(); - if (arch_spec.IsValid ()) - { - if (log) - log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ()); - - switch (arch_spec.GetTriple ().getOS ()) - { - case llvm::Triple::Linux: - if (arch_spec.GetTriple ().getArch () == llvm::Triple::mips64 || arch_spec.GetTriple ().getArch () == llvm::Triple::mips64el) - SetUnixSignals (UnixSignalsSP (new process_linux::MipsLinuxSignals ())); - else - SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ())); - if (log) - log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); - break; - case llvm::Triple::OpenBSD: - case llvm::Triple::FreeBSD: - case llvm::Triple::NetBSD: - SetUnixSignals (UnixSignalsSP (new FreeBSDSignals ())); - if (log) - log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); - break; - default: - SetUnixSignals (UnixSignalsSP (new UnixSignals ())); - if (log) - log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); - break; - } - } - } + if (error.Success()) + SetUnixSignals(std::make_shared<GDBRemoteSignals>(GetTarget().GetPlatform()->GetUnixSignals())); return error; } @@ -3524,7 +3489,7 @@ ProcessGDBRemote::MonitorDebugserverProcess char error_str[1024]; if (signo) { - const char *signal_cstr = process->GetUnixSignals().GetSignalAsCString (signo); + const char *signal_cstr = process->GetUnixSignals()->GetSignalAsCString(signo); if (signal_cstr) ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); else @@ -3985,6 +3950,44 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) { if (!response.Empty()) { + object_sp = StructuredData::ParseJSON (response.GetStringRef()); + } + } + } + } + return object_sp; +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) +{ + StructuredData::ObjectSP object_sp; + + if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) + { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); + args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); + + StreamString packet; + packet << "jGetLoadedDynamicLibrariesInfos:"; + args_dict->Dump (packet); + + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char) (0x7d ^ 0x20); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) + { + StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) + { + if (!response.Empty()) + { // The packet has already had the 0x7d xor quoting stripped out at the // GDBRemoteCommunication packet receive level. object_sp = StructuredData::ParseJSON (response.GetStringRef()); @@ -3995,6 +3998,7 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) return object_sp; } + // Establish the largest memory read/write payloads we should use. // If the remote stub has a max packet size, stay under that size. // @@ -4418,83 +4422,135 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) GDBRemoteCommunicationClient & comm = m_gdb_comm; // check that we have extended feature read support - if (!comm.GetQXferLibrariesSVR4ReadSupported ()) - return Error (0, ErrorType::eErrorTypeGeneric); + if (comm.GetQXferLibrariesSVR4ReadSupported ()) { + list.clear (); - list.clear (); + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - // request the loaded library list - std::string raw; - lldb_private::Error lldberr; - if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) - return Error (0, ErrorType::eErrorTypeGeneric); + if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) + return Error (0, ErrorType::eErrorTypeGeneric); - // parse the xml file in memory - if (log) - log->Printf ("parsing: %s", raw.c_str()); - XMLDocument doc; - - if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) - return Error (0, ErrorType::eErrorTypeGeneric); + // parse the xml file in memory + if (log) + log->Printf ("parsing: %s", raw.c_str()); + XMLDocument doc; + + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error (0, ErrorType::eErrorTypeGeneric); - XMLNode root_element = doc.GetRootElement("library-list-svr4"); - if (!root_element) - return Error(); + XMLNode root_element = doc.GetRootElement("library-list-svr4"); + if (!root_element) + return Error(); - // main link map structure - llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); - if (!main_lm.empty()) - { - list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); - } + // main link map structure + llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); + if (!main_lm.empty()) + { + list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); + } - root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { + root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - GDBLoadedModuleInfoList::LoadedModuleInfo module; + GDBLoadedModuleInfoList::LoadedModuleInfo module; - library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - - if (name == "name") - module.set_name (value.str()); - else if (name == "lm") - { - // the address of the link_map struct. - module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); - } - else if (name == "l_addr") - { - // the displacement as read from the field 'l_addr' of the link_map struct. - module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { - } - else if (name == "l_ld") + if (name == "name") + module.set_name (value.str()); + else if (name == "lm") + { + // the address of the link_map struct. + module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + } + else if (name == "l_addr") + { + // the displacement as read from the field 'l_addr' of the link_map struct. + module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + + } + else if (name == "l_ld") + { + // the memory address of the libraries PT_DYAMIC section. + module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + } + + return true; // Keep iterating over all properties of "library" + }); + + if (log) { - // the memory address of the libraries PT_DYAMIC section. - module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); + std::string name; + lldb::addr_t lm=0, base=0, ld=0; + + module.get_name (name); + module.get_link_map (lm); + module.get_base (base); + module.get_dynamic (ld); + + log->Printf ("found (link_map:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str()); } - - return true; // Keep iterating over all properties of "library" + + list.add (module); + return true; // Keep iterating over all "library" elements in the root node }); if (log) - { - std::string name; - lldb::addr_t lm=0, base=0, ld=0; + log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); + } else if (comm.GetQXferLibrariesReadSupported ()) { + list.clear (); - module.get_name (name); - module.get_link_map (lm); - module.get_base (base); - module.get_dynamic (ld); + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; - log->Printf ("found (link_map:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str()); - } + if (!comm.ReadExtFeature (ConstString ("libraries"), ConstString (""), raw, lldberr)) + return Error (0, ErrorType::eErrorTypeGeneric); - list.add (module); - return true; // Keep iterating over all "library" elements in the root node - }); + if (log) + log->Printf ("parsing: %s", raw.c_str()); + XMLDocument doc; - if (log) - log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); + if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) + return Error (0, ErrorType::eErrorTypeGeneric); + + XMLNode root_element = doc.GetRootElement("library-list"); + if (!root_element) + return Error(); + + root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { + GDBLoadedModuleInfoList::LoadedModuleInfo module; + + llvm::StringRef name = library.GetAttributeValue("name"); + module.set_name(name.str()); + + // The base address of a given library will be the address of its + // first section. Most remotes send only one section for Windows + // targets for example. + const XMLNode §ion = library.FindFirstChildElementWithName("section"); + llvm::StringRef address = section.GetAttributeValue("address"); + module.set_base(StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); + + if (log) + { + std::string name; + lldb::addr_t base = 0; + module.get_name (name); + module.get_base (base); + + log->Printf ("found (base:0x%" PRIx64 ", name:'%s')", base, name.c_str()); + } + + list.add (module); + return true; // Keep iterating over all "library" elements in the root node + }); + + if (log) + log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); + } else { + return Error (0, ErrorType::eErrorTypeGeneric); + } return Error(); } diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 0a5e4a8a41b4..45c74ea64ee5 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -27,11 +27,11 @@ #include "lldb/Core/ThreadSafeValue.h" #include "lldb/Host/HostThread.h" #include "lldb/lldb-private-forward.h" +#include "lldb/Utility/StringExtractor.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "GDBRemoteCommunicationClient.h" -#include "Utility/StringExtractor.h" #include "GDBRemoteRegisterContext.h" namespace lldb_private { @@ -247,6 +247,9 @@ public: void ModulesDidLoad (ModuleList &module_list) override; + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override; + protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 59c701d75a68..d2a6503caf8e 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -215,14 +215,14 @@ ThreadGDBRemote::WillResume (StateType resume_state) break; case eStateRunning: - if (gdb_process->GetUnixSignals().SignalIsValid (signo)) + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo)); else gdb_process->m_continue_c_tids.push_back(tid); break; case eStateStepping: - if (gdb_process->GetUnixSignals().SignalIsValid (signo)) + if (gdb_process->GetUnixSignals()->SignalIsValid(signo)) gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo)); else gdb_process->m_continue_s_tids.push_back(tid); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 75934f966bcd..60933108c97a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -669,6 +669,7 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, GetOffset()); } + const LanguageType cu_language = GetLanguageType(); DWARFDebugInfoEntry::const_iterator pos; DWARFDebugInfoEntry::const_iterator begin = m_die_array.begin(); DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); @@ -882,8 +883,9 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, { Mangled mangled (ConstString(mangled_cstr), true); func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset()); - if (mangled.GetDemangledName()) - func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset()); + ConstString demangled = mangled.GetDemangledName(cu_language); + if (demangled) + func_fullnames.Insert (demangled, die.GetOffset()); } } } @@ -904,8 +906,9 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, { Mangled mangled (ConstString(mangled_cstr), true); func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset()); - if (mangled.GetDemangledName()) - func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset()); + ConstString demangled = mangled.GetDemangledName(cu_language); + if (demangled) + func_fullnames.Insert (demangled, die.GetOffset()); } } else @@ -951,8 +954,9 @@ DWARFCompileUnit::Index (const uint32_t cu_idx, { Mangled mangled (ConstString(mangled_cstr), true); globals.Insert (mangled.GetMangledName(), die.GetOffset()); - if (mangled.GetDemangledName()) - globals.Insert (mangled.GetDemangledName(), die.GetOffset()); + ConstString demangled = mangled.GetDemangledName(cu_language); + if (demangled) + globals.Insert (demangled, die.GetOffset()); } } break; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index dafd389449a2..ea8aedcc2be0 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -988,24 +988,38 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) std::string remapped_file; if (module_sp->RemapSourceFile(cu_file_spec.GetCString(), remapped_file)) cu_file_spec.SetFile(remapped_file, false); + } - LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0)); + LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0)); - cu_sp.reset(new CompileUnit (module_sp, - dwarf_cu, - cu_file_spec, - MakeUserID(dwarf_cu->GetOffset()), - cu_language)); - if (cu_sp) + cu_sp.reset(new CompileUnit (module_sp, + dwarf_cu, + cu_file_spec, + MakeUserID(dwarf_cu->GetOffset()), + cu_language)); + if (cu_sp) + { + // If we just created a compile unit with an invalid file spec, try and get the + // first entry in the supports files from the line table as that should be the + // compile unit. + if (!cu_file_spec) { - dwarf_cu->SetUserData(cu_sp.get()); - - // Figure out the compile unit index if we weren't given one - if (cu_idx == UINT32_MAX) - DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); - - m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp); + cu_file_spec = cu_sp->GetSupportFiles().GetFileSpecAtIndex(1); + if (cu_file_spec) + { + (FileSpec &)(*cu_sp) = cu_file_spec; + // Also fix the invalid file spec which was copied from the compile unit. + cu_sp->GetSupportFiles().Replace(0, cu_file_spec); + } } + + dwarf_cu->SetUserData(cu_sp.get()); + + // Figure out the compile unit index if we weren't given one + if (cu_idx == UINT32_MAX) + DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); + + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp); } } } @@ -2196,7 +2210,7 @@ SymbolFileDWARF::ParseChildMembers } } - if (prop_name != NULL) + if (prop_name != NULL && member_type) { clang::ObjCIvarDecl *ivar_decl = NULL; @@ -3761,9 +3775,10 @@ SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die, } } - if (best_name.GetDemangledName()) + const LanguageType cu_language = const_cast<DWARFCompileUnit *>(dwarf_cu)->GetLanguageType(); + if (best_name.GetDemangledName(cu_language)) { - const char *demangled = best_name.GetDemangledName().GetCString(); + const char *demangled = best_name.GetDemangledName(cu_language).GetCString(); if (demangled) { std::string name_no_parens(partial_name, base_name_end - partial_name); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 5579a23ce716..de972acd7ed7 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -113,7 +113,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // correctly to the new addresses in the main executable. // First we find the original symbol in the .o file's symbol table - Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), + Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled), eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny); @@ -145,7 +145,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // sizes from the DWARF info as we are parsing. // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file - Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), + Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled), eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny); diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 64c88ab716bf..09b919782608 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -161,7 +161,7 @@ SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) { const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]); if (cu_symbol) - cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetMangled().GetName().AsCString(), 0, eLanguageTypeUnknown)); + cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetName().AsCString(), 0, eLanguageTypeUnknown)); } return cu_sp; } diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp index 3c3e2e51d9af..68bcde8a47c1 100644 --- a/source/Symbol/ClangASTContext.cpp +++ b/source/Symbol/ClangASTContext.cpp @@ -1592,6 +1592,7 @@ ClangASTContext::CreateObjCClass SourceLocation(), &ast->Idents.get(name), nullptr, + nullptr, SourceLocation(), /*isForwardDecl,*/ isInternal); diff --git a/source/Symbol/ClangASTImporter.cpp b/source/Symbol/ClangASTImporter.cpp index 64a7323d25cf..dd73b35d86a9 100644 --- a/source/Symbol/ClangASTImporter.cpp +++ b/source/Symbol/ClangASTImporter.cpp @@ -17,6 +17,7 @@ #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangNamespaceDecl.h" +#include "lldb/Utility/LLDBAssert.h" using namespace lldb_private; using namespace clang; @@ -109,6 +110,134 @@ ClangASTImporter::CopyDecl (clang::ASTContext *dst_ast, return nullptr; } +class DeclContextOverride +{ +private: + struct Backup + { + clang::DeclContext *decl_context; + clang::DeclContext *lexical_decl_context; + }; + + std::map<clang::Decl *, Backup> m_backups; + + void OverrideOne(clang::Decl *decl) + { + if (m_backups.find(decl) != m_backups.end()) + { + return; + } + + m_backups[decl] = { decl->getDeclContext(), decl->getLexicalDeclContext() }; + + decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl()); + decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl()); + } + + bool ChainPassesThrough(clang::Decl *decl, + clang::DeclContext *base, + clang::DeclContext *(clang::Decl::*contextFromDecl)(), + clang::DeclContext *(clang::DeclContext::*contextFromContext)()) + { + for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); + decl_ctx; + decl_ctx = (decl_ctx->*contextFromContext)()) + { + if (decl_ctx == base) + { + return true; + } + } + + return false; + } + + clang::Decl *GetEscapedChild(clang::Decl *decl, clang::DeclContext *base = nullptr) + { + if (base) + { + // decl's DeclContext chains must pass through base. + + if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, &clang::DeclContext::getParent) || + !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, &clang::DeclContext::getLexicalParent)) + { + return decl; + } + } + else + { + base = clang::dyn_cast<clang::DeclContext>(decl); + + if (!base) + { + return nullptr; + } + } + + if (clang::DeclContext *context = clang::dyn_cast<clang::DeclContext>(decl)) + { + for (clang::Decl *decl : context->decls()) + { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) + { + return escaped_child; + } + } + } + + return nullptr; + } + + void Override(clang::Decl *decl) + { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) + { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + log->Printf(" [ClangASTImporter] DeclContextOverride couldn't override (%sDecl*)%p - its child (%sDecl*)%p escapes", + decl->getDeclKindName(), static_cast<void*>(decl), + escaped_child->getDeclKindName(), static_cast<void*>(escaped_child)); + lldbassert(0 && "Couldn't override!"); + } + + OverrideOne(decl); + } + +public: + DeclContextOverride() + { + } + + void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) + { + for (DeclContext *decl_context = decl->getLexicalDeclContext(); + decl_context; + decl_context = decl_context->getLexicalParent()) + { + DeclContext *redecl_context = decl_context->getRedeclContext(); + + if (llvm::isa<FunctionDecl>(redecl_context) && + llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) + { + for (clang::Decl *child_decl : decl_context->decls()) + { + Override(child_decl); + } + } + } + } + + ~DeclContextOverride() + { + for (const std::pair<clang::Decl *, Backup> &backup : m_backups) + { + backup.first->setDeclContext(backup.second.decl_context); + backup.first->setLexicalDeclContext(backup.second.lexical_decl_context); + } + } +}; + lldb::clang_type_t ClangASTImporter::DeportType (clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx, @@ -122,6 +251,13 @@ ClangASTImporter::DeportType (clang::ASTContext *dst_ctx, std::set<NamedDecl *> decls_to_deport; std::set<NamedDecl *> decls_already_deported; + DeclContextOverride decl_context_override; + + if (const clang::TagType *tag_type = clang::QualType::getFromOpaquePtr(type)->getAs<TagType>()) + { + decl_context_override.OverrideAllDeclsFromContainingFunction(tag_type->getDecl()); + } + minion_sp->InitDeportWorkQueues(&decls_to_deport, &decls_already_deported); @@ -156,6 +292,10 @@ ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx, std::set<NamedDecl *> decls_to_deport; std::set<NamedDecl *> decls_already_deported; + + DeclContextOverride decl_context_override; + + decl_context_override.OverrideAllDeclsFromContainingFunction(decl); minion_sp->InitDeportWorkQueues(&decls_to_deport, &decls_already_deported); @@ -568,7 +708,8 @@ ClangASTImporter::Minion::ImportDefinitionTo (clang::Decl *to, clang::Decl *from if (!to_objc_interface->hasDefinition()) to_objc_interface->startDefinition(); - to_objc_interface->setSuperClass(imported_from_superclass); + to_objc_interface->setSuperClass( + m_source_ctx->getTrivialTypeSourceInfo(m_source_ctx->getObjCInterfaceType(imported_from_superclass))); } while (0); } diff --git a/source/Symbol/ClangASTType.cpp b/source/Symbol/ClangASTType.cpp index a62cc9f45a6b..6f1002fbd9fc 100644 --- a/source/Symbol/ClangASTType.cpp +++ b/source/Symbol/ClangASTType.cpp @@ -5354,7 +5354,9 @@ ClangASTType::SetObjCSuperClass (const ClangASTType &superclass_clang_type) clang::ObjCInterfaceDecl *super_interface_decl = superclass_clang_type.GetAsObjCInterfaceDecl (); if (class_interface_decl && super_interface_decl) { - class_interface_decl->setSuperClass(super_interface_decl); + + class_interface_decl->setSuperClass( + m_ast->getTrivialTypeSourceInfo(m_ast->getObjCInterfaceType(super_interface_decl))); return true; } } diff --git a/source/Symbol/Function.cpp b/source/Symbol/Function.cpp index 0b7430ad75e3..77448d4f2a22 100644 --- a/source/Symbol/Function.cpp +++ b/source/Symbol/Function.cpp @@ -77,7 +77,7 @@ FunctionInfo::GetDeclaration() const return m_declaration; } -const ConstString& +ConstString FunctionInfo::GetName() const { return m_name; @@ -140,25 +140,32 @@ InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const } void -InlineFunctionInfo::DumpStopContext (Stream *s) const +InlineFunctionInfo::DumpStopContext (Stream *s, LanguageType language) const { // s->Indent("[inlined] "); s->Indent(); if (m_mangled) - s->PutCString (m_mangled.GetName().AsCString()); + s->PutCString (m_mangled.GetName(language).AsCString()); else s->PutCString (m_name.AsCString()); } -const ConstString & -InlineFunctionInfo::GetName () const +ConstString +InlineFunctionInfo::GetName (LanguageType language) const { if (m_mangled) - return m_mangled.GetName(); + return m_mangled.GetName(language); return m_name; } +ConstString +InlineFunctionInfo::GetDisplayName (LanguageType language) const +{ + if (m_mangled) + return m_mangled.GetDisplayDemangledName(language); + return m_name; +} Declaration & InlineFunctionInfo::GetCallSite () @@ -459,6 +466,14 @@ Function::MemorySize () const return mem_size; } +ConstString +Function::GetDisplayName () const +{ + if (!m_mangled) + return ConstString(); + return m_mangled.GetDisplayDemangledName(GetLanguage()); +} + clang::DeclContext * Function::GetClangDeclContext() { @@ -602,5 +617,32 @@ Function::GetPrologueByteSize () return m_prologue_byte_size; } +lldb::LanguageType +Function::GetLanguage() const +{ + if (m_comp_unit) + return m_comp_unit->GetLanguage(); + else + return lldb::eLanguageTypeUnknown; +} + +ConstString +Function::GetName() const +{ + LanguageType language = lldb::eLanguageTypeUnknown; + if (m_comp_unit) + language = m_comp_unit->GetLanguage(); + return m_mangled.GetName(language); +} + +ConstString +Function::GetNameNoArguments() const +{ + LanguageType language = lldb::eLanguageTypeUnknown; + if (m_comp_unit) + language = m_comp_unit->GetLanguage(); + return m_mangled.GetName(language, Mangled::ePreferDemangledWithoutArguments); +} + diff --git a/source/Symbol/Symbol.cpp b/source/Symbol/Symbol.cpp index dff15dd92613..5884fcaa551d 100644 --- a/source/Symbol/Symbol.cpp +++ b/source/Symbol/Symbol.cpp @@ -185,6 +185,14 @@ Symbol::ValueIsAddress() const } ConstString +Symbol::GetDisplayName () const +{ + if (!m_mangled) + return ConstString(); + return m_mangled.GetDisplayDemangledName(GetLanguage()); +} + +ConstString Symbol::GetReExportedSymbolName() const { if (m_type == eSymbolTypeReExported) @@ -288,8 +296,9 @@ Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) else s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); } - if (m_mangled.GetDemangledName()) - s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString()); + ConstString demangled = m_mangled.GetDemangledName(GetLanguage()); + if (demangled) + s->Printf(", name=\"%s\"", demangled.AsCString()); if (m_mangled.GetMangledName()) s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString()); @@ -309,6 +318,7 @@ Symbol::Dump(Stream *s, Target *target, uint32_t index) const // Make sure the size of the symbol is up to date before dumping GetByteSize(); + ConstString name = m_mangled.GetName(GetLanguage()); if (ValueIsAddress()) { if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress)) @@ -325,13 +335,13 @@ Symbol::Dump(Stream *s, Target *target, uint32_t index) const s->Printf( format, GetByteSize(), m_flags, - m_mangled.GetName().AsCString("")); + name.AsCString("")); } else if (m_type == eSymbolTypeReExported) { s->Printf (" 0x%8.8x %s", m_flags, - m_mangled.GetName().AsCString("")); + name.AsCString("")); ConstString reexport_name = GetReExportedSymbolName(); intptr_t shlib = m_addr_range.GetByteSize(); @@ -349,7 +359,7 @@ Symbol::Dump(Stream *s, Target *target, uint32_t index) const m_addr_range.GetBaseAddress().GetOffset(), GetByteSize(), m_flags, - m_mangled.GetName().AsCString("")); + name.AsCString("")); } } @@ -439,7 +449,7 @@ bool Symbol::Compare(const ConstString& name, SymbolType type) const { if (type == eSymbolTypeAny || m_type == type) - return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name; + return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName(GetLanguage()) == name; return false; } @@ -635,6 +645,18 @@ Symbol::GetLoadAddress (Target *target) const return LLDB_INVALID_ADDRESS; } +ConstString +Symbol::GetName () const +{ + return m_mangled.GetName(GetLanguage()); +} + +ConstString +Symbol::GetNameNoArguments () const +{ + return m_mangled.GetName(GetLanguage(), Mangled::ePreferDemangledWithoutArguments); +} + lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const diff --git a/source/Symbol/SymbolContext.cpp b/source/Symbol/SymbolContext.cpp index 8e4240a4587d..4fb0dbc237c8 100644 --- a/source/Symbol/SymbolContext.cpp +++ b/source/Symbol/SymbolContext.cpp @@ -160,15 +160,15 @@ SymbolContext::DumpStopContext ( s->Printf("<"); dumped_something = true; } - else if (show_function_arguments == false && function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments)) - { - dumped_something = true; - function->GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments).Dump(s); - } - else if (function->GetMangled().GetName()) + else { - dumped_something = true; - function->GetMangled().GetName().Dump(s); + ConstString name; + if (show_function_arguments == false) + name = function->GetNameNoArguments(); + if (!name) + name = function->GetName(); + if (name) + name.Dump(s); } if (addr.IsValid()) @@ -192,7 +192,7 @@ SymbolContext::DumpStopContext ( dumped_something = true; Block *inlined_block = block->GetContainingInlinedBlock(); const InlineFunctionInfo* inlined_block_info = inlined_block->GetInlinedFunctionInfo(); - s->Printf (" [inlined] %s", inlined_block_info->GetName().GetCString()); + s->Printf (" [inlined] %s", inlined_block_info->GetName(function->GetLanguage()).GetCString()); lldb_private::AddressRange block_range; if (inlined_block->GetRangeContainingAddress(addr, block_range)) @@ -235,12 +235,12 @@ SymbolContext::DumpStopContext ( s->Printf("<"); dumped_something = true; } - else if (symbol->GetMangled().GetName()) + else if (symbol->GetName()) { dumped_something = true; if (symbol->GetType() == eSymbolTypeTrampoline) s->PutCString("symbol stub for: "); - symbol->GetMangled().GetName().Dump(s); + symbol->GetName().Dump(s); } if (addr.IsValid() && symbol->ValueIsAddress()) @@ -438,7 +438,7 @@ SymbolContext::Dump(Stream *s, Target *target) const s->Indent(); *s << "Symbol = " << (void *)symbol; if (symbol != nullptr && symbol->GetMangled()) - *s << ' ' << symbol->GetMangled().GetName().AsCString(); + *s << ' ' << symbol->GetName().AsCString(); s->EOL(); *s << "Variable = " << (void *)variable; if (variable != nullptr) @@ -681,14 +681,14 @@ SymbolContext::GetFunctionName (Mangled::NamePreference preference) const { const InlineFunctionInfo *inline_info = inlined_block->GetInlinedFunctionInfo(); if (inline_info) - return inline_info->GetName(); + return inline_info->GetName(function->GetLanguage()); } } - return function->GetMangled().GetName(preference); + return function->GetMangled().GetName(function->GetLanguage(), preference); } else if (symbol && symbol->ValueIsAddress()) { - return symbol->GetMangled().GetName(preference); + return symbol->GetMangled().GetName(symbol->GetLanguage(), preference); } else { @@ -916,7 +916,7 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { was_inlined = true; const Mangled &name = inline_info->GetMangled(); - if (!name.NameMatches (func_name)) + if (!name.NameMatches (func_name, sc.function->GetLanguage())) return false; } } @@ -925,12 +925,12 @@ SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { if (sc.function != nullptr) { - if (!sc.function->GetMangled().NameMatches(func_name)) + if (!sc.function->GetMangled().NameMatches(func_name, sc.function->GetLanguage())) return false; } else if (sc.symbol != nullptr) { - if (!sc.symbol->GetMangled().NameMatches(func_name)) + if (!sc.symbol->GetMangled().NameMatches(func_name, sc.function->GetLanguage())) return false; } } diff --git a/source/Symbol/Symtab.cpp b/source/Symbol/Symtab.cpp index 4cc03345d05b..c11efc0d9b24 100644 --- a/source/Symbol/Symtab.cpp +++ b/source/Symbol/Symtab.cpp @@ -136,7 +136,7 @@ Symtab::Dump (Stream *s, Target *target, SortOrder sort_order) CStringToSymbol name_map; for (const_iterator pos = m_symbols.begin(), end = m_symbols.end(); pos != end; ++pos) { - const char *name = pos->GetMangled().GetName(Mangled::ePreferDemangled).AsCString(); + const char *name = pos->GetName().AsCString(); if (name && name[0]) name_map.insert (std::make_pair(name, &(*pos))); } @@ -329,7 +329,7 @@ Symtab::InitNameIndexes() entry.cstring[2] != 'G' && // avoid guard variables entry.cstring[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back) { - CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName()); + CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus)); entry.cstring = ConstString(cxx_method.GetBasename()).GetCString(); if (entry.cstring && entry.cstring[0]) { @@ -378,7 +378,7 @@ Symtab::InitNameIndexes() } } - entry.cstring = mangled.GetDemangledName().GetCString(); + entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()).GetCString(); if (entry.cstring && entry.cstring[0]) { m_name_to_index.Append (entry); @@ -486,7 +486,7 @@ Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes, const Mangled &mangled = symbol->GetMangled(); if (add_demangled) { - entry.cstring = mangled.GetDemangledName().GetCString(); + entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()).GetCString(); if (entry.cstring && entry.cstring[0]) name_to_index_map.Append (entry); } @@ -746,7 +746,7 @@ Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression ®exp { if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type) { - const char *name = m_symbols[i].GetMangled().GetName().AsCString(); + const char *name = m_symbols[i].GetName().AsCString(); if (name) { if (regexp.Execute (name)) @@ -773,7 +773,7 @@ Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression ®exp if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility) == false) continue; - const char *name = m_symbols[i].GetMangled().GetName().AsCString(); + const char *name = m_symbols[i].GetName().AsCString(); if (name) { if (regexp.Execute (name)) diff --git a/source/Symbol/Variable.cpp b/source/Symbol/Variable.cpp index 5665e4702ca6..2490e98ac1e8 100644 --- a/source/Symbol/Variable.cpp +++ b/source/Symbol/Variable.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Symbol/Block.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Type.h" @@ -65,22 +66,48 @@ Variable::~Variable() { } +lldb::LanguageType +Variable::GetLanguage () const +{ + SymbolContext variable_sc; + m_owner_scope->CalculateSymbolContext(&variable_sc); + if (variable_sc.comp_unit) + return variable_sc.comp_unit->GetLanguage(); + return lldb::eLanguageTypeUnknown; +} + -const ConstString& + +ConstString Variable::GetName() const { - const ConstString &name = m_mangled.GetName(); + ConstString name = m_mangled.GetName(GetLanguage()); if (name) return name; return m_name; } bool +Variable::NameMatches (const ConstString &name) const +{ + if (m_name == name) + return true; + SymbolContext variable_sc; + m_owner_scope->CalculateSymbolContext(&variable_sc); + + LanguageType language = eLanguageTypeUnknown; + if (variable_sc.comp_unit) + language = variable_sc.comp_unit->GetLanguage(); + return m_mangled.NameMatches (name, language); +} +bool Variable::NameMatches (const RegularExpression& regex) const { if (regex.Execute (m_name.AsCString())) return true; - return m_mangled.NameMatches (regex); + if (m_mangled) + return m_mangled.NameMatches (regex, GetLanguage()); + return false; } Type * diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp index 6758ecf7e22e..2b586933ccd4 100644 --- a/source/Target/Platform.cpp +++ b/source/Target/Platform.cpp @@ -36,6 +36,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Utils.h" #include "llvm/Support/FileSystem.h" @@ -1536,27 +1537,6 @@ Platform::CalculateMD5 (const FileSpec& file_spec, return false; } -Error -Platform::LaunchNativeProcess ( - ProcessLaunchInfo &launch_info, - lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, - NativeProcessProtocolSP &process_sp) -{ - // Platforms should override this implementation if they want to - // support lldb-gdbserver. - return Error("unimplemented"); -} - -Error -Platform::AttachNativeProcess (lldb::pid_t pid, - lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, - NativeProcessProtocolSP &process_sp) -{ - // Platforms should override this implementation if they want to - // support lldb-gdbserver. - return Error("unimplemented"); -} - void Platform::SetLocalCacheDirectory (const char* local) { @@ -1951,3 +1931,18 @@ Platform::GetCacheHostname () { return GetHostname (); } + +const UnixSignalsSP & +Platform::GetRemoteUnixSignals() +{ + static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); + return s_default_unix_signals_sp; +} + +const UnixSignalsSP & +Platform::GetUnixSignals() +{ + if (IsHost()) + return Host::GetUnixSignals(); + return GetRemoteUnixSignals(); +} diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 41942829ca55..3abae4fce5b1 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -693,7 +693,7 @@ Process::GetStaticBroadcasterClass () // Process constructor //---------------------------------------------------------------------- Process::Process(Target &target, Listener &listener) : - Process(target, listener, Host::GetUnixSignals ()) + Process(target, listener, UnixSignals::Create(HostInfo::GetArchitecture())) { // This constructor just delegates to the full Process constructor, // defaulting to using the Host's UnixSignals. @@ -754,6 +754,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s m_force_next_event_delivery (false), m_last_broadcast_state (eStateInvalid), m_destroy_in_process (false), + m_can_interpret_function_calls(false), m_can_jit(eCanJITDontKnow) { CheckInWithManager (); @@ -763,14 +764,14 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s log->Printf ("%p Process::Process()", static_cast<void*>(this)); if (!m_unix_signals_sp) - m_unix_signals_sp.reset (new UnixSignals ()); + m_unix_signals_sp = std::make_shared<UnixSignals>(); SetEventName (eBroadcastBitStateChanged, "state-changed"); SetEventName (eBroadcastBitInterrupt, "interrupt"); SetEventName (eBroadcastBitSTDOUT, "stdout-available"); SetEventName (eBroadcastBitSTDERR, "stderr-available"); SetEventName (eBroadcastBitProfileData, "profile-data-available"); - + m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlStop , "control-stop" ); m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlPause , "control-pause" ); m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlResume, "control-resume"); @@ -1145,6 +1146,7 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp, // Prefer a thread that has just completed its plan over another thread as current thread. ThreadSP plan_thread; ThreadSP other_thread; + const size_t num_threads = thread_list.GetSize(); size_t i; for (i = 0; i < num_threads; ++i) @@ -1157,10 +1159,22 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp, case eStopReasonNone: break; + case eStopReasonSignal: + { + // Don't select a signal thread if we weren't going to stop at that + // signal. We have to have had another reason for stopping here, and + // the user doesn't want to see this thread. + uint64_t signo = thread->GetStopInfo()->GetValue(); + if (process_sp->GetUnixSignals()->GetShouldStop(signo)) + { + if (!other_thread) + other_thread = thread; + } + break; + } case eStopReasonTrace: case eStopReasonBreakpoint: case eStopReasonWatchpoint: - case eStopReasonSignal: case eStopReasonException: case eStopReasonExec: case eStopReasonThreadExiting: @@ -1510,7 +1524,7 @@ Process::SetProcessExitStatus (void *callback_baton, { const char *signal_cstr = NULL; if (signo) - signal_cstr = process_sp->GetUnixSignals().GetSignalAsCString (signo); + signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); process_sp->SetExitStatus (exit_status, signal_cstr); } @@ -2998,6 +3012,13 @@ Process::SetCanJIT (bool can_jit) m_can_jit = (can_jit ? eCanJITYes : eCanJITNo); } +void +Process::SetCanRunCode (bool can_run_code) +{ + SetCanJIT(can_run_code); + m_can_interpret_function_calls = can_run_code; +} + Error Process::DeallocateMemory (addr_t ptr) { @@ -4088,11 +4109,11 @@ Process::SetUnixSignals (const UnixSignalsSP &signals_sp) m_unix_signals_sp = signals_sp; } -UnixSignals & +const lldb::UnixSignalsSP & Process::GetUnixSignals () { assert (m_unix_signals_sp && "null m_unix_signals_sp"); - return *m_unix_signals_sp; + return m_unix_signals_sp; } lldb::ByteOrder diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp index 30c5aee63cad..bd2e1bc4c4a1 100644 --- a/source/Target/ProcessLaunchInfo.cpp +++ b/source/Target/ProcessLaunchInfo.cpp @@ -284,6 +284,13 @@ ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty) log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling", __FUNCTION__); + if (m_flags.Test(eLaunchFlagLaunchInTTY)) + { + // Do nothing, if we are launching in a remote terminal + // no file actions should be done at all. + return; + } + if (m_flags.Test(eLaunchFlagDisableSTDIO)) { if (log) diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp index 76e5f374f952..4f6ef7a92949 100644 --- a/source/Target/StopInfo.cpp +++ b/source/Target/StopInfo.cpp @@ -891,7 +891,7 @@ public: { ThreadSP thread_sp (m_thread_wp.lock()); if (thread_sp) - return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value); + return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); return false; } @@ -900,7 +900,7 @@ public: { ThreadSP thread_sp (m_thread_wp.lock()); if (thread_sp) - return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value); + return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); return false; } @@ -912,13 +912,13 @@ public: ThreadSP thread_sp (m_thread_wp.lock()); if (thread_sp) { - bool should_notify = thread_sp->GetProcess()->GetUnixSignals().GetShouldNotify (m_value); + bool should_notify = thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value); if (should_notify) { StreamString strm; strm.Printf ("thread %d received signal: %s", thread_sp->GetIndexID(), - thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value)); + thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value)); Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData()); } return should_notify; @@ -933,7 +933,7 @@ public: ThreadSP thread_sp (m_thread_wp.lock()); if (thread_sp) { - if (thread_sp->GetProcess()->GetUnixSignals().GetShouldSuppress(m_value) == false) + if (thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress(m_value) == false) thread_sp->SetResumeSignal(m_value); } } @@ -947,7 +947,7 @@ public: if (thread_sp) { StreamString strm; - const char *signal_name = thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value); + const char *signal_name = thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value); if (signal_name) strm.Printf("signal %s", signal_name); else diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp index e742ece7ec50..e7b3abd3c941 100644 --- a/source/Target/ThreadPlanCallFunction.cpp +++ b/source/Target/ThreadPlanCallFunction.cpp @@ -147,15 +147,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, m_trap_exceptions (options.GetTrapExceptions()), m_function_addr (function), m_function_sp (0), - m_return_type (return_type), m_takedown_done (false), m_should_clear_objc_exception_bp(false), m_should_clear_cxx_exception_bp (false), - m_stop_address (LLDB_INVALID_ADDRESS) + m_stop_address (LLDB_INVALID_ADDRESS), + m_return_type (return_type) { - lldb::addr_t start_load_addr; - ABI *abi; - lldb::addr_t function_load_addr; + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr)) return; @@ -171,6 +172,27 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, m_valid = true; } +ThreadPlanCallFunction::ThreadPlanCallFunction(Thread &thread, + const Address &function, + const EvaluateExpressionOptions &options) : + ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), + m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), + m_function_addr(function), + m_function_sp(0), + m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), + m_return_type(ClangASTType()) +{ + +} + ThreadPlanCallFunction::~ThreadPlanCallFunction () { DoTakedown(PlanSucceeded()); @@ -222,13 +244,7 @@ ThreadPlanCallFunction::DoTakedown (bool success) { if (success) { - ProcessSP process_sp (m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL; - if (abi && m_return_type.IsValid()) - { - const bool persistent = false; - m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type, persistent); - } + SetReturnValue(); } if (log) log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", @@ -574,3 +590,15 @@ ThreadPlanCallFunction::RestoreThreadState() return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state); } + +void +ThreadPlanCallFunction::SetReturnValue() +{ + ProcessSP process_sp(m_thread.GetProcess()); + const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL; + if (abi && m_return_type.IsValid()) + { + const bool persistent = false; + m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent); + } +} diff --git a/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/source/Target/ThreadPlanCallFunctionUsingABI.cpp new file mode 100644 index 000000000000..53fabd2464e6 --- /dev/null +++ b/source/Target/ThreadPlanCallFunctionUsingABI.cpp @@ -0,0 +1,91 @@ +//===-- ThreadPlanCallFunctionUsingABI.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes + +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//-------------------------------------------------------------------------------------------- +// ThreadPlanCallFunctionUsingABI: Plan to call a single function using the ABI instead of JIT +//------------------------------------------------------------------------------------------- +ThreadPlanCallFunctionUsingABI::ThreadPlanCallFunctionUsingABI (Thread &thread, + const Address &function, + llvm::Type &prototype, + llvm::Type &return_type, + llvm::ArrayRef<ABI::CallArgument> args, + const EvaluateExpressionOptions &options) : + ThreadPlanCallFunction(thread,function,options), + m_return_type(return_type) +{ + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + if (!abi->PrepareTrivialCall(thread, + m_function_sp, + function_load_addr, + start_load_addr, + prototype, + args)) + return; + + ReportRegisterState("ABI Function call was set up. Register state was:"); + + m_valid = true; +} + +ThreadPlanCallFunctionUsingABI::~ThreadPlanCallFunctionUsingABI() +{ + +} + +void +ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, DescriptionLevel level) +{ + if (level == eDescriptionLevelBrief) + { + s->Printf("Function call thread plan using ABI instead of JIT"); + } + else + { + TargetSP target_sp(m_thread.CalculateTarget()); + s->Printf("Thread plan to call 0x%" PRIx64" using ABI instead of JIT", m_function_addr.GetLoadAddress(target_sp.get())); + } +} + +void +ThreadPlanCallFunctionUsingABI::SetReturnValue() +{ + ProcessSP process_sp(m_thread.GetProcess()); + const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL; + + // Ask the abi for the return value + if (abi) + { + const bool persistent = false; + m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent); + } +} diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp index 701e93d3c4de..aba89224239c 100644 --- a/source/Target/ThreadPlanStepOverRange.cpp +++ b/source/Target/ThreadPlanStepOverRange.cpp @@ -430,7 +430,7 @@ ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool curren const InlineFunctionInfo *inline_info = frame_block->GetInlinedFunctionInfo(); const char *name; if (inline_info) - name = inline_info->GetName().AsCString(); + name = inline_info->GetName(frame_block->CalculateSymbolContextFunction()->GetLanguage()).AsCString(); else name = "<unknown-notinlined>"; diff --git a/source/Target/UnixSignals.cpp b/source/Target/UnixSignals.cpp index 7f57579c1ee5..91579e8d7852 100644 --- a/source/Target/UnixSignals.cpp +++ b/source/Target/UnixSignals.cpp @@ -13,16 +13,21 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Core/ArchSpec.h" #include "lldb/Host/StringConvert.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" +#include "Plugins/Process/Utility/LinuxSignals.h" +#include "Plugins/Process/Utility/MipsLinuxSignals.h" + using namespace lldb_private; -UnixSignals::Signal::Signal +UnixSignals::Signal::Signal ( - const char *name, - const char *short_name, - bool default_suppress, - bool default_stop, + const char *name, + const char *short_name, + bool default_suppress, + bool default_stop, bool default_notify, const char *description ) : @@ -37,6 +42,34 @@ UnixSignals::Signal::Signal m_description.assign (description); } +lldb::UnixSignalsSP +UnixSignals::Create(const ArchSpec &arch) +{ + const auto &triple = arch.GetTriple(); + switch (triple.getOS()) + { + case llvm::Triple::Linux: + { + switch (triple.getArch()) + { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return std::make_shared<MipsLinuxSignals>(); + default: + return std::make_shared<LinuxSignals>(); + } + } + case llvm::Triple::FreeBSD: + case llvm::Triple::OpenBSD: + case llvm::Triple::NetBSD: + return std::make_shared<FreeBSDSignals>(); + default: + return std::make_shared<UnixSignals>(); + } +} + //---------------------------------------------------------------------- // UnixSignals constructor //---------------------------------------------------------------------- @@ -45,6 +78,11 @@ UnixSignals::UnixSignals () Reset (); } +UnixSignals::UnixSignals(const UnixSignals &rhs) + : m_signals(rhs.m_signals) +{ +} + //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -291,3 +329,19 @@ UnixSignals::SetShouldNotify (const char *signal_name, bool value) return SetShouldNotify (signo, value); return false; } + +int32_t +UnixSignals::GetNumSignals() const +{ + return m_signals.size(); +} + +int32_t +UnixSignals::GetSignalAtIndex(int32_t index) const +{ + if (index < 0 || m_signals.size() <= static_cast<size_t>(index)) + return LLDB_INVALID_SIGNAL_NUMBER; + auto it = m_signals.begin(); + std::advance(it, index); + return it->first; +} diff --git a/source/Utility/JSON.cpp b/source/Utility/JSON.cpp index 0ba8cf4399ce..1e16a5ac9952 100644 --- a/source/Utility/JSON.cpp +++ b/source/Utility/JSON.cpp @@ -9,6 +9,10 @@ #include "lldb/Utility/JSON.h" +#include <limits.h> +#include "lldb/Core/StreamString.h" +#include "lldb/Host/StringConvert.h" + using namespace lldb_private; std::string @@ -33,20 +37,20 @@ JSONString::json_string_quote_metachars (const std::string &s) } JSONString::JSONString () : -JSONValue(JSONValue::Kind::String), -m_data() + JSONValue(JSONValue::Kind::String), + m_data() { } JSONString::JSONString (const char* s) : -JSONValue(JSONValue::Kind::String), -m_data(s ? s : "") + JSONValue(JSONValue::Kind::String), + m_data(s ? s : "") { } JSONString::JSONString (const std::string& s) : -JSONValue(JSONValue::Kind::String), -m_data(s) + JSONValue(JSONValue::Kind::String), + m_data(s) { } @@ -57,25 +61,41 @@ JSONString::Write (Stream& s) } JSONNumber::JSONNumber () : -JSONValue(JSONValue::Kind::Number), -m_data(0) + JSONValue(JSONValue::Kind::Number), + m_is_integer(true), + m_data(0), + m_double(0.0) +{ +} + +JSONNumber::JSONNumber (uint64_t i) : + JSONValue(JSONValue::Kind::Number), + m_is_integer(true), + m_data(i), + m_double(0.0) { } -JSONNumber::JSONNumber (int64_t i) : -JSONValue(JSONValue::Kind::Number), -m_data(i) + +JSONNumber::JSONNumber (double d) : + JSONValue(JSONValue::Kind::Number), + m_is_integer(false), + m_data(0), + m_double(d) { } void JSONNumber::Write (Stream& s) { - s.Printf("%" PRId64, m_data); + if (m_is_integer) + s.Printf("%" PRIu64, m_data); + else + s.Printf("%g", m_double); } JSONTrue::JSONTrue () : -JSONValue(JSONValue::Kind::True) + JSONValue(JSONValue::Kind::True) { } @@ -86,7 +106,7 @@ JSONTrue::Write(Stream& s) } JSONFalse::JSONFalse () : -JSONValue(JSONValue::Kind::False) + JSONValue(JSONValue::Kind::False) { } @@ -97,7 +117,7 @@ JSONFalse::Write(Stream& s) } JSONNull::JSONNull () : -JSONValue(JSONValue::Kind::Null) + JSONValue(JSONValue::Kind::Null) { } @@ -108,7 +128,7 @@ JSONNull::Write(Stream& s) } JSONObject::JSONObject () : -JSONValue(JSONValue::Kind::Object) + JSONValue(JSONValue::Kind::Object) { } @@ -153,7 +173,7 @@ JSONObject::GetObject (const std::string& key) } JSONArray::JSONArray () : -JSONValue(JSONValue::Kind::Array) + JSONValue(JSONValue::Kind::Array) { } @@ -215,3 +235,419 @@ JSONArray::GetNumElements () { return m_elements.size(); } + + +JSONParser::JSONParser (const char *cstr) : + StringExtractor(cstr) +{ +} + +JSONParser::Token +JSONParser::GetToken (std::string &value) +{ + StreamString error; + + value.clear(); + SkipSpaces (); + const uint64_t start_index = m_index; + const char ch = GetChar(); + switch (ch) + { + case '{': return Token::ObjectStart; + case '}': return Token::ObjectEnd; + case '[': return Token::ArrayStart; + case ']': return Token::ArrayEnd; + case ',': return Token::Comma; + case ':': return Token::Colon; + case '\0': return Token::EndOfFile; + case 't': + if (GetChar() == 'r') + if (GetChar() == 'u') + if (GetChar() == 'e') + return Token::True; + break; + + case 'f': + if (GetChar() == 'a') + if (GetChar() == 'l') + if (GetChar() == 's') + if (GetChar() == 'e') + return Token::False; + break; + + case 'n': + if (GetChar() == 'u') + if (GetChar() == 'l') + if (GetChar() == 'l') + return Token::Null; + break; + + case '"': + { + while (1) + { + bool was_escaped = false; + int escaped_ch = GetEscapedChar(was_escaped); + if (escaped_ch == -1) + { + error.Printf("error: an error occurred getting a character from offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + + } + else + { + const bool is_end_quote = escaped_ch == '"'; + const bool is_null = escaped_ch == 0; + if (was_escaped || (!is_end_quote && !is_null)) + { + if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) + { + value.append(1, (char)escaped_ch); + } + else + { + error.Printf("error: wide character support is needed for unicode character 0x%4.4x at offset %" PRIu64, escaped_ch, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + } + else if (is_end_quote) + { + return Token::String; + } + else if (is_null) + { + value = "error: missing end quote for string"; + return Token::Error; + } + } + } + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + bool done = false; + bool got_decimal_point = false; + uint64_t exp_index = 0; + bool got_int_digits = (ch >= '0') && (ch <= '9'); + bool got_frac_digits = false; + bool got_exp_digits = false; + while (!done) + { + const char next_ch = PeekChar(); + switch (next_ch) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (exp_index != 0) + { + got_exp_digits = true; + } + else if (got_decimal_point) + { + got_frac_digits = true; + } + else + { + got_int_digits = true; + } + ++m_index; // Skip this character + break; + + case '.': + if (got_decimal_point) + { + error.Printf("error: extra decimal point found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + else + { + got_decimal_point = true; + ++m_index; // Skip this character + } + break; + + case 'e': + case 'E': + if (exp_index != 0) + { + error.Printf("error: extra expenent character found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + else + { + exp_index = m_index; + ++m_index; // Skip this character + } + break; + + case '+': + case '-': + // The '+' and '-' can only come after an exponent character... + if (exp_index == m_index - 1) + { + ++m_index; // Skip the exponent sign character + } + else + { + error.Printf("error: unexpected %c character at offset %" PRIu64, next_ch, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + + default: + done = true; + break; + } + } + + if (m_index > start_index) + { + value = m_packet.substr(start_index, m_index - start_index); + if (got_decimal_point) + { + if (exp_index != 0) + { + // We have an exponent, make sure we got exponent digits + if (got_exp_digits) + { + return Token::Float; + } + else + { + error.Printf("error: got exponent character but no exponent digits at offset in float value \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + else + { + // No exponent, but we need at least one decimal after the decimal point + if (got_frac_digits) + { + return Token::Float; + } + else + { + error.Printf("error: no digits after decimal point \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + } + else + { + // No decimal point + if (got_int_digits) + { + // We need at least some integer digits to make an integer + return Token::Integer; + } + else + { + error.Printf("error: no digits negate sign \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + } + else + { + error.Printf("error: invalid number found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + } + break; + default: + break; + } + error.Printf("error: failed to parse token at offset %" PRIu64 " (around character '%c')", start_index, ch); + value = std::move(error.GetString()); + return Token::Error; +} + +int +JSONParser::GetEscapedChar(bool &was_escaped) +{ + was_escaped = false; + const char ch = GetChar(); + if (ch == '\\') + { + was_escaped = true; + const char ch2 = GetChar(); + switch (ch2) + { + case '"': + case '\\': + case '/': + default: + break; + + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'u': + { + const int hi_byte = DecodeHexU8(); + const int lo_byte = DecodeHexU8(); + if (hi_byte >=0 && lo_byte >= 0) + return hi_byte << 8 | lo_byte; + return -1; + } + break; + } + return ch2; + } + return ch; +} + +JSONValue::SP +JSONParser::ParseJSONObject () +{ + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<JSONObject> dict_up(new JSONObject()); + + std::string value; + std::string key; + while (1) + { + JSONParser::Token token = GetToken(value); + + if (token == JSONParser::Token::String) + { + key.swap(value); + token = GetToken(value); + if (token == JSONParser::Token::Colon) + { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + dict_up->SetObject(key, value_sp); + else + break; + } + } + else if (token == JSONParser::Token::ObjectEnd) + { + return JSONValue::SP(dict_up.release()); + } + else if (token == JSONParser::Token::Comma) + { + continue; + } + else + { + break; + } + } + return JSONValue::SP(); +} + +JSONValue::SP +JSONParser::ParseJSONArray () +{ + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<JSONArray> array_up(new JSONArray()); + + std::string value; + std::string key; + while (1) + { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + array_up->AppendObject(value_sp); + else + break; + + JSONParser::Token token = GetToken(value); + if (token == JSONParser::Token::Comma) + { + continue; + } + else if (token == JSONParser::Token::ArrayEnd) + { + return JSONValue::SP(array_up.release()); + } + else + { + break; + } + } + return JSONValue::SP(); +} + +JSONValue::SP +JSONParser::ParseJSONValue () +{ + std::string value; + const JSONParser::Token token = GetToken(value); + switch (token) + { + case JSONParser::Token::ObjectStart: + return ParseJSONObject(); + + case JSONParser::Token::ArrayStart: + return ParseJSONArray(); + + case JSONParser::Token::Integer: + { + bool success = false; + uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); + if (success) + return JSONValue::SP(new JSONNumber(uval)); + } + break; + + case JSONParser::Token::Float: + { + bool success = false; + double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); + if (success) + return JSONValue::SP(new JSONNumber(val)); + } + break; + + case JSONParser::Token::String: + return JSONValue::SP(new JSONString(value)); + + case JSONParser::Token::True: + return JSONValue::SP(new JSONTrue()); + + case JSONParser::Token::False: + return JSONValue::SP(new JSONFalse()); + + case JSONParser::Token::Null: + return JSONValue::SP(new JSONNull()); + + default: + break; + } + return JSONValue::SP(); + +} diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp index e82c83dfd093..6302c033c0c1 100644 --- a/source/Utility/StringExtractor.cpp +++ b/source/Utility/StringExtractor.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Utility/StringExtractor.h" +#include "lldb/Utility/StringExtractor.h" // C Includes #include <stdlib.h> @@ -476,3 +476,12 @@ StringExtractor::GetNameColonValue (std::string &name, std::string &value) m_index = UINT64_MAX; return false; } + +void +StringExtractor::SkipSpaces () +{ + const size_t n = m_packet.size(); + while (m_index < n && isspace(m_packet[m_index])) + ++m_index; +} + diff --git a/source/Utility/StringExtractor.h b/source/Utility/StringExtractor.h deleted file mode 100644 index 49dfe99bd358..000000000000 --- a/source/Utility/StringExtractor.h +++ /dev/null @@ -1,164 +0,0 @@ -//===-- StringExtractor.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_StringExtractor_h_ -#define utility_StringExtractor_h_ - -// C Includes -// C++ Includes -#include <string> -#include <stdint.h> - -// Other libraries and framework includes -// Project includes - -class StringExtractor -{ -public: - - enum { - BigEndian = 0, - LittleEndian = 1 - }; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - StringExtractor(); - StringExtractor(const char *packet_cstr); - StringExtractor(const StringExtractor& rhs); - virtual ~StringExtractor(); - - //------------------------------------------------------------------ - // Operators - //------------------------------------------------------------------ - const StringExtractor& - operator=(const StringExtractor& rhs); - - // Returns true if the file position is still valid for the data - // contained in this string extractor object. - bool - IsGood() const - { - return m_index != UINT64_MAX; - } - - uint64_t - GetFilePos () const - { - return m_index; - } - - void - SetFilePos (uint32_t idx) - { - m_index = idx; - } - - void - Clear () - { - m_packet.clear(); - m_index = 0; - } - - std::string & - GetStringRef () - { - return m_packet; - } - - const std::string & - GetStringRef () const - { - return m_packet; - } - - bool - Empty() - { - return m_packet.empty(); - } - - size_t - GetBytesLeft () - { - if (m_index < m_packet.size()) - return m_packet.size() - m_index; - return 0; - } - - char - GetChar (char fail_value = '\0'); - - int - DecodeHexU8(); - - uint8_t - GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true); - - bool - GetNameColonValue (std::string &name, std::string &value); - - int32_t - GetS32 (int32_t fail_value, int base = 0); - - uint32_t - GetU32 (uint32_t fail_value, int base = 0); - - int64_t - GetS64 (int64_t fail_value, int base = 0); - - uint64_t - GetU64 (uint64_t fail_value, int base = 0); - - uint32_t - GetHexMaxU32 (bool little_endian, uint32_t fail_value); - - uint64_t - GetHexMaxU64 (bool little_endian, uint64_t fail_value); - - size_t - GetHexBytes (void *dst, size_t dst_len, uint8_t fail_fill_value); - - size_t - GetHexBytesAvail (void *dst, size_t dst_len); - - uint64_t - GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value); - - size_t - GetHexByteString (std::string &str); - - size_t - GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length); - - size_t - GetHexByteStringTerminatedBy (std::string &str, - char terminator); - - const char * - Peek () - { - if (m_index < m_packet.size()) - return m_packet.c_str() + m_index; - return nullptr; - } - -protected: - //------------------------------------------------------------------ - // For StringExtractor only - //------------------------------------------------------------------ - std::string m_packet; // The string in which to extract data. - uint64_t m_index; // When extracting data from a packet, this index - // will march along as things get extracted. If set - // to UINT64_MAX the end of the packet data was - // reached when decoding information -}; - -#endif // utility_StringExtractor_h_ diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp index aeceaa00fa1c..17ee0b63f3e5 100644 --- a/source/Utility/StringExtractorGDBRemote.cpp +++ b/source/Utility/StringExtractorGDBRemote.cpp @@ -82,7 +82,7 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'A': return eServerPacketType_A; - + case 'Q': switch (packet_cstr[1]) @@ -122,7 +122,7 @@ StringExtractorGDBRemote::GetServerPacketType () const break; } break; - + case 'q': switch (packet_cstr[1]) { @@ -219,6 +219,10 @@ StringExtractorGDBRemote::GetServerPacketType () const break; } break; + + case 'j': + if (PACKET_MATCHES("jSignalInfo")) return eServerPacketType_jSignalsInfo; + case 'v': if (PACKET_STARTS_WITH("vFile:")) { diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h index beb07e5b57ea..475b5a8e36c8 100644 --- a/source/Utility/StringExtractorGDBRemote.h +++ b/source/Utility/StringExtractorGDBRemote.h @@ -15,7 +15,7 @@ #include <string> // Other libraries and framework includes // Project includes -#include "Utility/StringExtractor.h" +#include "lldb/Utility/StringExtractor.h" class StringExtractorGDBRemote : public StringExtractor { @@ -118,6 +118,8 @@ public: eServerPacketType_qWatchpointSupportInfoSupported, eServerPacketType_qXfer_auxv_read, + eServerPacketType_jSignalsInfo, + eServerPacketType_vAttach, eServerPacketType_vAttachWait, eServerPacketType_vAttachOrWait, |