Merge branch 'master' into mxstillpresente

This commit is contained in:
Christian Semmler 2023-12-07 07:08:12 -05:00
commit 90d7605216
7 changed files with 273 additions and 77 deletions

View File

@ -375,15 +375,16 @@ MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palett
if (p_palette) {
if (p_palette->GetEntries(entries))
return ret;
goto done;
}
else {
MxPalette local_pal;
if (local_pal.GetEntries(entries))
return ret;
goto done;
}
for (MxS32 i = 0; i < 256; i++) {
MxS32 i;
for (i = 0; i < 256; i++) {
p_rgbquad[i].rgbRed = entries[i].peRed;
p_rgbquad[i].rgbGreen = entries[i].peGreen;
p_rgbquad[i].rgbBlue = entries[i].peBlue;
@ -391,5 +392,7 @@ MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palett
}
ret = SUCCESS;
done:
return ret;
}

View File

@ -19,12 +19,50 @@ MxCompositePresenter::MxCompositePresenter()
NotificationManager()->Register(this);
}
// TEMPLATE: LEGO1 0x100b61a0
// list<MxPresenter *,allocator<MxPresenter *> >::~list<MxPresenter *,allocator<MxPresenter *> >
// FUNCTION: LEGO1 0x100b6210
// MxCompositePresenter::ClassName
// FUNCTION: LEGO1 0x100b6220
// MxCompositePresenter::IsA
// SYNTHETIC: LEGO1 0x100b62d0
// MxCompositePresenter::`scalar deleting destructor'
// FUNCTION: LEGO1 0x100b62f0
// MxCompositePresenterList::~MxCompositePresenterList
// TEMPLATE: LEGO1 0x100b6340
// List<MxPresenter *>::~List<MxPresenter *>
// FUNCTION: LEGO1 0x100b6390
MxCompositePresenter::~MxCompositePresenter()
{
NotificationManager()->Unregister(this);
}
// STUB: LEGO1 0x100b6410
MxResult MxCompositePresenter::StartAction(MxStreamController*, MxDSAction*)
{
// TODO
return SUCCESS;
}
// STUB: LEGO1 0x100b65e0
void MxCompositePresenter::EndAction()
{
// TODO
}
// STUB: LEGO1 0x100b6760
MxLong MxCompositePresenter::Notify(MxParam& p)
{
// TODO
return 0;
}
// STUB: LEGO1 0x100b67f0
void MxCompositePresenter::VTable0x58()
{
@ -37,8 +75,40 @@ void MxCompositePresenter::VTable0x5c()
// TODO
}
// STUB: LEGO1 0x100b6b40
// FUNCTION: LEGO1 0x100b6b40
void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter)
{
for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) {
if (*it == p_presenter) {
if (++it == m_list.end()) {
if (m_compositePresenter)
m_compositePresenter->VTable0x60(this);
}
else if (m_action->IsA("MxDSSerialAction")) {
MxPresenter* presenter = *it;
if (presenter->GetCurrentTickleState() == TickleState_Idle)
presenter->SetTickleState(TickleState_Ready);
}
return;
}
}
}
// STUB: LEGO1 0x100b6bc0
void MxCompositePresenter::SetTickleState(TickleState p_tickleState)
{
// TODO
}
// STUB: LEGO1 0x100b6c30
void MxCompositePresenter::Enable(MxBool p_enable)
{
// TODO
}
// STUB: LEGO1 0x100b6c80
MxBool MxCompositePresenter::HasTickleStatePassed(TickleState p_tickleState)
{
// TODO
return TRUE;
}

View File

@ -1,8 +1,10 @@
#ifndef MXCOMPOSITEPRESENTER_H
#define MXCOMPOSITEPRESENTER_H
#include "compat.h" // STL
#include "mxpresenter.h"
#include "mxunklist.h"
class MxCompositePresenterList : public list<MxPresenter*> {};
// VTABLE: LEGO1 0x100dc618
// SIZE 0x4c
@ -11,26 +13,31 @@ class MxCompositePresenter : public MxPresenter {
MxCompositePresenter();
virtual ~MxCompositePresenter() override; // vtable+0x0
// FUNCTION: LEGO1 0x100b6210
virtual MxLong Notify(MxParam& p) override; // vtable+0x04
inline virtual const char* ClassName() const override // vtable+0x0c
{
// GLOBAL: LEGO1 0x100f0774
return "MxCompositePresenter";
}
// FUNCTION: LEGO1 0x100b6220
inline virtual MxBool IsA(const char* name) const override // vtable+0x10
{
return !strcmp(name, MxCompositePresenter::ClassName()) || MxPresenter::IsA(name);
}
virtual void VTable0x58();
virtual void VTable0x5c();
virtual void VTable0x60(MxPresenter* p_presenter);
virtual MxBool VTable0x64(undefined4 p_unknown);
virtual MxResult StartAction(MxStreamController*, MxDSAction*) override; // vtable+0x3c
virtual void EndAction() override; // vtable+0x40
virtual void SetTickleState(TickleState p_tickleState) override; // vtable+0x44
virtual MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48
virtual void Enable(MxBool p_enable) override; // vtable+0x54
virtual void VTable0x58(); // vtable+0x58
virtual void VTable0x5c(); // vtable+0x5c
virtual void VTable0x60(MxPresenter* p_presenter); // vtable+0x60
virtual MxBool VTable0x64(undefined4 p_unknown); // vtable+0x64
private:
MxUnkList m_list;
MxCompositePresenterList m_list; // 0x40
};
#endif // MXCOMPOSITEPRESENTER_H

View File

@ -1,38 +0,0 @@
#ifndef MXUNKLIST_H
#define MXUNKLIST_H
#include "decomp.h"
#include "mxtypes.h"
/*
* This is an as-of-yet unknown list-like data structure.
* The class hierarchy/structure isn't quite correct yet.
*/
struct MxUnkListNode {
MxUnkListNode* m_unk00;
MxUnkListNode* m_unk04;
undefined4 m_unk08;
};
class MxUnkList {
public:
inline MxUnkList()
{
undefined unk;
this->m_unk00 = unk;
MxUnkListNode* node = new MxUnkListNode();
node->m_unk00 = node;
node->m_unk04 = node;
this->m_head = node;
this->m_count = 0;
}
undefined m_unk00;
MxUnkListNode* m_head;
MxU32 m_count;
};
#endif // MXUNKLIST_H

View File

@ -1,47 +1,200 @@
import struct
from collections import namedtuple
class MZHeaderNotFoundError(Exception):
"""MZ magic string not found at the start of the binary."""
class PEHeaderNotFoundError(Exception):
"""PE magic string not found at the offset given in 0x3c."""
class SectionNotFoundError(KeyError):
"""The specified section was not found in the file."""
class InvalidVirtualAddressError(IndexError):
"""The given virtual address is too high or low
to point to something in the binary file."""
PEHeader = namedtuple(
"PEHeader",
[
"Signature",
"Machine",
"NumberOfSections",
"TimeDateStamp",
"PointerToSymbolTable", # deprecated
"NumberOfSymbols", # deprecated
"SizeOfOptionalHeader",
"Characteristics",
],
)
ImageSectionHeader = namedtuple(
"ImageSectionHeader",
[
"Name",
"Misc",
"VirtualAddress",
"SizeOfRawData",
"PointerToRawData",
"PointerToRelocations",
"PointerToLineNumbers",
"NumberOfRelocations",
"NumberOfLineNumbers",
"Characteristics",
],
)
def section_name_match(section, name):
return section.Name == struct.pack("8s", name.encode("ascii"))
def section_contains_vaddr(section, imagebase, vaddr) -> bool:
debased = vaddr - imagebase
ofs = debased - section.VirtualAddress
return 0 <= ofs < section.SizeOfRawData
# Declare a class that can automatically convert virtual executable addresses
# to file addresses
class Bin:
def __init__(self, filename, logger):
"""Parses a PE format EXE and allows reading data from a virtual address.
Reference: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"""
def __init__(self, filename, logger=None):
self.logger = logger
self.logger.debug('Parsing headers of "%s"... ', filename)
self._debuglog(f'Parsing headers of "{filename}"... ')
self.filename = filename
self.file = None
self.imagebase = None
self.textvirt = None
self.textraw = None
self.sections = []
self.last_section = None
def __enter__(self):
self.logger.debug(f"Bin {self.filename} Enter")
self._debuglog(f"Bin {self.filename} Enter")
self.file = open(self.filename, "rb")
# HACK: Strictly, we should be parsing the header, but we know where
# everything is in these two files so we just jump straight there
(mz_str,) = struct.unpack("2s", self.file.read(2))
if mz_str != b"MZ":
raise MZHeaderNotFoundError
# Read ImageBase
self.file.seek(0xB4)
(self.imagebase,) = struct.unpack("<i", self.file.read(4))
# Skip to PE header offset in MZ header.
self.file.seek(0x3C)
(pe_header_start,) = struct.unpack("<I", self.file.read(4))
# Read .text VirtualAddress
self.file.seek(0x184)
(self.textvirt,) = struct.unpack("<i", self.file.read(4))
# PE header offset is absolute, so seek there
self.file.seek(pe_header_start)
pe_hdr = PEHeader(*struct.unpack("<2s2x2H3I2H", self.file.read(0x18)))
# Read .text PointerToRawData
self.file.seek(0x18C)
(self.textraw,) = struct.unpack("<i", self.file.read(4))
self.logger.debug("... Parsing finished")
if pe_hdr.Signature != b"PE":
raise PEHeaderNotFoundError
optional_hdr = self.file.read(pe_hdr.SizeOfOptionalHeader)
(self.imagebase,) = struct.unpack("<i", optional_hdr[0x1C:0x20])
self.sections = [
ImageSectionHeader(*struct.unpack("<8s6I2HI", self.file.read(0x28)))
for i in range(pe_hdr.NumberOfSections)
]
text_section = self._get_section_by_name(".text")
self.last_section = text_section
self._debuglog("... Parsing finished")
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
self.logger.debug(f"Bin {self.filename} Exit")
self._debuglog(f"Bin {self.filename} Exit")
if self.file:
self.file.close()
def get_addr(self, virt):
return virt - self.imagebase - self.textvirt + self.textraw
def _debuglog(self, msg):
"""Write to the logger, if present"""
if self.logger is not None:
self.logger.debug(msg)
def _set_section_for_vaddr(self, vaddr):
if self.last_section is not None and section_contains_vaddr(
self.last_section, self.imagebase, vaddr
):
return
# TODO: assumes no potential for section overlap. reasonable?
self.last_section = next(
filter(
lambda section: section_contains_vaddr(section, self.imagebase, vaddr),
self.sections,
),
None,
)
if self.last_section is None:
raise InvalidVirtualAddressError
def _get_section_by_name(self, name):
section = next(
filter(lambda section: section_name_match(section, name), self.sections),
None,
)
if section is None:
raise SectionNotFoundError
return section
def get_section_offset_by_index(self, index) -> int:
"""The symbols output from cvdump gives addresses in this format: AAAA.BBBBBBBB
where A is the index (1-based) into the section table and B is the local offset.
This will return the virtual address for the start of the section at the given index
so you can get the virtual address for whatever symbol you are looking at.
"""
section = self.sections[index - 1]
return self.imagebase + section.VirtualAddress
def get_section_offset_by_name(self, name) -> int:
"""Same as above, but use the section name as the lookup"""
section = self._get_section_by_name(name)
return self.imagebase + section.VirtualAddress
def get_raw_addr(self, vaddr) -> int:
"""Returns the raw offset in the PE binary for the given virtual address."""
self._set_section_for_vaddr(vaddr)
return (
vaddr
- self.imagebase
- self.last_section.VirtualAddress
+ self.last_section.PointerToRawData
)
def is_valid_vaddr(self, vaddr) -> bool:
"""Does this virtual address point to anything in the exe?"""
section = next(
filter(
lambda section: section_contains_vaddr(section, self.imagebase, vaddr),
self.sections,
),
None,
)
return section is not None
def read(self, offset, size):
self.file.seek(self.get_addr(offset))
return self.file.read(size)
self._set_section_for_vaddr(offset)
raw_addr = self.get_raw_addr(offset)
self.file.seek(raw_addr)
# Clamp the read within the extent of the current section.
# Reading off the end will most likely misrepresent the virtual addressing.
_size = min(
size,
self.last_section.PointerToRawData
+ self.last_section.SizeOfRawData
- raw_addr,
)
return self.file.read(_size)

View File

@ -40,11 +40,12 @@ def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None
current_section = line[4:]
if current_section == "SYMBOLS" and "S_GPROC32" in line:
sym_section = int(line[21:25], 16)
sym_addr = int(line[26:34], 16)
info = RecompiledInfo()
info.addr = (
sym_addr + sym_recompfile.imagebase + sym_recompfile.textvirt
info.addr = sym_addr + sym_recompfile.get_section_offset_by_index(
sym_section
)
use_dbg_offs = False

View File

@ -86,7 +86,7 @@ def filter_out_ptr(ptype, op_str):
for i, word in enumerate(words):
try:
inttest = int(word, 16)
if inttest >= file.imagebase + file.textvirt:
if inttest >= file.get_section_offset_by_index(1):
words[i] = placeholder_generator.get(inttest)
except ValueError:
pass