VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/efi_lldb.py@ 105681

最後變更 在這個檔案從105681是 99404,由 vboxsync 提交於 20 月 前

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:executable 設為 *
檔案大小: 33.0 KB
 
1#!/usr/bin/python3
2'''
3Copyright (c) Apple Inc. 2021
4SPDX-License-Identifier: BSD-2-Clause-Patent
5
6Example usage:
7OvmfPkg/build.sh qemu -gdb tcp::9000
8lldb -o "gdb-remote localhost:9000" -o "command script import efi_lldb.py"
9'''
10
11import optparse
12import shlex
13import subprocess
14import uuid
15import sys
16import os
17from pathlib import Path
18from efi_debugging import EfiDevicePath, EfiConfigurationTable, EfiTpl
19from efi_debugging import EfiHob, GuidNames, EfiStatusClass, EfiBootMode
20from efi_debugging import PeTeImage, patch_ctypes
21
22try:
23 # Just try for LLDB in case PYTHONPATH is already correctly setup
24 import lldb
25except ImportError:
26 try:
27 env = os.environ.copy()
28 env['LLDB_DEFAULT_PYTHON_VERSION'] = str(sys.version_info.major)
29 lldb_python_path = subprocess.check_output(
30 ["xcrun", "lldb", "-P"], env=env).decode("utf-8").strip()
31 sys.path.append(lldb_python_path)
32 import lldb
33 except ValueError:
34 print("Couldn't find LLDB.framework from lldb -P")
35 print("PYTHONPATH should match the currently selected lldb")
36 sys.exit(-1)
37
38
39class LldbFileObject(object):
40 '''
41 Class that fakes out file object to abstract lldb from the generic code.
42 For lldb this is memory so we don't have a concept of the end of the file.
43 '''
44
45 def __init__(self, process):
46 # _exe_ctx is lldb.SBExecutionContext
47 self._process = process
48 self._offset = 0
49 self._SBError = lldb.SBError()
50
51 def tell(self):
52 return self._offset
53
54 def read(self, size=-1):
55 if size == -1:
56 # arbitrary default size
57 size = 0x1000000
58
59 data = self._process.ReadMemory(self._offset, size, self._SBError)
60 if self._SBError.fail:
61 raise MemoryError(
62 f'lldb could not read memory 0x{size:x} '
63 f' bytes from 0x{self._offset:08x}')
64 else:
65 return data
66
67 def readable(self):
68 return True
69
70 def seek(self, offset, whence=0):
71 if whence == 0:
72 self._offset = offset
73 elif whence == 1:
74 self._offset += offset
75 else:
76 # whence == 2 is seek from end
77 raise NotImplementedError
78
79 def seekable(self):
80 return True
81
82 def write(self, data):
83 result = self._process.WriteMemory(self._offset, data, self._SBError)
84 if self._SBError.fail:
85 raise MemoryError(
86 f'lldb could not write memory to 0x{self._offset:08x}')
87 return result
88
89 def writable(self):
90 return True
91
92 def truncate(self, size=None):
93 raise NotImplementedError
94
95 def flush(self):
96 raise NotImplementedError
97
98 def fileno(self):
99 raise NotImplementedError
100
101
102class EfiSymbols:
103 """
104 Class to manage EFI Symbols
105 You need to pass file, and exe_ctx to load symbols.
106 You can print(EfiSymbols()) to see the currently loaded symbols
107 """
108
109 loaded = {}
110 stride = None
111 range = None
112 verbose = False
113
114 def __init__(self, target=None):
115 if target:
116 EfiSymbols.target = target
117 EfiSymbols._file = LldbFileObject(target.process)
118
119 @ classmethod
120 def __str__(cls):
121 return ''.join(f'{pecoff}\n' for (pecoff, _) in cls.loaded.values())
122
123 @ classmethod
124 def configure_search(cls, stride, range, verbose=False):
125 cls.stride = stride
126 cls.range = range
127 cls.verbose = verbose
128
129 @ classmethod
130 def clear(cls):
131 cls.loaded = {}
132
133 @ classmethod
134 def add_symbols_for_pecoff(cls, pecoff):
135 '''Tell lldb the location of the .text and .data sections.'''
136
137 if pecoff.LoadAddress in cls.loaded:
138 return 'Already Loaded: '
139
140 module = cls.target.AddModule(None, None, str(pecoff.CodeViewUuid))
141 if not module:
142 module = cls.target.AddModule(pecoff.CodeViewPdb,
143 None,
144 str(pecoff.CodeViewUuid))
145 if module.IsValid():
146 SBError = cls.target.SetModuleLoadAddress(
147 module, pecoff.LoadAddress + pecoff.TeAdjust)
148 if SBError.success:
149 cls.loaded[pecoff.LoadAddress] = (pecoff, module)
150 return ''
151
152 return 'Symbols NOT FOUND: '
153
154 @ classmethod
155 def address_to_symbols(cls, address, reprobe=False):
156 '''
157 Given an address search backwards for a PE/COFF (or TE) header
158 and load symbols. Return a status string.
159 '''
160 if not isinstance(address, int):
161 address = int(address)
162
163 pecoff, _ = cls.address_in_loaded_pecoff(address)
164 if not reprobe and pecoff is not None:
165 # skip the probe of the remote
166 return f'{pecoff} is already loaded'
167
168 pecoff = PeTeImage(cls._file, None)
169 if pecoff.pcToPeCoff(address, cls.stride, cls.range):
170 res = cls.add_symbols_for_pecoff(pecoff)
171 return f'{res}{pecoff}'
172 else:
173 return f'0x{address:08x} not in a PE/COFF (or TE) image'
174
175 @ classmethod
176 def address_in_loaded_pecoff(cls, address):
177 if not isinstance(address, int):
178 address = int(address)
179
180 for (pecoff, module) in cls.loaded.values():
181 if (address >= pecoff.LoadAddress and
182 address <= pecoff.EndLoadAddress):
183
184 return pecoff, module
185
186 return None, None
187
188 @ classmethod
189 def unload_symbols(cls, address):
190 pecoff, module = cls.address_in_loaded_pecoff(address)
191 if module:
192 name = str(module)
193 cls.target.ClearModuleLoadAddress(module)
194 cls.target.RemoveModule(module)
195 del cls.loaded[pecoff.LoadAddress]
196 return f'{name:s} was unloaded'
197 return f'0x{address:x} was not in a loaded image'
198
199
200def arg_to_address(frame, arg):
201 ''' convert an lldb command arg into a memory address (addr_t)'''
202
203 if arg is None:
204 return None
205
206 arg_str = arg if isinstance(arg, str) else str(arg)
207 SBValue = frame.EvaluateExpression(arg_str)
208 if SBValue.error.fail:
209 return arg
210
211 if (SBValue.TypeIsPointerType() or
212 SBValue.value_type == lldb.eValueTypeRegister or
213 SBValue.value_type == lldb.eValueTypeRegisterSet or
214 SBValue.value_type == lldb.eValueTypeConstResult):
215 try:
216 addr = SBValue.GetValueAsAddress()
217 except ValueError:
218 addr = SBValue.unsigned
219 else:
220 try:
221 addr = SBValue.address_of.GetValueAsAddress()
222 except ValueError:
223 addr = SBValue.address_of.unsigned
224
225 return addr
226
227
228def arg_to_data(frame, arg):
229 ''' convert an lldb command arg into a data vale (uint32_t/uint64_t)'''
230 if not isinstance(arg, str):
231 arg_str = str(str)
232
233 SBValue = frame.EvaluateExpression(arg_str)
234 return SBValue.unsigned
235
236
237class EfiDevicePathCommand:
238
239 def create_options(self):
240 ''' standard lldb command help/options parser'''
241 usage = "usage: %prog [options]"
242 description = '''Command that can EFI Config Tables
243'''
244
245 # Pass add_help_option = False, since this keeps the command in line
246 # with lldb commands, and we wire up "help command" to work by
247 # providing the long & short help methods below.
248 self.parser = optparse.OptionParser(
249 description=description,
250 prog='devicepath',
251 usage=usage,
252 add_help_option=False)
253
254 self.parser.add_option(
255 '-v',
256 '--verbose',
257 action='store_true',
258 dest='verbose',
259 help='hex dump extra data',
260 default=False)
261
262 self.parser.add_option(
263 '-n',
264 '--node',
265 action='store_true',
266 dest='node',
267 help='dump a single device path node',
268 default=False)
269
270 self.parser.add_option(
271 '-h',
272 '--help',
273 action='store_true',
274 dest='help',
275 help='Show help for the command',
276 default=False)
277
278 def get_short_help(self):
279 '''standard lldb function method'''
280 return "Display EFI Tables"
281
282 def get_long_help(self):
283 '''standard lldb function method'''
284 return self.help_string
285
286 def __init__(self, debugger, internal_dict):
287 '''standard lldb function method'''
288 self.create_options()
289 self.help_string = self.parser.format_help()
290
291 def __call__(self, debugger, command, exe_ctx, result):
292 '''standard lldb function method'''
293 # Use the Shell Lexer to properly parse up command options just like a
294 # shell would
295 command_args = shlex.split(command)
296
297 try:
298 (options, args) = self.parser.parse_args(command_args)
299 dev_list = []
300 for arg in args:
301 dev_list.append(arg_to_address(exe_ctx.frame, arg))
302 except ValueError:
303 # if you don't handle exceptions, passing an incorrect argument
304 # to the OptionParser will cause LLDB to exit (courtesy of
305 # OptParse dealing with argument errors by throwing SystemExit)
306 result.SetError("option parsing failed")
307 return
308
309 if options.help:
310 self.parser.print_help()
311 return
312
313 file = LldbFileObject(exe_ctx.process)
314
315 for dev_addr in dev_list:
316 if options.node:
317 print(EfiDevicePath(file).device_path_node_str(
318 dev_addr, options.verbose))
319 else:
320 device_path = EfiDevicePath(file, dev_addr, options.verbose)
321 if device_path.valid():
322 print(device_path)
323
324
325class EfiHobCommand:
326 def create_options(self):
327 ''' standard lldb command help/options parser'''
328 usage = "usage: %prog [options]"
329 description = '''Command that can EFI dump EFI HOBs'''
330
331 # Pass add_help_option = False, since this keeps the command in line
332 # with lldb commands, and we wire up "help command" to work by
333 # providing the long & short help methods below.
334 self.parser = optparse.OptionParser(
335 description=description,
336 prog='table',
337 usage=usage,
338 add_help_option=False)
339
340 self.parser.add_option(
341 '-a',
342 '--address',
343 type="int",
344 dest='address',
345 help='Parse HOBs from address',
346 default=None)
347
348 self.parser.add_option(
349 '-t',
350 '--type',
351 type="int",
352 dest='type',
353 help='Only dump HOBS of his type',
354 default=None)
355
356 self.parser.add_option(
357 '-v',
358 '--verbose',
359 action='store_true',
360 dest='verbose',
361 help='hex dump extra data',
362 default=False)
363
364 self.parser.add_option(
365 '-h',
366 '--help',
367 action='store_true',
368 dest='help',
369 help='Show help for the command',
370 default=False)
371
372 def get_short_help(self):
373 '''standard lldb function method'''
374 return "Display EFI Hobs"
375
376 def get_long_help(self):
377 '''standard lldb function method'''
378 return self.help_string
379
380 def __init__(self, debugger, internal_dict):
381 '''standard lldb function method'''
382 self.create_options()
383 self.help_string = self.parser.format_help()
384
385 def __call__(self, debugger, command, exe_ctx, result):
386 '''standard lldb function method'''
387 # Use the Shell Lexer to properly parse up command options just like a
388 # shell would
389 command_args = shlex.split(command)
390
391 try:
392 (options, _) = self.parser.parse_args(command_args)
393 except ValueError:
394 # if you don't handle exceptions, passing an incorrect argument
395 # to the OptionParser will cause LLDB to exit (courtesy of
396 # OptParse dealing with argument errors by throwing SystemExit)
397 result.SetError("option parsing failed")
398 return
399
400 if options.help:
401 self.parser.print_help()
402 return
403
404 address = arg_to_address(exe_ctx.frame, options.address)
405
406 file = LldbFileObject(exe_ctx.process)
407 hob = EfiHob(file, address, options.verbose).get_hob_by_type(
408 options.type)
409 print(hob)
410
411
412class EfiTableCommand:
413
414 def create_options(self):
415 ''' standard lldb command help/options parser'''
416 usage = "usage: %prog [options]"
417 description = '''Command that can display EFI Config Tables
418'''
419
420 # Pass add_help_option = False, since this keeps the command in line
421 # with lldb commands, and we wire up "help command" to work by
422 # providing the long & short help methods below.
423 self.parser = optparse.OptionParser(
424 description=description,
425 prog='table',
426 usage=usage,
427 add_help_option=False)
428
429 self.parser.add_option(
430 '-h',
431 '--help',
432 action='store_true',
433 dest='help',
434 help='Show help for the command',
435 default=False)
436
437 def get_short_help(self):
438 '''standard lldb function method'''
439 return "Display EFI Tables"
440
441 def get_long_help(self):
442 '''standard lldb function method'''
443 return self.help_string
444
445 def __init__(self, debugger, internal_dict):
446 '''standard lldb function method'''
447 self.create_options()
448 self.help_string = self.parser.format_help()
449
450 def __call__(self, debugger, command, exe_ctx, result):
451 '''standard lldb function method'''
452 # Use the Shell Lexer to properly parse up command options just like a
453 # shell would
454 command_args = shlex.split(command)
455
456 try:
457 (options, _) = self.parser.parse_args(command_args)
458 except ValueError:
459 # if you don't handle exceptions, passing an incorrect argument
460 # to the OptionParser will cause LLDB to exit (courtesy of
461 # OptParse dealing with argument errors by throwing SystemExit)
462 result.SetError("option parsing failed")
463 return
464
465 if options.help:
466 self.parser.print_help()
467 return
468
469 gST = exe_ctx.target.FindFirstGlobalVariable('gST')
470 if gST.error.fail:
471 print('Error: This command requires symbols for gST to be loaded')
472 return
473
474 file = LldbFileObject(exe_ctx.process)
475 table = EfiConfigurationTable(file, gST.unsigned)
476 if table:
477 print(table, '\n')
478
479
480class EfiGuidCommand:
481
482 def create_options(self):
483 ''' standard lldb command help/options parser'''
484 usage = "usage: %prog [options]"
485 description = '''
486 Command that can display all EFI GUID's or give info on a
487 specific GUID's
488 '''
489 self.parser = optparse.OptionParser(
490 description=description,
491 prog='guid',
492 usage=usage,
493 add_help_option=False)
494
495 self.parser.add_option(
496 '-n',
497 '--new',
498 action='store_true',
499 dest='new',
500 help='Generate a new GUID',
501 default=False)
502
503 self.parser.add_option(
504 '-v',
505 '--verbose',
506 action='store_true',
507 dest='verbose',
508 help='Also display GUID C structure values',
509 default=False)
510
511 self.parser.add_option(
512 '-h',
513 '--help',
514 action='store_true',
515 dest='help',
516 help='Show help for the command',
517 default=False)
518
519 def get_short_help(self):
520 '''standard lldb function method'''
521 return "Display EFI GUID's"
522
523 def get_long_help(self):
524 '''standard lldb function method'''
525 return self.help_string
526
527 def __init__(self, debugger, internal_dict):
528 '''standard lldb function method'''
529 self.create_options()
530 self.help_string = self.parser.format_help()
531
532 def __call__(self, debugger, command, exe_ctx, result):
533 '''standard lldb function method'''
534 # Use the Shell Lexer to properly parse up command options just like a
535 # shell would
536 command_args = shlex.split(command)
537
538 try:
539 (options, args) = self.parser.parse_args(command_args)
540 if len(args) >= 1:
541 # guid { 0x414e6bdd, 0xe47b, 0x47cc,
542 # { 0xb2, 0x44, 0xbb, 0x61, 0x02, 0x0c,0xf5, 0x16 }}
543 # this generates multiple args
544 arg = ' '.join(args)
545 except ValueError:
546 # if you don't handle exceptions, passing an incorrect argument
547 # to the OptionParser will cause LLDB to exit (courtesy of
548 # OptParse dealing with argument errors by throwing SystemExit)
549 result.SetError("option parsing failed")
550 return
551
552 if options.help:
553 self.parser.print_help()
554 return
555
556 if options.new:
557 guid = uuid.uuid4()
558 print(str(guid).upper())
559 print(GuidNames.to_c_guid(guid))
560 return
561
562 if len(args) > 0:
563 if GuidNames.is_guid_str(arg):
564 # guid 05AD34BA-6F02-4214-952E-4DA0398E2BB9
565 key = arg.lower()
566 name = GuidNames.to_name(key)
567 elif GuidNames.is_c_guid(arg):
568 # guid { 0x414e6bdd, 0xe47b, 0x47cc,
569 # { 0xb2, 0x44, 0xbb, 0x61, 0x02, 0x0c,0xf5, 0x16 }}
570 key = GuidNames.from_c_guid(arg)
571 name = GuidNames.to_name(key)
572 else:
573 # guid gEfiDxeServicesTableGuid
574 name = arg
575 try:
576 key = GuidNames.to_guid(name)
577 name = GuidNames.to_name(key)
578 except ValueError:
579 return
580
581 extra = f'{GuidNames.to_c_guid(key)}: ' if options.verbose else ''
582 print(f'{key}: {extra}{name}')
583
584 else:
585 for key, value in GuidNames._dict_.items():
586 if options.verbose:
587 extra = f'{GuidNames.to_c_guid(key)}: '
588 else:
589 extra = ''
590 print(f'{key}: {extra}{value}')
591
592
593class EfiSymbolicateCommand(object):
594 '''Class to abstract an lldb command'''
595
596 def create_options(self):
597 ''' standard lldb command help/options parser'''
598 usage = "usage: %prog [options]"
599 description = '''Command that can load EFI PE/COFF and TE image
600 symbols. If you are having trouble in PEI try adding --pei.
601 '''
602
603 # Pass add_help_option = False, since this keeps the command in line
604 # with lldb commands, and we wire up "help command" to work by
605 # providing the long & short help methods below.
606 self.parser = optparse.OptionParser(
607 description=description,
608 prog='efi_symbols',
609 usage=usage,
610 add_help_option=False)
611
612 self.parser.add_option(
613 '-a',
614 '--address',
615 type="int",
616 dest='address',
617 help='Load symbols for image at address',
618 default=None)
619
620 self.parser.add_option(
621 '-f',
622 '--frame',
623 action='store_true',
624 dest='frame',
625 help='Load symbols for current stack frame',
626 default=False)
627
628 self.parser.add_option(
629 '-p',
630 '--pc',
631 action='store_true',
632 dest='pc',
633 help='Load symbols for pc',
634 default=False)
635
636 self.parser.add_option(
637 '--pei',
638 action='store_true',
639 dest='pei',
640 help='Load symbols for PEI (searches every 4 bytes)',
641 default=False)
642
643 self.parser.add_option(
644 '-e',
645 '--extended',
646 action='store_true',
647 dest='extended',
648 help='Try to load all symbols based on config tables.',
649 default=False)
650
651 self.parser.add_option(
652 '-r',
653 '--range',
654 type="long",
655 dest='range',
656 help='How far to search backward for start of PE/COFF Image',
657 default=None)
658
659 self.parser.add_option(
660 '-s',
661 '--stride',
662 type="long",
663 dest='stride',
664 help='Boundary to search for PE/COFF header',
665 default=None)
666
667 self.parser.add_option(
668 '-t',
669 '--thread',
670 action='store_true',
671 dest='thread',
672 help='Load symbols for the frames of all threads',
673 default=False)
674
675 self.parser.add_option(
676 '-h',
677 '--help',
678 action='store_true',
679 dest='help',
680 help='Show help for the command',
681 default=False)
682
683 def get_short_help(self):
684 '''standard lldb function method'''
685 return (
686 "Load symbols based on an address that is part of"
687 " a PE/COFF EFI image.")
688
689 def get_long_help(self):
690 '''standard lldb function method'''
691 return self.help_string
692
693 def __init__(self, debugger, unused):
694 '''standard lldb function method'''
695 self.create_options()
696 self.help_string = self.parser.format_help()
697
698 def lldb_print(self, lldb_str):
699 # capture command out like an lldb command
700 self.result.PutCString(lldb_str)
701 # flush the output right away
702 self.result.SetImmediateOutputFile(
703 self.exe_ctx.target.debugger.GetOutputFile())
704
705 def __call__(self, debugger, command, exe_ctx, result):
706 '''standard lldb function method'''
707 # Use the Shell Lexer to properly parse up command options just like a
708 # shell would
709 command_args = shlex.split(command)
710
711 try:
712 (options, _) = self.parser.parse_args(command_args)
713 except ValueError:
714 # if you don't handle exceptions, passing an incorrect argument
715 # to the OptionParser will cause LLDB to exit (courtesy of
716 # OptParse dealing with argument errors by throwing SystemExit)
717 result.SetError("option parsing failed")
718 return
719
720 if options.help:
721 self.parser.print_help()
722 return
723
724 file = LldbFileObject(exe_ctx.process)
725 efi_symbols = EfiSymbols(exe_ctx.target)
726 self.result = result
727 self.exe_ctx = exe_ctx
728
729 if options.pei:
730 # XIP code ends up on a 4 byte boundary.
731 options.stride = 4
732 options.range = 0x100000
733 efi_symbols.configure_search(options.stride, options.range)
734
735 if not options.pc and options.address is None:
736 # default to
737 options.frame = True
738
739 if options.frame:
740 if not exe_ctx.frame.IsValid():
741 result.SetError("invalid frame")
742 return
743
744 threads = exe_ctx.process.threads if options.thread else [
745 exe_ctx.thread]
746
747 for thread in threads:
748 for frame in thread:
749 res = efi_symbols.address_to_symbols(frame.pc)
750 self.lldb_print(res)
751
752 else:
753 if options.address is not None:
754 address = options.address
755 elif options.pc:
756 try:
757 address = exe_ctx.thread.GetSelectedFrame().pc
758 except ValueError:
759 result.SetError("invalid pc")
760 return
761 else:
762 address = 0
763
764 res = efi_symbols.address_to_symbols(address.pc)
765 print(res)
766
767 if options.extended:
768
769 gST = exe_ctx.target.FindFirstGlobalVariable('gST')
770 if gST.error.fail:
771 print('Error: This command requires symbols to be loaded')
772 else:
773 table = EfiConfigurationTable(file, gST.unsigned)
774 for address, _ in table.DebugImageInfo():
775 res = efi_symbols.address_to_symbols(address)
776 self.lldb_print(res)
777
778 # keep trying module file names until we find a GUID xref file
779 for m in exe_ctx.target.modules:
780 if GuidNames.add_build_guid_file(str(m.file)):
781 break
782
783
784def CHAR16_TypeSummary(valobj, internal_dict):
785 '''
786 Display CHAR16 as a String in the debugger.
787 Note: utf-8 is returned as that is the value for the debugger.
788 '''
789 SBError = lldb.SBError()
790 Str = ''
791 if valobj.TypeIsPointerType():
792 if valobj.GetValueAsUnsigned() == 0:
793 return "NULL"
794
795 # CHAR16 * max string size 1024
796 for i in range(1024):
797 Char = valobj.GetPointeeData(i, 1).GetUnsignedInt16(SBError, 0)
798 if SBError.fail or Char == 0:
799 break
800 Str += chr(Char)
801 return 'L"' + Str + '"'
802
803 if valobj.num_children == 0:
804 # CHAR16
805 return "L'" + chr(valobj.unsigned) + "'"
806
807 else:
808 # CHAR16 []
809 for i in range(valobj.num_children):
810 Char = valobj.GetChildAtIndex(i).data.GetUnsignedInt16(SBError, 0)
811 if Char == 0:
812 break
813 Str += chr(Char)
814 return 'L"' + Str + '"'
815
816 return Str
817
818
819def CHAR8_TypeSummary(valobj, internal_dict):
820 '''
821 Display CHAR8 as a String in the debugger.
822 Note: utf-8 is returned as that is the value for the debugger.
823 '''
824 SBError = lldb.SBError()
825 Str = ''
826 if valobj.TypeIsPointerType():
827 if valobj.GetValueAsUnsigned() == 0:
828 return "NULL"
829
830 # CHAR8 * max string size 1024
831 for i in range(1024):
832 Char = valobj.GetPointeeData(i, 1).GetUnsignedInt8(SBError, 0)
833 if SBError.fail or Char == 0:
834 break
835 Str += chr(Char)
836 Str = '"' + Str + '"'
837 return Str
838
839 if valobj.num_children == 0:
840 # CHAR8
841 return "'" + chr(valobj.unsigned) + "'"
842 else:
843 # CHAR8 []
844 for i in range(valobj.num_children):
845 Char = valobj.GetChildAtIndex(i).data.GetUnsignedInt8(SBError, 0)
846 if SBError.fail or Char == 0:
847 break
848 Str += chr(Char)
849 return '"' + Str + '"'
850
851 return Str
852
853
854def EFI_STATUS_TypeSummary(valobj, internal_dict):
855 if valobj.TypeIsPointerType():
856 return ''
857 return str(EfiStatusClass(valobj.unsigned))
858
859
860def EFI_TPL_TypeSummary(valobj, internal_dict):
861 if valobj.TypeIsPointerType():
862 return ''
863 return str(EfiTpl(valobj.unsigned))
864
865
866def EFI_GUID_TypeSummary(valobj, internal_dict):
867 if valobj.TypeIsPointerType():
868 return ''
869 return str(GuidNames(bytes(valobj.data.uint8)))
870
871
872def EFI_BOOT_MODE_TypeSummary(valobj, internal_dict):
873 if valobj.TypeIsPointerType():
874 return ''
875 '''Return #define name for EFI_BOOT_MODE'''
876 return str(EfiBootMode(valobj.unsigned))
877
878
879def lldb_type_formaters(debugger, mod_name):
880 '''Teach lldb about EFI types'''
881
882 category = debugger.GetDefaultCategory()
883 FormatBool = lldb.SBTypeFormat(lldb.eFormatBoolean)
884 category.AddTypeFormat(lldb.SBTypeNameSpecifier("BOOLEAN"), FormatBool)
885
886 FormatHex = lldb.SBTypeFormat(lldb.eFormatHex)
887 category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT64"), FormatHex)
888 category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT64"), FormatHex)
889 category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT32"), FormatHex)
890 category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT32"), FormatHex)
891 category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT16"), FormatHex)
892 category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT16"), FormatHex)
893 category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINT8"), FormatHex)
894 category.AddTypeFormat(lldb.SBTypeNameSpecifier("INT8"), FormatHex)
895 category.AddTypeFormat(lldb.SBTypeNameSpecifier("UINTN"), FormatHex)
896 category.AddTypeFormat(lldb.SBTypeNameSpecifier("INTN"), FormatHex)
897 category.AddTypeFormat(lldb.SBTypeNameSpecifier("CHAR8"), FormatHex)
898 category.AddTypeFormat(lldb.SBTypeNameSpecifier("CHAR16"), FormatHex)
899 category.AddTypeFormat(lldb.SBTypeNameSpecifier(
900 "EFI_PHYSICAL_ADDRESS"), FormatHex)
901 category.AddTypeFormat(lldb.SBTypeNameSpecifier(
902 "PHYSICAL_ADDRESS"), FormatHex)
903 category.AddTypeFormat(lldb.SBTypeNameSpecifier("EFI_LBA"), FormatHex)
904 category.AddTypeFormat(
905 lldb.SBTypeNameSpecifier("EFI_BOOT_MODE"), FormatHex)
906 category.AddTypeFormat(lldb.SBTypeNameSpecifier(
907 "EFI_FV_FILETYPE"), FormatHex)
908
909 #
910 # Smart type printing for EFI
911 #
912
913 debugger.HandleCommand(
914 f'type summary add GUID - -python-function '
915 f'{mod_name}.EFI_GUID_TypeSummary')
916 debugger.HandleCommand(
917 f'type summary add EFI_GUID --python-function '
918 f'{mod_name}.EFI_GUID_TypeSummary')
919 debugger.HandleCommand(
920 f'type summary add EFI_STATUS --python-function '
921 f'{mod_name}.EFI_STATUS_TypeSummary')
922 debugger.HandleCommand(
923 f'type summary add EFI_TPL - -python-function '
924 f'{mod_name}.EFI_TPL_TypeSummary')
925 debugger.HandleCommand(
926 f'type summary add EFI_BOOT_MODE --python-function '
927 f'{mod_name}.EFI_BOOT_MODE_TypeSummary')
928
929 debugger.HandleCommand(
930 f'type summary add CHAR16 --python-function '
931 f'{mod_name}.CHAR16_TypeSummary')
932
933 # W605 this is the correct escape sequence for the lldb command
934 debugger.HandleCommand(
935 f'type summary add --regex "CHAR16 \[[0-9]+\]" ' # noqa: W605
936 f'--python-function {mod_name}.CHAR16_TypeSummary')
937
938 debugger.HandleCommand(
939 f'type summary add CHAR8 --python-function '
940 f'{mod_name}.CHAR8_TypeSummary')
941
942 # W605 this is the correct escape sequence for the lldb command
943 debugger.HandleCommand(
944 f'type summary add --regex "CHAR8 \[[0-9]+\]" ' # noqa: W605
945 f'--python-function {mod_name}.CHAR8_TypeSummary')
946
947
948class LldbWorkaround:
949 needed = True
950
951 @classmethod
952 def activate(cls):
953 if cls.needed:
954 lldb.debugger.HandleCommand("process handle SIGALRM -n false")
955 cls.needed = False
956
957
958def LoadEmulatorEfiSymbols(frame, bp_loc, internal_dict):
959 #
960 # This is an lldb breakpoint script, and assumes the breakpoint is on a
961 # function with the same prototype as SecGdbScriptBreak(). The
962 # argument names are important as lldb looks them up.
963 #
964 # VOID
965 # SecGdbScriptBreak (
966 # char *FileName,
967 # int FileNameLength,
968 # long unsigned int LoadAddress,
969 # int AddSymbolFlag
970 # )
971 # {
972 # return;
973 # }
974 #
975 # When the emulator loads a PE/COFF image, it calls the stub function with
976 # the filename of the symbol file, the length of the FileName, the
977 # load address and a flag to indicate if this is a load or unload operation
978 #
979 LldbWorkaround().activate()
980
981 symbols = EfiSymbols(frame.thread.process.target)
982 LoadAddress = frame.FindVariable("LoadAddress").unsigned
983 if frame.FindVariable("AddSymbolFlag").unsigned == 1:
984 res = symbols.address_to_symbols(LoadAddress)
985 else:
986 res = symbols.unload_symbols(LoadAddress)
987 print(res)
988
989 # make breakpoint command continue
990 return False
991
992
993def __lldb_init_module(debugger, internal_dict):
994 '''
995 This initializer is being run from LLDB in the embedded command interpreter
996 '''
997
998 mod_name = Path(__file__).stem
999 lldb_type_formaters(debugger, mod_name)
1000
1001 # Add any commands contained in this module to LLDB
1002 debugger.HandleCommand(
1003 f'command script add -c {mod_name}.EfiSymbolicateCommand efi_symbols')
1004 debugger.HandleCommand(
1005 f'command script add -c {mod_name}.EfiGuidCommand guid')
1006 debugger.HandleCommand(
1007 f'command script add -c {mod_name}.EfiTableCommand table')
1008 debugger.HandleCommand(
1009 f'command script add -c {mod_name}.EfiHobCommand hob')
1010 debugger.HandleCommand(
1011 f'command script add -c {mod_name}.EfiDevicePathCommand devicepath')
1012
1013 print('EFI specific commands have been installed.')
1014
1015 # patch the ctypes c_void_p values if the debuggers OS and EFI have
1016 # different ideas on the size of the debug.
1017 try:
1018 patch_ctypes(debugger.GetSelectedTarget().addr_size)
1019 except ValueError:
1020 # incase the script is imported and the debugger has not target
1021 # defaults to sizeof(UINTN) == sizeof(UINT64)
1022 patch_ctypes()
1023
1024 try:
1025 target = debugger.GetSelectedTarget()
1026 if target.FindFunctions('SecGdbScriptBreak').symbols:
1027 breakpoint = target.BreakpointCreateByName('SecGdbScriptBreak')
1028 # Set the emulator breakpoints, if we are in the emulator
1029 cmd = 'breakpoint command add -s python -F '
1030 cmd += f'efi_lldb.LoadEmulatorEfiSymbols {breakpoint.GetID()}'
1031 debugger.HandleCommand(cmd)
1032 print('Type r to run emulator.')
1033 else:
1034 raise ValueError("No Emulator Symbols")
1035
1036 except ValueError:
1037 # default action when the script is imported
1038 debugger.HandleCommand("efi_symbols --frame --extended")
1039 debugger.HandleCommand("register read")
1040 debugger.HandleCommand("bt all")
1041
1042
1043if __name__ == '__main__':
1044 pass
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette