4 # Copyright 2014 Apple Inc. All righes reserved.
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.
25 def EFI_GUID_TypeSummary (valobj
,internal_dict
):
26 """ Type summary for EFI GUID, print C Name if known
34 SBError
= lldb
.SBError()
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
)
44 data4_val
= valobj
.GetChildMemberWithName('Data4')
45 for i
in range (data4_val
.num_children
):
48 str += "%02x" % data4_val
.GetChildAtIndex(i
).data
.GetUnsignedInt8(SBError
, 0)
50 return guid_dict
.get (str.upper(), '')
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",
81 1 : "Warning Unknown Glyph",
82 2 : "Warning Delete Failure",
83 3 : "Warning Write Failure",
84 4 : "Warning Buffer Too Small",
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",
112 def EFI_STATUS_TypeSummary (valobj
,internal_dict
):
114 # Return summary string for EFI_STATUS from dictionary
116 Status
= valobj
.GetValueAsUnsigned(0)
117 return EFI_STATUS_Dict
.get (Status
, '')
120 def EFI_TPL_TypeSummary (valobj
,internal_dict
):
125 if valobj
.TypeIsPointerType():
128 Tpl
= valobj
.GetValueAsUnsigned(0)
132 Str
= "TPL_DRIVER (Obsolete Concept in edk2)"
134 Str
= "TPL_APPLICATION"
136 Str
+= " + " + "%d" % (Tpl
- 4)
140 Str
+= " + " + "%d" % (Tpl
- 4)
144 Str
+= " + " + "%d" % (Tpl
- 4)
146 Str
= "TPL_HIGH_LEVEL"
153 def CHAR16_TypeSummary (valobj
,internal_dict
):
155 # Display EFI CHAR16 'unsigned short' as string
157 SBError
= lldb
.SBError()
159 if valobj
.TypeIsPointerType():
160 if valobj
.GetValueAsUnsigned () == 0:
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:
169 Str
= 'L"' + Str
+ '"'
170 return Str
.encode ('utf-8', 'replace')
172 if valobj
.num_children
== 0:
174 if chr (valobj
.unsigned
) in string
.printable
:
175 Str
= "L'" + unichr (valobj
.unsigned
) + "'"
176 return Str
.encode ('utf-8', 'replace')
179 for i
in range (valobj
.num_children
):
180 Char
= valobj
.GetChildAtIndex(i
).data
.GetUnsignedInt16(SBError
, 0)
184 Str
= 'L"' + Str
+ '"'
185 return Str
.encode ('utf-8', 'replace')
189 def CHAR8_TypeSummary (valobj
,internal_dict
):
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)
195 SBError
= lldb
.SBError()
197 if valobj
.TypeIsPointerType():
198 if valobj
.GetValueAsUnsigned () == 0:
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:
207 Str
= '"' + Str
+ '"'
208 return Str
.encode ('utf-8', 'replace')
210 if valobj
.num_children
== 0:
212 if chr (valobj
.unsigned
) in string
.printable
:
213 Str
= '"' + unichr (valobj
.unsigned
) + '"'
214 return Str
.encode ('utf-8', 'replace')
217 for i
in range (valobj
.num_children
):
218 Char
= valobj
.GetChildAtIndex(i
).data
.GetUnsignedInt8(SBError
, 0)
222 Str
= '"' + Str
+ '"'
223 return Str
.encode ('utf-8', 'replace')
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",
262 def EFI_DEVICE_PATH_PROTOCOL_TypeSummary (valobj
,internal_dict
):
266 if valobj
.TypeIsPointerType():
267 # EFI_DEVICE_PATH_PROTOCOL *
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
]
280 LenLow
= valobj
.GetChildMemberWithName('Length').GetChildAtIndex(0).unsigned
281 LenHigh
= valobj
.GetChildMemberWithName('Length').GetChildAtIndex(1).unsigned
282 Len
= LenLow
+ (LenHigh
>> 8)
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
288 elif (Type
& 0x7f == 0x7f):
289 ExprStr
= "End Device Path" if SubType
== 0xff else "End This Instance"
291 ExprStr
= "expr *(%s *)0x%08x" % (TypeStr
, Address
)
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
300 if (Type
& 0x7f == 0x7f) and (SubType
== 0xff):
303 NextNode
= Address
+ Len
304 Str
+= "// Next node 'expr *(EFI_DEVICE_PATH_PROTOCOL *)0x%08x'\n" % NextNode
310 def TypePrintFormating(debugger
):
312 # Set the default print formating for EFI types in lldb.
313 # seems lldb defaults to decimal.
315 category
= debugger
.GetDefaultCategory()
316 FormatBool
= lldb
.SBTypeFormat(lldb
.eFormatBoolean
)
317 category
.AddTypeFormat(lldb
.SBTypeNameSpecifier("BOOLEAN"), FormatBool
)
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
)
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
)
342 # Smart type printing for EFI
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")
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')
355 gEmulatorBreakWorkaroundNeeded
= True
357 def LoadEmulatorEfiSymbols(frame
, bp_loc
, internal_dict
):
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.
364 # SecGdbScriptBreak (
366 # int FileNameLength,
367 # long unsigned int LoadAddress,
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
378 global gEmulatorBreakWorkaroundNeeded
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
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()
395 debugger
= frame
.thread
.process
.target
.debugger
396 if frame
.FindVariable ("AddSymbolFlag").GetValueAsUnsigned() == 1:
397 LoadAddress
= frame
.FindVariable ("LoadAddress").GetValueAsUnsigned()
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
))
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
412 # make breakpoint command contiue
413 frame
.thread
.process
.Continue()
415 def GuidToCStructStr (guid
, Name
=False):
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 } }
420 # Name=True means lookup name in GuidNameDict and us it if you find it
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
)
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])
431 def ParseGuidString(GuidStr
):
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 } }")
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()
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.
463 parser
= optparse
.OptionParser(description
=description
, prog
='guid',usage
=usage
)
466 def efi_guid_command(debugger
, command
, result
, dict):
467 # Use the Shell Lexer to properly parse up command options just like a
469 command_args
= shlex
.split(command
)
470 parser
= create_guid_options()
472 (options
, args
) = parser
.parse_args(command_args
)
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])
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()
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")
491 if GuidStr
in guid_dict
:
492 print "%s = %s" % (guid_dict
[GuidStr
], GuidStr
)
493 print "%s = %s" % (guid_dict
[GuidStr
], GuidToCStructStr (GuidStr
))
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
))
506 ########## Code that runs when this script is imported into LLDB ###########
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
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
:
520 data
= line
.split(' ')
522 guid_dict
[data
[0].upper()] = data
[1].strip('\n')
524 # init EFI specific type formaters
525 TypePrintFormating (debugger
)
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')
534 Target
= debugger
.GetTargetAtIndex(0)
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.'