mirror of
https://github.com/isledecomp/isle.git
synced 2025-10-26 09:54:18 +00:00
Match static function variables (#530)
* Match static function variables * IsleApp::Tick static variables
This commit is contained in:
@@ -134,7 +134,9 @@ class Compare:
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
self._db.set_recomp_symbol(addr, sym.node_type, sym.name(), sym.size())
|
||||
self._db.set_recomp_symbol(
|
||||
addr, sym.node_type, sym.name(), sym.decorated_name, sym.size()
|
||||
)
|
||||
|
||||
for lineref in cv.lines:
|
||||
addr = self.recomp_bin.get_abs_addr(lineref.section, lineref.offset)
|
||||
@@ -168,7 +170,12 @@ class Compare:
|
||||
self._db.skip_compare(fun.offset)
|
||||
|
||||
for var in codebase.iter_variables():
|
||||
self._db.match_variable(var.offset, var.name)
|
||||
if var.is_static and var.parent_function is not None:
|
||||
self._db.match_static_variable(
|
||||
var.offset, var.name, var.parent_function
|
||||
)
|
||||
else:
|
||||
self._db.match_variable(var.offset, var.name)
|
||||
|
||||
for tbl in codebase.iter_vtables():
|
||||
self._db.match_vtable(tbl.offset, tbl.name)
|
||||
|
||||
@@ -12,6 +12,7 @@ _SETUP_SQL = """
|
||||
orig_addr int,
|
||||
recomp_addr int,
|
||||
name text,
|
||||
decorated_name text,
|
||||
size int,
|
||||
should_skip int default(FALSE)
|
||||
);
|
||||
@@ -65,12 +66,13 @@ class CompareDb:
|
||||
addr: int,
|
||||
compare_type: Optional[SymbolType],
|
||||
name: Optional[str],
|
||||
decorated_name: Optional[str],
|
||||
size: Optional[int],
|
||||
):
|
||||
compare_value = compare_type.value if compare_type is not None else None
|
||||
self._db.execute(
|
||||
"INSERT INTO `symbols` (recomp_addr, compare_type, name, size) VALUES (?,?,?,?)",
|
||||
(addr, compare_value, name, size),
|
||||
"INSERT INTO `symbols` (recomp_addr, compare_type, name, decorated_name, size) VALUES (?,?,?,?,?)",
|
||||
(addr, compare_value, name, decorated_name, size),
|
||||
)
|
||||
|
||||
def get_unmatched_strings(self) -> List[str]:
|
||||
@@ -214,6 +216,56 @@ class CompareDb:
|
||||
|
||||
return did_match
|
||||
|
||||
def match_static_variable(self, addr: int, name: str, function_addr: int) -> bool:
|
||||
"""Matching a static function variable by combining the variable name
|
||||
with the decorated (mangled) name of its parent function."""
|
||||
|
||||
cur = self._db.execute(
|
||||
"""SELECT name, decorated_name
|
||||
FROM `symbols`
|
||||
WHERE orig_addr = ?""",
|
||||
(function_addr,),
|
||||
)
|
||||
|
||||
if (result := cur.fetchone()) is None:
|
||||
logger.error("No function for static variable: %s", name)
|
||||
return False
|
||||
|
||||
# Get the friendly name for the "failed to match" error message
|
||||
(function_name, decorated_name) = result
|
||||
|
||||
# Now we have to combine the variable name (read from the marker)
|
||||
# and the decorated name of the enclosing function (the above variable)
|
||||
# into a LIKE clause and try to match.
|
||||
# For example, the variable "g_startupDelay" from function "IsleApp::Tick"
|
||||
# has symbol: "?g_startupDelay@?1??Tick@IsleApp@@QAEXH@Z@4HA"
|
||||
# The function's decorated name is: "?Tick@IsleApp@@QAEXH@Z"
|
||||
cur = self._db.execute(
|
||||
"""UPDATE `symbols`
|
||||
SET orig_addr = ?
|
||||
WHERE name LIKE '%' || ? || '%' || ? || '%'
|
||||
AND orig_addr IS NULL
|
||||
AND (compare_type = ? OR compare_type = ? OR compare_type IS NULL)""",
|
||||
(
|
||||
addr,
|
||||
name,
|
||||
decorated_name,
|
||||
SymbolType.DATA.value,
|
||||
SymbolType.POINTER.value,
|
||||
),
|
||||
)
|
||||
|
||||
did_match = cur.rowcount > 0
|
||||
|
||||
if not did_match:
|
||||
logger.error(
|
||||
"Failed to match static variable %s from function %s",
|
||||
name,
|
||||
function_name,
|
||||
)
|
||||
|
||||
return did_match
|
||||
|
||||
def match_variable(self, addr: int, name: str) -> bool:
|
||||
did_match = self._match_on(SymbolType.DATA, addr, name) or self._match_on(
|
||||
SymbolType.POINTER, addr, name
|
||||
|
||||
@@ -47,6 +47,10 @@ class ParserError(Enum):
|
||||
# to ignore things like string literal that are not variables.
|
||||
GLOBAL_NOT_VARIABLE = 111
|
||||
|
||||
# WARN: A marked static variable inside a function needs to have its
|
||||
# function marked too, and in the same module.
|
||||
ORPHANED_STATIC_VARIABLE = 112
|
||||
|
||||
# This code or higher is an error, not a warning
|
||||
DECOMP_ERROR_START = 200
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ class ParserFunction(ParserSymbol):
|
||||
@dataclass
|
||||
class ParserVariable(ParserSymbol):
|
||||
is_static: bool = False
|
||||
parent_function: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -13,6 +13,7 @@ from .util import (
|
||||
)
|
||||
from .marker import (
|
||||
DecompMarker,
|
||||
MarkerCategory,
|
||||
match_marker,
|
||||
is_marker_exact,
|
||||
)
|
||||
@@ -53,6 +54,9 @@ class MarkerDict:
|
||||
self.markers[key] = marker
|
||||
return False
|
||||
|
||||
def query(self, category: MarkerCategory, module: str) -> Optional[DecompMarker]:
|
||||
return self.markers.get((category, module))
|
||||
|
||||
def iter(self) -> Iterator[DecompMarker]:
|
||||
for _, marker in self.markers.items():
|
||||
yield marker
|
||||
@@ -305,6 +309,23 @@ class DecompParser:
|
||||
)
|
||||
)
|
||||
else:
|
||||
parent_function = None
|
||||
is_static = self.state == ReaderState.IN_FUNC_GLOBAL
|
||||
|
||||
# If this is a static variable, we need to get the function
|
||||
# where it resides so that we can match it up later with the
|
||||
# mangled names of both variable and function from cvdump.
|
||||
if is_static:
|
||||
fun_marker = self.fun_markers.query(
|
||||
MarkerCategory.FUNCTION, marker.module
|
||||
)
|
||||
|
||||
if fun_marker is None:
|
||||
self._syntax_warning(ParserError.ORPHANED_STATIC_VARIABLE)
|
||||
continue
|
||||
|
||||
parent_function = fun_marker.offset
|
||||
|
||||
self._symbols.append(
|
||||
ParserVariable(
|
||||
type=marker.type,
|
||||
@@ -312,7 +333,8 @@ class DecompParser:
|
||||
module=marker.module,
|
||||
offset=marker.offset,
|
||||
name=self.curly.get_prefix(variable_name),
|
||||
is_static=self.state == ReaderState.IN_FUNC_GLOBAL,
|
||||
is_static=is_static,
|
||||
parent_function=parent_function,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user