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