aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter/Python
diff options
context:
space:
mode:
authorAdrian Prantl <aprantl@apple.com>2024-08-20 16:01:22 -0700
committerGitHub <noreply@github.com>2024-08-20 16:01:22 -0700
commitf01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9 (patch)
treec38a79f19b1eef07a0b315cc067035d380a83c80 /lldb/source/Plugins/ScriptInterpreter/Python
parent1e9d0028d35ae69263aa848b4cb02245f442eb5c (diff)
downloadllvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.zip
llvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.tar.gz
llvm-f01f80ce6ca7640bb0e267b84b1ed0e89b57e2d9.tar.bz2
[lldb] Extend frame recognizers to hide frames from backtraces (#104523)
Compilers and language runtimes often use helper functions that are fundamentally uninteresting when debugging anything but the compiler/runtime itself. This patch introduces a user-extensible mechanism that allows for these frames to be hidden from backtraces and automatically skipped over when navigating the stack with `up` and `down`. This does not affect the numbering of frames, so `f <N>` will still provide access to the hidden frames. The `bt` output will also print a hint that frames have been hidden. My primary motivation for this feature is to hide thunks in the Swift programming language, but I'm including an example recognizer for `std::function::operator()` that I wished for myself many times while debugging LLDB. rdar://126629381 Example output. (Yes, my proof-of-concept recognizer could hide even more frames if we had a method that returned the function name without the return type or I used something that isn't based off regex, but it's really only meant as an example). before: ``` (lldb) thread backtrace --filtered=false * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 * frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10 frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25 frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12 frame #3: 0x0000000100003968 a.out`std::__1::__function::__alloc_func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()[abi:se200000](this=0x000000016fdff280, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:171:12 frame #4: 0x00000001000026bc a.out`std::__1::__function::__func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()(this=0x000000016fdff278, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:313:10 frame #5: 0x0000000100003c38 a.out`std::__1::__function::__value_func<int (int, int)>::operator()[abi:se200000](this=0x000000016fdff278, __args=0x000000016fdff224, __args=0x000000016fdff220) const at function.h:430:12 frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10 frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10 frame #8: 0x0000000183cdf154 dyld`start + 2476 (lldb) ``` after ``` (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 * frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10 frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25 frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12 frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10 frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10 frame #8: 0x0000000183cdf154 dyld`start + 2476 Note: Some frames were hidden by frame recognizers ```
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h3
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp29
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h3
3 files changed, 35 insertions, 0 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 3026b61..5351c1a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -227,6 +227,9 @@ public:
LLDBSwigPython_GetRecognizedArguments(PyObject *implementor,
const lldb::StackFrameSP &frame_sp);
+ static bool LLDBSwigPython_ShouldHide(PyObject *implementor,
+ const lldb::StackFrameSP &frame_sp);
+
static bool LLDBSWIGPythonRunScriptKeywordProcess(
const char *python_function_name, const char *session_dictionary_name,
const lldb::ProcessSP &process, std::string &output);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 335c482..2a94f11 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1524,6 +1524,35 @@ lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments(
return ValueObjectListSP();
}
+bool ScriptInterpreterPythonImpl::ShouldHide(
+ const StructuredData::ObjectSP &os_plugin_object_sp,
+ lldb::StackFrameSP frame_sp) {
+ Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
+
+ if (!os_plugin_object_sp)
+ return false;
+
+ StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+ if (!generic)
+ return false;
+
+ PythonObject implementor(PyRefType::Borrowed,
+ (PyObject *)generic->GetValue());
+
+ if (!implementor.IsAllocated())
+ return false;
+
+ bool result =
+ SWIGBridge::LLDBSwigPython_ShouldHide(implementor.get(), frame_sp);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ return result;
+}
+
ScriptedProcessInterfaceUP
ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() {
return std::make_unique<ScriptedProcessPythonInterface>(*this);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index c2024ef..85d7995 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -107,6 +107,9 @@ public:
GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
lldb::StackFrameSP frame_sp) override;
+ bool ShouldHide(const StructuredData::ObjectSP &implementor,
+ lldb::StackFrameSP frame_sp) override;
+
lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override;
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;