mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-21 20:46:49 +00:00
Add a new affordance that the Python module in a dSYM (#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.
This commit is contained in:
parent
ec290a43f6
commit
347c5a7af5
lldb
bindings/python
include/lldb/Interpreter
source
Core
Interpreter
Plugins/ScriptInterpreter/Python
test/API/macosx/dsym_modules
unittests/ScriptInterpreter/Python
@ -966,6 +966,28 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
|
||||
const char *python_module_name, const char *session_dictionary_name,
|
||||
lldb::TargetSP target_sp) {
|
||||
std::string python_function_name_string = python_module_name;
|
||||
python_function_name_string += ".__lldb_module_added_to_target";
|
||||
const char *python_function_name = python_function_name_string.c_str();
|
||||
|
||||
PyErr_Cleaner py_err_cleaner(true);
|
||||
|
||||
auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
|
||||
session_dictionary_name);
|
||||
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
|
||||
python_function_name, dict);
|
||||
|
||||
if (!pfunc.IsAllocated())
|
||||
return true;
|
||||
|
||||
pfunc(SWIGBridge::ToSWIGWrapper(std::move(target_sp)), dict);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
|
||||
const char *python_module_name, const char *session_dictionary_name,
|
||||
lldb::DebuggerSP debugger) {
|
||||
|
@ -522,7 +522,8 @@ public:
|
||||
LoadScriptingModule(const char *filename, const LoadScriptOptions &options,
|
||||
lldb_private::Status &error,
|
||||
StructuredData::ObjectSP *module_sp = nullptr,
|
||||
FileSpec extra_search_dir = {});
|
||||
FileSpec extra_search_dir = {},
|
||||
lldb::TargetSP loaded_into_target_sp = {});
|
||||
|
||||
virtual bool IsReservedWord(const char *word) { return false; }
|
||||
|
||||
|
@ -1485,7 +1485,9 @@ bool Module::LoadScriptingResourceInTarget(Target *target, Status &error,
|
||||
scripting_fspec.Dump(scripting_stream.AsRawOstream());
|
||||
LoadScriptOptions options;
|
||||
bool did_load = script_interpreter->LoadScriptingModule(
|
||||
scripting_stream.GetData(), options, error);
|
||||
scripting_stream.GetData(), options, error,
|
||||
/*module_sp*/ nullptr, /*extra_path*/ {},
|
||||
target->shared_from_this());
|
||||
if (!did_load)
|
||||
return false;
|
||||
}
|
||||
|
@ -48,11 +48,10 @@ StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ScriptInterpreter::LoadScriptingModule(const char *filename,
|
||||
const LoadScriptOptions &options,
|
||||
lldb_private::Status &error,
|
||||
StructuredData::ObjectSP *module_sp,
|
||||
FileSpec extra_search_dir) {
|
||||
bool ScriptInterpreter::LoadScriptingModule(
|
||||
const char *filename, const LoadScriptOptions &options,
|
||||
lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
|
||||
FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
|
||||
error = Status::FromErrorString(
|
||||
"This script interpreter does not support importing modules.");
|
||||
return false;
|
||||
|
@ -215,6 +215,11 @@ public:
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP debugger);
|
||||
|
||||
static bool
|
||||
LLDBSwigPythonCallModuleNewTarget(const char *python_module_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::TargetSP target);
|
||||
|
||||
static python::PythonObject
|
||||
LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
|
@ -2316,7 +2316,7 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
|
||||
bool ScriptInterpreterPythonImpl::LoadScriptingModule(
|
||||
const char *pathname, const LoadScriptOptions &options,
|
||||
lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
|
||||
FileSpec extra_search_dir) {
|
||||
FileSpec extra_search_dir, lldb::TargetSP target_sp) {
|
||||
namespace fs = llvm::sys::fs;
|
||||
namespace path = llvm::sys::path;
|
||||
|
||||
@ -2495,6 +2495,12 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
|
||||
PyRefType::Owned, static_cast<PyObject *>(module_pyobj)));
|
||||
}
|
||||
|
||||
// Finally, if we got a target passed in, then we should tell the new module
|
||||
// about this target:
|
||||
if (target_sp)
|
||||
return SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
|
||||
module_name.c_str(), m_dictionary_name.c_str(), target_sp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,8 @@ public:
|
||||
const LoadScriptOptions &options,
|
||||
lldb_private::Status &error,
|
||||
StructuredData::ObjectSP *module_sp = nullptr,
|
||||
FileSpec extra_search_dir = {}) override;
|
||||
FileSpec extra_search_dir = {},
|
||||
lldb::TargetSP loaded_into_target_sp = {}) override;
|
||||
|
||||
bool IsReservedWord(const char *word) override;
|
||||
|
||||
|
4
lldb/test/API/macosx/dsym_modules/Makefile
Normal file
4
lldb/test/API/macosx/dsym_modules/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
C_SOURCES := main.c
|
||||
CFLAGS_EXTRAS := -std=c99
|
||||
|
||||
include Makefile.rules
|
63
lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
Normal file
63
lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
Normal file
@ -0,0 +1,63 @@
|
||||
"""
|
||||
Test that we read in the Python module from a dSYM, and run the
|
||||
init in debugger and the init in target routines.
|
||||
"""
|
||||
|
||||
import os, shutil
|
||||
|
||||
import lldb
|
||||
import lldbsuite.test.lldbutil as lldbutil
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test.decorators import *
|
||||
|
||||
|
||||
@skipUnlessDarwin
|
||||
class TestdSYMModuleInit(TestBase):
|
||||
@no_debug_info_test
|
||||
def test_add_module(self):
|
||||
"""This loads a file into a target and ensures that the python module was
|
||||
correctly added and the two intialization functions are called."""
|
||||
self.exe_name = "has_dsym"
|
||||
self.py_name = self.exe_name + ".py"
|
||||
|
||||
# Now load the target the first time into the debugger:
|
||||
self.runCmd("settings set target.load-script-from-symbol-file true")
|
||||
self.interp = self.dbg.GetCommandInterpreter()
|
||||
|
||||
executable = self.build_dsym(self.exe_name + "_1")
|
||||
target = self.createTestTarget(file_path=executable)
|
||||
self.check_answers(executable, ["1", "1", "has_dsym_1"])
|
||||
|
||||
# Now make a second target and make sure both get called:
|
||||
executable_2 = self.build_dsym(self.exe_name + "_2")
|
||||
target_2 = self.createTestTarget(file_path=executable_2)
|
||||
self.check_answers(executable_2, ["2", "2", "has_dsym_2"])
|
||||
|
||||
def check_answers(self, name, answers):
|
||||
result = lldb.SBCommandReturnObject()
|
||||
self.interp.HandleCommand("report_command", result)
|
||||
self.assertTrue(
|
||||
result.Succeeded(), f"report_command succeeded {result.GetError()}"
|
||||
)
|
||||
|
||||
cmd_results = result.GetOutput().split()
|
||||
self.assertEqual(answers[0], cmd_results[0], "Right number of module imports")
|
||||
self.assertEqual(answers[1], cmd_results[1], "Right number of target notices")
|
||||
self.assertIn(answers[2], name, "Right target name")
|
||||
|
||||
def build_dsym(self, name):
|
||||
self.build(debug_info="dsym", dictionary={"EXE": name})
|
||||
executable = self.getBuildArtifact(name)
|
||||
dsym_path = self.getBuildArtifact(name + ".dSYM")
|
||||
python_dir_path = dsym_path
|
||||
python_dir_path = os.path.join(dsym_path, "Contents", "Resources", "Python")
|
||||
if not os.path.exists(python_dir_path):
|
||||
os.mkdir(python_dir_path)
|
||||
|
||||
python_file_name = name + ".py"
|
||||
|
||||
module_dest_path = os.path.join(python_dir_path, python_file_name)
|
||||
module_origin_path = os.path.join(self.getSourceDir(), self.py_name)
|
||||
shutil.copy(module_origin_path, module_dest_path)
|
||||
|
||||
return executable
|
28
lldb/test/API/macosx/dsym_modules/has_dsym.py
Normal file
28
lldb/test/API/macosx/dsym_modules/has_dsym.py
Normal file
@ -0,0 +1,28 @@
|
||||
import lldb
|
||||
|
||||
|
||||
def report_command(debugger, command, exe_ctx, result, internal_dict):
|
||||
result.AppendMessage(
|
||||
f'{lldb.num_module_inits} {lldb.num_target_inits} "{lldb.target_name}"'
|
||||
)
|
||||
result.SetStatus(lldb.eReturnStatusSuccessFinishResult)
|
||||
|
||||
|
||||
def __lldb_init_module(debugger, internal_dict):
|
||||
# We only want to make one copy of the report command so it will be shared
|
||||
if "has_dsym_1" in __name__:
|
||||
# lldb is a convenient place to store our counters.
|
||||
lldb.num_module_inits = 0
|
||||
lldb.num_target_inits = 0
|
||||
lldb.target_name = "<unknown>"
|
||||
|
||||
debugger.HandleCommand(
|
||||
f"command script add -o -f '{__name__}.report_command' report_command"
|
||||
)
|
||||
|
||||
lldb.num_module_inits += 1
|
||||
|
||||
|
||||
def __lldb_module_added_to_target(target, internal_dict):
|
||||
lldb.num_target_inits += 1
|
||||
target_name = target.executable.fullpath
|
9
lldb/test/API/macosx/dsym_modules/main.c
Normal file
9
lldb/test/API/macosx/dsym_modules/main.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int global_test_var = 10;
|
||||
|
||||
int main() {
|
||||
int test_var = 10;
|
||||
printf("Set a breakpoint here: %d.\n", test_var);
|
||||
return global_test_var;
|
||||
}
|
@ -230,6 +230,12 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleNewTarget(
|
||||
const char *python_module_name, const char *session_dictionary_name,
|
||||
lldb::TargetSP target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
python::PythonObject
|
||||
lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin(
|
||||
const char *python_class_name, const char *session_dictionary_name,
|
||||
|
Loading…
x
Reference in New Issue
Block a user