From bf86433ea8a32b60d04f26dd1ad0879e1fd8c845 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Thu, 10 Jan 2019 18:30:53 +0300 Subject: [PATCH] Add debug scripts and fix NOOPT build --- Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll | Bin 0 -> 130369 bytes Debug/GdbSyms/GdbSyms.c | 79 +++ Debug/GdbSyms/GdbSyms.inf | 57 ++ Debug/README.md | 88 +++ Debug/Scripts/gdb_uefi.py | 671 ++++++++++++++++++ Debug/macgdb.tool | 28 + Include/Library/OcMiscLib.h | 18 + .../OcDevicePropertyLib/OcDevicePropertyLib.c | 6 +- Library/OcMiscLib/DebugHelp.c | 63 ++ Library/OcMiscLib/OcMiscLib.inf | 1 + OcSupportPkg.dsc | 10 +- 11 files changed, 1015 insertions(+), 6 deletions(-) create mode 100644 Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll create mode 100644 Debug/GdbSyms/GdbSyms.c create mode 100644 Debug/GdbSyms/GdbSyms.inf create mode 100644 Debug/README.md create mode 100644 Debug/Scripts/gdb_uefi.py create mode 100755 Debug/macgdb.tool create mode 100644 Library/OcMiscLib/DebugHelp.c diff --git a/Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll b/Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll new file mode 100644 index 0000000000000000000000000000000000000000..b1e49b6c92f96dae66064eb0b70b33a69b561e60 GIT binary patch literal 130369 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 G8Tvm4%iqxe literal 0 HcmV?d00001 diff --git a/Debug/GdbSyms/GdbSyms.c b/Debug/GdbSyms/GdbSyms.c new file mode 100644 index 00000000..2e23ed94 --- /dev/null +++ b/Debug/GdbSyms/GdbSyms.c @@ -0,0 +1,79 @@ +/** @file + + Bare-minimum GDB symbols needed for reloading symbols. + + This is not a "driver" and should not be placed in a FD. + + Copyright (c) 2011, Andrei Warkentin + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PiDxe.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Main entry point. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Successfully initialized. + +**/ +EFI_STATUS +EFIAPI +Initialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_SYSTEM_TABLE_POINTER ESTP; + EFI_DEBUG_IMAGE_INFO_TABLE_HEADER EDIITH; + EFI_IMAGE_DOS_HEADER EIDH; + EFI_IMAGE_OPTIONAL_HEADER_UNION EIOHU; + EFI_IMAGE_SECTION_HEADER EISH; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY EIDDE; + EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY EIDCNE; + EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY EIDCRE; + EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY EIDCME; + UINTN Dummy = + (UINTN) &ESTP | + (UINTN) &EDIITH | + (UINTN) &EIDH | + (UINTN) &EIOHU | + (UINTN) &EISH | + (UINTN) &EIDDE | + (UINTN) &EIDCNE | + (UINTN) &EIDCRE | + (UINTN) &EIDCME | + 1 + ; + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &ESTP)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EDIITH)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIDH)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIOHU)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EISH)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIDDE)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIDCNE)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIDCRE)); + DEBUG ((DEBUG_VERBOSE, "%a: %llx\n", __FUNCTION__, &EIDCME)); + return !!Dummy & EFI_SUCCESS; +} diff --git a/Debug/GdbSyms/GdbSyms.inf b/Debug/GdbSyms/GdbSyms.inf new file mode 100644 index 00000000..89dfd395 --- /dev/null +++ b/Debug/GdbSyms/GdbSyms.inf @@ -0,0 +1,57 @@ +## @file +# +# Bare-minimum GDB symbols needed for reloading symbols. +# +# This is not a "driver" and should not be placed in a FD. +# +# Copyright (c) 2011, Andrei Warkentin +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSyms + FILE_GUID = 22abcb60-fb40-42ac-b01f-3ab1fad9aad8 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Initialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM +# + +[Sources] + GdbSyms.c + +[Packages] + OcSupportPkg/OcSupportPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DxeServicesTableLib + HobLib + MemoryAllocationLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Guids] + +[Protocols] + +[Depex] + TRUE diff --git a/Debug/README.md b/Debug/README.md new file mode 100644 index 00000000..d898172b --- /dev/null +++ b/Debug/README.md @@ -0,0 +1,88 @@ +UEFI Debugging with GDB +======================= + +These scripts provide support for easier UEFI code debugging on virtual machines like VMware Fusion +or QEMU. The code is based on [Andrei Warkentin](https://github.com/andreiw)'s +[DebugPkg](https://github.com/andreiw/andreiw-wip/tree/master/uefi/DebugPkg) with improvements +in macOS support, pretty printing, and bug fixing. + +The general approach is as follows: + +1. Build GdbSyms binary with EDK II type info in DWARF +1. Locate `EFI_SYSTEM_TABLE` in memory by its magic +1. Locate `EFI_DEBUG_IMAGE_INFO_TABLE` by its GUID +1. Map relocated images within GDB +1. Provide handy functions and pretty printers + +#### Preparing Source Code + +By default EDK II optimises produced binaries, so to build a "real" debug binary one should target +`NOOPT`. Do be aware that it strongly affects resulting binary size. + +`GdbSyms.dll` is built as a part of OcSupportPkg, yet prebuilt binaries are also available: + +- `GdbSyms/Bin/X64_XCODE5/GdbSyms.dll` is built with UDK2018 and XCODE5 + +To wait for debugger connection on startup `WaitForKeyPress` functions from `OcMiscLib.h` can be +utilised. Do be aware that this function additionally calls `DebugBreak` function, which may +be broken at during GDB init. + +#### VMware Configuration + +VMware Fusion contains a dedicated debugStub, which can be enabled by adding the following +lines to .vmx file. Afterwards vmware-vmx will listen on TCP ports 8832 and 8864 (on the host) +for 32-bit and 64-bit gdb connections respectively, similarly to QEMU: +``` +debugStub.listen.guest32 = "TRUE" +debugStub.listen.guest64 = "TRUE" +``` + +In case the debugging session is remote the following lines should be appended: +``` +debugStub.listen.guest32.remote = "TRUE" +debugStub.listen.guest64.remote = "TRUE" +``` + +To halt the virtual machine upon executing the first instruction the following line code be added. +Note, that it does not seem to work on VMware Fusion 11 and results in freezes: +``` +monitor.debugOnStartGuest32 = "TRUE" +``` + +To force hardware breakpoints (instead of software INT 3 breakpoints) add the following line: +``` +debugStub.hideBreakpoints = "TRUE" +``` + +To stall during POST for 3 seconds add the following line. Pressing any key will boot into firmware +settings: +``` +bios.bootDelay = "3000" +``` + +#### GDB Configuration + +It is a good idea to use GDB Multiarch in case different debugging architectures are planned to be +used. This can be done in several ways: + +- https://www.gnu.org/software/gdb/ — from source +- https://macports.org/ — via MacPorts (`sudo port install gdb +multiarch`) +- Your preferred method here + +Once GDB is installed the process is as simple as running the following set of commands: + +``` +$ ggdb /opt/UDK/Build/OcSupportPkg/NOOPT_XCODE5/X64/OcSupportPkg/Debug/GdbSyms/GdbSyms/DEBUG/GdbSyms.dll.dSYM/Contents/Resources/DWARF/GdbSyms.dll + +target remote localhost:8864 +source /opt/UDK/OcSupportPkg/Debug/Scripts/gdb_uefi.py +set pagination off +reload-uefi +b DebugBreak +``` + +#### References + +1. https://communities.vmware.com/thread/390128 +1. https://wiki.osdev.org/VMware +1. https://github.com/andreiw/andreiw-wip/tree/master/uefi/DebugPkg diff --git a/Debug/Scripts/gdb_uefi.py b/Debug/Scripts/gdb_uefi.py new file mode 100644 index 00000000..4e935b55 --- /dev/null +++ b/Debug/Scripts/gdb_uefi.py @@ -0,0 +1,671 @@ +""" +Allows loading TianoCore symbols into a GDB session attached to EFI +Firmware. + +This is how it works: build GdbSyms - it's a dummy binary that +contains the relevant symbols needed to find and load image symbols. + +$ gdb /path/to/GdbSyms.dll +(gdb) target remote .... +(gdb) source Scripts/gdb_uefi.py +(gdb) reload-uefi -o /path/to/GdbSyms.dll + +N.B: it was noticed that GDB for certain targets behaves strangely +when run without any binary - like assuming a certain physical +address space size and endianness. To avoid this madness and +seing strange bugs, make sure to pass /path/to/GdbSyms.dll +when starting gdb. + +The -o option should be used if you've debugging EFI, where the PE +images were converted from MACH-O or ELF binaries. + +""" + +import array +import getopt +import binascii +import re +import sys +import os +import subprocess + +__license__ = "BSD" +__version = "1.0.0" +__maintainer__ = "Andrei Warkentin" +__email__ = "andrey.warkentin@gmail.com" +__status__ = "Works" + +if sys.version_info > (3,): + long = int + +class UefiMisc(): + # + # Returns string corresponding to type value in specified charset. + # + @classmethod + def parse_string (cls, value, type, charset): + index = 0 + data = array.array (type) + while value[index] != 0: + # TODO: add more ASCII symbols? + v = value[index] + if v == 0x0A: # \n + data.append(0x5C) + data.append(0x6E) + elif v == 0x0D: # \r + data.append(0x5C) + data.append(0x72) + elif v == 0x09: # \t + data.append(0x5C) + data.append(0x74) + elif v == 0x22: # " + data.append(0x5C) + data.append(0x22) + elif v == 0x5C: # \ + data.append(0x5C) + data.append(0x5C) + else: + data.append (v) + index = index + 1 + return data.tostring ().decode (charset) + + # + # Returns a UTF16 string corresponding to a (CHAR16 *) value in EFI. + # + @classmethod + def parse_utf16 (cls, value): + return UefiMisc.parse_string (value, 'H', 'utf-16') + + # + # Returns a UTF8 string corresponding to a (CHAR8 *) value in EFI. + # + @classmethod + def parse_utf8 (cls, value): + return UefiMisc.parse_string (value, 'B', 'utf-8') + + # + # Returns a printable EFI or RETURN status. + # + @classmethod + def parse_status (cls, value, efi): + suffix = '' + err = 0 + val = long(value) + if val & 0x80000000: + err = val & ~0x80000000 + elif val & 0x8000000000000000: + err = val & ~0x8000000000000000 + + if err != 0: + # TODO: make this a collection... + if err == 1: + suffix = 'LOAD_ERROR' + elif err == 2: + suffix = 'INVALID_PARAMETER' + elif err == 3: + suffix = 'UNSUPPORTED' + elif err == 4: + suffix = 'BAD_BUFFER_SIZE' + elif err == 5: + suffix = 'BUFFER_TOO_SMALL' + elif err == 6: + suffix = 'NOT_READY' + elif err == 7: + suffix = 'DEVICE_ERROR' + elif err == 8: + suffix = 'WRITE_PROTECTED' + elif err == 9: + suffix = 'OUT_OF_RESOURCES' + elif err == 10: + suffix = 'VOLUME_CORRUPTED' + elif err == 11: + suffix = 'VOLUME_FULL' + elif err == 12: + suffix = 'NO_MEDIA' + elif err == 13: + suffix = 'MEDIA_CHANGED' + elif err == 14: + suffix = 'NOT_FOUND' + elif err == 15: + suffix = 'ACCESS_DENIED' + elif err == 16: + suffix = 'NO_RESPONSE' + elif err == 17: + suffix = 'NO_MAPPING' + elif err == 18: + suffix = 'TIMEOUT' + elif err == 19: + suffix = 'NOT_STARTED' + elif err == 20: + suffix = 'ALREADY_STARTED' + elif err == 21: + suffix = 'ABORTED' + elif err == 22: + suffix = 'ICMP_ERROR' + elif err == 23: + suffix = 'TFTP_ERROR' + elif err == 24: + suffix = 'PROTOCOL_ERROR' + elif err == 25: + suffix = 'INCOMPATIBLE_VERSION' + elif err == 26: + suffix = 'SECURITY_VIOLATION' + elif err == 27: + suffix = 'CRC_ERROR' + elif err == 28: + suffix = 'END_OF_MEDIA' + elif err == 31: + suffix = 'END_OF_FILE' + elif err == 32: + suffix = 'INVALID_LANGUAGE' + elif err == 33: + suffix = 'COMPROMISED_DATA' + elif err == 35: + suffix = 'HTTP_ERROR' + elif efi and err == 100: + suffix = 'NETWORK_UNREACHABLE' + elif efi and err == 101: + suffix = 'HOST_UNREACHABLE' + elif efi and err == 102: + suffix = 'PROTOCOL_UNREACHABLE' + elif efi and err == 103: + suffix = 'PORT_UNREACHABLE' + elif efi and err == 104: + suffix = 'CONNECTION_FIN' + elif efi and err == 105: + suffix = 'CONNECTION_RESET' + elif efi and err == 106: + suffix = 'CONNECTION_REFUSED' + else: + if val == 0: + suffix = 'SUCCESS' + elif val == 1: + suffix = 'WARN_UNKNOWN_GLYPH' + elif val == 2: + suffix = 'WARN_DELETE_FAILURE' + elif val == 3: + suffix = 'WARN_WRITE_FAILURE' + elif val == 4: + suffix = 'WARN_BUFFER_TOO_SMALL' + elif val == 5: + suffix = 'WARN_STALE_DATA' + elif val == 6: + suffix = 'WARN_FILE_SYSTEM' + if suffix != '': + return ('EFI_' if efi else 'RETURN_') + suffix + return hex(val) + + # + # Returns a UTF16 string corresponding to a (CHAR16 *) value in EFI. + # + @classmethod + def parse_guid (cls, value): + guid = "<%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>" % ( + value['Data1'], + value['Data2'], + value['Data3'], + value['Data4'][0], + value['Data4'][1], + value['Data4'][2], + value['Data4'][3], + value['Data4'][4], + value['Data4'][5], + value['Data4'][6], + value['Data4'][7]) + return guid + +class ReloadUefi (gdb.Command): + """Reload UEFI symbols""" + + # + # Various constants. + # + + EINVAL = 0xffffffff + CV_NB10 = 0x3031424E + CV_RSDS = 0x53445352 + CV_MTOC = 0x434F544D + DOS_MAGIC = 0x5A4D + PE32PLUS_MAGIC = 0x20b + EST_SIGNATURE = 0x5453595320494249L + DEBUG_GUID = [0x49152E77, 0x1ADA, 0x4764, + [0xB7,0xA2,0x7A,0xFE, + 0xFE,0xD9,0x5E, 0x8B]] + DEBUG_IS_UPDATING = 0x1 + + # + # If the images were built as ELF/MACH-O and then converted to PE, + # then the base address needs to be offset by PE headers. + # + + offset_by_headers = False + + def __init__ (self): + super (ReloadUefi, self).__init__ ("reload-uefi", gdb.COMMAND_OBSCURE) + + # + # Returns gdb.Type for a type. + # + + def type (self, typename): + return gdb.lookup_type (typename) + + # + # Returns gdb.Type for a pointer to a type. + # + + def ptype (self, typename): + return gdb.lookup_type (typename).pointer () + + # + # Computes CRC32 on an array of data. + # + + def crc32 (self, data): + return binascii.crc32 (data) & 0xFFFFFFFF + + # + # Sets a field in a struct to a value, i.e. + # value->field_name = data. + # + # Newer Py bindings to Gdb provide access to the inferior + # memory, but not all, so have to do it this awkward way. + # + + def set_field (self, value, field_name, data): + gdb.execute ("set *(%s *) 0x%x = 0x%x" % \ + (str (value[field_name].type), \ + long (value[field_name].address), data)) + + # + # Returns data backing a gdb.Value as an array. + # Same comment as above regarding newer Py bindings... + # + + def value_data (self, value, bytes=0): + value_address = gdb.Value (value.address) + array_t = self.ptype ('UINT8') + value_array = value_address.cast (array_t) + if bytes == 0: + bytes = value.type.sizeof + data = array.array ('B') + for i in range (0, bytes): + data.append (value_array[i]) + return data + + # + # Locates the EFI_SYSTEM_TABLE as per UEFI spec 17.4. + # Returns base address or -1. + # + + def search_est (self): + address = 0 + estp_t = self.ptype ('EFI_SYSTEM_TABLE_POINTER') + while True: + try: + estp = gdb.Value(address).cast(estp_t) + if estp['Signature'] == self.EST_SIGNATURE: + oldcrc = long(estp['Crc32']) + self.set_field (estp, 'Crc32', 0) + newcrc = self.crc32 (self.value_data (estp.dereference (), 0)) + self.set_field (estp, 'Crc32', long(oldcrc)) + if newcrc == oldcrc: + return estp['EfiSystemTableBase'] + except gdb.MemoryError: + pass + + address = address + 4*1024*1024 + if long(address) == 0: + return gdb.Value(self.EINVAL) + + # + # Searches for a vendor-specific configuration table (in EST), + # given a vendor-specific table GUID. GUID is a list like - + # [32-bit, 16-bit, 16-bit, [8 bytes]] + # + + def search_config (self, cfg_table, count, guid): + index = 0 + while index != count: + cfg_entry = cfg_table[index]['VendorGuid'] + if cfg_entry['Data1'] == guid[0] and \ + cfg_entry['Data2'] == guid[1] and \ + cfg_entry['Data3'] == guid[2] and \ + self.value_data (cfg_entry['Data4']).tolist () == guid[3]: + return cfg_table[index]['VendorTable'] + index = index + 1 + return gdb.Value(self.EINVAL) + + # + # Returns offset of a field within structure. Useful + # for getting container of a structure. + # + + def offsetof (self, typename, field): + t = gdb.Value (0).cast (self.ptype (typename)) + return long(t[field].address) + + # + # Returns sizeof of a type. + # + + def sizeof (self, typename): + return self.type (typename).sizeof + + # + # Returns the EFI_IMAGE_NT_HEADERS32 pointer, given + # an ImageBase address as a gdb.Value. + # + + def pe_headers (self, imagebase): + dosh_t = self.ptype ('EFI_IMAGE_DOS_HEADER') + head_t = self.ptype ('EFI_IMAGE_OPTIONAL_HEADER_UNION') + dosh = imagebase.cast (dosh_t) + h_addr = imagebase + if dosh['e_magic'] == self.DOS_MAGIC: + h_addr = h_addr + dosh['e_lfanew'] + return gdb.Value(h_addr).cast (head_t) + + def pe_sections (self, opt, file, imagebase): + sect_t = self.ptype ('EFI_IMAGE_SECTION_HEADER') + sections = (opt.address + 1).cast (sect_t) + sects = {} + for i in xrange (file['NumberOfSections']): + name = UefiMisc.parse_utf8 (sections[i]['Name']) + addr = long(sections[i]['VirtualAddress']) + if name != '': + sects[name] = addr + return sects + + # TODO: implement pe sections + + # + # Returns True if pe_headers refer to a PE32+ image. + # + + def pe_is_64 (self, pe_headers): + if pe_headers['Pe32']['OptionalHeader']['Magic'] == self.PE32PLUS_MAGIC: + return True + return False + + # + # Returns the PE fileheader. + # + + def pe_file (self, pe): + if self.pe_is_64 (pe): + return pe['Pe32Plus']['FileHeader'] + else: + return pe['Pe32']['FileHeader'] + + # + # Returns the PE (not so) optional header. + # + + def pe_optional (self, pe): + if self.pe_is_64 (pe): + return pe['Pe32Plus']['OptionalHeader'] + else: + return pe['Pe32']['OptionalHeader'] + + # + # Returns the symbol file name for a PE image. + # + + def pe_parse_debug (self, pe): + opt = self.pe_optional (pe) + debug_dir_entry = opt['DataDirectory'][6] + dep = debug_dir_entry['VirtualAddress'] + opt['ImageBase'] + dep = dep.cast (self.ptype ('EFI_IMAGE_DEBUG_DIRECTORY_ENTRY')) + cvp = dep.dereference ()['RVA'] + opt['ImageBase'] + cvv = cvp.cast(self.ptype ('UINT32')).dereference () + if cvv == self.CV_NB10: + return cvp + self.sizeof('EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY') + elif cvv == self.CV_RSDS: + return cvp + self.sizeof('EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY') + elif cvv == self.CV_MTOC: + return cvp + self.sizeof('EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY') + return gdb.Value(self.EINVAL) + + # + # Prepares gdb symbol load command with proper section information. + # Currently supports Mach-O and single-section files. + # + # TODO: Proper ELF support. + # + def get_sym_cmd (self, file, orgbase, sections, macho, fallack_base): + cmd = 'add-symbol-file %s' % file + + # Fallback case, no sections, just load .text. + if not sections.get('.text') or not sections.get('.data'): + cmd += ' 0x%x' % (fallack_base) + return cmd + + cmd += ' 0x%x' % (long(orgbase) + sections['.text']) + + if not macho or not os.path.exists(file): + # Another fallback, try to load data at least. + cmd += ' -s .data 0x%x' % (long(orgbase) + sections['.data']) + return cmd + + # 1. Parse Mach-O. + # FIXME: We should not rely on otool really. + commands = subprocess.check_output(['otool', '-l', file]) + in_sect = False + machsections = {} + for line in commands.split('\n'): + line = line.strip() + if line.startswith('Section'): + in_sect = True + sectname = None + segname = None + elif in_sect: + if line.startswith('sectname'): + sectname = line.split()[1] + elif line.startswith('segname'): + segname = line.split()[1] + elif line.startswith('addr'): + machsections[segname + '.' + sectname] = long(line.split()[1], base=16) + in_sect = False + + # 2. Convert section names to gdb sections. + mapping = { + '__TEXT.__cstring': '.cstring', + '__TEXT.__const': '.const', + '__TEXT.__ustring': '__TEXT.__ustring', + '__DATA.__const': '.const_data', + '__DATA.__data': '.data', + '__DATA.__bss': '.bss', + '__DATA.__common': '__DATA.__common', + # FIXME: These should not be loadable, but gdb still loads them :/ + # '__DWARF.__apple_names': '__DWARF.__apple_names', + # '__DWARF.__apple_namespac': '__DWARF.__apple_namespac', + # '__DWARF.__apple_types': '__DWARF.__apple_types', + # '__DWARF.__apple_objc': '__DWARF.__apple_objc', + } + + # 3. Rebase. + for entry in mapping: + if machsections.get(entry): + cmd += ' -s %s 0x%x' % (mapping[entry], long(orgbase) + machsections[entry]) + + return cmd + + # + # Parses an EFI_LOADED_IMAGE_PROTOCOL, figuring out the symbol file name. + # This file name is then appended to list of loaded symbols. + # + # TODO: Support TE images. + # + + def parse_image (self, image, syms): + orgbase = base = image['ImageBase'] + pe = self.pe_headers (base) + opt = self.pe_optional (pe) + file = self.pe_file (pe) + sym_name = self.pe_parse_debug (pe) + sections = self.pe_sections (opt, file, base) + + # For ELF and Mach-O-derived images... + if self.offset_by_headers: + base = base + opt['SizeOfHeaders'] + if sym_name != self.EINVAL: + sym_name = sym_name.cast (self.ptype('CHAR8')).string () + sym_name_dbg = re.sub(r"\.dll$", ".debug", sym_name) + macho = False + if os.path.isdir(sym_name + '.dSYM'): + sym_name += '.dSYM/Contents/Resources/DWARF/' + os.path.basename(sym_name) + macho = True + elif sym_name_dbg != sym_name and os.path.exists(sym_name_dbg): + # TODO: implement .elf handling. + sym_name = sym_name_dbg + syms.append (self.get_sym_cmd (sym_name, long(orgbase), sections, macho, long(base))) + + # + # Parses table EFI_DEBUG_IMAGE_INFO structures, builds + # a list of add-symbol-file commands, and reloads debugger + # symbols. + # + + def parse_edii (self, edii, count): + index = 0 + syms = [] + while index != count: + entry = edii[index] + if entry['ImageInfoType'].dereference () == 1: + entry = entry['NormalImage'] + self.parse_image(entry['LoadedImageProtocolInstance'], syms) + else: + print ("Skipping unknown EFI_DEBUG_IMAGE_INFO (Type 0x%x)" % \ + entry['ImageInfoType'].dereference ()) + index = index + 1 + gdb.execute ("symbol-file") + print ("Loading new symbols...") + for sym in syms: + try: + gdb.execute (sym) + except (gdb.error) as err: + print ('Failed: %s' % err) + + # + # Parses EFI_DEBUG_IMAGE_INFO_TABLE_HEADER, in order to load + # image symbols. + # + + def parse_dh (self, dh): + dh_t = self.ptype ('EFI_DEBUG_IMAGE_INFO_TABLE_HEADER') + dh = dh.cast (dh_t) + print ("DebugImageInfoTable @ 0x%x, 0x%x entries" % \ + (long (dh['EfiDebugImageInfoTable']), dh['TableSize'])) + if dh['UpdateStatus'] & self.DEBUG_IS_UPDATING: + print ("EfiDebugImageInfoTable update in progress, retry later") + return + self.parse_edii (dh['EfiDebugImageInfoTable'], dh['TableSize']) + + # + # Parses EFI_SYSTEM_TABLE, in order to load image symbols. + # + + def parse_est (self, est): + est_t = self.ptype ('EFI_SYSTEM_TABLE') + est = est.cast (est_t) + print ("Connected to %s (Rev. 0x%x)" % \ + (UefiMisc.parse_utf16 (est['FirmwareVendor']), \ + long (est['FirmwareRevision']))) + print ("ConfigurationTable @ 0x%x, 0x%x entries" % \ + (long (est['ConfigurationTable']), est['NumberOfTableEntries'])) + + dh = self.search_config(est['ConfigurationTable'], + est['NumberOfTableEntries'], self.DEBUG_GUID) + if dh == self.EINVAL: + print ("No EFI_DEBUG_IMAGE_INFO_TABLE_HEADER") + return + self.parse_dh (dh) + + # + # Usage information. + # + + def usage (self): + print ("Usage: reload-uefi [-o] [/path/to/GdbSyms.dll]") + + # + # Handler for reload-uefi. + # + + def invoke (self, arg, from_tty): + args = arg.split(' ') + try: + opts, args = getopt.getopt(args, "o", ["offset-by-headers"]) + except (getopt.GetoptError) as err: + self.usage () + return + for opt, arg in opts: + if opt == "-o": + self.offset_by_headers = True + + if len(args) >= 1 and args[0] != '': + gdb.execute ("symbol-file") + gdb.execute ("symbol-file %s" % args[0]) + else: + # FIXME: gdb.objfiles () loses files after symbol-file execution, + # so we have to extract GdbSymbs.dll manually. + lines = gdb.execute ("info files", to_string=True).split('\n') + for line in lines: + m = re.search("`([^']+)'", line) + if m: + gdb.execute ("symbol-file") + gdb.execute ("symbol-file %s" % m.group(1)) + break + + est = self.search_est () + if est == self.EINVAL: + print ("No EFI_SYSTEM_TABLE...") + return + + print ("EFI_SYSTEM_TABLE @ 0x%x" % est) + self.parse_est (est) + +class UefiStringPrinter: + def __init__(self, val): + self.val = val + + def to_string (self): + if not self.val: + return "NULL" + return 'L"' + UefiMisc.parse_utf16(self.val) + '"' + +class UefiEfiStatusPrinter: + def __init__(self, val): + self.val = val + + def to_string (self): + return UefiMisc.parse_status(self.val, True) + +class UefiReturnStatusPrinter: + def __init__(self, val): + self.val = val + + def to_string (self): + return UefiMisc.parse_status(self.val, False) + +class UefiGuidPrinter: + def __init__(self, val): + self.val = val + + def to_string (self): + return UefiMisc.parse_guid(self.val) + +def lookup_uefi_type (val): + if str(val.type) == 'const CHAR16 *' or str(val.type) == 'CHAR16 *': + return UefiStringPrinter(val) + elif str(val.type) == 'EFI_STATUS': + return UefiEfiStatusPrinter(val) + elif str(val.type) == 'RETURN_STATUS': + return UefiReturnStatusPrinter(val) + elif str(val.type) == 'GUID' or str(val.type) == 'EFI_GUID': + return UefiGuidPrinter(val) + return None + +ReloadUefi () +gdb.pretty_printers.append (lookup_uefi_type) diff --git a/Debug/macgdb.tool b/Debug/macgdb.tool new file mode 100755 index 00000000..69039f5e --- /dev/null +++ b/Debug/macgdb.tool @@ -0,0 +1,28 @@ +#!/bin/bash + +RUNDIR=$(dirname "$0") +pushd "$RUNDIR" >/dev/null +RUNDIR=$(pwd) +popd >/dev/null + +cd "$RUNDIR" + +if [ "$GDB" = "" ]; then + GDB=$(which ggdb) +fi + +if [ "$GDB" = "" ]; then + GDB=$(which gdb) +fi + +if [ "$GDB" = "" ]; then + echo "Failed to find GDB" + exit 1 +fi + +"$GDB" -ex "target remote localhost:8864" \ + -ex "source Scripts/gdb_uefi.py" \ + -ex "set pagination off" \ + -ex "reload-uefi" \ + -ex "b DebugBreak" \ + GdbSyms/Bin/X64_XCODE5/GdbSyms.dll diff --git a/Include/Library/OcMiscLib.h b/Include/Library/OcMiscLib.h index c7b3df77..12c70fc2 100755 --- a/Include/Library/OcMiscLib.h +++ b/Include/Library/OcMiscLib.h @@ -145,4 +145,22 @@ AllocateNullTextOutSystemTable ( EFI_SYSTEM_TABLE *SystemTable ); +/** + Dummy function that debuggers may break on. +**/ +VOID +DebugBreak ( + VOID + ); + +/** + Wait for user input after printing message. + + @param[in] Message Message to print. +**/ +VOID +WaitForKeyPress ( + CONST CHAR16 *Message + ); + #endif // OC_MISC_LIB_H_ diff --git a/Library/OcDevicePropertyLib/OcDevicePropertyLib.c b/Library/OcDevicePropertyLib/OcDevicePropertyLib.c index fe821fca..c50816f4 100755 --- a/Library/OcDevicePropertyLib/OcDevicePropertyLib.c +++ b/Library/OcDevicePropertyLib/OcDevicePropertyLib.c @@ -228,7 +228,7 @@ InternalSyncWithThunderboltDevices ( } } -// DppDbGetPropertyValue +// DppDbGetProperty /** Locates a device property in the database and returns its value into Value. @param[in] This A pointer to the protocol instance. @@ -252,7 +252,7 @@ InternalSyncWithThunderboltDevices ( **/ EFI_STATUS EFIAPI -DppDbGetPropertyValue ( +DppDbGetProperty ( IN EFI_DEVICE_PATH_PROPERTY_DATABASE_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST CHAR16 *Name, @@ -784,7 +784,7 @@ InternalReadEfiVariableProperties ( STATIC EFI_DEVICE_PATH_PROPERTY_DATABASE_PROTOCOL DppDbProtocolTemplate = { EFI_DEVICE_PATH_PROPERTY_DATABASE_PROTOCOL_REVISION, - DppDbGetPropertyValue, + DppDbGetProperty, DppDbSetProperty, DppDbRemoveProperty, DppDbGetPropertyBuffer diff --git a/Library/OcMiscLib/DebugHelp.c b/Library/OcMiscLib/DebugHelp.c new file mode 100644 index 00000000..7436c682 --- /dev/null +++ b/Library/OcMiscLib/DebugHelp.c @@ -0,0 +1,63 @@ +/** @file + Copyright (C) 2019, vit9696. All rights reserved. + + All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include +#include +#include +#include + +VOID +#ifdef __GNUC__ +__attribute__ ((noinline)) +#endif +DebugBreak ( + VOID + ) +{ + // + // This function has no code, debuggers may break on it. + // +} + +VOID +WaitForKeyPress ( + CONST CHAR16 *Message + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + volatile BOOLEAN Proceed; + + // + // Print message. + // + gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) Message); + gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\r\n"); + + // + // Skip previously pressed characters. + // + do { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } while (!EFI_ERROR (Status)); + + // + // Wait for debugger signal or key press. + // + Proceed = FALSE; + while (EFI_ERROR (Status) && !Proceed) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + DebugBreak (); + } +} diff --git a/Library/OcMiscLib/OcMiscLib.inf b/Library/OcMiscLib/OcMiscLib.inf index d479f19d..f2d06e00 100755 --- a/Library/OcMiscLib/OcMiscLib.inf +++ b/Library/OcMiscLib/OcMiscLib.inf @@ -48,6 +48,7 @@ [Sources] Base64Decode.c ConvertDataToString.c + DebugHelp.c LegacyRegionLock.c LegacyRegionUnLock.c LogBootOrder.c diff --git a/OcSupportPkg.dsc b/OcSupportPkg.dsc index 255d5994..7d2654c9 100644 --- a/OcSupportPkg.dsc +++ b/OcSupportPkg.dsc @@ -44,6 +44,8 @@ UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf [Components] OcSupportPkg/Library/OcAppleImageVerificationLib/OcAppleImageVerificationLib.inf @@ -66,6 +68,7 @@ OcSupportPkg/Library/OcSerializeLib/OcSerializeLib.inf OcSupportPkg/Library/OcTemplateLib/OcTemplateLib.inf OcSupportPkg/Library/OcXmlLib/OcXmlLib.inf + OcSupportPkg/Debug/GdbSyms/GdbSyms.inf [PcdsFixedAtBuild] gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|0 @@ -87,11 +90,12 @@ # While there are no PCDs as of now, there at least are some custom macros. DEFINE OCSUPPORTPKG_BUILD_OPTIONS_GEN = -D DISABLE_NEW_DEPRECATED_INTERFACES $(OCSUPPORTPKG_BUILD_OPTIONS) - INTEL:DEBUG_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) - INTEL:RELEASE_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) GCC:DEBUG_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) + GCC:NOOPT_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) GCC:RELEASE_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) MSFT:DEBUG_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) + MSFT:NOOPT_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) MSFT:RELEASE_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) - XCODE:RELEASE_*_*_CC_FLAGS = -flto $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) XCODE:DEBUG_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) + XCODE:NOOPT_*_*_CC_FLAGS = $(OCSUPPORTPKG_BUILD_OPTIONS_GEN) + XCODE:RELEASE_*_*_CC_FLAGS = -flto $(OCSUPPORTPKG_BUILD_OPTIONS_GEN)