Skip to content

Commit 81ef0b9

Browse files
committed
Add a new affordance that the Python module in a dSYM (llvm#133290)
So the dSYM can be told what target it has been loaded into. When lldb is loading modules, while creating a target, it will run "command script import" on any Python modules in Resources/Python in the dSYM. However, this happens WHILE the target is being created, so it is not yet in the target list. That means that these scripts can't act on the target that they a part of when they get loaded. This patch adds a new python API that lldb will call: __lldb_module_added_to_target if it is defined in the module, passing in the Target the module was being added to, so that code in these dSYM's don't have to guess. (cherry picked from commit 347c5a7)
1 parent d5a9c5f commit 81ef0b9

File tree

12 files changed

+155
-9
lines changed

12 files changed

+155
-9
lines changed

lldb/bindings/python/python-wrapper.swig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,28 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue(
10511051
return true;
10521052
}
10531053

1054+
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
1055+
const char *python_module_name, const char *session_dictionary_name,
1056+
lldb::TargetSP target_sp) {
1057+
std::string python_function_name_string = python_module_name;
1058+
python_function_name_string += ".__lldb_module_added_to_target";
1059+
const char *python_function_name = python_function_name_string.c_str();
1060+
1061+
PyErr_Cleaner py_err_cleaner(true);
1062+
1063+
auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
1064+
session_dictionary_name);
1065+
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
1066+
python_function_name, dict);
1067+
1068+
if (!pfunc.IsAllocated())
1069+
return true;
1070+
1071+
pfunc(SWIGBridge::ToSWIGWrapper(std::move(target_sp)), dict);
1072+
1073+
return true;
1074+
}
1075+
10541076
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
10551077
const char *python_module_name, const char *session_dictionary_name,
10561078
lldb::DebuggerSP debugger) {

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ class ScriptInterpreter : public PluginInterface {
539539
LoadScriptingModule(const char *filename, const LoadScriptOptions &options,
540540
lldb_private::Status &error,
541541
StructuredData::ObjectSP *module_sp = nullptr,
542-
FileSpec extra_search_dir = {});
542+
FileSpec extra_search_dir = {},
543+
lldb::TargetSP loaded_into_target_sp = {});
543544

544545
virtual bool IsReservedWord(const char *word) { return false; }
545546

lldb/source/Core/Module.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1624,7 +1624,9 @@ bool Module::LoadScriptingResourceInTarget(Target *target, Status &error,
16241624
scripting_fspec.Dump(scripting_stream.AsRawOstream());
16251625
LoadScriptOptions options;
16261626
bool did_load = script_interpreter->LoadScriptingModule(
1627-
scripting_stream.GetData(), options, error);
1627+
scripting_stream.GetData(), options, error,
1628+
/*module_sp*/ nullptr, /*extra_path*/ {},
1629+
target->shared_from_this());
16281630
if (!did_load)
16291631
return false;
16301632
}

lldb/source/Interpreter/ScriptInterpreter.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
4848
return nullptr;
4949
}
5050

51-
bool ScriptInterpreter::LoadScriptingModule(const char *filename,
52-
const LoadScriptOptions &options,
53-
lldb_private::Status &error,
54-
StructuredData::ObjectSP *module_sp,
55-
FileSpec extra_search_dir) {
51+
bool ScriptInterpreter::LoadScriptingModule(
52+
const char *filename, const LoadScriptOptions &options,
53+
lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
54+
FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
5655
error = Status::FromErrorString(
5756
"This script interpreter does not support importing modules.");
5857
return false;

lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ class SWIGBridge {
224224
const char *session_dictionary_name,
225225
lldb::DebuggerSP debugger);
226226

227+
static bool
228+
LLDBSwigPythonCallModuleNewTarget(const char *python_module_name,
229+
const char *session_dictionary_name,
230+
lldb::TargetSP target);
231+
227232
static python::PythonObject
228233
LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
229234
const char *session_dictionary_name,

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2377,7 +2377,7 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
23772377
bool ScriptInterpreterPythonImpl::LoadScriptingModule(
23782378
const char *pathname, const LoadScriptOptions &options,
23792379
lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
2380-
FileSpec extra_search_dir) {
2380+
FileSpec extra_search_dir, lldb::TargetSP target_sp) {
23812381
namespace fs = llvm::sys::fs;
23822382
namespace path = llvm::sys::path;
23832383

@@ -2555,6 +2555,12 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
25552555
PyRefType::Owned, static_cast<PyObject *>(module_pyobj)));
25562556
}
25572557

2558+
// Finally, if we got a target passed in, then we should tell the new module
2559+
// about this target:
2560+
if (target_sp)
2561+
return SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
2562+
module_name.c_str(), m_dictionary_name.c_str(), target_sp);
2563+
25582564
return true;
25592565
}
25602566

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
252252
const LoadScriptOptions &options,
253253
lldb_private::Status &error,
254254
StructuredData::ObjectSP *module_sp = nullptr,
255-
FileSpec extra_search_dir = {}) override;
255+
FileSpec extra_search_dir = {},
256+
lldb::TargetSP loaded_into_target_sp = {}) override;
256257

257258
bool IsReservedWord(const char *word) override;
258259

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
Test that we read in the Python module from a dSYM, and run the
3+
init in debugger and the init in target routines.
4+
"""
5+
6+
import os, shutil
7+
8+
import lldb
9+
import lldbsuite.test.lldbutil as lldbutil
10+
from lldbsuite.test.lldbtest import *
11+
from lldbsuite.test.decorators import *
12+
13+
14+
@skipUnlessDarwin
15+
class TestdSYMModuleInit(TestBase):
16+
@no_debug_info_test
17+
def test_add_module(self):
18+
"""This loads a file into a target and ensures that the python module was
19+
correctly added and the two intialization functions are called."""
20+
self.exe_name = "has_dsym"
21+
self.py_name = self.exe_name + ".py"
22+
23+
# Now load the target the first time into the debugger:
24+
self.runCmd("settings set target.load-script-from-symbol-file true")
25+
self.interp = self.dbg.GetCommandInterpreter()
26+
27+
executable = self.build_dsym(self.exe_name + "_1")
28+
target = self.createTestTarget(file_path=executable)
29+
self.check_answers(executable, ["1", "1", "has_dsym_1"])
30+
31+
# Now make a second target and make sure both get called:
32+
executable_2 = self.build_dsym(self.exe_name + "_2")
33+
target_2 = self.createTestTarget(file_path=executable_2)
34+
self.check_answers(executable_2, ["2", "2", "has_dsym_2"])
35+
36+
def check_answers(self, name, answers):
37+
result = lldb.SBCommandReturnObject()
38+
self.interp.HandleCommand("report_command", result)
39+
self.assertTrue(
40+
result.Succeeded(), f"report_command succeeded {result.GetError()}"
41+
)
42+
43+
cmd_results = result.GetOutput().split()
44+
self.assertEqual(answers[0], cmd_results[0], "Right number of module imports")
45+
self.assertEqual(answers[1], cmd_results[1], "Right number of target notices")
46+
self.assertIn(answers[2], name, "Right target name")
47+
48+
def build_dsym(self, name):
49+
self.build(debug_info="dsym", dictionary={"EXE": name})
50+
executable = self.getBuildArtifact(name)
51+
dsym_path = self.getBuildArtifact(name + ".dSYM")
52+
python_dir_path = dsym_path
53+
python_dir_path = os.path.join(dsym_path, "Contents", "Resources", "Python")
54+
if not os.path.exists(python_dir_path):
55+
os.mkdir(python_dir_path)
56+
57+
python_file_name = name + ".py"
58+
59+
module_dest_path = os.path.join(python_dir_path, python_file_name)
60+
module_origin_path = os.path.join(self.getSourceDir(), self.py_name)
61+
shutil.copy(module_origin_path, module_dest_path)
62+
63+
return executable
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import lldb
2+
3+
4+
def report_command(debugger, command, exe_ctx, result, internal_dict):
5+
result.AppendMessage(
6+
f'{lldb.num_module_inits} {lldb.num_target_inits} "{lldb.target_name}"'
7+
)
8+
result.SetStatus(lldb.eReturnStatusSuccessFinishResult)
9+
10+
11+
def __lldb_init_module(debugger, internal_dict):
12+
# We only want to make one copy of the report command so it will be shared
13+
if "has_dsym_1" in __name__:
14+
# lldb is a convenient place to store our counters.
15+
lldb.num_module_inits = 0
16+
lldb.num_target_inits = 0
17+
lldb.target_name = "<unknown>"
18+
19+
debugger.HandleCommand(
20+
f"command script add -o -f '{__name__}.report_command' report_command"
21+
)
22+
23+
lldb.num_module_inits += 1
24+
25+
26+
def __lldb_module_added_to_target(target, internal_dict):
27+
lldb.num_target_inits += 1
28+
target_name = target.executable.fullpath
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdio.h>
2+
3+
int global_test_var = 10;
4+
5+
int main() {
6+
int test_var = 10;
7+
printf("Set a breakpoint here: %d.\n", test_var);
8+
return global_test_var;
9+
}

lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
225225
return false;
226226
}
227227

228+
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
229+
const char *python_module_name, const char *session_dictionary_name,
230+
lldb::TargetSP target) {
231+
return false;
232+
}
233+
228234
python::PythonObject
229235
lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin(
230236
const char *python_class_name, const char *session_dictionary_name,

0 commit comments

Comments
 (0)