diff options
| author | Med Ismail Bennani <ismail@bennani.ma> | 2023-05-23 16:01:39 -0700 |
|---|---|---|
| committer | Med Ismail Bennani <ismail@bennani.ma> | 2023-05-23 16:03:34 -0700 |
| commit | 429e74839506ea8ba962d24647264ed81f680bbf (patch) | |
| tree | 796988295a7998bcd15567d060f4e51653f322ef /lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py | |
| parent | 472913c7ef7456958760cfb2cd5c6bb86323b500 (diff) | |
Revert "[lldb] Move PassthroughScriptedProcess to `lldb.scripted_process` module"
This reverts commit 273a2d337f675f3ee050f281b1fecc3e806b9a3c, since it
might be the cause for `TestStackCoreScriptedProcess` and
`TestInteractiveScriptedProcess` failures on GreenDragon:
https://green.lab.llvm.org/green/job/lldb-cmake/55460/`
Diffstat (limited to 'lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py')
| -rw-r--r-- | lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py | 212 |
1 files changed, 192 insertions, 20 deletions
diff --git a/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py b/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py index 61ba3fc2c7b5..c97909906679 100644 --- a/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py +++ b/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py @@ -12,10 +12,102 @@ from threading import Thread from typing import Any, Dict import lldb -from lldb.plugins.scripted_process import PassthroughScriptedProcess -from lldb.plugins.scripted_process import PassthroughScriptedThread +from lldb.plugins.scripted_process import ScriptedProcess +from lldb.plugins.scripted_process import ScriptedThread -class MultiplexedScriptedProcess(PassthroughScriptedProcess): + +class PassthruScriptedProcess(ScriptedProcess): + driving_target = None + driving_process = None + + def __init__( + self, + exe_ctx: lldb.SBExecutionContext, + args: lldb.SBStructuredData, + launched_driving_process: bool = True, + ): + super().__init__(exe_ctx, args) + + self.driving_target = None + self.driving_process = None + + self.driving_target_idx = args.GetValueForKey("driving_target_idx") + if self.driving_target_idx and self.driving_target_idx.IsValid(): + if self.driving_target_idx.GetType() == lldb.eStructuredDataTypeInteger: + idx = self.driving_target_idx.GetIntegerValue(42) + if self.driving_target_idx.GetType() == lldb.eStructuredDataTypeString: + idx = int(self.driving_target_idx.GetStringValue(100)) + self.driving_target = self.target.GetDebugger().GetTargetAtIndex(idx) + + if launched_driving_process: + self.driving_process = self.driving_target.GetProcess() + for driving_thread in self.driving_process: + structured_data = lldb.SBStructuredData() + structured_data.SetFromJSON( + json.dumps( + { + "driving_target_idx": idx, + "thread_idx": driving_thread.GetIndexID(), + } + ) + ) + + self.threads[driving_thread.GetThreadID()] = PassthruScriptedThread( + self, structured_data + ) + + for module in self.driving_target.modules: + path = module.file.fullpath + load_addr = module.GetObjectFileHeaderAddress().GetLoadAddress( + self.driving_target + ) + self.loaded_images.append({"path": path, "load_addr": load_addr}) + + def get_memory_region_containing_address( + self, addr: int + ) -> lldb.SBMemoryRegionInfo: + mem_region = lldb.SBMemoryRegionInfo() + error = self.driving_process.GetMemoryRegionInfo(addr, mem_region) + if error.Fail(): + return None + return mem_region + + def read_memory_at_address( + self, addr: int, size: int, error: lldb.SBError + ) -> lldb.SBData: + data = lldb.SBData() + bytes_read = self.driving_process.ReadMemory(addr, size, error) + + if error.Fail(): + return data + + data.SetDataWithOwnership( + error, + bytes_read, + self.driving_target.GetByteOrder(), + self.driving_target.GetAddressByteSize(), + ) + + return data + + def write_memory_at_address( + self, addr: int, data: lldb.SBData, error: lldb.SBError + ) -> int: + return self.driving_process.WriteMemory( + addr, bytearray(data.uint8.all()), error + ) + + def get_process_id(self) -> int: + return 42 + + def is_alive(self) -> bool: + return True + + def get_scripted_thread_plugin(self) -> str: + return f"{PassthruScriptedThread.__module__}.{PassthruScriptedThread.__name__}" + + +class MultiplexedScriptedProcess(PassthruScriptedProcess): def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData): super().__init__(exe_ctx, args) self.multiplexer = None @@ -23,11 +115,11 @@ class MultiplexedScriptedProcess(PassthroughScriptedProcess): parity = args.GetValueForKey("parity") # TODO: Change to Walrus operator (:=) with oneline if assignment # Requires python 3.8 - val = parity.GetUnsignedIntegerValue() + val = extract_value_from_structured_data(parity, 0) if val is not None: self.parity = val - # Turn PassthroughScriptedThread into MultiplexedScriptedThread + # Turn PassThruScriptedThread into MultiplexedScriptedThread for thread in self.threads.values(): thread.__class__ = MultiplexedScriptedThread @@ -52,7 +144,7 @@ class MultiplexedScriptedProcess(PassthroughScriptedProcess): if not self.multiplexer: return super().get_threads_info() filtered_threads = self.multiplexer.get_threads_info(pid=self.get_process_id()) - # Update the filtered thread class from PassthroughScriptedThread to MultiplexedScriptedThread + # Update the filtered thread class from PassthruScriptedThread to MultiplexedScriptedThread return dict( map( lambda pair: (pair[0], MultiplexedScriptedThread(pair[1])), @@ -68,13 +160,92 @@ class MultiplexedScriptedProcess(PassthroughScriptedProcess): def get_scripted_thread_plugin(self) -> str: return f"{MultiplexedScriptedThread.__module__}.{MultiplexedScriptedThread.__name__}" -class MultiplexedScriptedThread(PassthroughScriptedThread): + +class PassthruScriptedThread(ScriptedThread): + def __init__(self, process, args): + super().__init__(process, args) + driving_target_idx = args.GetValueForKey("driving_target_idx") + thread_idx = args.GetValueForKey("thread_idx") + + # TODO: Change to Walrus operator (:=) with oneline if assignment + # Requires python 3.8 + val = extract_value_from_structured_data(thread_idx, 0) + if val is not None: + self.idx = val + + self.driving_target = None + self.driving_process = None + self.driving_thread = None + + # TODO: Change to Walrus operator (:=) with oneline if assignment + # Requires python 3.8 + val = extract_value_from_structured_data(driving_target_idx, 42) + if val is not None: + self.driving_target = self.target.GetDebugger().GetTargetAtIndex(val) + self.driving_process = self.driving_target.GetProcess() + self.driving_thread = self.driving_process.GetThreadByIndexID(self.idx) + + if self.driving_thread: + self.id = self.driving_thread.GetThreadID() + + def get_thread_id(self) -> int: + return self.id + + def get_name(self) -> str: + return f"{PassthruScriptedThread.__name__}.thread-{self.idx}" + + def get_stop_reason(self) -> Dict[str, Any]: + stop_reason = {"type": lldb.eStopReasonInvalid, "data": {}} + + if ( + self.driving_thread + and self.driving_thread.IsValid() + and self.get_thread_id() == self.driving_thread.GetThreadID() + ): + stop_reason["type"] = lldb.eStopReasonNone + + if self.driving_thread.GetStopReason() != lldb.eStopReasonNone: + if "arm64" in self.scripted_process.arch: + stop_reason["type"] = lldb.eStopReasonException + stop_reason["data"][ + "desc" + ] = self.driving_thread.GetStopDescription(100) + elif self.scripted_process.arch == "x86_64": + stop_reason["type"] = lldb.eStopReasonSignal + stop_reason["data"]["signal"] = signal.SIGTRAP + else: + stop_reason["type"] = self.driving_thread.GetStopReason() + + return stop_reason + + def get_register_context(self) -> str: + if not self.driving_thread or self.driving_thread.GetNumFrames() == 0: + return None + frame = self.driving_thread.GetFrameAtIndex(0) + + GPRs = None + registerSet = frame.registers # Returns an SBValueList. + for regs in registerSet: + if "general purpose" in regs.name.lower(): + GPRs = regs + break + + if not GPRs: + return None + + for reg in GPRs: + self.register_ctx[reg.name] = int(reg.value, base=16) + + return struct.pack(f"{len(self.register_ctx)}Q", *self.register_ctx.values()) + + +class MultiplexedScriptedThread(PassthruScriptedThread): def get_name(self) -> str: parity = "Odd" if self.scripted_process.parity % 2 else "Even" return f"{parity}{MultiplexedScriptedThread.__name__}.thread-{self.idx}" -class MultiplexerScriptedProcess(PassthroughScriptedProcess): +class MultiplexerScriptedProcess(PassthruScriptedProcess): listener = None multiplexed_processes = None @@ -83,9 +254,9 @@ class MultiplexerScriptedProcess(PassthroughScriptedProcess): # Update multiplexer process log("Updating interactive scripted process threads") dbg = self.driving_target.GetDebugger() - new_driving_thread_ids = [] + log("Clearing interactive scripted process threads") + self.threads.clear() for driving_thread in self.driving_process: - new_driving_thread_ids.append(driving_thread.id) log(f"{len(self.threads)} New thread {hex(driving_thread.id)}") structured_data = lldb.SBStructuredData() structured_data.SetFromJSON( @@ -99,17 +270,10 @@ class MultiplexerScriptedProcess(PassthroughScriptedProcess): ) ) - self.threads[driving_thread.id] = PassthroughScriptedThread( + self.threads[driving_thread.GetThreadID()] = PassthruScriptedThread( self, structured_data ) - for thread_id in self.threads: - if thread_id not in new_driving_thread_ids: - log(f"Removing old thread {hex(thread_id)}") - del self.threads[thread_id] - - print(f"New thread count: {len(self.threads)}") - mux_process = self.target.GetProcess() mux_process.ForceScriptedState(lldb.eStateRunning) mux_process.ForceScriptedState(lldb.eStateStopped) @@ -120,8 +284,6 @@ class MultiplexerScriptedProcess(PassthroughScriptedProcess): event = lldb.SBEvent() while True: - if not self.driving_process: - continue if self.listener.WaitForEvent(1, event): event_mask = event.GetType() if event_mask & lldb.SBProcess.eBroadcastBitStateChanged: @@ -312,6 +474,16 @@ def duplicate_target(driving_target): debugger = driving_target.GetDebugger() return debugger.CreateTargetWithFileAndTargetTriple(exe, triple) + +def extract_value_from_structured_data(data, default_val): + if data and data.IsValid(): + if data.GetType() == lldb.eStructuredDataTypeInteger: + return data.GetIntegerValue(default_val) + if data.GetType() == lldb.eStructuredDataTypeString: + return int(data.GetStringValue(100)) + return default_val + + def create_mux_process(debugger, command, exe_ctx, result, dict): if not debugger.GetNumTargets() > 0: return result.SetError( |
