mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Add debug scripts and fix NOOPT build
This commit is contained in:
parent
e92ab78bfc
commit
bf86433ea8
BIN
Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll
Normal file
BIN
Debug/GdbSyms/Bin/X64_XCODE5/GdbSyms.dll
Normal file
Binary file not shown.
79
Debug/GdbSyms/GdbSyms.c
Normal file
79
Debug/GdbSyms/GdbSyms.c
Normal file
@ -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 <andreiw@motorola.com>
|
||||
|
||||
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 <Library/UefiLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/UefiRuntimeLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Guid/DebugImageInfoTable.h>
|
||||
|
||||
/**
|
||||
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;
|
||||
}
|
||||
57
Debug/GdbSyms/GdbSyms.inf
Normal file
57
Debug/GdbSyms/GdbSyms.inf
Normal file
@ -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 <andreiw@motorola.com>
|
||||
#
|
||||
# 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
|
||||
88
Debug/README.md
Normal file
88
Debug/README.md
Normal file
@ -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
|
||||
671
Debug/Scripts/gdb_uefi.py
Normal file
671
Debug/Scripts/gdb_uefi.py
Normal file
@ -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)
|
||||
28
Debug/macgdb.tool
Executable file
28
Debug/macgdb.tool
Executable file
@ -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
|
||||
@ -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_
|
||||
|
||||
@ -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
|
||||
|
||||
63
Library/OcMiscLib/DebugHelp.c
Normal file
63
Library/OcMiscLib/DebugHelp.c
Normal file
@ -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 <Uefi.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,7 @@
|
||||
[Sources]
|
||||
Base64Decode.c
|
||||
ConvertDataToString.c
|
||||
DebugHelp.c
|
||||
LegacyRegionLock.c
|
||||
LegacyRegionUnLock.c
|
||||
LogBootOrder.c
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user