mirror of https://github.com/acidanthera/audk.git
ArmPlatformPkg/Scripts: Added ARM DS-5 scripts to debug UEFI
These scripts allow to automatically load the symbols using either the report file created by the BaseTools or using the memory regions defined in the arguments. This is the scripts for DS-5 prior to DS5 v5.12. Signed-off-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13874 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
6f6c7857c2
commit
a8e812dea5
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (c) 2011-2012, ARM Limited. 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.
|
||||
#
|
||||
|
||||
import re
|
||||
|
||||
class BuildReport:
|
||||
PCDs = {}
|
||||
|
||||
def parse_platform_summary(self, file):
|
||||
pass
|
||||
|
||||
def parse_pcd_report(self, report_file):
|
||||
pcd_reg = re.compile(" (\*P|\*F|\*M| ) (\w+)(\ +)\: (.*) \((\w+)\) = (.*)\n")
|
||||
|
||||
for line in report_file.xreadlines():
|
||||
stripped_line = line.strip()
|
||||
if re.match("\<=+\>", stripped_line):
|
||||
return
|
||||
elif re.match("g.*Guid", stripped_line):
|
||||
guid = stripped_line
|
||||
self.PCDs[guid] = {}
|
||||
else:
|
||||
m = pcd_reg.match(line)
|
||||
if m:
|
||||
self.PCDs[guid][m.group(2)] = (m.group(6).strip(),m.group(5))
|
||||
|
||||
def parse_firmware_device(self, file):
|
||||
pass
|
||||
|
||||
def parse_module_summary(self, file):
|
||||
#print "Module Summary"
|
||||
pass
|
||||
|
||||
CONST_SECTION_HEADERS = [('Platform Summary', parse_platform_summary),
|
||||
('Platform Configuration Database Report',parse_pcd_report),
|
||||
('Firmware Device (FD)',parse_firmware_device),
|
||||
('Module Summary',parse_module_summary)]
|
||||
|
||||
def __init__(self, filename = 'report.log'):
|
||||
report_file = open(filename, 'r')
|
||||
for line in report_file.xreadlines():
|
||||
for section_header in BuildReport.CONST_SECTION_HEADERS:
|
||||
if line.strip() == section_header[0]:
|
||||
section_header[1](self, report_file)
|
||||
#print self.PCDs
|
|
@ -0,0 +1,100 @@
|
|||
#
|
||||
# Copyright (c) 2011-2012, ARM Limited. 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.
|
||||
#
|
||||
|
||||
from arm_ds.debugger_v1 import Debugger
|
||||
from arm_ds.debugger_v1 import DebugException
|
||||
|
||||
import re, sys, getopt
|
||||
|
||||
import edk2_debugger
|
||||
|
||||
# Reload external classes
|
||||
reload(edk2_debugger)
|
||||
|
||||
def usage():
|
||||
print "-a,--all: Load all symbols"
|
||||
print "-l,--report=: Filename for the EDK2 report log"
|
||||
print "-m,--sysmem=(base,size): System Memory region"
|
||||
print "-f,--fv=(base,size): Firmware region"
|
||||
print "-r,--rom=(base,size): ROM region"
|
||||
|
||||
load_all = False
|
||||
report_file = None
|
||||
regions = []
|
||||
opts,args = getopt.getopt(sys.argv[1:], "har:vm:vr:vf:v", ["help","all","report=","sysmem=","rom=","fv="])
|
||||
if (opts is None) or (not opts):
|
||||
report_file = '../../../report.log'
|
||||
else:
|
||||
region_reg = re.compile("\((.*),(.*)\)")
|
||||
base_reg = re.compile("(.*)")
|
||||
|
||||
for o,a in opts:
|
||||
region_type = None
|
||||
regex = None
|
||||
m = None
|
||||
if o in ("-h","--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
elif o in ("-a","--all"):
|
||||
load_all = True
|
||||
elif o in ("-l","--report"):
|
||||
report_file = a
|
||||
elif o in ("-m","--sysmem"):
|
||||
region_type = edk2_debugger.ArmPlatformDebugger.REGION_TYPE_SYSMEM
|
||||
regex = region_reg
|
||||
elif o in ("-f","--fv"):
|
||||
region_type = edk2_debugger.ArmPlatformDebugger.REGION_TYPE_FV
|
||||
regex = region_reg
|
||||
elif o in ("-r","--rom"):
|
||||
region_type = edk2_debugger.ArmPlatformDebugger.REGION_TYPE_ROM
|
||||
regex = region_reg
|
||||
else:
|
||||
assert False, "Unhandled option"
|
||||
|
||||
if region_type:
|
||||
m = regex.match(a)
|
||||
if m:
|
||||
if regex.groups == 1:
|
||||
regions.append((region_type,int(m.group(1),0),0))
|
||||
else:
|
||||
regions.append((region_type,int(m.group(1),0),int(m.group(2),0)))
|
||||
else:
|
||||
if regex.groups == 1:
|
||||
raise Exception('cmd_load_symbols', "Expect a base address")
|
||||
else:
|
||||
raise Exception('cmd_load_symbols', "Expect a region format as (base,size)")
|
||||
|
||||
# Debugger object for accessing the debugger
|
||||
debugger = Debugger()
|
||||
|
||||
# Initialisation commands
|
||||
ec = debugger.getExecutionContext(0)
|
||||
ec.getExecutionService().stop()
|
||||
ec.getExecutionService().waitForStop()
|
||||
# in case the execution context reference is out of date
|
||||
ec = debugger.getExecutionContext(0)
|
||||
|
||||
armplatform_debugger = edk2_debugger.ArmPlatformDebugger(ec, report_file, regions)
|
||||
|
||||
try:
|
||||
armplatform_debugger = edk2_debugger.ArmPlatformDebugger(ec, report_file, regions)
|
||||
|
||||
if load_all:
|
||||
armplatform_debugger.load_all_symbols()
|
||||
else:
|
||||
armplatform_debugger.load_current_symbols()
|
||||
except IOError, (ErrorNumber, ErrorMessage):
|
||||
print "Error: %s" % ErrorMessage
|
||||
except Exception, (ErrorClass, ErrorMessage):
|
||||
print "Error(%s): %s" % (ErrorClass, ErrorMessage)
|
||||
except DebugException, de:
|
||||
print "DebugError: %s" % (de.getMessage())
|
|
@ -0,0 +1,212 @@
|
|||
#
|
||||
# Copyright (c) 2011-2012, ARM Limited. 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.
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
import firmware_volume
|
||||
import build_report
|
||||
import system_table
|
||||
|
||||
# Reload external classes
|
||||
reload(firmware_volume)
|
||||
reload(build_report)
|
||||
reload(system_table)
|
||||
|
||||
def readMem32(executionContext, address):
|
||||
bytes = executionContext.getMemoryService().read(address, 4, 32)
|
||||
return struct.unpack('<I',bytes)[0]
|
||||
|
||||
def dump_fv(ec, fv_base, fv_size):
|
||||
fv = firmware_volume.FirmwareVolume(ec,
|
||||
int(build.PCDs['gArmTokenSpaceGuid']['PcdFvBaseAddress'][0],16),
|
||||
int(build.PCDs['gArmTokenSpaceGuid']['PcdFvSize'][0],16))
|
||||
|
||||
ffs = fv.get_next_ffs()
|
||||
while ffs != None:
|
||||
print "# %s" % ffs
|
||||
|
||||
section = ffs.get_next_section()
|
||||
while section != None:
|
||||
print "\t%s" % section
|
||||
try:
|
||||
print "\t\t- %s" % section.get_debug_filepath()
|
||||
except Exception:
|
||||
pass
|
||||
section = ffs.get_next_section(section)
|
||||
|
||||
ffs = fv.get_next_ffs(ffs)
|
||||
|
||||
def dump_system_table(ec, mem_base, mem_size):
|
||||
st = system_table.SystemTable(ec, mem_base, mem_size)
|
||||
|
||||
debug_info_table_base = st.get_configuration_table(system_table.DebugInfoTable.CONST_DEBUG_INFO_TABLE_GUID)
|
||||
|
||||
debug_info_table = system_table.DebugInfoTable(ec, debug_info_table_base)
|
||||
debug_info_table.dump()
|
||||
|
||||
def load_symbol_from_file(ec, filename, address):
|
||||
try:
|
||||
ec.executeDSCommand("discard-symbol-file \'%s\'" % filename)
|
||||
except:
|
||||
pass
|
||||
ec.executeDSCommand("add-symbol-file \'%s\' 0x%X" % (filename, address))
|
||||
|
||||
class ArmPlatform:
|
||||
def __init__(self, sysmembase=None, sysmemsize=None, fvs={}):
|
||||
self.sysmembase = sysmembase
|
||||
self.sysmemsize = sysmemsize
|
||||
self.fvs = fvs
|
||||
|
||||
class ArmPlatformDebugger:
|
||||
system_table = None
|
||||
firmware_volumes = {}
|
||||
|
||||
REGION_TYPE_SYSMEM = 1
|
||||
REGION_TYPE_ROM = 2
|
||||
REGION_TYPE_FV = 3
|
||||
|
||||
def __init__(self, ec, report_log, regions):
|
||||
self.ec = ec
|
||||
fvs = []
|
||||
sysmem_base = None
|
||||
sysmem_size = None
|
||||
|
||||
if report_log and os.path.isfile(report_log):
|
||||
try:
|
||||
self.build = build_report.BuildReport(report_log)
|
||||
except IOError:
|
||||
raise IOError(2, 'Report \'%s\' isnot valid' % report_log)
|
||||
|
||||
# Generate list of supported Firmware Volumes
|
||||
if self.build.PCDs['gArmTokenSpaceGuid'].has_key('PcdFvSize') and int(self.build.PCDs['gArmTokenSpaceGuid']['PcdFvSize'][0],16) != 0:
|
||||
fvs.append((int(self.build.PCDs['gArmTokenSpaceGuid']['PcdFvBaseAddress'][0],16),int(self.build.PCDs['gArmTokenSpaceGuid']['PcdFvSize'][0],16)))
|
||||
if self.build.PCDs['gArmTokenSpaceGuid'].has_key('PcdSecureFvSize') and int(self.build.PCDs['gArmTokenSpaceGuid']['PcdSecureFvSize'][0],16) != 0:
|
||||
fvs.append((int(self.build.PCDs['gArmTokenSpaceGuid']['PcdSecureFvBaseAddress'][0],16),int(self.build.PCDs['gArmTokenSpaceGuid']['PcdSecureFvSize'][0],16)))
|
||||
if self.build.PCDs['gArmTokenSpaceGuid'].has_key('PcdHypFvSize') and int(self.build.PCDs['gArmTokenSpaceGuid']['PcdHypFvSize'][0],16) != 0:
|
||||
fvs.append((int(self.build.PCDs['gArmTokenSpaceGuid']['PcdHypFvBaseAddress'][0],16),int(self.build.PCDs['gArmTokenSpaceGuid']['PcdHypFvSize'][0],16)))
|
||||
|
||||
sysmem_base = int(self.build.PCDs['gArmTokenSpaceGuid']['PcdSystemMemoryBase'][0],16)
|
||||
sysmem_size = int(self.build.PCDs['gArmTokenSpaceGuid']['PcdSystemMemorySize'][0],16)
|
||||
else:
|
||||
for region in regions:
|
||||
if region[0] == ArmPlatformDebugger.REGION_TYPE_SYSMEM:
|
||||
sysmem_base = region[1]
|
||||
sysmem_size = region[2]
|
||||
elif region[0] == ArmPlatformDebugger.REGION_TYPE_FV:
|
||||
fvs.append((region[1],region[2]))
|
||||
elif region[0] == ArmPlatformDebugger.REGION_TYPE_ROM:
|
||||
for base in xrange(region[1], region[1] + region[2], 0x400000):
|
||||
signature = struct.unpack("cccc", self.ec.getMemoryService().read(base, 4, 32))
|
||||
if signature == FirmwareVolume.CONST_FV_SIGNATURE:
|
||||
fvs.append((base,0))
|
||||
else:
|
||||
print "Region type '%d' Not Supported" % region[0]
|
||||
|
||||
self.platform = ArmPlatform(sysmem_base, sysmem_size, fvs)
|
||||
|
||||
def in_sysmem(self, addr):
|
||||
return (self.platform.sysmembase is not None) and (self.platform.sysmembase <= addr) and (addr < self.platform.sysmembase + self.platform.sysmemsize)
|
||||
|
||||
def in_fv(self, addr):
|
||||
return (self.get_fv_at(addr) != None)
|
||||
|
||||
def get_fv_at(self, addr):
|
||||
for fv in self.platform.fvs:
|
||||
if (fv[0] <= addr) and (addr < fv[0] + fv[1]):
|
||||
return fv
|
||||
return None
|
||||
|
||||
def load_current_symbols(self):
|
||||
pc = int(self.ec.getRegisterService().getValue('PC')) & 0xFFFFFFFF
|
||||
if self.in_fv(pc):
|
||||
debug_infos = []
|
||||
|
||||
(fv_base, fv_size) = self.get_fv_at(pc)
|
||||
|
||||
if self.firmware_volumes.has_key(fv_base) == False:
|
||||
self.firmware_volumes[fv_base] = firmware_volume.FirmwareVolume(self.ec, fv_base, fv_size)
|
||||
|
||||
stack_frame = self.ec.getTopLevelStackFrame()
|
||||
info = self.firmware_volumes[fv_base].load_symbols_at(int(stack_frame.getRegisterService().getValue('PC')) & 0xFFFFFFFF)
|
||||
debug_infos.append(info)
|
||||
while stack_frame.next() is not None:
|
||||
stack_frame = stack_frame.next()
|
||||
|
||||
# Stack frame attached to 'PC'
|
||||
pc = int(stack_frame.getRegisterService().getValue('PC')) & 0xFFFFFFFF
|
||||
|
||||
# Check if the symbols for this stack frame have already been loaded
|
||||
found = False
|
||||
for debug_info in debug_infos:
|
||||
if (pc >= debug_info[0]) and (pc < debug_info[0] + debug_info[1]):
|
||||
found = True
|
||||
if found == False:
|
||||
info = self.firmware_volumes[fv_base].load_symbols_at(pc)
|
||||
debug_infos.append(info)
|
||||
|
||||
#self.firmware_volumes[fv_base].load_symbols_at(pc)
|
||||
elif self.in_sysmem(pc):
|
||||
debug_infos = []
|
||||
|
||||
if self.system_table is None:
|
||||
# Find the System Table
|
||||
self.system_table = system_table.SystemTable(self.ec, self.platform.sysmembase, self.platform.sysmemsize)
|
||||
|
||||
# Find the Debug Info Table
|
||||
debug_info_table_base = self.system_table.get_configuration_table(system_table.DebugInfoTable.CONST_DEBUG_INFO_TABLE_GUID)
|
||||
self.debug_info_table = system_table.DebugInfoTable(self.ec, debug_info_table_base)
|
||||
|
||||
stack_frame = self.ec.getTopLevelStackFrame()
|
||||
info = self.debug_info_table.load_symbols_at(int(stack_frame.getRegisterService().getValue('PC')) & 0xFFFFFFFF)
|
||||
debug_infos.append(info)
|
||||
while stack_frame.next() is not None:
|
||||
stack_frame = stack_frame.next()
|
||||
|
||||
# Stack frame attached to 'PC'
|
||||
pc = int(stack_frame.getRegisterService().getValue('PC')) & 0xFFFFFFFF
|
||||
|
||||
# Check if the symbols for this stack frame have already been loaded
|
||||
found = False
|
||||
for debug_info in debug_infos:
|
||||
if (pc >= debug_info[0]) and (pc < debug_info[0] + debug_info[1]):
|
||||
found = True
|
||||
if found == False:
|
||||
info = self.debug_info_table.load_symbols_at(pc)
|
||||
debug_infos.append(info)
|
||||
|
||||
#self.debug_info_table.load_symbols_at(pc)
|
||||
else:
|
||||
raise Exception('ArmPlatformDebugger', "Not supported region")
|
||||
|
||||
def load_all_symbols(self):
|
||||
# Load all the XIP symbols attached to the Firmware Volume
|
||||
for (fv_base, fv_size) in self.platform.fvs:
|
||||
if self.firmware_volumes.has_key(fv_base) == False:
|
||||
self.firmware_volumes[fv_base] = firmware_volume.FirmwareVolume(self.ec, fv_base, fv_size)
|
||||
self.firmware_volumes[fv_base].load_all_symbols()
|
||||
|
||||
try:
|
||||
# Load all symbols of module loaded into System Memory
|
||||
if self.system_table is None:
|
||||
# Find the System Table
|
||||
self.system_table = system_table.SystemTable(self.ec, self.platform.sysmembase, self.platform.sysmemsize)
|
||||
|
||||
|
||||
# Find the Debug Info Table
|
||||
debug_info_table_base = self.system_table.get_configuration_table(system_table.DebugInfoTable.CONST_DEBUG_INFO_TABLE_GUID)
|
||||
self.debug_info_table = system_table.DebugInfoTable(self.ec, debug_info_table_base)
|
||||
|
||||
self.debug_info_table.load_all_symbols()
|
||||
except:
|
||||
# Debugger exception could be excepted if DRAM has not been initialized or if we have not started to run from DRAM yet
|
||||
print "Note: no symbols have been found in System Memory (possible cause: the UEFI permanent memory has been installed yet)"
|
||||
pass
|
|
@ -0,0 +1,299 @@
|
|||
#
|
||||
# Copyright (c) 2011-2012, ARM Limited. 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.
|
||||
#
|
||||
|
||||
from arm_ds.debugger_v1 import DebugException
|
||||
|
||||
import struct
|
||||
import string
|
||||
|
||||
class EfiFileSection(object):
|
||||
EFI_SECTION_PE32 = 0x10
|
||||
EFI_SECTION_PIC = 0x11
|
||||
EFI_SECTION_TE = 0x12
|
||||
|
||||
EFI_IMAGE_DEBUG_TYPE_CODEVIEW = 0x2
|
||||
|
||||
SIZEOF_EFI_FFS_FILE_HEADER = 0x28
|
||||
|
||||
def __init__(self, ec, base):
|
||||
self.base = base
|
||||
self.ec = ec
|
||||
|
||||
def __str__(self):
|
||||
return "FileSection(type:0x%X, size:0x%x)" % (self.get_type(), self.get_size())
|
||||
|
||||
def get_base(self):
|
||||
return self.base
|
||||
|
||||
def get_type(self):
|
||||
return struct.unpack("B", self.ec.getMemoryService().read(self.base + 0x3, 1, 8))[0]
|
||||
|
||||
def get_size(self):
|
||||
return (struct.unpack("<I", self.ec.getMemoryService().read(self.base, 4, 32))[0] & 0x00ffffff)
|
||||
|
||||
def get_debug_filepath(self):
|
||||
type = self.get_type()
|
||||
if type == EfiFileSection.EFI_SECTION_TE:
|
||||
section = EfiSectionTE(self, ec, self.base + 0x4)
|
||||
elif type == EfiFileSection.EFI_SECTION_PE32:
|
||||
section = EfiSectionPE32(self, ec, self.base + 0x4)
|
||||
else:
|
||||
raise Exception("EfiFileSection", "No debug section")
|
||||
return section.get_debug_filepath()
|
||||
|
||||
class EfiSectionTE:
|
||||
SIZEOF_EFI_TE_IMAGE_HEADER = 0x28
|
||||
EFI_TE_IMAGE_SIGNATURE = ('V','Z')
|
||||
|
||||
def __init__(self, ec, base_te):
|
||||
self.ec = ec
|
||||
self.base_te = int(base_te)
|
||||
te_sig = struct.unpack("cc", self.ec.getMemoryService().read(self.base_te, 2, 32))
|
||||
if te_sig != EfiSectionTE.EFI_TE_IMAGE_SIGNATURE:
|
||||
raise Exception("EfiFileSectionTE","TE Signature incorrect")
|
||||
|
||||
def get_debug_filepath(self):
|
||||
stripped_size = struct.unpack("<H", self.ec.getMemoryService().read(self.base_te + 0x6, 2, 32))[0]
|
||||
stripped_size -= EfiSectionTE.SIZEOF_EFI_TE_IMAGE_HEADER
|
||||
|
||||
debug_dir_entry_rva = self.ec.getMemoryService().readMemory32(self.base_te + 0x20)
|
||||
if debug_dir_entry_rva == 0:
|
||||
raise Exception("EfiFileSectionTE","No debug directory for image")
|
||||
debug_dir_entry_rva -= stripped_size
|
||||
|
||||
debug_type = self.ec.getMemoryService().readMemory32(self.base_te + debug_dir_entry_rva + 0xC)
|
||||
if (debug_type != 0xdf) and (debug_type != EfiFileSection.EFI_IMAGE_DEBUG_TYPE_CODEVIEW):
|
||||
raise Exception("EfiFileSectionTE","Debug type is not dwarf")
|
||||
|
||||
debug_rva = self.ec.getMemoryService().readMemory32(self.base_te + debug_dir_entry_rva + 0x14)
|
||||
debug_rva -= stripped_size
|
||||
|
||||
dwarf_sig = struct.unpack("cccc", self.ec.getMemoryService().read(self.base_te + debug_rva, 4, 32))
|
||||
if (dwarf_sig != 0x66727764) and (dwarf_sig != FirmwareFile.CONST_NB10_SIGNATURE):
|
||||
raise Exception("EfiFileSectionTE","Dwarf debug signature not found")
|
||||
|
||||
if dwarf_sig == 0x66727764:
|
||||
filename = self.base_te + debug_rva + 0xc
|
||||
else:
|
||||
filename = self.base_te + debug_rva + 0x10
|
||||
filename = struct.unpack("200s", self.ec.getMemoryService().read(filename, 200, 32))[0]
|
||||
return filename[0:string.find(filename,'\0')]
|
||||
|
||||
def get_debug_elfbase(self):
|
||||
stripped_size = struct.unpack("<H", self.ec.getMemoryService().read(self.base_te + 0x6, 2, 32))[0]
|
||||
stripped_size -= EfiSectionTE.SIZEOF_EFI_TE_IMAGE_HEADER
|
||||
|
||||
base_of_code = self.ec.getMemoryService().readMemory32(self.base_te + 0xC)
|
||||
|
||||
return self.base_te + base_of_code - stripped_size
|
||||
|
||||
class EfiSectionPE32:
|
||||
def __init__(self, ec, base_pe32):
|
||||
self.ec = ec
|
||||
self.base_pe32 = base_pe32
|
||||
|
||||
def get_debug_filepath(self):
|
||||
# Offset from dos hdr to PE file hdr
|
||||
file_header_offset = self.ec.getMemoryService().readMemory32(self.base_pe32 + 0x3C)
|
||||
|
||||
# Offset to debug dir in PE hdrs
|
||||
debug_dir_entry_rva = self.ec.getMemoryService().readMemory32(self.base_pe32 + file_header_offset + 0xA8)
|
||||
if debug_dir_entry_rva == 0:
|
||||
raise Exception("EfiFileSectionPE32","No Debug Directory")
|
||||
|
||||
debug_type = self.ec.getMemoryService().readMemory32(self.base_pe32 + debug_dir_entry_rva + 0xC)
|
||||
if (debug_type != 0xdf) and (debug_type != EfiFileSection.EFI_IMAGE_DEBUG_TYPE_CODEVIEW):
|
||||
raise Exception("EfiFileSectionPE32","Debug type is not dwarf")
|
||||
|
||||
|
||||
debug_rva = self.ec.getMemoryService().readMemory32(self.base_pe32 + debug_dir_entry_rva + 0x14)
|
||||
|
||||
dwarf_sig = struct.unpack("cccc", self.ec.getMemoryService().read(str(self.base_pe32 + debug_rva), 4, 32))
|
||||
if (dwarf_sig != 0x66727764) and (dwarf_sig != FirmwareFile.CONST_NB10_SIGNATURE):
|
||||
raise Exception("EfiFileSectionPE32","Dwarf debug signature not found")
|
||||
|
||||
if dwarf_sig == 0x66727764:
|
||||
filename = self.base_pe32 + debug_rva + 0xc
|
||||
else:
|
||||
filename = self.base_pe32 + debug_rva + 0x10
|
||||
filename = struct.unpack("200s", self.ec.getMemoryService().read(str(filename), 200, 32))[0]
|
||||
return filename[0:string.find(filename,'\0')]
|
||||
|
||||
def get_debug_elfbase(self):
|
||||
# Offset from dos hdr to PE file hdr
|
||||
pe_file_header = self.base_pe32 + self.ec.getMemoryService().readMemory32(self.base_pe32 + 0x3C)
|
||||
|
||||
base_of_code = self.base_pe32 + self.ec.getMemoryService().readMemory32(pe_file_header + 0x28)
|
||||
base_of_data = self.base_pe32 + self.ec.getMemoryService().readMemory32(pe_file_header + 0x2C)
|
||||
|
||||
if (base_of_code < base_of_data) and (base_of_code != 0):
|
||||
return base_of_code
|
||||
else:
|
||||
return base_of_data
|
||||
|
||||
class FirmwareFile:
|
||||
EFI_FV_FILETYPE_RAW = 0x01
|
||||
EFI_FV_FILETYPE_FREEFORM = 0x02
|
||||
EFI_FV_FILETYPE_SECURITY_CORE = 0x03
|
||||
EFI_FV_FILETYPE_PEI_CORE = 0x04
|
||||
EFI_FV_FILETYPE_DXE_CORE = 0x05
|
||||
EFI_FV_FILETYPE_PEIM = 0x06
|
||||
EFI_FV_FILETYPE_DRIVER = 0x07
|
||||
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER = 0x08
|
||||
EFI_FV_FILETYPE_APPLICATION = 0x09
|
||||
EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B
|
||||
EFI_FV_FILETYPE_FFS_MIN = 0xF0
|
||||
|
||||
CONST_NB10_SIGNATURE = ('N','B','1','0')
|
||||
|
||||
def __init__(self, fv, base, ec):
|
||||
self.fv = fv
|
||||
self.base = base
|
||||
self.ec = ec
|
||||
|
||||
def __str__(self):
|
||||
return "FFS(state:0x%x, type:0x%X, size:0x%x)" % (self.get_state(), self.get_type(), self.get_size())
|
||||
|
||||
def get_base(self):
|
||||
return self.base
|
||||
|
||||
def get_size(self):
|
||||
size = (self.ec.getMemoryService().readMemory32(self.base + 0x14) & 0x00ffffff)
|
||||
|
||||
# Occupied size is the size considering the alignment
|
||||
return size + ((0x8 - (size & 0x7)) & 0x7)
|
||||
|
||||
def get_type(self):
|
||||
return self.ec.getMemoryService().readMemory8(self.base + 0x12)
|
||||
|
||||
def get_state(self):
|
||||
state = self.ec.getMemoryService().readMemory8(self.base + 0x17)
|
||||
|
||||
polarity = self.fv.get_polarity()
|
||||
if polarity:
|
||||
state = ~state
|
||||
|
||||
highest_bit = 0x80;
|
||||
while (highest_bit != 0) and ((highest_bit & state) == 0):
|
||||
highest_bit >>= 1
|
||||
|
||||
return highest_bit
|
||||
|
||||
def get_next_section(self, section=None):
|
||||
if section == None:
|
||||
if self.get_type() != FirmwareFile.EFI_FV_FILETYPE_FFS_MIN:
|
||||
section_base = self.get_base() + 0x18;
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
section_base = int(section.get_base() + section.get_size())
|
||||
|
||||
# Align to next 4 byte boundary
|
||||
if (section_base & 0x3) != 0:
|
||||
section_base = section_base + 0x4 - (section_base & 0x3)
|
||||
|
||||
if section_base < self.get_base() + self.get_size():
|
||||
return EfiFileSection(self.ec, section_base)
|
||||
else:
|
||||
return None
|
||||
|
||||
class FirmwareVolume:
|
||||
CONST_FV_SIGNATURE = ('_','F','V','H')
|
||||
EFI_FVB2_ERASE_POLARITY = 0x800
|
||||
|
||||
DebugInfos = []
|
||||
|
||||
def __init__(self, ec, fv_base, fv_size):
|
||||
self.ec = ec
|
||||
self.fv_base = fv_base
|
||||
self.fv_size = fv_size
|
||||
|
||||
try:
|
||||
signature = struct.unpack("cccc", self.ec.getMemoryService().read(fv_base + 0x28, 4, 32))
|
||||
except DebugException:
|
||||
raise Exception("FirmwareVolume", "Not possible to access the defined firmware volume at [0x%X,0x%X]. Could be the used build report does not correspond to your current debugging context." % (int(fv_base),int(fv_base+fv_size)))
|
||||
if signature != FirmwareVolume.CONST_FV_SIGNATURE:
|
||||
raise Exception("FirmwareVolume", "This is not a valid firmware volume")
|
||||
|
||||
def get_size(self):
|
||||
return self.ec.getMemoryService().readMemory32(self.fv_base + 0x20)
|
||||
|
||||
def get_attributes(self):
|
||||
return self.ec.getMemoryService().readMemory32(self.fv_base + 0x2C)
|
||||
|
||||
def get_polarity(self):
|
||||
attributes = self.get_attributes()
|
||||
if attributes & FirmwareVolume.EFI_FVB2_ERASE_POLARITY:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_next_ffs(self, ffs=None):
|
||||
if ffs == None:
|
||||
# Get the offset of the first FFS file from the FV header
|
||||
ffs_base = self.fv_base + self.ec.getMemoryService().readMemory16(self.fv_base + 0x30)
|
||||
else:
|
||||
# Goto the next FFS file
|
||||
ffs_base = int(ffs.get_base() + ffs.get_size())
|
||||
|
||||
# Align to next 8 byte boundary
|
||||
if (ffs_base & 0x7) != 0:
|
||||
ffs_base = ffs_base + 0x8 - (ffs_base & 0x7)
|
||||
|
||||
if ffs_base < self.fv_base + self.get_size():
|
||||
return FirmwareFile(self, ffs_base, self.ec)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_debug_info(self):
|
||||
self.DebugInfos = []
|
||||
|
||||
ffs = self.get_next_ffs()
|
||||
while ffs != None:
|
||||
section = ffs.get_next_section()
|
||||
while section != None:
|
||||
type = section.get_type()
|
||||
if (type == EfiFileSection.EFI_SECTION_TE) or (type == EfiFileSection.EFI_SECTION_PE32):
|
||||
self.DebugInfos.append((section.get_base(), section.get_size(), section.get_type()))
|
||||
section = ffs.get_next_section(section)
|
||||
ffs = self.get_next_ffs(ffs)
|
||||
|
||||
def load_symbols_at(self, addr):
|
||||
if self.DebugInfos == []:
|
||||
self.get_debug_info()
|
||||
|
||||
for debug_info in self.DebugInfos:
|
||||
if (addr >= debug_info[0]) and (addr < debug_info[0] + debug_info[1]):
|
||||
if debug_info[2] == EfiFileSection.EFI_SECTION_TE:
|
||||
section = EfiSectionTE(self.ec, debug_info[0] + 0x4)
|
||||
elif debug_info[2] == EfiFileSection.EFI_SECTION_PE32:
|
||||
section = EfiSectionPE32(self.ec, debug_info[0] + 0x4)
|
||||
else:
|
||||
raise Exception('FirmwareVolume','Section Type not supported')
|
||||
|
||||
edk2_debugger.load_symbol_from_file(self.ec, section.get_debug_filepath(), section.get_debug_elfbase())
|
||||
|
||||
return debug_info
|
||||
|
||||
def load_all_symbols(self):
|
||||
if self.DebugInfos == []:
|
||||
self.get_debug_info()
|
||||
|
||||
for debug_info in self.DebugInfos:
|
||||
if debug_info[2] == EfiFileSection.EFI_SECTION_TE:
|
||||
section = EfiSectionTE(self.ec, debug_info[0] + 0x4)
|
||||
elif debug_info[2] == EfiFileSection.EFI_SECTION_PE32:
|
||||
section = EfiSectionPE32(self.ec, debug_info[0] + 0x4)
|
||||
else:
|
||||
continue
|
||||
|
||||
edk2_debugger.load_symbol_from_file(self.ec, section.get_debug_filepath(), section.get_debug_elfbase())
|
|
@ -0,0 +1,127 @@
|
|||
#
|
||||
# Copyright (c) 2011-2012, ARM Limited. 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.
|
||||
#
|
||||
|
||||
from arm_ds.debugger_v1 import DebugException
|
||||
|
||||
import firmware_volume
|
||||
import struct
|
||||
|
||||
class DebugInfoTable:
|
||||
CONST_DEBUG_INFO_TABLE_GUID = ( 0x49152E77L, 0x47641ADAL, 0xFE7AA2B7L, 0x8B5ED9FEL)
|
||||
|
||||
DebugInfos = []
|
||||
|
||||
def __init__(self, ec, debug_info_table_header_offset):
|
||||
self.ec = ec
|
||||
self.base = debug_info_table_header_offset
|
||||
|
||||
def get_debug_info(self):
|
||||
count = self.ec.getMemoryService().readMemory32(self.base + 0x4)
|
||||
debug_info_table_base = self.ec.getMemoryService().readMemory32(self.base + 0x8)
|
||||
|
||||
self.DebugInfos = []
|
||||
|
||||
for i in range(0, count):
|
||||
# Get the address of the structure EFI_DEBUG_IMAGE_INFO
|
||||
debug_info = self.ec.getMemoryService().readMemory32(debug_info_table_base + (i * 4))
|
||||
if debug_info:
|
||||
debug_info_type = self.ec.getMemoryService().readMemory32(debug_info)
|
||||
# Normal Debug Info Type
|
||||
if debug_info_type == 1:
|
||||
# Get the base address of the structure EFI_LOADED_IMAGE_PROTOCOL
|
||||
loaded_image_protocol = self.ec.getMemoryService().readMemory32(debug_info + 0x4)
|
||||
|
||||
image_base = self.ec.getMemoryService().readMemory32(loaded_image_protocol + 0x20)
|
||||
image_size = self.ec.getMemoryService().readMemory32(loaded_image_protocol + 0x28)
|
||||
|
||||
self.DebugInfos.append((image_base,image_size))
|
||||
|
||||
# Return (base, size)
|
||||
def load_symbols_at(self, addr):
|
||||
if self.DebugInfos == []:
|
||||
self.get_debug_info()
|
||||
|
||||
found = False
|
||||
for debug_info in self.DebugInfos:
|
||||
if (addr >= debug_info[0]) and (addr < debug_info[0] + debug_info[1]):
|
||||
section = firmware_volume.EfiSectionPE32(self.ec, debug_info[0])
|
||||
|
||||
edk2_debugger.load_symbol_from_file(self.ec, section.get_debug_filepath(), section.get_debug_elfbase())
|
||||
|
||||
found = True
|
||||
return debug_info
|
||||
|
||||
if found == False:
|
||||
raise Exception('DebugInfoTable','No symbol found at 0x%x' % addr)
|
||||
|
||||
def load_all_symbols(self):
|
||||
if self.DebugInfos == []:
|
||||
self.get_debug_info()
|
||||
|
||||
for debug_info in self.DebugInfos:
|
||||
section = firmware_volume.EfiSectionPE32(self.ec, debug_info[0])
|
||||
|
||||
edk2_debugger.load_symbol_from_file(self.ec, section.get_debug_filepath(), section.get_debug_elfbase())
|
||||
|
||||
def dump(self):
|
||||
self.get_debug_info()
|
||||
for debug_info in self.DebugInfos:
|
||||
base_pe32 = debug_info[0]
|
||||
section = firmware_volume.EfiSectionPE32(self.ec, base_pe32)
|
||||
print section.get_debug_filepath()
|
||||
|
||||
class SystemTable:
|
||||
CONST_ST_SIGNATURE = ('I','B','I',' ','S','Y','S','T')
|
||||
|
||||
def __init__(self, ec, membase, memsize):
|
||||
self.membase = membase
|
||||
self.memsize = memsize
|
||||
self.ec = ec
|
||||
|
||||
found = False
|
||||
|
||||
# Start from the top of the memory
|
||||
offset = self.membase + self.memsize
|
||||
# Align to highest 4MB boundary
|
||||
offset = offset & ~0x3FFFFF
|
||||
# We should not have a System Table at the top of the System Memory
|
||||
offset = offset - 0x400000
|
||||
|
||||
# Start at top and look on 4MB boundaries for system table ptr structure
|
||||
while offset > self.membase:
|
||||
try:
|
||||
signature = struct.unpack("cccccccc", self.ec.getMemoryService().read(str(offset), 8, 32))
|
||||
except DebugException:
|
||||
raise Exception('SystemTable','Fail to access System Memory. Ensure all the memory in the region [0x%x;0x%X] is accessible.' % (membase,membase+memsize))
|
||||
if signature == SystemTable.CONST_ST_SIGNATURE:
|
||||
found = True
|
||||
self.system_table_base = self.ec.getMemoryService().readMemory32(offset + 0x8)
|
||||
break
|
||||
offset = offset - 0x400000
|
||||
|
||||
if not found:
|
||||
raise Exception('SystemTable','System Table not found in System Memory [0x%x;0x%X]' % (membase,membase+memsize))
|
||||
|
||||
def get_configuration_table(self, conf_table_guid):
|
||||
# Number of configuration Table entry
|
||||
conf_table_entry_count = self.ec.getMemoryService().readMemory32(self.system_table_base + 0x40)
|
||||
|
||||
# Get location of the Configuration Table entries
|
||||
conf_table_offset = self.ec.getMemoryService().readMemory32(self.system_table_base + 0x44)
|
||||
|
||||
for i in range(0, conf_table_entry_count):
|
||||
offset = conf_table_offset + (i * 0x14)
|
||||
guid = struct.unpack("<IIII", self.ec.getMemoryService().read(str(offset), 16, 32))
|
||||
if guid == conf_table_guid:
|
||||
return self.ec.getMemoryService().readMemory32(offset + 0x10)
|
||||
|
||||
raise Exception('SystemTable','Configuration Table not found')
|
Loading…
Reference in New Issue