149 changes: 78 additions & 71 deletions lldb/examples/python/scripted_process/scripted_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ def __init__(self, target, args):
"""
self.target = None
self.args = None
self.arch = None
if isinstance(target, lldb.SBTarget) and target.IsValid():
self.target = target
triple = self.target.triple
if triple:
self.arch = triple.split('-')[0]
if isinstance(args, lldb.SBStructuredData) and args.IsValid():
self.args = args

Expand Down Expand Up @@ -201,19 +205,21 @@ class ScriptedThread:
"""

@abstractmethod
def __init__(self, process, args):
def __init__(self, scripted_process, args):
""" Construct a scripted thread.
Args:
process (lldb.SBProcess): The scripted process owning this thread.
process (ScriptedProcess): The scripted process owning this thread.
args (lldb.SBStructuredData): A Dictionary holding arbitrary
key/value pairs used by the scripted thread.
"""
self.target = None
self.scripted_process = None
self.process = None
self.args = None
if isinstance(process, ScriptedProcess):
self.target = process.target
if isinstance(scripted_process, ScriptedProcess):
self.target = scripted_process.target
self.scripted_process = scripted_process
self.process = self.target.GetProcess()

self.id = None
Expand Down Expand Up @@ -302,73 +308,13 @@ def __init__(idx, cfa, pc, symbol_ctx):
def get_register_info(self):
if self.register_info is None:
self.register_info = dict()
triple = self.target.triple
if triple:
arch = triple.split('-')[0]
if arch == 'x86_64':
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},
{'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}
]
elif 'arm64' in arch:
self.register_info['sets'] = ['General Purpose Registers']
self.register_info['registers'] = [
{'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}
]
else: raise ValueError('Unknown architecture', arch)
if self.scripted_process.arch == 'x86_64':
self.register_info['sets'] = ['General Purpose Registers']
self.register_info['registers'] = INTEL64_GPR
elif 'arm64' in self.scripted_process.arch:
self.register_info['sets'] = ['General Purpose Registers']
self.register_info['registers'] = ARM64_GPR
else: raise ValueError('Unknown architecture', self.scripted_process.arch)
return self.register_info

@abstractmethod
Expand All @@ -379,3 +325,64 @@ def get_register_context(self):
str: A byte representing all register's value.
"""
pass

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}
]


Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Test python scripted process in lldb
"""

import os, json, tempfile
import os

import lldb
from lldbsuite.test.decorators import *
Expand All @@ -12,6 +12,8 @@

class ScriptedProcesTestCase(TestBase):

NO_DEBUG_INFO_TESTCASE = True

mydir = TestBase.compute_mydir(__file__)

def setUp(self):
Expand Down Expand Up @@ -131,74 +133,3 @@ def cleanup():
break
self.assertEqual(idx, int(reg.value, 16))

def create_stack_skinny_corefile(self, file):
self.build()
target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
lldb.SBFileSpec("main.cpp"))
self.assertTrue(process.IsValid(), "Process is invalid.")
# FIXME: Use SBAPI to save the process corefile.
self.runCmd("process save-core -s stack " + file)
self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")

@skipUnlessDarwin
@skipIf(archs=no_match(['arm64', 'arm64e']))
@skipIfOutOfTreeDebugserver
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."""
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.assertTrue(target, VALID_TARGET)

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

os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
def cleanup():
del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
self.addTearDownHook(cleanup)

scripted_process_example_relpath = 'stack_core_scripted_process.py'
self.runCmd("command script import " + os.path.join(self.getSourceDir(),
scripted_process_example_relpath))

corefile_process = None
with tempfile.NamedTemporaryFile() as file:
self.create_stack_skinny_corefile(file.name)
corefile_target = self.dbg.CreateTarget(None)
corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
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(), 3)
thread = process.GetThreadAtIndex(2)
self.assertTrue(thread, "Invalid thread.")
self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")

self.assertEqual(thread.GetNumFrames(), 6)
frame = thread.GetSelectedFrame()
self.assertTrue(frame, "Invalid frame.")
self.assertIn("bar", frame.GetFunctionName())
self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Test python scripted process in lldb
"""

import os, json, tempfile

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test import lldbtest

class StackCoreScriptedProcesTestCase(TestBase):

NO_DEBUG_INFO_TESTCASE = True

mydir = TestBase.compute_mydir(__file__)

def setUp(self):
TestBase.setUp(self)

def tearDown(self):
TestBase.tearDown(self)

def create_stack_skinny_corefile(self, file):
self.build()
target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
lldb.SBFileSpec("main.cpp"))
self.assertTrue(process.IsValid(), "Process is invalid.")
# FIXME: Use SBAPI to save the process corefile.
self.runCmd("process save-core -s stack " + file)
self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")

@skipUnlessDarwin
@skipIfOutOfTreeDebugserver
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."""
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.assertTrue(target, VALID_TARGET)

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

os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
def cleanup():
del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
self.addTearDownHook(cleanup)

scripted_process_example_relpath = 'stack_core_scripted_process.py'
self.runCmd("command script import " + os.path.join(self.getSourceDir(),
scripted_process_example_relpath))

corefile_process = None
with tempfile.NamedTemporaryFile() as file:
self.create_stack_skinny_corefile(file.name)
corefile_target = self.dbg.CreateTarget(None)
corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
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(), 3)
thread = process.GetSelectedThread()
self.assertTrue(thread, "Invalid thread.")
self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")

self.assertTrue(target.triple, "Invalid target triple")
arch = target.triple.split('-')[0]
supported_arch = ['x86_64', 'arm64', 'arm64e']
self.assertIn(arch, supported_arch)
# When creating a corefile of a arm process, lldb saves the exception
# that triggers the breakpoint in the LC_NOTES of the corefile, so they
# can be reloaded with the corefile on the next debug session.
if arch in 'arm64e':
self.assertTrue(thread.GetStopReason(), lldb.eStopReasonException)
# However, it's architecture specific, and corefiles made from intel
# process don't save any metadata to retrieve to stop reason.
# To mitigate this, the StackCoreScriptedProcess will report a
# eStopReasonSignal with a SIGTRAP, mimicking what debugserver does.
else:
self.assertTrue(thread.GetStopReason(), lldb.eStopReasonSignal)

self.assertEqual(thread.GetNumFrames(), 6)
frame = thread.GetSelectedFrame()
self.assertTrue(frame, "Invalid frame.")
self.assertIn("bar", frame.GetFunctionName())
self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_state(self) -> int:

def get_stop_reason(self) -> Dict[str, Any]:
return { "type": lldb.eStopReasonSignal, "data": {
"signal": signal.SIGINT
"signal": signal.SIGTRAP
} }

def get_stackframes(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):

self.threads[corefile_thread.GetThreadID()] = StackCoreScriptedThread(self, structured_data)

if len(self.threads) == 3:
self.threads[len(self.threads) - 1].is_stopped = True

def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
mem_region = lldb.SBMemoryRegionInfo()
error = self.corefile_process.GetMemoryRegionInfo(addr, mem_region)
Expand Down Expand Up @@ -80,6 +83,7 @@ def __init__(self, process, args):
super().__init__(process, args)
backing_target_idx = args.GetValueForKey("backing_target_idx")
thread_idx = args.GetValueForKey("thread_idx")
self.is_stopped = False

def extract_value_from_structured_data(data, default_val):
if data and data.IsValid():
Expand Down Expand Up @@ -119,17 +123,19 @@ def get_name(self) -> str:
def get_stop_reason(self) -> Dict[str, Any]:
stop_reason = { "type": lldb.eStopReasonInvalid, "data": { }}

if self.corefile_thread and self.corefile_thread.IsValid:
stop_reason["type"] = self.corefile_thread.GetStopReason()
if self.corefile_thread and self.corefile_thread.IsValid() \
and self.get_thread_id() == self.corefile_thread.GetThreadID():
stop_reason["type"] = lldb.eStopReasonNone

if self.corefile_thread.GetStopReasonDataCount() > 0:
if stop_reason["type"] == lldb.eStopReasonBreakpoint:
stop_reason["data"]["break_id"] = self.corefile_thread.GetStopReasonDataAtIndex(0)
stop_reason["data"]["break_loc_id"] = self.corefile_thread.GetStopReasonDataAtIndex(1)
elif stop_reason["type"] == lldb.eStopReasonSignal:
stop_reason["data"]["signal"] = signal.SIGINT
elif stop_reason["type"] == lldb.eStopReasonException:
if self.is_stopped:
if 'arm64' in self.scripted_process.arch:
stop_reason["type"] = lldb.eStopReasonException
stop_reason["data"]["desc"] = self.corefile_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.corefile_thread.GetStopReason()

return stop_reason

Expand Down