1
0
Fork 0

Finished formatting, added section type to tuple

This commit is contained in:
JoshuaMKW 2020-09-28 13:54:19 -05:00
parent 6f9d6141c9
commit 6c8d2c464d
2 changed files with 74 additions and 50 deletions

View file

@ -9,6 +9,10 @@ class AddressOutOfRangeError(Exception): pass
class DolFile(object): class DolFile(object):
class SectionType():
Text = 0
Data = 1
def __init__(self, f=None): def __init__(self, f=None):
self.fileOffsetLoc = 0 self.fileOffsetLoc = 0
self.fileAddressLoc = 0x48 self.fileAddressLoc = 0x48
@ -40,9 +44,9 @@ class DolFile(object):
f.seek(offset) f.seek(offset)
data = BytesIO(f.read(size)) data = BytesIO(f.read(size))
if i < self.maxTextSections: if i < self.maxTextSections:
self.textSections.append((offset, address, size, data)) self.textSections.append([offset, address, size, data, DolFile.SectionType.Text])
else: else:
self.dataSections.append((offset, address, size, data)) self.dataSections.append([offset, address, size, data, DolFile.SectionType.Data])
f.seek(self.fileBssInfoLoc) f.seek(self.fileBssInfoLoc)
self.bssAddress = read_uint32(f) self.bssAddress = read_uint32(f)
@ -59,31 +63,27 @@ class DolFile(object):
return "Nintendo DOL format executable for the Wii and Gamecube" return "Nintendo DOL format executable for the Wii and Gamecube"
# Internal function for # Internal function for
def resolve_address(self, gcAddr, raiseError=True) -> tuple: def resolve_address(self, gcAddr) -> tuple:
'''Returns the data of the section that houses the given address """ Returns the data of the section that houses the given address\n
If raiseError is True, a RuntimeError is raised when the address is unmapped, UnmappedAddressError is raised when the address is unmapped """
otherwise it returns None'''
for offset, address, size, data in self.textSections: for offset, address, size, data, sectiontype in self.textSections:
if address <= gcAddr < address+size: if address <= gcAddr < address+size:
return offset, address, size, data return offset, address, size, data, sectiontype
for offset, address, size, data in self.dataSections: for offset, address, size, data, sectiontype in self.dataSections:
if address <= gcAddr < address+size: if address <= gcAddr < address+size:
return offset, address, size, data return offset, address, size, data, sectiontype
if raiseError: raise UnmappedAddressError(f"Unmapped address: 0x{gcAddr:X}")
raise UnmappedAddressError(f"Unmapped address: 0x{gcAddr:X}")
return None
def seek_nearest_unmapped(self, gcAddr, buffer=0) -> int: def seek_nearest_unmapped(self, gcAddr, buffer=0) -> int:
'''Returns the nearest unmapped address (greater) if the given address is already taken by data''' '''Returns the nearest unmapped address (greater) if the given address is already taken by data'''
for _, address, size, _ in self.textSections: for _, address, size, _, _ in self.textSections:
if address > (gcAddr + buffer) or address+size < gcAddr: if address > (gcAddr + buffer) or address+size < gcAddr:
continue continue
gcAddr = address + size gcAddr = address + size
for _, address, size, _ in self.dataSections: for _, address, size, _, _ in self.dataSections:
if address > (gcAddr + buffer) or address+size < gcAddr: if address > (gcAddr + buffer) or address+size < gcAddr:
continue continue
gcAddr = address + size gcAddr = address + size
@ -92,6 +92,7 @@ class DolFile(object):
@property @property
def sections(self) -> tuple: def sections(self) -> tuple:
""" Generator that yields each section's data """ """ Generator that yields each section's data """
for i in self.textSections: for i in self.textSections:
yield i yield i
for i in self.dataSections: for i in self.dataSections:
@ -100,43 +101,47 @@ class DolFile(object):
return return
def get_final_section(self) -> tuple: def get_final_section(self) -> tuple:
""" Returns the last section in the dol file as sorted by internal offset """
largestOffset = 0 largestOffset = 0
indexToTarget = 0 indexToTarget = 0
targetType = "Text" targetType = DolFile.SectionType.Text
for i, sectionData in enumerate(self.textSections): for i, sectionData in enumerate(self.textSections):
if sectionData[0] > largestOffset: if sectionData[0] > largestOffset:
largestOffset = sectionData[0] largestOffset = sectionData[0]
indexToTarget = i indexToTarget = i
targetType = "Text" targetType = DolFile.SectionType.Text
for i, sectionData in enumerate(self.dataSections): for i, sectionData in enumerate(self.dataSections):
if sectionData[0] > largestOffset: if sectionData[0] > largestOffset:
largestOffset = sectionData[0] largestOffset = sectionData[0]
indexToTarget = i indexToTarget = i
targetType = "Data" targetType = DolFile.SectionType.Data
if targetType == "Text": if targetType == DolFile.SectionType.Text:
return self.textSections[indexToTarget] return self.textSections[indexToTarget]
else: else:
return self.dataSections[indexToTarget] return self.dataSections[indexToTarget]
def get_first_section(self) -> tuple: def get_first_section(self) -> tuple:
""" Returns the first section in the dol file as sorted by internal offset """
smallestOffset = 0xFFFFFFFF smallestOffset = 0xFFFFFFFF
indexToTarget = 0 indexToTarget = 0
targetType = "Text" targetType = DolFile.SectionType.Text
for i, sectionData in enumerate(self.textSections): for i, sectionData in enumerate(self.textSections):
if sectionData[0] < smallestOffset: if sectionData[0] < smallestOffset:
smallestOffset = sectionData[0] smallestOffset = sectionData[0]
indexToTarget = i indexToTarget = i
targetType = "Text" targetType = DolFile.SectionType.Text
for i, sectionData in enumerate(self.dataSections): for i, sectionData in enumerate(self.dataSections):
if sectionData[0] < smallestOffset: if sectionData[0] < smallestOffset:
smallestOffset = sectionData[0] smallestOffset = sectionData[0]
indexToTarget = i indexToTarget = i
targetType = "Data" targetType = DolFile.SectionType.Data
if targetType == "Text": if targetType == DolFile.SectionType.Text:
return self.textSections[indexToTarget] return self.textSections[indexToTarget]
else: else:
return self.dataSections[indexToTarget] return self.dataSections[indexToTarget]
@ -144,35 +149,35 @@ class DolFile(object):
# Unsupported: Reading an entire dol file # Unsupported: Reading an entire dol file
# Assumption: A read should not go beyond the current section # Assumption: A read should not go beyond the current section
def read(self, _size) -> bytes: def read(self, _size) -> bytes:
_, address, size, data = self.resolve_address(self._currLogicAddr) _, address, size, data, _ = self.resolve_address(self._currLogicAddr)
if self._currLogicAddr + _size > address + size: if self._currLogicAddr + _size > address + size:
raise RuntimeError("Read goes over current section") raise UnmappedAddressError("Read goes over current section")
self._currLogicAddr += _size self._currLogicAddr += _size
return data.read(_size) return data.read(_size)
# Assumption: A write should not go beyond the current section # Assumption: A write should not go beyond the current section
def write(self, _data): def write(self, _data):
_, address, size, data = self.resolve_address(self._currLogicAddr) _, address, size, data, _ = self.resolve_address(self._currLogicAddr)
if self._currLogicAddr + len(_data) > address + size: if self._currLogicAddr + len(_data) > address + size:
raise RuntimeError("Write goes over current section") raise UnmappedAddressError("Write goes over current section")
data.write(_data) data.write(_data)
self._currLogicAddr += len(_data) self._currLogicAddr += len(_data)
def seek(self, where, whence=0): def seek(self, where, whence=0):
if whence == 0: if whence == 0:
_, address, _, data = self.resolve_address(where) _, address, _, data, _ = self.resolve_address(where)
data.seek(where - address) data.seek(where - address)
self._currLogicAddr = where self._currLogicAddr = where
elif whence == 1: elif whence == 1:
_, address, _, data = self.resolve_address(self._currLogicAddr + where) _, address, _, data, _ = self.resolve_address(self._currLogicAddr + where)
data.seek((self._currLogicAddr + where) - address) data.seek((self._currLogicAddr + where) - address)
self._currLogicAddr += where self._currLogicAddr += where
else: else:
raise RuntimeError(f"Unsupported whence type '{whence}'") raise NotImplementedError(f"Unsupported whence type '{whence}'")
def tell(self) -> int: def tell(self) -> int:
return self._currLogicAddr return self._currLogicAddr
@ -184,12 +189,12 @@ class DolFile(object):
for i in range(self.maxTextSections + self.maxDataSections): for i in range(self.maxTextSections + self.maxDataSections):
if i < self.maxTextSections: if i < self.maxTextSections:
if i < len(self.textSections): if i < len(self.textSections):
offset, address, size, data = self.textSections[i] offset, address, size, data, _ = self.textSections[i]
else: else:
continue continue
else: else:
if i - self.maxTextSections < len(self.dataSections): if i - self.maxTextSections < len(self.dataSections):
offset, address, size, data = self.dataSections[i - self.maxTextSections] offset, address, size, data, _ = self.dataSections[i - self.maxTextSections]
else: else:
continue continue
@ -212,26 +217,36 @@ class DolFile(object):
align_byte_size(f, 256) align_byte_size(f, 256)
def get_full_size(self) -> int: def get_full_size(self) -> int:
offset, _, size, _ = self.get_final_section() offset, _, size, _, _ = self.get_final_section()
return (0x100 + offset + size + 255) & -256 return (offset + size + 255) & -256
def get_section_size(self, index: int, section: SectionType) -> int:
""" Return the current size of the specified section\n
section: DolFile.SectionType """
if section == DolFile.SectionType.Text:
return self.textSections[index][2]
else:
return self.dataSections[index][2]
def get_section_size(self, sectionsList: list, index: int) -> int:
return sectionsList[index][2]
def append_text_sections(self, sectionsList: list) -> bool: def append_text_sections(self, sectionsList: list) -> bool:
""" Follows the list format: [tuple(<Bytes>Data, <Int>GameAddress or None), tuple(<Bytes>Data... """ """ Follows the list format: [tuple(<Bytes>Data, <Int>GameAddress or None), tuple(<Bytes>Data... """
'''Write offset/address/size to each section in DOL file header'''
for i, dataSet in enumerate(sectionsList): for i, dataSet in enumerate(sectionsList):
if len(self.textSections) >= self.maxTextSections: if len(self.textSections) >= self.maxTextSections:
raise SectionCountFullError(f"Exceeded max text section limit of {self.maxTextSections}") raise SectionCountFullError(f"Exceeded max text section limit of {self.maxTextSections}")
fOffset, _, fSize, _ = self.get_final_section() fOffset, _, fSize, _, _ = self.get_final_section()
_, pAddress, pSize, _ = self.textSections[len(self.textSections) - 1] _, pAddress, pSize, _, _ = self.textSections[len(self.textSections) - 1]
data, address = dataSet data, address = dataSet
if not isinstance(data, BytesIO): if not hasattr(data, "getbuffer"):
data = BytesIO(data) if hasattr(data, "read"):
data.seek(0)
data = BytesIO(data.read())
else:
data = BytesIO(data)
offset = fOffset + fSize offset = fOffset + fSize
@ -246,22 +261,25 @@ class DolFile(object):
if address < 0x80000000 or address >= 0x81200000: if address < 0x80000000 or address >= 0x81200000:
raise AddressOutOfRangeError(f"Address '{address:08X}' of text section {i} is beyond scope (0x80000000 <-> 0x81200000)") raise AddressOutOfRangeError(f"Address '{address:08X}' of text section {i} is beyond scope (0x80000000 <-> 0x81200000)")
self.textSections.append((offset, address, size, data)) self.textSections.append((offset, address, size, data, DolFile.SectionType.Text))
def append_data_sections(self, sectionsList: list) -> bool: def append_data_sections(self, sectionsList: list) -> bool:
""" Follows the list format: [tuple(<Bytes>Data, <Int>GameAddress or None), tuple(<Bytes>Data... """ """ Follows the list format: [tuple(<Bytes>Data, <Int>GameAddress or None), tuple(<Bytes>Data... """
'''Write offset/address/size to each section in DOL file header'''
for i, dataSet in enumerate(sectionsList): for i, dataSet in enumerate(sectionsList):
if len(self.dataSections) >= self.maxDataSections: if len(self.dataSections) >= self.maxDataSections:
raise SectionCountFullError(f"Exceeded max data section limit of {self.maxDataSections}") raise SectionCountFullError(f"Exceeded max data section limit of {self.maxDataSections}")
fOffset, _, fSize, _ = self.get_final_section() fOffset, _, fSize, _, _ = self.get_final_section()
_, pAddress, pSize, _ = self.dataSections[len(self.dataSections) - 1] _, pAddress, pSize, _, _ = self.dataSections[len(self.dataSections) - 1]
data, address = dataSet data, address = dataSet
if not isinstance(data, BytesIO): if not hasattr(data, "getbuffer"):
data = BytesIO(data) if hasattr(data, "read"):
data.seek(0)
data = BytesIO(data.read())
else:
data = BytesIO(data)
offset = fOffset + fSize offset = fOffset + fSize
@ -276,9 +294,14 @@ class DolFile(object):
if address < 0x80000000 or address >= 0x81200000: if address < 0x80000000 or address >= 0x81200000:
raise AddressOutOfRangeError(f"Address '{address:08X}' of data section {i} is beyond scope (0x80000000 <-> 0x81200000)") raise AddressOutOfRangeError(f"Address '{address:08X}' of data section {i} is beyond scope (0x80000000 <-> 0x81200000)")
self.dataSections.append((offset, address, size, data)) self.dataSections.append((offset, address, size, data, DolFile.SectionType.Data))
def insert_branch(self, to: int, _from: int, lk=0): def insert_branch(self, to: int, _from: int, lk=0):
""" Insert a branch instruction at _from\n
to: address to branch to\n
_from: address to branch from\n
lk: 0 | 1, is branch linking? """
self.seek(_from) self.seek(_from)
write_uint32(self, (to - _from) & 0x3FFFFFD | 0x48000000 | lk) write_uint32(self, (to - _from) & 0x3FFFFFD | 0x48000000 | lk)
@ -328,6 +351,7 @@ class DolFile(object):
def print_info(self): def print_info(self):
print("|---DOL INFO---|".center(20, " ")) print("|---DOL INFO---|".center(20, " "))
for i, (offset, addr, size, _) in enumerate(self.textSections): for i, (offset, addr, size, _) in enumerate(self.textSections):
header = f"| Text section {i} |" header = f"| Text section {i} |"
print("-"*len(header) + "\n" + header + "\n" + "-"*len(header) + f"\n File offset:\t0x{offset:X}\n Virtual addr:\t0x{addr:X}\n Size:\t\t0x{size:X}\n") print("-"*len(header) + "\n" + header + "\n" + "-"*len(header) + f"\n File offset:\t0x{offset:X}\n Virtual addr:\t0x{addr:X}\n Size:\t\t0x{size:X}\n")

View file

@ -621,7 +621,7 @@ def determine_codehook(dolFile: DolFile, codeHandler: CodeHandler, hook=False):
def assert_code_hook(dolFile: DolFile, codeHandler: CodeHandler): def assert_code_hook(dolFile: DolFile, codeHandler: CodeHandler):
for _, address, size, _, in dolFile.textSections: for _, address, size, _, _ in dolFile.textSections:
dolFile.seek(address) dolFile.seek(address)
sample = dolFile.read(size) sample = dolFile.read(size)