mib created this revision. mib added a reviewer: JDevlieghere. mib added a project: LLDB. mib requested review of this revision. Herald added a subscriber: lldb-commits.
This patch changes the ScriptedProcess test to use a stack-only skinny corefile as a backing store. The corefile is saved as a temporary file at the beginning of the test, and a second target is created for the ScriptedProcess. To do so, we use the SBAPI from the ScriptedProcess' python script to interact with the corefile process. This patch also makes some small adjustments to the other ScriptedProcess scripts to resolve some inconsistencies and removes the raw memory dump that was previously checked in. Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112047 Files: lldb/examples/python/scripted_process/main.stack-dump lldb/examples/python/scripted_process/my_scripted_process.py lldb/examples/python/scripted_process/scripted_process.py lldb/examples/python/scripted_process/stack_core_scripted_process.py lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
Index: lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py =================================================================== --- lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py +++ lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py @@ -2,7 +2,7 @@ Test python scripted process in lldb """ -import os +import os, json, tempfile import lldb from lldbsuite.test.decorators import * @@ -10,14 +10,15 @@ from lldbsuite.test import lldbutil from lldbsuite.test import lldbtest - class ScriptedProcesTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) def setUp(self): TestBase.setUp(self) - self.source = "main.c" + self.scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process'] + self.scripted_process_example_abspath = os.path.join(self.getSourceDir(), + *self.scripted_process_example_relpath) def tearDown(self): TestBase.tearDown(self) @@ -89,8 +90,19 @@ for idx, reg in enumerate(registers, start=1): self.assertEqual(idx, int(reg.value, 16)) - @skipIfDarwin - @skipUnlessDarwin + def create_stack_skinny_corefile(self): + self.build() + target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + self.assertTrue(process.IsValid(), "Process is invalid.") + # FIXME: Use SBAPI to save the process corefile. + stack_core = tempfile.NamedTemporaryFile() + self.runCmd("process save-core -s stack " + stack_core.name) + self.assertTrue(os.path.exists(stack_core.name), "No stack-only corefile found.") + self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target") + print(stack_core.name) + target = self.dbg.CreateTarget(None) + return target.LoadCore(self.getBuildArtifact(stack_core.name)) + def test_launch_scripted_process_stack_frames(self): """Test that we can launch an lldb scripted process from the command line, check its process ID and read string from memory.""" @@ -101,24 +113,38 @@ for module in target.modules: if 'a.out' in module.GetFileSpec().GetFilename(): main_module = module + break self.assertTrue(main_module, "Invalid main module.") error = target.SetModuleLoadAddress(main_module, 0) self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.") - scripted_process_example_relpath = ['..','..','..','..','examples','python','scripted_process','my_scripted_process.py'] - self.runCmd("command script import " + os.path.join(self.getSourceDir(), - *scripted_process_example_relpath)) + os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' + self.runCmd("command script import " + os.path.join(self.scripted_process_example_abspath, + "stack_core_scripted_process.py")) - process = target.GetProcess() + corefile_process = self.create_stack_skinny_corefile() + self.assertTrue(corefile_process, PROCESS_IS_VALID) + + structured_data = lldb.SBStructuredData() + structured_data.SetFromJSON(json.dumps({ + "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget()) + })) + launch_info = lldb.SBLaunchInfo(None) + launch_info.SetProcessPluginName("ScriptedProcess") + launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess") + launch_info.SetScriptedProcessDictionary(structured_data) + + error = lldb.SBError() + process = target.Launch(launch_info, error) + self.assertTrue(error.Success(), error.GetCString()) self.assertTrue(process, PROCESS_IS_VALID) self.assertEqual(process.GetProcessID(), 42) - self.assertEqual(process.GetNumThreads(), 1) + self.assertEqual(process.GetNumThreads(), 1) thread = process.GetSelectedThread() self.assertTrue(thread, "Invalid thread.") - self.assertEqual(thread.GetThreadID(), 0x19) - self.assertEqual(thread.GetName(), "MyScriptedThread.thread-1") + self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1") self.assertEqual(thread.GetNumFrames(), 4) frame = thread.GetSelectedFrame() Index: lldb/examples/python/scripted_process/stack_core_scripted_process.py =================================================================== --- /dev/null +++ lldb/examples/python/scripted_process/stack_core_scripted_process.py @@ -0,0 +1,129 @@ +import os,struct,signal + +from typing import Any, Dict + +import lldb +from lldb.plugins.scripted_process import ScriptedProcess +from lldb.plugins.scripted_process import ScriptedThread + +class StackCoreScriptedProcess(ScriptedProcess): + def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): + super().__init__(target, args) + + self.backing_target_idx = args.GetValueForKey("backing_target_idx") + + self.corefile_target = None + self.corefile_process = None + if (self.backing_target_idx and self.backing_target_idx.IsValid()): + if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeInteger: + idx = self.backing_target_idx.GetIntegerValue(42) + if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString: + idx = int(self.backing_target_idx.GetStringValue(100)) + self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx) + self.corefile_process = self.corefile_target.GetProcess() + + def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: + mem_region = lldb.SBMemoryRegionInfo() + error = self.corefile_process.GetMemoryRegionInfo(addr, mem_region) + if error.Fail(): + return None + return mem_region + + def get_thread_with_id(self, tid: int): + return {} + + def get_registers_for_thread(self, tid: int): + return {} + + def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData: + error = lldb.SBError() + data = self.corefile_process.ReadMemory(addr, size, error) + if error.Fail(): + return None + return data + + def get_loaded_images(self): + # TODO: Iterate over corefile_target modules and build a data structure + # from it. + return self.loaded_images + + def get_process_id(self) -> int: + return 42 + + def should_stop(self) -> bool: + return True + + def is_alive(self) -> bool: + return True + + def get_scripted_thread_plugin(self): + return StackCoreScriptedThread.__module__ + "." + StackCoreScriptedThread.__name__ + + +class StackCoreScriptedThread(ScriptedThread): + def __init__(self, process, args): + super().__init__(process, args) + import pdb + pdb.set_trace() + self.backing_target_idx = args.GetValueForKey("backing_target_idx") + + self.corefile_target = None + self.corefile_process = None + if (self.backing_target_idx and self.backing_target_idx.IsValid()): + if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeInteger: + idx = self.backing_target_idx.GetIntegerValue(42) + if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString: + idx = int(self.backing_target_idx.GetStringValue(100)) + self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(idx) + self.corefile_process = self.corefile_target.GetProcess() + + def get_thread_id(self) -> int: + return 0x19 + + def get_name(self) -> str: + return StackCoreScriptedThread.__name__ + ".thread-1" + + def get_stop_reason(self) -> Dict[str, Any]: + return { "type": lldb.eStopReasonSignal, "data": { + "signal": signal.SIGINT + } } + + def get_stackframes(self): + class ScriptedStackFrame: + def __init__(idx, cfa, pc, symbol_ctx): + self.idx = idx + self.cfa = cfa + self.pc = pc + self.symbol_ctx = symbol_ctx + + + symbol_ctx = lldb.SBSymbolContext() + frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx) + self.frames.append(frame_zero) + + return self.frame_zero[0:0] + + def get_register_context(self) -> str: + thread = self.corefile_process.GetSelectedThread() + if not thread or thread.GetNumFrames() == 0: + return None + frame = thread.GetFrameAtIndex(0) + GPRs = lldbutil.get_GPRs(frame) + + if not GPRs: + return None + + for reg in GPRs: + self.register_ctx[reg.name] = int(reg.value, base=16) + + return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values()) + + +def __lldb_init_module(debugger, dict): + if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ: + debugger.HandleCommand( + "process launch -C %s.%s" % (__name__, + StackCoreScriptedProcess.__name__)) + else: + print("Name of the class that will manage the scripted process: '%s.%s'" + % (__name__, StackCoreScriptedProcess.__name__)) Index: lldb/examples/python/scripted_process/scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/scripted_process.py +++ lldb/examples/python/scripted_process/scripted_process.py @@ -210,7 +210,7 @@ self.state = None self.stop_reason = None self.register_info = None - self.register_ctx = [] + self.register_ctx = {} self.frames = [] @abstractmethod @@ -293,7 +293,7 @@ if triple: arch = triple.split('-')[0] if arch == 'x86_64': - self.register_info['sets'] = ['GPR', 'FPU', 'EXC'] + self.register_info['sets'] = ['General Purpose Registers'] self.register_info['registers'] = [ {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0}, {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3}, Index: lldb/examples/python/scripted_process/my_scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/my_scripted_process.py +++ lldb/examples/python/scripted_process/my_scripted_process.py @@ -115,7 +115,7 @@ class MyScriptedThread(ScriptedThread): - registers = { + register_ctx = { "rax":0x00000000000006e4, "rbx":0x00000001040b6060, "rcx":0x00000001040b2e00, @@ -169,7 +169,7 @@ return self.frame_zero[0:0] def get_register_context(self) -> str: - return struct.pack("{}Q".format(len(self.registers)), *self.registers.values()) + return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values()) def __lldb_init_module(debugger, dict):
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits