1from abc import ABCMeta, abstractmethod 2import six 3 4import lldb 5 6@six.add_metaclass(ABCMeta) 7class ScriptedProcess: 8 9 """ 10 The base class for a scripted process. 11 12 Most of the base class methods are `@abstractmethod` that need to be 13 overwritten by the inheriting class. 14 15 DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. 16 THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. 17 """ 18 19 memory_regions = None 20 stack_memory_dump = None 21 loaded_images = None 22 23 @abstractmethod 24 def __init__(self, target, args): 25 """ Construct a scripted process. 26 27 Args: 28 target (lldb.SBTarget): The target launching the scripted process. 29 args (lldb.SBStructuredData): A Dictionary holding arbitrary 30 key/value pairs used by the scripted process. 31 """ 32 self.target = None 33 self.args = None 34 if isinstance(target, lldb.SBTarget) and target.IsValid(): 35 self.target = target 36 if isinstance(args, lldb.SBStructuredData) and args.IsValid(): 37 self.args = args 38 39 @abstractmethod 40 def get_memory_region_containing_address(self, addr): 41 """ Get the memory region for the scripted process, containing a 42 specific address. 43 44 Args: 45 addr (int): Address to look for in the scripted process memory 46 regions. 47 48 Returns: 49 lldb.SBMemoryRegionInfo: The memory region containing the address. 50 None if out of bounds. 51 """ 52 pass 53 54 @abstractmethod 55 def get_thread_with_id(self, tid): 56 """ Get the scripted process thread with a specific ID. 57 58 Args: 59 tid (int): Thread ID to look for in the scripted process. 60 61 Returns: 62 Dict: The thread represented as a dictionary, withr the 63 tid thread ID. None if tid doesn't match any of the scripted 64 process threads. 65 """ 66 pass 67 68 @abstractmethod 69 def get_registers_for_thread(self, tid): 70 """ Get the register context dictionary for a certain thread of 71 the scripted process. 72 73 Args: 74 tid (int): Thread ID for the thread's register context. 75 76 Returns: 77 Dict: The register context represented as a dictionary, for the 78 tid thread. None if tid doesn't match any of the scripted 79 process threads. 80 """ 81 pass 82 83 @abstractmethod 84 def read_memory_at_address(self, addr, size): 85 """ Get a memory buffer from the scripted process at a certain address, 86 of a certain size. 87 88 Args: 89 addr (int): Address from which we should start reading. 90 size (int): Size of the memory to read. 91 92 Returns: 93 lldb.SBData: An `lldb.SBData` buffer with the target byte size and 94 byte order storing the memory read. 95 """ 96 pass 97 98 def get_loaded_images(self): 99 """ Get the list of loaded images for the scripted process. 100 101 ``` 102 class ScriptedProcessImage: 103 def __init__(name, file_spec, uuid, load_address): 104 self.name = name 105 self.file_spec = file_spec 106 self.uuid = uuid 107 self.load_address = load_address 108 ``` 109 110 Returns: 111 List[ScriptedProcessImage]: A list of `ScriptedProcessImage` 112 containing for each entry, the name of the library, a UUID, 113 an `lldb.SBFileSpec` and a load address. 114 None if the list is empty. 115 """ 116 return self.loaded_images 117 118 def get_process_id(self): 119 """ Get the scripted process identifier. 120 121 Returns: 122 int: The scripted process identifier. 123 """ 124 return 0 125 126 127 def launch(self): 128 """ Simulate the scripted process launch. 129 130 Returns: 131 lldb.SBError: An `lldb.SBError` with error code 0. 132 """ 133 return lldb.SBError() 134 135 def resume(self): 136 """ Simulate the scripted process resume. 137 138 Returns: 139 lldb.SBError: An `lldb.SBError` with error code 0. 140 """ 141 return lldb.SBError() 142 143 @abstractmethod 144 def should_stop(self): 145 """ Check if the scripted process plugin should produce the stop event. 146 147 Returns: 148 bool: True if scripted process should broadcast a stop event. 149 False otherwise. 150 """ 151 pass 152 153 def stop(self): 154 """ Trigger the scripted process stop. 155 156 Returns: 157 lldb.SBError: An `lldb.SBError` with error code 0. 158 """ 159 return lldb.SBError() 160 161 @abstractmethod 162 def is_alive(self): 163 """ Check if the scripted process is alive. 164 165 Returns: 166 bool: True if scripted process is alive. False otherwise. 167 """ 168 pass 169 170 @abstractmethod 171 def get_scripted_thread_plugin(self): 172 """ Get scripted thread plugin name. 173 174 Returns: 175 str: Name of the scripted thread plugin. 176 """ 177 return None 178 179@six.add_metaclass(ABCMeta) 180class ScriptedThread: 181 182 """ 183 The base class for a scripted thread. 184 185 Most of the base class methods are `@abstractmethod` that need to be 186 overwritten by the inheriting class. 187 188 DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. 189 THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. 190 """ 191 192 @abstractmethod 193 def __init__(self, process, args): 194 """ Construct a scripted thread. 195 196 Args: 197 process (lldb.SBProcess): The scripted process owning this thread. 198 args (lldb.SBStructuredData): A Dictionary holding arbitrary 199 key/value pairs used by the scripted thread. 200 """ 201 self.target = None 202 self.process = None 203 self.args = None 204 if isinstance(process, lldb.SBProcess) and process.IsValid(): 205 self.process = process 206 self.target = process.GetTarget() 207 208 self.id = None 209 self.name = None 210 self.queue = None 211 self.state = None 212 self.stop_reason = None 213 self.register_info = None 214 self.register_ctx = {} 215 self.frames = [] 216 217 @abstractmethod 218 def get_thread_id(self): 219 """ Get the scripted thread identifier. 220 221 Returns: 222 int: The identifier of the scripted thread. 223 """ 224 pass 225 226 @abstractmethod 227 def get_name(self): 228 """ Get the scripted thread name. 229 230 Returns: 231 str: The name of the scripted thread. 232 """ 233 pass 234 235 def get_state(self): 236 """ Get the scripted thread state type. 237 238 eStateStopped, ///< Process or thread is stopped and can be examined. 239 eStateRunning, ///< Process or thread is running and can't be examined. 240 eStateStepping, ///< Process or thread is in the process of stepping and can 241 /// not be examined. 242 243 Returns: 244 int: The state type of the scripted thread. 245 Returns lldb.eStateStopped by default. 246 """ 247 return lldb.eStateStopped 248 249 def get_queue(self): 250 """ Get the scripted thread associated queue name. 251 This method is optional. 252 253 Returns: 254 str: The queue name associated with the scripted thread. 255 """ 256 pass 257 258 @abstractmethod 259 def get_stop_reason(self): 260 """ Get the dictionary describing the stop reason type with some data. 261 This method is optional. 262 263 Returns: 264 Dict: The dictionary holding the stop reason type and the possibly 265 the stop reason data. 266 """ 267 pass 268 269 def get_stackframes(self): 270 """ Get the list of stack frames for the scripted thread. 271 272 ``` 273 class ScriptedStackFrame: 274 def __init__(idx, cfa, pc, symbol_ctx): 275 self.idx = idx 276 self.cfa = cfa 277 self.pc = pc 278 self.symbol_ctx = symbol_ctx 279 ``` 280 281 Returns: 282 List[ScriptedFrame]: A list of `ScriptedStackFrame` 283 containing for each entry, the frame index, the canonical 284 frame address, the program counter value for that frame 285 and a symbol context. 286 None if the list is empty. 287 """ 288 return 0 289 290 def get_register_info(self): 291 if self.register_info is None: 292 self.register_info = dict() 293 triple = self.target.triple 294 if triple: 295 arch = triple.split('-')[0] 296 if arch == 'x86_64': 297 self.register_info['sets'] = ['General Purpose Registers'] 298 self.register_info['registers'] = [ 299 {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0}, 300 {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3}, 301 {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4'}, 302 {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3'}, 303 {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1'}, 304 {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2'}, 305 {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp'}, 306 {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp'}, 307 {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5'}, 308 {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6'}, 309 {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10}, 310 {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11}, 311 {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12}, 312 {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13}, 313 {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14}, 314 {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15}, 315 {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'}, 316 {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'}, 317 {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0}, 318 {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0}, 319 {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0} 320 ] 321 elif 'arm64' in arch: 322 self.register_info['sets'] = ['General Purpose Registers'] 323 self.register_info['registers'] = [ 324 {'name': 'x0', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0, 'generic': 'arg0', 'alt-name': 'arg0'}, 325 {'name': 'x1', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg1', 'alt-name': 'arg1'}, 326 {'name': 'x2', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg2', 'alt-name': 'arg2'}, 327 {'name': 'x3', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3, 'generic': 'arg3', 'alt-name': 'arg3'}, 328 {'name': 'x4', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg4', 'alt-name': 'arg4'}, 329 {'name': 'x5', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg5', 'alt-name': 'arg5'}, 330 {'name': 'x6', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'arg6', 'alt-name': 'arg6'}, 331 {'name': 'x7', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'arg7', 'alt-name': 'arg7'}, 332 {'name': 'x8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8 }, 333 {'name': 'x9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9 }, 334 {'name': 'x10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10}, 335 {'name': 'x11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11}, 336 {'name': 'x12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12}, 337 {'name': 'x13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13}, 338 {'name': 'x14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14}, 339 {'name': 'x15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15}, 340 {'name': 'x16', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16}, 341 {'name': 'x17', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 17, 'dwarf': 17}, 342 {'name': 'x18', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 18, 'dwarf': 18}, 343 {'name': 'x19', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 19, 'dwarf': 19}, 344 {'name': 'x20', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 20, 'dwarf': 20}, 345 {'name': 'x21', 'bitsize': 64, 'offset': 168, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 21, 'dwarf': 21}, 346 {'name': 'x22', 'bitsize': 64, 'offset': 176, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 22, 'dwarf': 22}, 347 {'name': 'x23', 'bitsize': 64, 'offset': 184, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 23, 'dwarf': 23}, 348 {'name': 'x24', 'bitsize': 64, 'offset': 192, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 24, 'dwarf': 24}, 349 {'name': 'x25', 'bitsize': 64, 'offset': 200, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 25, 'dwarf': 25}, 350 {'name': 'x26', 'bitsize': 64, 'offset': 208, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 26, 'dwarf': 26}, 351 {'name': 'x27', 'bitsize': 64, 'offset': 216, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 27, 'dwarf': 27}, 352 {'name': 'x28', 'bitsize': 64, 'offset': 224, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 28, 'dwarf': 28}, 353 {'name': 'x29', 'bitsize': 64, 'offset': 232, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 29, 'dwarf': 29, 'generic': 'fp', 'alt-name': 'fp'}, 354 {'name': 'x30', 'bitsize': 64, 'offset': 240, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 30, 'dwarf': 30, 'generic': 'lr', 'alt-name': 'lr'}, 355 {'name': 'sp', 'bitsize': 64, 'offset': 248, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 31, 'dwarf': 31, 'generic': 'sp', 'alt-name': 'sp'}, 356 {'name': 'pc', 'bitsize': 64, 'offset': 256, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 32, 'dwarf': 32, 'generic': 'pc', 'alt-name': 'pc'}, 357 {'name': 'cpsr', 'bitsize': 32, 'offset': 264, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 33, 'dwarf': 33} 358 ] 359 else: raise ValueError('Unknown architecture', arch) 360 return self.register_info 361 362 @abstractmethod 363 def get_register_context(self): 364 """ Get the scripted thread register context 365 366 Returns: 367 str: A byte representing all register's value. 368 """ 369 pass 370