1#!/usr/bin/env python 2 3import lldb 4import struct 5 6 7class OperatingSystemPlugIn(object): 8 """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class""" 9 10 def __init__(self, process): 11 """Initialization needs a valid.SBProcess object. 12 13 This plug-in will get created after a live process is valid and has stopped for the 14 first time.""" 15 self.process = None 16 self.registers = None 17 self.threads = None 18 if isinstance(process, lldb.SBProcess) and process.IsValid(): 19 self.process = process 20 self.threads = None # Will be an dictionary containing info for each thread 21 22 def get_target(self): 23 # NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target" 24 # tracks the current target in the LLDB command interpreter which isn't the 25 # correct thing to use for this plug-in. 26 return self.process.target 27 28 def create_thread(self, tid, context): 29 if tid == 0x444444444: 30 thread_info = { 31 "tid": tid, 32 "name": "four", 33 "queue": "queue4", 34 "state": "stopped", 35 "stop_reason": "none", 36 } 37 self.threads.append(thread_info) 38 return thread_info 39 return None 40 41 def get_thread_info(self): 42 if not self.threads: 43 # The sample dictionary below shows the values that can be returned for a thread 44 # tid => thread ID (mandatory) 45 # name => thread name (optional key/value pair) 46 # queue => thread dispatch queue name (optional key/value pair) 47 # state => thred state (mandatory, set to 'stopped' for now) 48 # stop_reason => thread stop reason. (mandatory, usually set to 'none') 49 # Possible values include: 50 # 'breakpoint' if the thread is stopped at a breakpoint 51 # 'none' thread is just stopped because the process is stopped 52 # 'trace' the thread just single stepped 53 # The usual value for this while threads are in memory is 'none' 54 # register_data_addr => the address of the register data in memory (optional key/value pair) 55 # Specifying this key/value pair for a thread will avoid a call to get_register_data() 56 # and can be used when your registers are in a thread context structure that is contiguous 57 # in memory. Don't specify this if your register layout in memory doesn't match the layout 58 # described by the dictionary returned from a call to the 59 # get_register_info() method. 60 self.threads = [ 61 { 62 "tid": 0x111111111, 63 "name": "one", 64 "queue": "queue1", 65 "state": "stopped", 66 "stop_reason": "breakpoint", 67 }, 68 { 69 "tid": 0x222222222, 70 "name": "two", 71 "queue": "queue2", 72 "state": "stopped", 73 "stop_reason": "none", 74 }, 75 { 76 "tid": 0x333333333, 77 "name": "three", 78 "queue": "queue3", 79 "state": "stopped", 80 "stop_reason": "trace", 81 "register_data_addr": 0x100000000, 82 }, 83 ] 84 return self.threads 85 86 def get_register_info(self): 87 if self.registers is None: 88 self.registers = dict() 89 triple = self.process.target.triple 90 if triple: 91 arch = triple.split("-")[0] 92 if arch == "x86_64": 93 self.registers["sets"] = ["GPR", "FPU", "EXC"] 94 self.registers["registers"] = [ 95 { 96 "name": "rax", 97 "bitsize": 64, 98 "offset": 0, 99 "encoding": "uint", 100 "format": "hex", 101 "set": 0, 102 "gcc": 0, 103 "dwarf": 0, 104 }, 105 { 106 "name": "rbx", 107 "bitsize": 64, 108 "offset": 8, 109 "encoding": "uint", 110 "format": "hex", 111 "set": 0, 112 "gcc": 3, 113 "dwarf": 3, 114 }, 115 { 116 "name": "rcx", 117 "bitsize": 64, 118 "offset": 16, 119 "encoding": "uint", 120 "format": "hex", 121 "set": 0, 122 "gcc": 2, 123 "dwarf": 2, 124 "generic": "arg4", 125 "alt-name": "arg4", 126 }, 127 { 128 "name": "rdx", 129 "bitsize": 64, 130 "offset": 24, 131 "encoding": "uint", 132 "format": "hex", 133 "set": 0, 134 "gcc": 1, 135 "dwarf": 1, 136 "generic": "arg3", 137 "alt-name": "arg3", 138 }, 139 { 140 "name": "rdi", 141 "bitsize": 64, 142 "offset": 32, 143 "encoding": "uint", 144 "format": "hex", 145 "set": 0, 146 "gcc": 5, 147 "dwarf": 5, 148 "generic": "arg1", 149 "alt-name": "arg1", 150 }, 151 { 152 "name": "rsi", 153 "bitsize": 64, 154 "offset": 40, 155 "encoding": "uint", 156 "format": "hex", 157 "set": 0, 158 "gcc": 4, 159 "dwarf": 4, 160 "generic": "arg2", 161 "alt-name": "arg2", 162 }, 163 { 164 "name": "rbp", 165 "bitsize": 64, 166 "offset": 48, 167 "encoding": "uint", 168 "format": "hex", 169 "set": 0, 170 "gcc": 6, 171 "dwarf": 6, 172 "generic": "fp", 173 "alt-name": "fp", 174 }, 175 { 176 "name": "rsp", 177 "bitsize": 64, 178 "offset": 56, 179 "encoding": "uint", 180 "format": "hex", 181 "set": 0, 182 "gcc": 7, 183 "dwarf": 7, 184 "generic": "sp", 185 "alt-name": "sp", 186 }, 187 { 188 "name": "r8", 189 "bitsize": 64, 190 "offset": 64, 191 "encoding": "uint", 192 "format": "hex", 193 "set": 0, 194 "gcc": 8, 195 "dwarf": 8, 196 "generic": "arg5", 197 "alt-name": "arg5", 198 }, 199 { 200 "name": "r9", 201 "bitsize": 64, 202 "offset": 72, 203 "encoding": "uint", 204 "format": "hex", 205 "set": 0, 206 "gcc": 9, 207 "dwarf": 9, 208 "generic": "arg6", 209 "alt-name": "arg6", 210 }, 211 { 212 "name": "r10", 213 "bitsize": 64, 214 "offset": 80, 215 "encoding": "uint", 216 "format": "hex", 217 "set": 0, 218 "gcc": 10, 219 "dwarf": 10, 220 }, 221 { 222 "name": "r11", 223 "bitsize": 64, 224 "offset": 88, 225 "encoding": "uint", 226 "format": "hex", 227 "set": 0, 228 "gcc": 11, 229 "dwarf": 11, 230 }, 231 { 232 "name": "r12", 233 "bitsize": 64, 234 "offset": 96, 235 "encoding": "uint", 236 "format": "hex", 237 "set": 0, 238 "gcc": 12, 239 "dwarf": 12, 240 }, 241 { 242 "name": "r13", 243 "bitsize": 64, 244 "offset": 104, 245 "encoding": "uint", 246 "format": "hex", 247 "set": 0, 248 "gcc": 13, 249 "dwarf": 13, 250 }, 251 { 252 "name": "r14", 253 "bitsize": 64, 254 "offset": 112, 255 "encoding": "uint", 256 "format": "hex", 257 "set": 0, 258 "gcc": 14, 259 "dwarf": 14, 260 }, 261 { 262 "name": "r15", 263 "bitsize": 64, 264 "offset": 120, 265 "encoding": "uint", 266 "format": "hex", 267 "set": 0, 268 "gcc": 15, 269 "dwarf": 15, 270 }, 271 { 272 "name": "rip", 273 "bitsize": 64, 274 "offset": 128, 275 "encoding": "uint", 276 "format": "hex", 277 "set": 0, 278 "gcc": 16, 279 "dwarf": 16, 280 "generic": "pc", 281 "alt-name": "pc", 282 }, 283 { 284 "name": "rflags", 285 "bitsize": 64, 286 "offset": 136, 287 "encoding": "uint", 288 "format": "hex", 289 "set": 0, 290 "generic": "flags", 291 "alt-name": "flags", 292 }, 293 { 294 "name": "cs", 295 "bitsize": 64, 296 "offset": 144, 297 "encoding": "uint", 298 "format": "hex", 299 "set": 0, 300 }, 301 { 302 "name": "fs", 303 "bitsize": 64, 304 "offset": 152, 305 "encoding": "uint", 306 "format": "hex", 307 "set": 0, 308 }, 309 { 310 "name": "gs", 311 "bitsize": 64, 312 "offset": 160, 313 "encoding": "uint", 314 "format": "hex", 315 "set": 0, 316 }, 317 ] 318 return self.registers 319 320 def get_register_data(self, tid): 321 if tid == 0x111111111: 322 return struct.pack( 323 "21Q", 324 1, 325 2, 326 3, 327 4, 328 5, 329 6, 330 7, 331 8, 332 9, 333 10, 334 11, 335 12, 336 13, 337 14, 338 15, 339 16, 340 17, 341 18, 342 19, 343 20, 344 21, 345 ) 346 elif tid == 0x222222222: 347 return struct.pack( 348 "21Q", 349 11, 350 12, 351 13, 352 14, 353 15, 354 16, 355 17, 356 18, 357 19, 358 110, 359 111, 360 112, 361 113, 362 114, 363 115, 364 116, 365 117, 366 118, 367 119, 368 120, 369 121, 370 ) 371 elif tid == 0x333333333: 372 return struct.pack( 373 "21Q", 374 21, 375 22, 376 23, 377 24, 378 25, 379 26, 380 27, 381 28, 382 29, 383 210, 384 211, 385 212, 386 213, 387 214, 388 215, 389 216, 390 217, 391 218, 392 219, 393 220, 394 221, 395 ) 396 elif tid == 0x444444444: 397 return struct.pack( 398 "21Q", 399 31, 400 32, 401 33, 402 34, 403 35, 404 36, 405 37, 406 38, 407 39, 408 310, 409 311, 410 312, 411 313, 412 314, 413 315, 414 316, 415 317, 416 318, 417 319, 418 320, 419 321, 420 ) 421 else: 422 return struct.pack( 423 "21Q", 424 41, 425 42, 426 43, 427 44, 428 45, 429 46, 430 47, 431 48, 432 49, 433 410, 434 411, 435 412, 436 413, 437 414, 438 415, 439 416, 440 417, 441 418, 442 419, 443 420, 444 421, 445 ) 446 return None 447