summaryrefslogtreecommitdiff
path: root/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
diff options
context:
space:
mode:
authorMed Ismail Bennani <ismail@bennani.ma>2023-05-23 16:01:39 -0700
committerMed Ismail Bennani <ismail@bennani.ma>2023-05-23 16:03:34 -0700
commit429e74839506ea8ba962d24647264ed81f680bbf (patch)
tree796988295a7998bcd15567d060f4e51653f322ef /lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
parent472913c7ef7456958760cfb2cd5c6bb86323b500 (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.py212
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(