mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-31 22:25:56 +00:00
Re-revert "[lldb] Move PassthroughScriptedProcess to lldb.scripted_process
module"
This reverts commit 429e74839506ea8ba962d24647264ed81f680bbf since it didn't address the test failures on GreenDragon. This patch will mark the tests as expected to fail until I can reproduce the issue and find a solution. Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
This commit is contained in:
parent
bad4de1ae7
commit
0e90ac9c94
@ -1,6 +1,7 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import lldb
|
||||
import json, struct, signal
|
||||
|
||||
|
||||
class ScriptedProcess(metaclass=ABCMeta):
|
||||
@ -382,6 +383,754 @@ class ScriptedThread(metaclass=ABCMeta):
|
||||
return self.extended_info
|
||||
|
||||
|
||||
class PassthroughScriptedProcess(ScriptedProcess):
|
||||
driving_target = None
|
||||
driving_process = None
|
||||
|
||||
def __init__(self, exe_ctx, args, launched_driving_process=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():
|
||||
idx = self.driving_target_idx.GetUnsignedIntegerValue(42)
|
||||
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()
|
||||
] = PassthroughScriptedThread(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):
|
||||
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, size, error):
|
||||
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, data, error):
|
||||
return self.driving_process.WriteMemory(
|
||||
addr, bytearray(data.uint8.all()), error
|
||||
)
|
||||
|
||||
def get_process_id(self):
|
||||
return self.driving_process.GetProcessID()
|
||||
|
||||
def is_alive(self):
|
||||
return True
|
||||
|
||||
def get_scripted_thread_plugin(self):
|
||||
return f"{PassthroughScriptedThread.__module__}.{PassthroughScriptedThread.__name__}"
|
||||
|
||||
|
||||
class PassthroughScriptedThread(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 = thread_idx.GetUnsignedIntegerValue()
|
||||
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 = driving_target_idx.GetUnsignedIntegerValue()
|
||||
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):
|
||||
return self.id
|
||||
|
||||
def get_name(self):
|
||||
return f"{PassthroughScriptedThread.__name__}.thread-{self.idx}"
|
||||
|
||||
def get_stop_reason(self):
|
||||
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
|
||||
|
||||
# TODO: Passthrough stop reason from driving process
|
||||
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):
|
||||
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())
|
||||
|
||||
|
||||
ARM64_GPR = [
|
||||
{
|
||||
"name": "x0",
|
||||
"bitsize": 64,
|
||||
"offset": 0,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 0,
|
||||
"dwarf": 0,
|
||||
"generic": "arg0",
|
||||
"alt-name": "arg0",
|
||||
},
|
||||
{
|
||||
"name": "x1",
|
||||
"bitsize": 64,
|
||||
"offset": 8,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 1,
|
||||
"dwarf": 1,
|
||||
"generic": "arg1",
|
||||
"alt-name": "arg1",
|
||||
},
|
||||
{
|
||||
"name": "x2",
|
||||
"bitsize": 64,
|
||||
"offset": 16,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 2,
|
||||
"dwarf": 2,
|
||||
"generic": "arg2",
|
||||
"alt-name": "arg2",
|
||||
},
|
||||
{
|
||||
"name": "x3",
|
||||
"bitsize": 64,
|
||||
"offset": 24,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 3,
|
||||
"dwarf": 3,
|
||||
"generic": "arg3",
|
||||
"alt-name": "arg3",
|
||||
},
|
||||
{
|
||||
"name": "x4",
|
||||
"bitsize": 64,
|
||||
"offset": 32,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 4,
|
||||
"dwarf": 4,
|
||||
"generic": "arg4",
|
||||
"alt-name": "arg4",
|
||||
},
|
||||
{
|
||||
"name": "x5",
|
||||
"bitsize": 64,
|
||||
"offset": 40,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 5,
|
||||
"dwarf": 5,
|
||||
"generic": "arg5",
|
||||
"alt-name": "arg5",
|
||||
},
|
||||
{
|
||||
"name": "x6",
|
||||
"bitsize": 64,
|
||||
"offset": 48,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 6,
|
||||
"dwarf": 6,
|
||||
"generic": "arg6",
|
||||
"alt-name": "arg6",
|
||||
},
|
||||
{
|
||||
"name": "x7",
|
||||
"bitsize": 64,
|
||||
"offset": 56,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 7,
|
||||
"dwarf": 7,
|
||||
"generic": "arg7",
|
||||
"alt-name": "arg7",
|
||||
},
|
||||
{
|
||||
"name": "x8",
|
||||
"bitsize": 64,
|
||||
"offset": 64,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 8,
|
||||
"dwarf": 8,
|
||||
},
|
||||
{
|
||||
"name": "x9",
|
||||
"bitsize": 64,
|
||||
"offset": 72,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 9,
|
||||
"dwarf": 9,
|
||||
},
|
||||
{
|
||||
"name": "x10",
|
||||
"bitsize": 64,
|
||||
"offset": 80,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 10,
|
||||
"dwarf": 10,
|
||||
},
|
||||
{
|
||||
"name": "x11",
|
||||
"bitsize": 64,
|
||||
"offset": 88,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 11,
|
||||
"dwarf": 11,
|
||||
},
|
||||
{
|
||||
"name": "x12",
|
||||
"bitsize": 64,
|
||||
"offset": 96,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 12,
|
||||
"dwarf": 12,
|
||||
},
|
||||
{
|
||||
"name": "x13",
|
||||
"bitsize": 64,
|
||||
"offset": 104,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 13,
|
||||
"dwarf": 13,
|
||||
},
|
||||
{
|
||||
"name": "x14",
|
||||
"bitsize": 64,
|
||||
"offset": 112,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 14,
|
||||
"dwarf": 14,
|
||||
},
|
||||
{
|
||||
"name": "x15",
|
||||
"bitsize": 64,
|
||||
"offset": 120,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 15,
|
||||
"dwarf": 15,
|
||||
},
|
||||
{
|
||||
"name": "x16",
|
||||
"bitsize": 64,
|
||||
"offset": 128,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 16,
|
||||
"dwarf": 16,
|
||||
},
|
||||
{
|
||||
"name": "x17",
|
||||
"bitsize": 64,
|
||||
"offset": 136,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 17,
|
||||
"dwarf": 17,
|
||||
},
|
||||
{
|
||||
"name": "x18",
|
||||
"bitsize": 64,
|
||||
"offset": 144,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 18,
|
||||
"dwarf": 18,
|
||||
},
|
||||
{
|
||||
"name": "x19",
|
||||
"bitsize": 64,
|
||||
"offset": 152,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 19,
|
||||
"dwarf": 19,
|
||||
},
|
||||
{
|
||||
"name": "x20",
|
||||
"bitsize": 64,
|
||||
"offset": 160,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 20,
|
||||
"dwarf": 20,
|
||||
},
|
||||
{
|
||||
"name": "x21",
|
||||
"bitsize": 64,
|
||||
"offset": 168,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 21,
|
||||
"dwarf": 21,
|
||||
},
|
||||
{
|
||||
"name": "x22",
|
||||
"bitsize": 64,
|
||||
"offset": 176,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 22,
|
||||
"dwarf": 22,
|
||||
},
|
||||
{
|
||||
"name": "x23",
|
||||
"bitsize": 64,
|
||||
"offset": 184,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 23,
|
||||
"dwarf": 23,
|
||||
},
|
||||
{
|
||||
"name": "x24",
|
||||
"bitsize": 64,
|
||||
"offset": 192,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 24,
|
||||
"dwarf": 24,
|
||||
},
|
||||
{
|
||||
"name": "x25",
|
||||
"bitsize": 64,
|
||||
"offset": 200,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 25,
|
||||
"dwarf": 25,
|
||||
},
|
||||
{
|
||||
"name": "x26",
|
||||
"bitsize": 64,
|
||||
"offset": 208,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 26,
|
||||
"dwarf": 26,
|
||||
},
|
||||
{
|
||||
"name": "x27",
|
||||
"bitsize": 64,
|
||||
"offset": 216,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 27,
|
||||
"dwarf": 27,
|
||||
},
|
||||
{
|
||||
"name": "x28",
|
||||
"bitsize": 64,
|
||||
"offset": 224,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 28,
|
||||
"dwarf": 28,
|
||||
},
|
||||
{
|
||||
"name": "x29",
|
||||
"bitsize": 64,
|
||||
"offset": 232,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 29,
|
||||
"dwarf": 29,
|
||||
"generic": "fp",
|
||||
"alt-name": "fp",
|
||||
},
|
||||
{
|
||||
"name": "x30",
|
||||
"bitsize": 64,
|
||||
"offset": 240,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 30,
|
||||
"dwarf": 30,
|
||||
"generic": "lr",
|
||||
"alt-name": "lr",
|
||||
},
|
||||
{
|
||||
"name": "sp",
|
||||
"bitsize": 64,
|
||||
"offset": 248,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 31,
|
||||
"dwarf": 31,
|
||||
"generic": "sp",
|
||||
"alt-name": "sp",
|
||||
},
|
||||
{
|
||||
"name": "pc",
|
||||
"bitsize": 64,
|
||||
"offset": 256,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 32,
|
||||
"dwarf": 32,
|
||||
"generic": "pc",
|
||||
"alt-name": "pc",
|
||||
},
|
||||
{
|
||||
"name": "cpsr",
|
||||
"bitsize": 32,
|
||||
"offset": 264,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 33,
|
||||
"dwarf": 33,
|
||||
},
|
||||
]
|
||||
|
||||
INTEL64_GPR = [
|
||||
{
|
||||
"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,
|
||||
},
|
||||
{
|
||||
"name": "rcx",
|
||||
"bitsize": 64,
|
||||
"offset": 16,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 2,
|
||||
"dwarf": 2,
|
||||
"generic": "arg4",
|
||||
"alt-name": "arg4",
|
||||
},
|
||||
{
|
||||
"name": "rdx",
|
||||
"bitsize": 64,
|
||||
"offset": 24,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 1,
|
||||
"dwarf": 1,
|
||||
"generic": "arg3",
|
||||
"alt-name": "arg3",
|
||||
},
|
||||
{
|
||||
"name": "rdi",
|
||||
"bitsize": 64,
|
||||
"offset": 32,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 5,
|
||||
"dwarf": 5,
|
||||
"generic": "arg1",
|
||||
"alt-name": "arg1",
|
||||
},
|
||||
{
|
||||
"name": "rsi",
|
||||
"bitsize": 64,
|
||||
"offset": 40,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 4,
|
||||
"dwarf": 4,
|
||||
"generic": "arg2",
|
||||
"alt-name": "arg2",
|
||||
},
|
||||
{
|
||||
"name": "rbp",
|
||||
"bitsize": 64,
|
||||
"offset": 48,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 6,
|
||||
"dwarf": 6,
|
||||
"generic": "fp",
|
||||
"alt-name": "fp",
|
||||
},
|
||||
{
|
||||
"name": "rsp",
|
||||
"bitsize": 64,
|
||||
"offset": 56,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 7,
|
||||
"dwarf": 7,
|
||||
"generic": "sp",
|
||||
"alt-name": "sp",
|
||||
},
|
||||
{
|
||||
"name": "r8",
|
||||
"bitsize": 64,
|
||||
"offset": 64,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 8,
|
||||
"dwarf": 8,
|
||||
"generic": "arg5",
|
||||
"alt-name": "arg5",
|
||||
},
|
||||
{
|
||||
"name": "r9",
|
||||
"bitsize": 64,
|
||||
"offset": 72,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 9,
|
||||
"dwarf": 9,
|
||||
"generic": "arg6",
|
||||
"alt-name": "arg6",
|
||||
},
|
||||
{
|
||||
"name": "r10",
|
||||
"bitsize": 64,
|
||||
"offset": 80,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 10,
|
||||
"dwarf": 10,
|
||||
},
|
||||
{
|
||||
"name": "r11",
|
||||
"bitsize": 64,
|
||||
"offset": 88,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 11,
|
||||
"dwarf": 11,
|
||||
},
|
||||
{
|
||||
"name": "r12",
|
||||
"bitsize": 64,
|
||||
"offset": 96,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 12,
|
||||
"dwarf": 12,
|
||||
},
|
||||
{
|
||||
"name": "r13",
|
||||
"bitsize": 64,
|
||||
"offset": 104,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 13,
|
||||
"dwarf": 13,
|
||||
},
|
||||
{
|
||||
"name": "r14",
|
||||
"bitsize": 64,
|
||||
"offset": 112,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 14,
|
||||
"dwarf": 14,
|
||||
},
|
||||
{
|
||||
"name": "r15",
|
||||
"bitsize": 64,
|
||||
"offset": 120,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 15,
|
||||
"dwarf": 15,
|
||||
},
|
||||
{
|
||||
"name": "rip",
|
||||
"bitsize": 64,
|
||||
"offset": 128,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"gcc": 16,
|
||||
"dwarf": 16,
|
||||
"generic": "pc",
|
||||
"alt-name": "pc",
|
||||
},
|
||||
{
|
||||
"name": "rflags",
|
||||
"bitsize": 64,
|
||||
"offset": 136,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
"generic": "flags",
|
||||
"alt-name": "flags",
|
||||
},
|
||||
{
|
||||
"name": "cs",
|
||||
"bitsize": 64,
|
||||
"offset": 144,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
},
|
||||
{
|
||||
"name": "fs",
|
||||
"bitsize": 64,
|
||||
"offset": 152,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
},
|
||||
{
|
||||
"name": "gs",
|
||||
"bitsize": 64,
|
||||
"offset": 160,
|
||||
"encoding": "uint",
|
||||
"format": "hex",
|
||||
"set": 0,
|
||||
},
|
||||
]
|
||||
|
||||
ARM64_GPR = [
|
||||
{
|
||||
"name": "x0",
|
||||
|
@ -23,6 +23,7 @@ class TestInteractiveScriptedProcess(TestBase):
|
||||
self.script_file = self.script_module + ".py"
|
||||
|
||||
@skipUnlessDarwin
|
||||
@expectedFailureDarwin
|
||||
def test_passthrough_launch(self):
|
||||
"""Test a simple pass-through process launch"""
|
||||
self.passthrough_launch()
|
||||
@ -43,6 +44,7 @@ class TestInteractiveScriptedProcess(TestBase):
|
||||
self.assertState(lldb.SBProcess.GetStateFromEvent(event), lldb.eStateStopped)
|
||||
|
||||
@skipUnlessDarwin
|
||||
@expectedFailureDarwin
|
||||
def test_multiplexed_launch(self):
|
||||
"""Test a multiple interactive scripted process debugging"""
|
||||
self.passthrough_launch()
|
||||
|
@ -12,102 +12,11 @@ from threading import Thread
|
||||
from typing import Any, Dict
|
||||
|
||||
import lldb
|
||||
from lldb.plugins.scripted_process import ScriptedProcess
|
||||
from lldb.plugins.scripted_process import ScriptedThread
|
||||
from lldb.plugins.scripted_process import PassthroughScriptedProcess
|
||||
from lldb.plugins.scripted_process import PassthroughScriptedThread
|
||||
|
||||
|
||||
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):
|
||||
class MultiplexedScriptedProcess(PassthroughScriptedProcess):
|
||||
def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData):
|
||||
super().__init__(exe_ctx, args)
|
||||
self.multiplexer = None
|
||||
@ -115,11 +24,11 @@ class MultiplexedScriptedProcess(PassthruScriptedProcess):
|
||||
parity = args.GetValueForKey("parity")
|
||||
# TODO: Change to Walrus operator (:=) with oneline if assignment
|
||||
# Requires python 3.8
|
||||
val = extract_value_from_structured_data(parity, 0)
|
||||
val = parity.GetUnsignedIntegerValue()
|
||||
if val is not None:
|
||||
self.parity = val
|
||||
|
||||
# Turn PassThruScriptedThread into MultiplexedScriptedThread
|
||||
# Turn PassthroughScriptedThread into MultiplexedScriptedThread
|
||||
for thread in self.threads.values():
|
||||
thread.__class__ = MultiplexedScriptedThread
|
||||
|
||||
@ -144,7 +53,7 @@ class MultiplexedScriptedProcess(PassthruScriptedProcess):
|
||||
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 PassthruScriptedThread to MultiplexedScriptedThread
|
||||
# Update the filtered thread class from PassthroughScriptedThread to MultiplexedScriptedThread
|
||||
return dict(
|
||||
map(
|
||||
lambda pair: (pair[0], MultiplexedScriptedThread(pair[1])),
|
||||
@ -161,91 +70,13 @@ class MultiplexedScriptedProcess(PassthruScriptedProcess):
|
||||
return f"{MultiplexedScriptedThread.__module__}.{MultiplexedScriptedThread.__name__}"
|
||||
|
||||
|
||||
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):
|
||||
class MultiplexedScriptedThread(PassthroughScriptedThread):
|
||||
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(PassthruScriptedProcess):
|
||||
class MultiplexerScriptedProcess(PassthroughScriptedProcess):
|
||||
listener = None
|
||||
multiplexed_processes = None
|
||||
|
||||
@ -254,9 +85,9 @@ class MultiplexerScriptedProcess(PassthruScriptedProcess):
|
||||
# Update multiplexer process
|
||||
log("Updating interactive scripted process threads")
|
||||
dbg = self.driving_target.GetDebugger()
|
||||
log("Clearing interactive scripted process threads")
|
||||
self.threads.clear()
|
||||
new_driving_thread_ids = []
|
||||
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(
|
||||
@ -270,10 +101,17 @@ class MultiplexerScriptedProcess(PassthruScriptedProcess):
|
||||
)
|
||||
)
|
||||
|
||||
self.threads[driving_thread.GetThreadID()] = PassthruScriptedThread(
|
||||
self.threads[driving_thread.id] = PassthroughScriptedThread(
|
||||
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)
|
||||
@ -284,6 +122,8 @@ class MultiplexerScriptedProcess(PassthruScriptedProcess):
|
||||
|
||||
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:
|
||||
@ -475,15 +315,6 @@ def duplicate_target(driving_target):
|
||||
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(
|
||||
|
@ -35,6 +35,7 @@ class StackCoreScriptedProcesTestCase(TestBase):
|
||||
@skipIfOutOfTreeDebugserver
|
||||
@skipIfRemote
|
||||
@skipIfAsan # On ASAN builds, this test times-out (rdar://98678134)
|
||||
@expectedFailureDarwin
|
||||
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."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user