mirror of
https://github.com/isledecomp/isle.git
synced 2025-10-22 16:04:17 +00:00
Implement LegoRaceCar::HandleSkeletonKicks
and dependents (#1065)
* Implement `LegoRaceCar::HandleSkeletonKicks` and dependents * Fix typo * Spike to fix array comparisons (needs refactor) * Refactor: Dedicated method for array element matching * Address review comments * Reformat with new version of black * Apply more review comments * Address more review comments --------- Co-authored-by: jonschz <jonschz@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,7 @@ from typing import Any, Callable, Iterable, List, Optional
|
||||
from isledecomp.bin import Bin as IsleBin, InvalidVirtualAddressError
|
||||
from isledecomp.cvdump.demangler import demangle_string_const
|
||||
from isledecomp.cvdump import Cvdump, CvdumpAnalysis
|
||||
from isledecomp.cvdump.types import scalar_type_pointer
|
||||
from isledecomp.parser import DecompCodebase
|
||||
from isledecomp.dir import walk_source_dir
|
||||
from isledecomp.types import SymbolType
|
||||
@@ -220,7 +221,8 @@ class Compare:
|
||||
var.offset, var.name, var.parent_function
|
||||
)
|
||||
else:
|
||||
self._db.match_variable(var.offset, var.name)
|
||||
if self._db.match_variable(var.offset, var.name):
|
||||
self._check_if_array_and_match_elements(var.offset, var.name)
|
||||
|
||||
for tbl in codebase.iter_vtables():
|
||||
self._db.match_vtable(tbl.offset, tbl.name, tbl.base_class)
|
||||
@@ -245,6 +247,69 @@ class Compare:
|
||||
|
||||
self._db.match_string(string.offset, string.name)
|
||||
|
||||
def _check_if_array_and_match_elements(self, orig_addr: int, name: str):
|
||||
"""
|
||||
Checks if the global variable at `orig_addr` is an array.
|
||||
If yes, adds a match for all its elements. If it is an array of structs, all fields in that struct are also matched.
|
||||
Note that there is no recursion, so an array of arrays would not be handled entirely.
|
||||
This step is necessary e.g. for `0x100f0a20` (LegoRacers.cpp).
|
||||
"""
|
||||
|
||||
def _add_match_in_array(
|
||||
name: str, type_id: str, orig_addr: int, recomp_addr: int
|
||||
):
|
||||
self._db.set_recomp_symbol(
|
||||
recomp_addr,
|
||||
SymbolType.POINTER if scalar_type_pointer(type_id) else SymbolType.DATA,
|
||||
name,
|
||||
name,
|
||||
# we only need the matches when they are referenced elsewhere, hence we don't need the size
|
||||
size=None,
|
||||
)
|
||||
self._db.set_pair(orig_addr, recomp_addr)
|
||||
|
||||
matchinfo = self._db.get_by_orig(orig_addr)
|
||||
if matchinfo is None or matchinfo.recomp_addr is None:
|
||||
return
|
||||
recomp_addr = matchinfo.recomp_addr
|
||||
|
||||
node = next(
|
||||
(x for x in self.cvdump_analysis.nodes if x.addr == recomp_addr),
|
||||
None,
|
||||
)
|
||||
if node is None or node.data_type is None:
|
||||
return
|
||||
|
||||
if not node.data_type.key.startswith("0x"):
|
||||
# scalar type, so clearly not an array
|
||||
return
|
||||
|
||||
data_type = self.cv.types.keys[node.data_type.key.lower()]
|
||||
|
||||
if data_type["type"] == "LF_ARRAY":
|
||||
array_element_type = self.cv.types.get(data_type["array_type"])
|
||||
|
||||
assert node.data_type.members is not None
|
||||
|
||||
for array_element in node.data_type.members:
|
||||
orig_element_base_addr = orig_addr + array_element.offset
|
||||
recomp_element_base_addr = recomp_addr + array_element.offset
|
||||
if array_element_type.members is None:
|
||||
_add_match_in_array(
|
||||
f"{name}{array_element.name}",
|
||||
array_element_type.key,
|
||||
orig_element_base_addr,
|
||||
recomp_element_base_addr,
|
||||
)
|
||||
else:
|
||||
for member in array_element_type.members:
|
||||
_add_match_in_array(
|
||||
f"{name}{array_element.name}.{member.name}",
|
||||
array_element_type.key,
|
||||
orig_element_base_addr + member.offset,
|
||||
recomp_element_base_addr + member.offset,
|
||||
)
|
||||
|
||||
def _find_original_strings(self):
|
||||
"""Go to the original binary and look for the specified string constants
|
||||
to find a match. This is a (relatively) expensive operation so we only
|
||||
|
@@ -5,7 +5,7 @@ from isledecomp.cvdump import SymbolsEntry
|
||||
from isledecomp.types import SymbolType
|
||||
from .parser import CvdumpParser
|
||||
from .demangler import demangle_string_const, demangle_vtable
|
||||
from .types import CvdumpKeyError, CvdumpIntegrityError
|
||||
from .types import CvdumpKeyError, CvdumpIntegrityError, TypeInfo
|
||||
|
||||
|
||||
class CvdumpNode:
|
||||
@@ -35,6 +35,8 @@ class CvdumpNode:
|
||||
section_contribution: Optional[int] = None
|
||||
addr: Optional[int] = None
|
||||
symbol_entry: Optional[SymbolsEntry] = None
|
||||
# Preliminary - only used for non-static variables at the moment
|
||||
data_type: Optional[TypeInfo] = None
|
||||
|
||||
def __init__(self, section: int, offset: int) -> None:
|
||||
self.section = section
|
||||
@@ -127,6 +129,7 @@ class CvdumpAnalysis:
|
||||
# get information for built-in "T_" types.
|
||||
g_info = parser.types.get(glo.type)
|
||||
node_dict[key].confirmed_size = g_info.size
|
||||
node_dict[key].data_type = g_info
|
||||
# Previously we set the symbol type to POINTER here if
|
||||
# the variable was known to be a pointer. We can derive this
|
||||
# information later when it's time to compare the variable,
|
||||
|
Reference in New Issue
Block a user