Anderw Fish | 4880fc9 | 2014-08-29 18:52:42 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | # |
| 4 | # Copyright 2014 Apple Inc. All righes reserved. |
| 5 | # |
| 6 | # This program and the accompanying materials |
| 7 | # are licensed and made available under the terms and conditions of the BSD License |
| 8 | # which accompanies this distribution. The full text of the license may be found at |
| 9 | # http://opensource.org/licenses/bsd-license.php. |
| 10 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| 12 | # |
| 13 | |
| 14 | import lldb |
| 15 | import os |
| 16 | import uuid |
| 17 | import string |
| 18 | import commands |
| 19 | import optparse |
| 20 | import shlex |
| 21 | |
| 22 | guid_dict = {} |
| 23 | |
| 24 | |
| 25 | def EFI_GUID_TypeSummary (valobj,internal_dict): |
| 26 | """ Type summary for EFI GUID, print C Name if known |
| 27 | """ |
| 28 | # typedef struct { |
| 29 | # UINT32 Data1; |
| 30 | # UINT16 Data2; |
| 31 | # UINT16 Data3; |
| 32 | # UINT8 Data4[8]; |
| 33 | # } EFI_GUID; |
| 34 | SBError = lldb.SBError() |
| 35 | |
| 36 | data1_val = valobj.GetChildMemberWithName('Data1') |
| 37 | data1 = data1_val.GetValueAsUnsigned(0) |
| 38 | data2_val = valobj.GetChildMemberWithName('Data2') |
| 39 | data2 = data2_val.GetValueAsUnsigned(0) |
| 40 | data3_val = valobj.GetChildMemberWithName('Data3') |
| 41 | data3 = data3_val.GetValueAsUnsigned(0) |
| 42 | str = "%x-%x-%x-" % (data1, data2, data3) |
| 43 | |
| 44 | data4_val = valobj.GetChildMemberWithName('Data4') |
| 45 | for i in range (data4_val.num_children): |
| 46 | if i == 2: |
| 47 | str +='-' |
| 48 | str += "%02x" % data4_val.GetChildAtIndex(i).data.GetUnsignedInt8(SBError, 0) |
| 49 | |
| 50 | return guid_dict.get (str.upper(), '') |
| 51 | |
| 52 | |
| 53 | |
| 54 | EFI_STATUS_Dict = { |
| 55 | (0x8000000000000000 | 1): "Load Error", |
| 56 | (0x8000000000000000 | 2): "Invalid Parameter", |
| 57 | (0x8000000000000000 | 3): "Unsupported", |
| 58 | (0x8000000000000000 | 4): "Bad Buffer Size", |
| 59 | (0x8000000000000000 | 5): "Buffer Too Small", |
| 60 | (0x8000000000000000 | 6): "Not Ready", |
| 61 | (0x8000000000000000 | 7): "Device Error", |
| 62 | (0x8000000000000000 | 8): "Write Protected", |
| 63 | (0x8000000000000000 | 9): "Out of Resources", |
| 64 | (0x8000000000000000 | 10): "Volume Corrupt", |
| 65 | (0x8000000000000000 | 11): "Volume Full", |
| 66 | (0x8000000000000000 | 12): "No Media", |
| 67 | (0x8000000000000000 | 13): "Media changed", |
| 68 | (0x8000000000000000 | 14): "Not Found", |
| 69 | (0x8000000000000000 | 15): "Access Denied", |
| 70 | (0x8000000000000000 | 16): "No Response", |
| 71 | (0x8000000000000000 | 17): "No mapping", |
| 72 | (0x8000000000000000 | 18): "Time out", |
| 73 | (0x8000000000000000 | 19): "Not started", |
| 74 | (0x8000000000000000 | 20): "Already started", |
| 75 | (0x8000000000000000 | 21): "Aborted", |
| 76 | (0x8000000000000000 | 22): "ICMP Error", |
| 77 | (0x8000000000000000 | 23): "TFTP Error", |
| 78 | (0x8000000000000000 | 24): "Protocol Error", |
| 79 | |
| 80 | 0 : "Success", |
| 81 | 1 : "Warning Unknown Glyph", |
| 82 | 2 : "Warning Delete Failure", |
| 83 | 3 : "Warning Write Failure", |
| 84 | 4 : "Warning Buffer Too Small", |
| 85 | |
| 86 | (0x80000000 | 1): "Load Error", |
| 87 | (0x80000000 | 2): "Invalid Parameter", |
| 88 | (0x80000000 | 3): "Unsupported", |
| 89 | (0x80000000 | 4): "Bad Buffer Size", |
| 90 | (0x80000000 | 5): "Buffer Too Small", |
| 91 | (0x80000000 | 6): "Not Ready", |
| 92 | (0x80000000 | 7): "Device Error", |
| 93 | (0x80000000 | 8): "Write Protected", |
| 94 | (0x80000000 | 9): "Out of Resources", |
| 95 | (0x80000000 | 10): "Volume Corrupt", |
| 96 | (0x80000000 | 11): "Volume Full", |
| 97 | (0x80000000 | 12): "No Media", |
| 98 | (0x80000000 | 13): "Media changed", |
| 99 | (0x80000000 | 14): "Not Found", |
| 100 | (0x80000000 | 15): "Access Denied", |
| 101 | (0x80000000 | 16): "No Response", |
| 102 | (0x80000000 | 17): "No mapping", |
| 103 | (0x80000000 | 18): "Time out", |
| 104 | (0x80000000 | 19): "Not started", |
| 105 | (0x80000000 | 20): "Already started", |
| 106 | (0x80000000 | 21): "Aborted", |
| 107 | (0x80000000 | 22): "ICMP Error", |
| 108 | (0x80000000 | 23): "TFTP Error", |
| 109 | (0x80000000 | 24): "Protocol Error", |
| 110 | } |
| 111 | |
| 112 | def EFI_STATUS_TypeSummary (valobj,internal_dict): |
| 113 | # |
| 114 | # Return summary string for EFI_STATUS from dictionary |
| 115 | # |
| 116 | Status = valobj.GetValueAsUnsigned(0) |
| 117 | return EFI_STATUS_Dict.get (Status, '') |
| 118 | |
| 119 | |
| 120 | def EFI_TPL_TypeSummary (valobj,internal_dict): |
| 121 | # |
| 122 | # Return TPL values |
| 123 | # |
| 124 | |
| 125 | if valobj.TypeIsPointerType(): |
| 126 | return "" |
| 127 | |
| 128 | Tpl = valobj.GetValueAsUnsigned(0) |
| 129 | if Tpl < 4: |
| 130 | Str = "%d" % Tpl |
| 131 | elif Tpl == 6: |
| 132 | Str = "TPL_DRIVER (Obsolete Concept in edk2)" |
| 133 | elif Tpl < 8: |
| 134 | Str = "TPL_APPLICATION" |
| 135 | if Tpl - 4 > 0: |
| 136 | Str += " + " + "%d" % (Tpl - 4) |
| 137 | elif Tpl < 16: |
| 138 | Str = "TPL_CALLBACK" |
| 139 | if Tpl - 8 > 0: |
| 140 | Str += " + " + "%d" % (Tpl - 4) |
| 141 | elif Tpl < 31: |
| 142 | Str = "TPL_NOTIFY" |
| 143 | if Tpl - 16 > 0: |
| 144 | Str += " + " + "%d" % (Tpl - 4) |
| 145 | elif Tpl == 31: |
| 146 | Str = "TPL_HIGH_LEVEL" |
| 147 | else: |
| 148 | Str = "Invalid TPL" |
| 149 | |
| 150 | return Str |
| 151 | |
| 152 | |
| 153 | def CHAR16_TypeSummary (valobj,internal_dict): |
| 154 | # |
| 155 | # Display EFI CHAR16 'unsigned short' as string |
| 156 | # |
| 157 | SBError = lldb.SBError() |
| 158 | Str = '' |
| 159 | if valobj.TypeIsPointerType(): |
| 160 | if valobj.GetValueAsUnsigned () == 0: |
| 161 | return "NULL" |
| 162 | |
| 163 | # CHAR16 * max string size 1024 |
| 164 | for i in range (1024): |
| 165 | Char = valobj.GetPointeeData(i,1).GetUnsignedInt16(SBError, 0) |
| 166 | if SBError.fail or Char == 0: |
| 167 | break |
| 168 | Str += unichr (Char) |
| 169 | Str = 'L"' + Str + '"' |
| 170 | return Str.encode ('utf-8', 'replace') |
| 171 | |
| 172 | if valobj.num_children == 0: |
| 173 | # CHAR16 |
| 174 | if chr (valobj.unsigned) in string.printable: |
| 175 | Str = "L'" + unichr (valobj.unsigned) + "'" |
| 176 | return Str.encode ('utf-8', 'replace') |
| 177 | else: |
| 178 | # CHAR16 [] |
| 179 | for i in range (valobj.num_children): |
| 180 | Char = valobj.GetChildAtIndex(i).data.GetUnsignedInt16(SBError, 0) |
| 181 | if Char == 0: |
| 182 | break |
| 183 | Str += unichr (Char) |
| 184 | Str = 'L"' + Str + '"' |
| 185 | return Str.encode ('utf-8', 'replace') |
| 186 | |
| 187 | return Str |
| 188 | |
| 189 | def CHAR8_TypeSummary (valobj,internal_dict): |
| 190 | # |
| 191 | # Display EFI CHAR8 'signed char' as string |
| 192 | # unichr() is used as a junk string can produce an error message like this: |
| 193 | # UnicodeEncodeError: 'ascii' codec can't encode character u'\x90' in position 1: ordinal not in range(128) |
| 194 | # |
| 195 | SBError = lldb.SBError() |
| 196 | Str = '' |
| 197 | if valobj.TypeIsPointerType(): |
| 198 | if valobj.GetValueAsUnsigned () == 0: |
| 199 | return "NULL" |
| 200 | |
| 201 | # CHAR8 * max string size 1024 |
| 202 | for i in range (1024): |
| 203 | Char = valobj.GetPointeeData(i,1).GetUnsignedInt8(SBError, 0) |
| 204 | if SBError.fail or Char == 0: |
| 205 | break |
| 206 | Str += unichr (Char) |
| 207 | Str = '"' + Str + '"' |
| 208 | return Str.encode ('utf-8', 'replace') |
| 209 | |
| 210 | if valobj.num_children == 0: |
| 211 | # CHAR8 |
| 212 | if chr (valobj.unsigned) in string.printable: |
| 213 | Str = '"' + unichr (valobj.unsigned) + '"' |
| 214 | return Str.encode ('utf-8', 'replace') |
| 215 | else: |
| 216 | # CHAR8 [] |
| 217 | for i in range (valobj.num_children): |
| 218 | Char = valobj.GetChildAtIndex(i).data.GetUnsignedInt8(SBError, 0) |
| 219 | if Char == 0: |
| 220 | break |
| 221 | Str += unichr (Char) |
| 222 | Str = '"' + Str + '"' |
| 223 | return Str.encode ('utf-8', 'replace') |
| 224 | |
| 225 | return Str |
| 226 | |
| 227 | device_path_dict = { |
| 228 | (0x01, 0x01): "PCI_DEVICE_PATH", |
| 229 | (0x01, 0x02): "PCCARD_DEVICE_PATH", |
| 230 | (0x01, 0x03): "MEMMAP_DEVICE_PATH", |
| 231 | (0x01, 0x04): "VENDOR_DEVICE_PATH", |
| 232 | (0x01, 0x05): "CONTROLLER_DEVICE_PATH", |
| 233 | (0x02, 0x01): "ACPI_HID_DEVICE_PATH", |
| 234 | (0x02, 0x02): "ACPI_EXTENDED_HID_DEVICE_PATH", |
| 235 | (0x02, 0x03): "ACPI_ADR_DEVICE_PATH", |
| 236 | (0x03, 0x01): "ATAPI_DEVICE_PATH", |
| 237 | (0x03, 0x12): "SATA_DEVICE_PATH", |
| 238 | (0x03, 0x02): "SCSI_DEVICE_PATH", |
| 239 | (0x03, 0x03): "FIBRECHANNEL_DEVICE_PATH", |
| 240 | (0x03, 0x04): "F1394_DEVICE_PATH", |
| 241 | (0x03, 0x05): "USB_DEVICE_PATH", |
| 242 | (0x03, 0x0f): "USB_CLASS_DEVICE_PATH", |
| 243 | (0x03, 0x10): "FW_SBP2_UNIT_LUN_DEVICE_PATH", |
| 244 | (0x03, 0x11): "DEVICE_LOGICAL_UNIT_DEVICE_PATH", |
| 245 | (0x03, 0x06): "I2O_DEVICE_PATH", |
| 246 | (0x03, 0x0b): "MAC_ADDR_DEVICE_PATH", |
| 247 | (0x03, 0x0c): "IPv4_DEVICE_PATH", |
| 248 | (0x03, 0x09): "INFINIBAND_DEVICE_PATH", |
| 249 | (0x03, 0x0e): "UART_DEVICE_PATH", |
| 250 | (0x03, 0x0a): "VENDOR_DEVICE_PATH", |
| 251 | (0x03, 0x13): "ISCSI_DEVICE_PATH", |
| 252 | (0x04, 0x01): "HARDDRIVE_DEVICE_PATH", |
| 253 | (0x04, 0x02): "CDROM_DEVICE_PATH", |
| 254 | (0x04, 0x03): "VENDOR_DEVICE_PATH", |
| 255 | (0x04, 0x04): "FILEPATH_DEVICE_PATH", |
| 256 | (0x04, 0x05): "MEDIA_PROTOCOL_DEVICE_PATH", |
| 257 | (0x05, 0x01): "BBS_BBS_DEVICE_PATH", |
| 258 | (0x7F, 0xFF): "EFI_DEVICE_PATH_PROTOCOL", |
| 259 | (0xFF, 0xFF): "EFI_DEVICE_PATH_PROTOCOL", |
| 260 | } |
| 261 | |
| 262 | def EFI_DEVICE_PATH_PROTOCOL_TypeSummary (valobj,internal_dict): |
| 263 | # |
| 264 | # |
| 265 | # |
| 266 | if valobj.TypeIsPointerType(): |
| 267 | # EFI_DEVICE_PATH_PROTOCOL * |
| 268 | return "" |
| 269 | |
| 270 | Str = "" |
| 271 | if valobj.num_children == 3: |
| 272 | # EFI_DEVICE_PATH_PROTOCOL |
| 273 | Type = valobj.GetChildMemberWithName('Type').unsigned |
| 274 | SubType = valobj.GetChildMemberWithName('SubType').unsigned |
| 275 | if (Type, SubType) in device_path_dict: |
| 276 | TypeStr = device_path_dict[Type, SubType] |
| 277 | else: |
| 278 | TypeStr = "" |
| 279 | |
| 280 | LenLow = valobj.GetChildMemberWithName('Length').GetChildAtIndex(0).unsigned |
| 281 | LenHigh = valobj.GetChildMemberWithName('Length').GetChildAtIndex(1).unsigned |
| 282 | Len = LenLow + (LenHigh >> 8) |
| 283 | |
| 284 | Address = long ("%d" % valobj.addr) |
| 285 | if (Address == lldb.LLDB_INVALID_ADDRESS): |
| 286 | # Need to reserach this, it seems to be the nested struct case |
| 287 | ExprStr = "" |
| 288 | elif (Type & 0x7f == 0x7f): |
| 289 | ExprStr = "End Device Path" if SubType == 0xff else "End This Instance" |
| 290 | else: |
| 291 | ExprStr = "expr *(%s *)0x%08x" % (TypeStr, Address) |
| 292 | |
| 293 | Str = " {\n" |
| 294 | Str += " (UINT8) Type = 0x%02x // %s\n" % (Type, "END" if (Type & 0x7f == 0x7f) else "") |
| 295 | Str += " (UINT8) SubType = 0x%02x // %s\n" % (SubType, ExprStr) |
| 296 | Str += " (UINT8 [2]) Length = { // 0x%04x (%d) bytes\n" % (Len, Len) |
| 297 | Str += " (UINT8) [0] = 0x%02x\n" % LenLow |
| 298 | Str += " (UINT8) [1] = 0x%02x\n" % LenHigh |
| 299 | Str += " }\n" |
| 300 | if (Type & 0x7f == 0x7f) and (SubType == 0xff): |
| 301 | pass |
| 302 | elif ExprStr != "": |
| 303 | NextNode = Address + Len |
| 304 | Str += "// Next node 'expr *(EFI_DEVICE_PATH_PROTOCOL *)0x%08x'\n" % NextNode |
| 305 | |
| 306 | return Str |
| 307 | |
| 308 | |
| 309 | |
| 310 | def TypePrintFormating(debugger): |
| 311 | # |
| 312 | # Set the default print formating for EFI types in lldb. |
| 313 | # seems lldb defaults to decimal. |
| 314 | # |
| 315 | category = debugger.GetDefaultCategory() |
| 316 | FormatBool = lldb.SBTypeFormat(lldb.eFormatBoolean) |
| 317 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("BOOLEAN"), FormatBool) |
| 318 | |
| 319 | FormatHex = lldb.SBTypeFormat(lldb.eFormatHex) |
| 320 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT64"), FormatHex) |
| 321 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT64"), FormatHex) |
| 322 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT32"), FormatHex) |
| 323 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT32"), FormatHex) |
| 324 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT16"), FormatHex) |
| 325 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT16"), FormatHex) |
| 326 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT8"), FormatHex) |
| 327 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT8"), FormatHex) |
| 328 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINTN"), FormatHex) |
| 329 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("INTN"), FormatHex) |
| 330 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("CHAR8"), FormatHex) |
| 331 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("CHAR16"), FormatHex) |
| 332 | |
| 333 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_PHYSICAL_ADDRESS"), FormatHex) |
| 334 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("PHYSICAL_ADDRESS"), FormatHex) |
| 335 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_STATUS"), FormatHex) |
| 336 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_TPL"), FormatHex) |
| 337 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_LBA"), FormatHex) |
| 338 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_BOOT_MODE"), FormatHex) |
| 339 | category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_FV_FILETYPE"), FormatHex) |
| 340 | |
| 341 | # |
| 342 | # Smart type printing for EFI |
| 343 | # |
| 344 | debugger.HandleCommand("type summary add EFI_GUID --python-function lldbefi.EFI_GUID_TypeSummary") |
| 345 | debugger.HandleCommand("type summary add EFI_STATUS --python-function lldbefi.EFI_STATUS_TypeSummary") |
| 346 | debugger.HandleCommand("type summary add EFI_TPL --python-function lldbefi.EFI_TPL_TypeSummary") |
| 347 | debugger.HandleCommand("type summary add EFI_DEVICE_PATH_PROTOCOL --python-function lldbefi.EFI_DEVICE_PATH_PROTOCOL_TypeSummary") |
| 348 | |
| 349 | debugger.HandleCommand("type summary add CHAR16 --python-function lldbefi.CHAR16_TypeSummary") |
| 350 | debugger.HandleCommand('type summary add --regex "CHAR16 \[[0-9]+\]" --python-function lldbefi.CHAR16_TypeSummary') |
| 351 | debugger.HandleCommand("type summary add CHAR8 --python-function lldbefi.CHAR8_TypeSummary") |
| 352 | debugger.HandleCommand('type summary add --regex "CHAR8 \[[0-9]+\]" --python-function lldbefi.CHAR8_TypeSummary') |
| 353 | |
| 354 | |
| 355 | gEmulatorBreakWorkaroundNeeded = True |
| 356 | |
| 357 | def LoadEmulatorEfiSymbols(frame, bp_loc , internal_dict): |
| 358 | # |
| 359 | # This is an lldb breakpoint script, and assumes the breakpoint is on a |
| 360 | # function with the same prototype as SecGdbScriptBreak(). The |
| 361 | # argument names are important as lldb looks them up. |
| 362 | # |
| 363 | # VOID |
| 364 | # SecGdbScriptBreak ( |
| 365 | # char *FileName, |
| 366 | # int FileNameLength, |
| 367 | # long unsigned int LoadAddress, |
| 368 | # int AddSymbolFlag |
| 369 | # ) |
| 370 | # { |
| 371 | # return; |
| 372 | # } |
| 373 | # |
| 374 | # When the emulator loads a PE/COFF image, it calls the stub function with |
| 375 | # the filename of the symbol file, the length of the FileName, the |
| 376 | # load address and a flag to indicate if this is a load or unload operation |
| 377 | # |
| 378 | global gEmulatorBreakWorkaroundNeeded |
| 379 | |
| 380 | if gEmulatorBreakWorkaroundNeeded: |
| 381 | # turn off lldb debug prints on SIGALRM (EFI timer tick) |
| 382 | frame.thread.process.target.debugger.HandleCommand("process handle SIGALRM -n false") |
| 383 | gEmulatorBreakWorkaroundNeeded = False |
| 384 | |
| 385 | # Convert C string to Python string |
| 386 | Error = lldb.SBError() |
| 387 | FileNamePtr = frame.FindVariable ("FileName").GetValueAsUnsigned() |
| 388 | FileNameLen = frame.FindVariable ("FileNameLength").GetValueAsUnsigned() |
| 389 | FileName = frame.thread.process.ReadCStringFromMemory (FileNamePtr, FileNameLen, Error) |
| 390 | if not Error.Success(): |
| 391 | print "!ReadCStringFromMemory() did not find a %d byte C string at %x" % (FileNameLen, FileNamePtr) |
| 392 | # make breakpoint command contiue |
| 393 | frame.GetThread().GetProcess().Continue() |
| 394 | |
| 395 | debugger = frame.thread.process.target.debugger |
| 396 | if frame.FindVariable ("AddSymbolFlag").GetValueAsUnsigned() == 1: |
| 397 | LoadAddress = frame.FindVariable ("LoadAddress").GetValueAsUnsigned() |
| 398 | |
| 399 | debugger.HandleCommand ("target modules add %s" % FileName) |
| 400 | print "target modules load --slid 0x%x %s" % (LoadAddress, FileName) |
| 401 | debugger.HandleCommand ("target modules load --slide 0x%x --file %s" % (LoadAddress, FileName)) |
| 402 | else: |
| 403 | target = debugger.GetSelectedTarget() |
| 404 | for SBModule in target.module_iter(): |
| 405 | ModuleName = SBModule.GetFileSpec().GetDirectory() + '/' |
| 406 | ModuleName += SBModule.GetFileSpec().GetFilename() |
| 407 | if FileName == ModuleName or FileName == SBModule.GetFileSpec().GetFilename(): |
| 408 | target.ClearModuleLoadAddress (SBModule) |
| 409 | if not target.RemoveModule (SBModule): |
| 410 | print "!lldb.target.RemoveModule (%s) FAILED" % SBModule |
| 411 | |
| 412 | # make breakpoint command contiue |
| 413 | frame.thread.process.Continue() |
| 414 | |
| 415 | def GuidToCStructStr (guid, Name=False): |
| 416 | # |
| 417 | # Convert a 16-byte bytesarry (or bytearray compat object) to C guid string |
| 418 | # { 0xB402621F, 0xA940, 0x1E4A, { 0x86, 0x6B, 0x4D, 0xC9, 0x16, 0x2B, 0x34, 0x7C } } |
| 419 | # |
| 420 | # Name=True means lookup name in GuidNameDict and us it if you find it |
| 421 | # |
| 422 | |
| 423 | if not isinstance (guid, bytearray): |
| 424 | # convert guid object to UUID, and UUID to bytearray |
| 425 | Uuid = uuid.UUID(guid) |
| 426 | guid = bytearray (Uuid.bytes_le) |
| 427 | |
| 428 | return "{ 0x%02.2X%02.2X%02.2X%02.2X, 0x%02.2X%02.2X, 0x%02.2X%02.2X, { 0x%02.2X, 0x%02.2X, 0x%02.2X, 0x%02.2X, 0x%02.2X, 0x%02.2X, 0x%02.2X, 0x%02.2X } }" % \ |
| 429 | (guid[3], guid[2], guid[1], guid[0], guid[5], guid[4], guid[7], guid[6], guid[8], guid[9], guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]) |
| 430 | |
| 431 | def ParseGuidString(GuidStr): |
| 432 | # |
| 433 | # Error check and convert C Guid init to string |
| 434 | # ParseGuidString("49152E77-1ADA-4764-B7A2-7AFEFED95E8B") |
| 435 | # ParseGuidString("{ 0xBA24B391, 0x73FD, 0xC54C, { 0x9E, 0xAF, 0x0C, 0xA7, 0x8A, 0x35, 0x46, 0xD1 } }") |
| 436 | # |
| 437 | |
| 438 | if "{" in GuidStr : |
| 439 | # convert C form "{ 0xBA24B391, 0x73FD, 0xC54C, { 0x9E, 0xAF, 0x0C, 0xA7, 0x8A, 0x35, 0x46, 0xD1 } }" |
| 440 | # to string form BA24B391-73FD-C54C-9EAF-0CA78A3546D1 |
| 441 | # make a list of Hex numbers like: ['0xBA24B391', '0x73FD', '0xC54C', '0x9E', '0xAF', '0x0C', '0xA7', '0x8A', '0x35', '0x46', '0xD1'] |
| 442 | Hex = ''.join(x for x in GuidStr if x not in '{,}').split() |
| 443 | Str = "%08X-%04X-%04X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X" % \ |
| 444 | (int(Hex[0], 0), int(Hex[1], 0), int(Hex[2], 0), int(Hex[3], 0), int(Hex[4], 0), \ |
| 445 | int(Hex[5], 0), int(Hex[6], 0), int(Hex[7], 0), int(Hex[8], 0), int(Hex[9], 0), int(Hex[10], 0)) |
| 446 | elif GuidStr.count('-') == 4: |
| 447 | # validate "49152E77-1ADA-4764-B7A2-7AFEFED95E8B" form |
| 448 | Check = "%s" % str(uuid.UUID(GuidStr)).upper() |
| 449 | if GuidStr.upper() == Check: |
| 450 | Str = GuidStr.upper() |
| 451 | else: |
| 452 | Ste = "" |
| 453 | else: |
| 454 | Str = "" |
| 455 | |
| 456 | return Str |
| 457 | |
| 458 | |
| 459 | def create_guid_options(): |
| 460 | usage = "usage: %prog [data]" |
| 461 | description='''lookup EFI_GUID by CName, C struct, or GUID string and print out all three. |
| 462 | ''' |
| 463 | parser = optparse.OptionParser(description=description, prog='guid',usage=usage) |
| 464 | return parser |
| 465 | |
| 466 | def efi_guid_command(debugger, command, result, dict): |
| 467 | # Use the Shell Lexer to properly parse up command options just like a |
| 468 | # shell would |
| 469 | command_args = shlex.split(command) |
| 470 | parser = create_guid_options() |
| 471 | try: |
| 472 | (options, args) = parser.parse_args(command_args) |
| 473 | if len(args) >= 1: |
| 474 | if args[0] == "{": |
| 475 | # caller forgot to quote the string" |
| 476 | # mark arg[0] a string containing all args[n] |
| 477 | args[0] = ' '.join(args) |
| 478 | GuidStr = ParseGuidString (args[0]) |
| 479 | if GuidStr == "": |
| 480 | # return Key of GuidNameDict for value args[0] |
| 481 | GuidStr = [Key for Key, Value in guid_dict.iteritems() if Value == args[0]][0] |
| 482 | GuidStr = GuidStr.upper() |
| 483 | except: |
| 484 | # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit |
| 485 | # (courtesy of OptParse dealing with argument errors by throwing SystemExit) |
| 486 | result.SetError ("option parsing failed") |
| 487 | return |
| 488 | |
| 489 | |
| 490 | if len(args) >= 1: |
| 491 | if GuidStr in guid_dict: |
| 492 | print "%s = %s" % (guid_dict[GuidStr], GuidStr) |
| 493 | print "%s = %s" % (guid_dict[GuidStr], GuidToCStructStr (GuidStr)) |
| 494 | else: |
| 495 | print GuidStr |
| 496 | else: |
| 497 | # dump entire dictionary |
| 498 | width = max(len(v) for k,v in guid_dict.iteritems()) |
| 499 | for value in sorted(guid_dict, key=guid_dict.get): |
| 500 | print '%-*s %s %s' % (width, guid_dict[value], value, GuidToCStructStr(value)) |
| 501 | |
| 502 | return |
| 503 | |
| 504 | |
| 505 | # |
| 506 | ########## Code that runs when this script is imported into LLDB ########### |
| 507 | # |
| 508 | def __lldb_init_module (debugger, internal_dict): |
| 509 | # This initializer is being run from LLDB in the embedded command interpreter |
| 510 | # Make the options so we can generate the help text for the new LLDB |
| 511 | # command line command prior to registering it with LLDB below |
| 512 | |
| 513 | global guid_dict |
| 514 | |
| 515 | # Source Guid.xref file if we can find it |
| 516 | inputfile = os.getcwd() |
| 517 | inputfile += os.sep + os.pardir + os.sep + 'FV' + os.sep + 'Guid.xref' |
| 518 | with open(inputfile) as f: |
| 519 | for line in f: |
| 520 | data = line.split(' ') |
| 521 | if len(data) >= 2: |
| 522 | guid_dict[data[0].upper()] = data[1].strip('\n') |
| 523 | |
| 524 | # init EFI specific type formaters |
| 525 | TypePrintFormating (debugger) |
| 526 | |
| 527 | |
| 528 | # add guid command |
| 529 | parser = create_guid_options() |
| 530 | efi_guid_command.__doc__ = parser.format_help() |
| 531 | debugger.HandleCommand('command script add -f lldbefi.efi_guid_command guid') |
| 532 | |
| 533 | |
| 534 | Target = debugger.GetTargetAtIndex(0) |
| 535 | if Target: |
| 536 | Breakpoint = Target.BreakpointCreateByName('SecGdbScriptBreak') |
| 537 | if Breakpoint.GetNumLocations() == 1: |
| 538 | # Set the emulator breakpoints, if we are in the emulator |
| 539 | debugger.HandleCommand("breakpoint command add -s python -F lldbefi.LoadEmulatorEfiSymbols {id}".format(id=Breakpoint.GetID())) |
| 540 | print 'Type r to run emulator. SecLldbScriptBreak armed. EFI modules should now get source level debugging in the emulator.' |