Skip to content

Commit

Permalink
Catch bitness mismatch on PS3
Browse files Browse the repository at this point in the history
  • Loading branch information
sevaa committed Apr 17, 2024
1 parent 1ec1d31 commit 3072ec3
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 74 deletions.
178 changes: 111 additions & 67 deletions dwex/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .locals import LocalsDlg

# Sync with version in setup.py
version = (3, 23)
version = (3, 24)

# TODO:
# On MacOS, start without a main window, instead show the Open dialog
Expand Down Expand Up @@ -92,74 +92,78 @@ def open_file(self, filename, arch = None):
if not di: # Covers both False and None
return di

# Some degree of graceful handling of wrong format
try:
# Some cached top level stuff
# Notably, iter_CUs doesn't cache
di._ranges = None # Loaded on first use
di._aranges = None
def decorate_cu(cu, i):
cu._i = i
cu._lineprogram = None
cu._exprparser = None
return cu
di._unsorted_CUs = [decorate_cu(cu, i) for (i, cu) in enumerate(di.iter_CUs())] # We'll need them first thing, might as well load here
if not len(di._unsorted_CUs):
return None # Weird, but saw it once - debug sections present, but no CUs
# For quick CU search by offset within the info section, regardless of sorting
di._CU_offsets = [cu.cu_offset for cu in di._unsorted_CUs]
di._CUs = list(di._unsorted_CUs)

if self.sortcus:
di._CUs.sort(key = cu_sort_key)
for (i, cu) in enumerate(di._CUs):
cu._i = i
di._locparser = None # Created on first use

self.dwarfinfo = di
self.filename = filename
self.tree_model = DWARFTreeModel(di, self.prefix, self.sortcus, self.sortdies)
self.the_tree.setModel(self.tree_model)
self.the_tree.selectionModel().currentChanged.connect(self.on_tree_selection)
s = os.path.basename(filename)
if arch is not None:
s += ' (' + arch + ')'
self.setWindowTitle("DWARF Explorer - " + s)
self.savesection_menuitem.setEnabled(True)
self.back_menuitem.setEnabled(False)
self.back_tbitem.setEnabled(False)
self.forward_menuitem.setEnabled(False)
self.forward_tbitem.setEnabled(False)
self.followref_menuitem.setEnabled(False)
self.followref_tbitem.setEnabled(False)
self.highlightcode_menuitem.setEnabled(True)
self.highlightsubstring_menuitem.setEnabled(True)
self.highlightcondition_menuitem.setEnabled(True)
self.highlightnothing_menuitem.setEnabled(True)
self.copy_menuitem.setEnabled(False)
self.copy_tbitem.setEnabled(False)
self.copyline_menuitem.setEnabled(False)
self.copytable_menuitem.setEnabled(False)
self.findbycondition_menuitem.setEnabled(True)
self.find_menuitem.setEnabled(True)
self.find_tbitem.setEnabled(True)
self.findip_menuitem.setEnabled(True)
self.byoffset_menuitem.setEnabled(True)
self.byoffset_tbitem.setEnabled(True)
self.localsat_menuitem.setEnabled(True)
self.on_highlight_nothing()
# Navigation stack - empty
self.navhistory = []
self.navpos = -1
self.save_filename_in_mru(filename, di._fat_arch if '_fat_arch' in dir(di) and di._fat_arch else None)
LocalsDlg.reset(di)
from .crash import set_binary_desc
set_binary_desc(("ELF", "MachO", "PE", "WASM")[di._format] + " " + di.config.machine_arch)
return True
except AssertionError as ass: # Covers exeptions during parsing
raise DWARFParseError(ass, di)
return self.load_dwarfinfo(di, filename, arch)
finally:
self.end_wait()

# May throw if parsing fails
def load_dwarfinfo(self, di, filename, arch):
# Some degree of graceful handling of wrong format
try:
# Some cached top level stuff
# Notably, iter_CUs doesn't cache (TODO, check that in the next version)
di._ranges = None # Loaded on first use
di._aranges = None
def decorate_cu(cu, i):
cu._i = i
cu._lineprogram = None
cu._exprparser = None
return cu
di._unsorted_CUs = [decorate_cu(cu, i) for (i, cu) in enumerate(di.iter_CUs())] # We'll need them first thing, might as well load here
if not len(di._unsorted_CUs):
return None # Weird, but saw it once - debug sections present, but no CUs
# For quick CU search by offset within the info section, regardless of sorting
di._CU_offsets = [cu.cu_offset for cu in di._unsorted_CUs]
di._CUs = list(di._unsorted_CUs)

if self.sortcus:
di._CUs.sort(key = cu_sort_key)
for (i, cu) in enumerate(di._CUs):
cu._i = i
di._locparser = None # Created on first use - but see #1683

self.dwarfinfo = di
self.filename = filename
self.tree_model = DWARFTreeModel(di, self.prefix, self.sortcus, self.sortdies)
self.the_tree.setModel(self.tree_model)
self.the_tree.selectionModel().currentChanged.connect(self.on_tree_selection)
s = os.path.basename(filename)
if arch is not None:
s += ' (' + arch + ')'
self.setWindowTitle("DWARF Explorer - " + s)
self.savesection_menuitem.setEnabled(True)
self.back_menuitem.setEnabled(False)
self.back_tbitem.setEnabled(False)
self.forward_menuitem.setEnabled(False)
self.forward_tbitem.setEnabled(False)
self.followref_menuitem.setEnabled(False)
self.followref_tbitem.setEnabled(False)
self.highlightcode_menuitem.setEnabled(True)
self.highlightsubstring_menuitem.setEnabled(True)
self.highlightcondition_menuitem.setEnabled(True)
self.highlightnothing_menuitem.setEnabled(True)
self.copy_menuitem.setEnabled(False)
self.copy_tbitem.setEnabled(False)
self.copyline_menuitem.setEnabled(False)
self.copytable_menuitem.setEnabled(False)
self.findbycondition_menuitem.setEnabled(True)
self.find_menuitem.setEnabled(True)
self.find_tbitem.setEnabled(True)
self.findip_menuitem.setEnabled(True)
self.byoffset_menuitem.setEnabled(True)
self.byoffset_tbitem.setEnabled(True)
self.localsat_menuitem.setEnabled(True)
self.on_highlight_nothing()
# Navigation stack - empty
self.navhistory = []
self.navpos = -1
self.save_filename_in_mru(filename, di._fat_arch if '_fat_arch' in dir(di) and di._fat_arch else None)
LocalsDlg.reset(di)
from .crash import set_binary_desc
set_binary_desc(("ELF", "MachO", "PE", "WASM")[di._format] + " " + di.config.machine_arch)
return True
except AssertionError as ass: # Covers exeptions during parsing
raise DWARFParseError(ass, di)

def save_mru(self):
for i, fa in enumerate(self.mru):
Expand Down Expand Up @@ -736,6 +740,46 @@ def on_issue(self):
def on_homepage(self):
QDesktopServices.openUrl(QUrl('https://github.com/sevaa/dwex'))

# All purpose debug hook
def on_debug(self):
import io
from elftools.dwarf.dwarfinfo import DWARFInfo, DwarfConfig, DebugSectionDescriptor
# Read the three saved sections as bytestreams
base = os.environ.get("DWEX_ARG")
with open(base + '.info.dat', 'rb') as f:
info = f.read()
with open(base + '.abbrev.dat', 'rb') as f:
abbrev = f.read()
with open(base + '.str.dat', 'rb') as f:
str = f.read()

# Parse the DWARF info
di = DWARFInfo(
config = DwarfConfig(little_endian = True, default_address_size = 8, machine_arch = "ARM64"),
debug_info_sec = DebugSectionDescriptor(io.BytesIO(info), '__debug_info', None, len(info), 0),
debug_aranges_sec = None,
debug_abbrev_sec = DebugSectionDescriptor(io.BytesIO(abbrev), '__debug_abbrev', None, len(abbrev), 0),
debug_frame_sec = None,
eh_frame_sec = None,
debug_str_sec = DebugSectionDescriptor(io.BytesIO(str), '__debug_str', None, len(str), 0),
debug_loc_sec = None,
debug_ranges_sec = None,
debug_line_sec = None,
debug_pubtypes_sec = None,
debug_pubnames_sec = None,
debug_addr_sec=None,
debug_str_offsets_sec=None,
debug_line_str_sec=None,
debug_loclists_sec = None,
debug_rnglists_sec = None,
debug_sup_sec = None,
gnu_debugaltlink_sec = None
)
di._start_address = 0
di._format = 1

self.load_dwarfinfo(di, "", "ARM64")

# Doesn't quite work for the delay on tree expansion :( TODO: timer checks before lighting up this
def start_wait(self):
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
Expand Down
3 changes: 3 additions & 0 deletions dwex/die.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,17 +212,20 @@ def format_value(self, attr):
return str(val)
else:
return hex(val) if self.hex and isinstance(val, int) else str(val)
# except BaseException as exc:
except ELFParseError as exc:
from .__main__ import version
from .crash import report_crash
from inspect import currentframe
tb = exc.__traceback__
di = die.cu.dwarfinfo
file_addr_size = di.config.default_address_size
loc_section = di.debug_loclists_sec if dwarf_version >= 5 else di.debug_loc_sec
loc_sec_len = len(loc_section.stream.getbuffer()) if loc_section else None
ctxt = {'attr': attr,
'die': die,
'cu_header': header,
'file_addr_size': file_addr_size,
'dwarf_version': dwarf_version,
'sec_size': loc_sec_len}
report_crash(exc, tb, version, currentframe(), ctxt)
Expand Down
11 changes: 5 additions & 6 deletions dwex/dwarfone.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,16 +255,15 @@ class DWARFInfoV1(object):
def __init__(self, elffile):
section = elffile.get_section_by_name(".debug")
section_data = section.data()
# TODO: relocation? Compression?
self.section_size = len(section_data)
self.stm = BytesIO()
self.stm.write(section_data)
self.stm.seek(0, 0)
self.stm = BytesIO(section_data)

lsection = elffile.get_section_by_name(".line")
if lsection:
self.linestream = BytesIO()
self.linestream.write(lsection.data())
self.linestream.seek(0, 0)
self.linestream = BytesIO(lsection.data())
# Sections .debug_pubnames, .debug_aranges also in the spec -
# those are indices into info, we ignore them

self.config = DwarfConfig(
little_endian = elffile.little_endian,
Expand Down
6 changes: 6 additions & 0 deletions dwex/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
from types import MethodType
from io import BytesIO

# Good reference on DWARF extensions here:
# https://sourceware.org/elfutils/DwarfExtensions

# ELF reference:
# https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.sheader.html

def monkeypatch():
#https://docs.hdoc.io/hdoc/llvm-project/e051F173385B23DEF.html
elftools.dwarf.enums.ENUM_DW_AT["DW_AT_LLVM_apinotes"] = 0x3e07
Expand Down
3 changes: 3 additions & 0 deletions dwex/ui.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from PyQt6.QtCore import Qt, QRectF, QSizeF, QPointF, QByteArray
from PyQt6.QtGui import QKeySequence, QAction, QImage, QPixmap, QPainter, QIcon
from PyQt6.QtWidgets import *
Expand All @@ -21,6 +22,8 @@ def setup_menu(win):
exit_menuitem.setMenuRole(QAction.MenuRole.QuitRole)
exit_menuitem.setShortcut(QKeySequence.StandardKey.Quit)
exit_menuitem.triggered.connect(win.on_exit)
if os.environ.get("DWEX_DEBUG") is not None:
file_menu.addAction("Debug").triggered.connect(win.on_debug)
#########
view_menu = menu.addMenu("View")
win.prefix_menuitem = view_menu.addAction("DWARF prefix")
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def run(self):

setup(
name='dwex',
version='3.23', # Sync with version in __main__
version='3.24', # Sync with version in __main__
packages=['dwex'],
url="https://github.com/sevaa/dwex/",
entry_points={"gui_scripts": ["dwex = dwex.__main__:main"]},
Expand Down

0 comments on commit 3072ec3

Please sign in to comment.