diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -101,8 +101,8 @@ class StackFrameRecognizerManager { public: static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, - ConstString module, ConstString symbol, - ConstString alternate_symbol, + ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only = true); static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, @@ -110,11 +110,11 @@ lldb::RegularExpressionSP symbol, bool first_instruction_only = true); - static void ForEach( - std::function const - &callback); + static void + ForEach(std::function symbols, + bool regexp)> const &callback); static bool RemoveRecognizerWithID(uint32_t recognizer_id); diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -797,7 +797,7 @@ test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads)) else: test.assertGreater(num_threads, 0, "No threads stopped at breakpoint") - + thread = threads[0] return (target, process, thread, bkpt) diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -746,7 +746,7 @@ m_module = std::string(option_arg); break; case 'n': - m_function = std::string(option_arg); + m_symbols.push_back(std::string(option_arg)); break; case 'x': m_regex = true; @@ -760,7 +760,7 @@ void OptionParsingStarting(ExecutionContext *execution_context) override { m_module = ""; - m_function = ""; + m_symbols.clear(); m_class_name = ""; m_regex = false; } @@ -772,7 +772,7 @@ // Instance variables to hold the values for command options. std::string m_class_name; std::string m_module; - std::string m_function; + std::vector m_symbols; bool m_regex; }; @@ -854,9 +854,10 @@ return false; } - if (m_options.m_function.empty()) { - result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", - m_cmd_name.c_str()); + if (m_options.m_symbols.empty()) { + result.AppendErrorWithFormat( + "%s needs at least one symbol name (-n argument).\n", + m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -876,12 +877,13 @@ auto module = RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = - RegularExpressionSP(new RegularExpression(m_options.m_function)); + RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); - auto func = ConstString(m_options.m_function); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func, {}); + std::vector symbols(m_options.m_symbols.begin(), + m_options.m_symbols.end()); + StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); } #endif @@ -958,9 +960,9 @@ bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; StackFrameRecognizerManager::ForEach( - [&result, &any_printed](uint32_t recognizer_id, std::string name, - std::string module, std::string symbol, - std::string alternate_symbol, bool regexp) { + [&result, &any_printed]( + uint32_t recognizer_id, std::string name, std::string module, + llvm::ArrayRef symbols, bool regexp) { Stream &stream = result.GetOutputStream(); if (name.empty()) @@ -969,10 +971,9 @@ stream << std::to_string(recognizer_id) << ": " << name; if (!module.empty()) stream << ", module " << module; - if (!symbol.empty()) - stream << ", function " << symbol; - if (!alternate_symbol.empty()) - stream << ", symbol " << alternate_symbol; + if (!symbols.empty()) + for (auto &symbol : symbols) + stream << ", symbol " << symbol; if (regexp) stream << " (regexp)"; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -2685,9 +2685,10 @@ FileSpec module; ConstString function; std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector symbols = {function}; StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), function, /*alternate_symbol*/ {}, + module.GetFilename(), symbols, /*first_instruction_only*/ true); }); } diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp --- a/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/lldb/source/Target/AssertFrameRecognizer.cpp @@ -21,8 +21,7 @@ /// name. struct SymbolLocation { FileSpec module_spec; - ConstString symbol_name; - ConstString alternate_symbol_name; + std::vector symbols; }; /// Fetches the abort frame location depending on the current platform. @@ -39,12 +38,13 @@ case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_kernel.dylib"); - location.symbol_name.SetString("__pthread_kill"); + location.symbols.push_back(ConstString("__pthread_kill")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("raise"); - location.alternate_symbol_name.SetString("__GI_raise"); + location.symbols.push_back(ConstString("raise")); + location.symbols.push_back(ConstString("__GI_raise")); + location.symbols.push_back(ConstString("gsignal")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -69,12 +69,12 @@ case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_c.dylib"); - location.symbol_name.SetString("__assert_rtn"); + location.symbols.push_back(ConstString("__assert_rtn")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("__assert_fail"); - location.alternate_symbol_name.SetString("__GI___assert_fail"); + location.symbols.push_back(ConstString("__assert_fail")); + location.symbols.push_back(ConstString("__GI___assert_fail")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -97,8 +97,7 @@ StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new AssertFrameRecognizer()), - location.module_spec.GetFilename(), ConstString(location.symbol_name), - ConstString(location.alternate_symbol_name), + location.module_spec.GetFilename(), location.symbols, /*first_instruction_only*/ false); }); } @@ -139,10 +138,7 @@ ConstString func_name = sym_ctx.GetFunctionName(); - if (func_name == location.symbol_name || - (!location.alternate_symbol_name.IsEmpty() && - func_name == location.alternate_symbol_name)) { - + if (llvm::is_contained(location.symbols, func_name)) { // We go a frame beyond the assert location because the most relevant // frame for the user is the one in which the assert function was called. // If the assert location is the last frame fetched, then it is set as diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -51,27 +51,25 @@ class StackFrameRecognizerManagerImpl { public: void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module, - ConstString symbol, ConstString alternate_symbol, + llvm::ArrayRef symbols, bool first_instruction_only) { m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - false, module, RegularExpressionSP(), symbol, - alternate_symbol, RegularExpressionSP(), - first_instruction_only}); + false, module, RegularExpressionSP(), symbols, + RegularExpressionSP(), first_instruction_only}); } void AddRecognizer(StackFrameRecognizerSP recognizer, RegularExpressionSP module, RegularExpressionSP symbol, bool first_instruction_only) { - m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - true, ConstString(), module, ConstString(), - ConstString(), symbol, first_instruction_only}); + m_recognizers.push_front( + {(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), + module, std::vector(), symbol, first_instruction_only}); } - void ForEach( - std::function const - &callback) { + void ForEach(std::function< + void(uint32_t recognized_id, std::string recognizer_name, + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { for (auto entry : m_recognizers) { if (entry.is_regexp) { std::string module_name; @@ -83,16 +81,11 @@ symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - symbol_name, {}, true); + llvm::makeArrayRef(ConstString(symbol_name)), true); } else { - std::string alternate_symbol; - if (!entry.alternate_symbol.IsEmpty()) - alternate_symbol.append(entry.alternate_symbol.GetCString()); - callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbol.GetCString(), - alternate_symbol, false); + entry.module.GetCString(), entry.symbols, false); } } } @@ -128,10 +121,8 @@ if (entry.module_regexp) if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; - if (entry.symbol) - if (entry.symbol != function_name && - (!entry.alternate_symbol || - entry.alternate_symbol != function_name)) + if (!entry.symbols.empty()) + if (!llvm::is_contained(entry.symbols, function_name)) continue; if (entry.symbol_regexp) @@ -160,8 +151,7 @@ bool is_regexp; ConstString module; RegularExpressionSP module_regexp; - ConstString symbol; - ConstString alternate_symbol; + std::vector symbols; RegularExpressionSP symbol_regexp; bool first_instruction_only; }; @@ -176,10 +166,10 @@ } void StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP recognizer, ConstString module, ConstString symbol, - ConstString alternate_symbol, bool first_instruction_only) { + StackFrameRecognizerSP recognizer, ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only) { GetStackFrameRecognizerManagerImpl().AddRecognizer( - recognizer, module, symbol, alternate_symbol, first_instruction_only); + recognizer, module, symbols, first_instruction_only); } void StackFrameRecognizerManager::AddRecognizer( @@ -191,9 +181,8 @@ void StackFrameRecognizerManager::ForEach( std::function const - &callback) { + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { GetStackFrameRecognizerManagerImpl().ForEach(callback); } diff --git a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py --- a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py +++ b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py @@ -18,9 +18,7 @@ @skipUnlessDarwin def test_frame_recognizer_1(self): self.build() - - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) - self.assertTrue(target, VALID_TARGET) + exe = self.getBuildArtifact("a.out") # Clear internal & plugins recognizers that get initialized at launch self.runCmd("frame recognizer clear") @@ -33,21 +31,21 @@ self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") self.expect("frame recognizer list", - substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo']) + substrs=['0: recognizer.MyFrameRecognizer, module a.out, symbol foo']) self.runCmd("frame recognizer add -l recognizer.MyOtherFrameRecognizer -s a.out -n bar -x") self.expect( "frame recognizer list", substrs=[ - '1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)', - '0: recognizer.MyFrameRecognizer, module a.out, function foo' + '1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)', + '0: recognizer.MyFrameRecognizer, module a.out, symbol foo' ]) self.runCmd("frame recognizer delete 0") self.expect("frame recognizer list", - substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)']) + substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)']) self.runCmd("frame recognizer clear") @@ -56,19 +54,10 @@ self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") - lldbutil.run_break_set_by_symbol(self, "foo") - self.runCmd("r") - - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', 'stop reason = breakpoint']) - - process = target.GetProcess() - thread = process.GetSelectedThread() + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) frame = thread.GetSelectedFrame() - self.assertEqual(frame.GetSymbol().GetName(), "foo") - self.assertFalse(frame.GetLineEntry().IsValid()) - self.expect("frame variable", substrs=['(int) a = 42', '(int) b = 56']) @@ -110,8 +99,9 @@ # FIXME: The following doesn't work yet, but should be fixed. """ - lldbutil.run_break_set_by_symbol(self, "bar") - self.runCmd("c") + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', 'stop reason = breakpoint']) @@ -122,3 +112,35 @@ self.expect("frame variable -t *a", substrs=['*a = 78']) """ + + @skipUnlessDarwin + def test_frame_recognizer_multi_symbol(self): + self.build() + exe = self.getBuildArtifact("a.out") + + # Clear internal & plugins recognizers that get initialized at launch + self.runCmd("frame recognizer clear") + + self.runCmd("command script import " + os.path.join(self.getSourceDir(), "recognizer.py")) + + self.expect("frame recognizer list", + substrs=['no matching results found.']) + + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar") + + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo, symbol bar']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) diff --git a/lldb/test/API/commands/frame/recognizer/main.m b/lldb/test/API/commands/frame/recognizer/main.m --- a/lldb/test/API/commands/frame/recognizer/main.m +++ b/lldb/test/API/commands/frame/recognizer/main.m @@ -5,10 +5,7 @@ printf("%d %d\n", a, b); } -void bar(int *ptr) -{ - printf("%d\n", *ptr); -} +void bar(int *ptr) { printf("%d\n", *ptr); } int main (int argc, const char * argv[]) { diff --git a/lldb/unittests/Target/StackFrameRecognizerTest.cpp b/lldb/unittests/Target/StackFrameRecognizerTest.cpp --- a/lldb/unittests/Target/StackFrameRecognizerTest.cpp +++ b/lldb/unittests/Target/StackFrameRecognizerTest.cpp @@ -76,8 +76,7 @@ bool any_printed = false; StackFrameRecognizerManager::ForEach( [&any_printed](uint32_t recognizer_id, std::string name, - std::string function, std::string symbol, - std::string alternate_symbol, + std::string function, llvm::ArrayRef symbols, bool regexp) { any_printed = true; }); EXPECT_TRUE(any_printed);