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:
Med Ismail Bennani 2023-05-25 13:59:26 -07:00
parent bad4de1ae7
commit 0e90ac9c94
4 changed files with 772 additions and 189 deletions

View File

@ -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",

View File

@ -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()

View File

@ -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(

View File

@ -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."""