Skip to content

Add a new affordance that the Python module in a dSYM #10462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lldb/bindings/python/python-wrapper.swig
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,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) {
Expand Down
22 changes: 22 additions & 0 deletions lldb/bindings/python/static-binding/LLDBWrapPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5895,6 +5895,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) {
Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Interpreter/ScriptInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,8 @@ class ScriptInterpreter : public PluginInterface {
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; }

Expand Down
4 changes: 3 additions & 1 deletion lldb/source/Core/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,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;
}
Expand Down
9 changes: 4 additions & 5 deletions lldb/source/Interpreter/ScriptInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() {
bool ScriptInterpreterLua::LoadScriptingModule(
const char *filename, const LoadScriptOptions &options,
lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
FileSpec extra_search_dir) {
FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {

if (llvm::Error e = m_lua->LoadModule(filename)) {
error = Status::FromErrorStringWithFormatv(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class ScriptInterpreterLua : public ScriptInterpreter {
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;

StructuredData::DictionarySP GetInterpreterInfo() override;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ class SWIGBridge {
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2377,7 +2377,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;

Expand Down Expand Up @@ -2555,6 +2555,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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
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;

Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/macosx/dsym_modules/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
C_SOURCES := main.c
CFLAGS_EXTRAS := -std=c99

include Makefile.rules
63 changes: 63 additions & 0 deletions lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions lldb/test/API/macosx/dsym_modules/has_dsym.py
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions lldb/test/API/macosx/dsym_modules/main.c
Original file line number Diff line number Diff line change
@@ -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;
}
6 changes: 6 additions & 0 deletions lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,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,
Expand Down