mirror of
https://github.com/isledecomp/isle.git
synced 2024-11-26 01:28:30 -05:00
reccmp: template compare annotations (#88)
* reccmp: Add ability to compare template instantiations * Add example of template instantiation comparison. * merge * Add template compare annotations for MxList instances --------- Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
parent
f7743c51fb
commit
b77cd067d3
5 changed files with 57 additions and 23 deletions
|
@ -25,4 +25,13 @@ class MxDSActionList : public MxList<MxDSAction>
|
||||||
|
|
||||||
typedef MxListCursorChild<MxDSAction> MxDSActionListCursor;
|
typedef MxListCursorChild<MxDSAction> MxDSActionListCursor;
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100c9d20 TEMPLATE
|
||||||
|
// MxListParent<MxDSAction>::Destroy
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100c9cd0 TEMPLATE
|
||||||
|
// MxListParent<MxDSAction>::~MxListParent<MxDSAction>
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x100c9d30 TEMPLATE
|
||||||
|
// MxList<MxDSAction>::~MxList<MxDSAction>
|
||||||
|
|
||||||
#endif // MXDSACTIONLIST_H
|
#endif // MXDSACTIONLIST_H
|
||||||
|
|
|
@ -31,15 +31,11 @@ class MxListParent : public MxCore
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
m_customDestructor = Destroy;
|
m_customDestructor = Destroy;
|
||||||
}
|
}
|
||||||
// OFFSET: LEGO1 0x1001cdd0
|
|
||||||
virtual ~MxListParent() {}
|
virtual ~MxListParent() {}
|
||||||
|
|
||||||
// OFFSET: LEGO1 0x1001cd30
|
|
||||||
static void Destroy(T *) {};
|
|
||||||
|
|
||||||
// OFFSET: LEGO1 0x1001cd20
|
|
||||||
virtual MxS8 Compare(T *, T *) = 0;
|
virtual MxS8 Compare(T *, T *) = 0;
|
||||||
|
|
||||||
|
static void Destroy(T *) {};
|
||||||
protected:
|
protected:
|
||||||
MxU32 m_count; // +0x8
|
MxU32 m_count; // +0x8
|
||||||
void (*m_customDestructor)(T *); // +0xc
|
void (*m_customDestructor)(T *); // +0xc
|
||||||
|
@ -114,7 +110,6 @@ class MxListCursorChildChild : public MxListCursorChild<T>
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
// OFFSET: LEGO1 0x1001ce20
|
|
||||||
MxList<T>::~MxList()
|
MxList<T>::~MxList()
|
||||||
{
|
{
|
||||||
DeleteAll();
|
DeleteAll();
|
||||||
|
|
|
@ -182,4 +182,4 @@ MxResult MxNotificationManager::Send(MxCore *p_listener, MxParam *p_param)
|
||||||
}
|
}
|
||||||
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
|
@ -26,4 +26,13 @@ class MxPresenterList : public MxPresenterListParent
|
||||||
|
|
||||||
typedef MxListCursorChildChild<MxPresenter> MxPresenterListCursor;
|
typedef MxListCursorChildChild<MxPresenter> MxPresenterListCursor;
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x1001cd30 TEMPLATE
|
||||||
|
// MxListParent<MxPresenter>::Destroy
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x1001cdd0 TEMPLATE
|
||||||
|
// MxListParent<MxPresenter>::~MxListParent<MxPresenter>
|
||||||
|
|
||||||
|
// OFFSET: LEGO1 0x1001ce20 TEMPLATE
|
||||||
|
// MxList<MxPresenter>::~MxList<MxPresenter>
|
||||||
|
|
||||||
#endif // MXPRESENTERLIST_H
|
#endif // MXPRESENTERLIST_H
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import colorama
|
import colorama
|
||||||
|
import html
|
||||||
import re
|
import re
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(allow_abbrev=False,
|
parser = argparse.ArgumentParser(allow_abbrev=False,
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
verbose = int(args.verbose, 16)
|
verbose = int(args.verbose, 16)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
parser.error('invalid verbose argument')
|
parser.error('invalid verbose argument')
|
||||||
html = args.html
|
html_path = args.html
|
||||||
|
|
||||||
plain = args.no_color
|
plain = args.no_color
|
||||||
|
|
||||||
|
@ -140,6 +141,7 @@ def get_file_in_script_dir(fn):
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
funcs = {}
|
funcs = {}
|
||||||
lines = {}
|
lines = {}
|
||||||
|
names = {}
|
||||||
|
|
||||||
def __init__(self, pdb, file, wine_path_converter):
|
def __init__(self, pdb, file, wine_path_converter):
|
||||||
call = [get_file_in_script_dir('cvdump.exe'), '-l', '-s']
|
call = [get_file_in_script_dir('cvdump.exe'), '-l', '-s']
|
||||||
|
@ -183,6 +185,7 @@ def __init__(self, pdb, file, wine_path_converter):
|
||||||
|
|
||||||
info.name = line[77:]
|
info.name = line[77:]
|
||||||
|
|
||||||
|
self.names[info.name] = info
|
||||||
self.funcs[addr] = info
|
self.funcs[addr] = info
|
||||||
elif current_section == 'LINES' and line.startswith(' ') and not line.startswith(' '):
|
elif current_section == 'LINES' and line.startswith(' ') and not line.startswith(' '):
|
||||||
sourcepath = line.split()[0]
|
sourcepath = line.split()[0]
|
||||||
|
@ -238,6 +241,14 @@ def get_recompiled_address(self, filename, line):
|
||||||
else:
|
else:
|
||||||
logger.error('Failed to find function symbol with filename and line: %s:%d', filename, line)
|
logger.error('Failed to find function symbol with filename and line: %s:%d', filename, line)
|
||||||
|
|
||||||
|
def get_recompiled_address_from_name(self, name):
|
||||||
|
logger.debug('Looking for %s', name)
|
||||||
|
|
||||||
|
if name in self.names:
|
||||||
|
return self.names[name]
|
||||||
|
else:
|
||||||
|
logger.error('Failed to find function symbol with name: %s', name)
|
||||||
|
|
||||||
wine_path_converter = None
|
wine_path_converter = None
|
||||||
if os.name != 'nt':
|
if os.name != 'nt':
|
||||||
wine_path_converter = WinePathConverter(source)
|
wine_path_converter = WinePathConverter(source)
|
||||||
|
@ -419,14 +430,24 @@ def can_resolve_register_differences(original_asm, new_asm):
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
find_open_bracket = line
|
if line.endswith("TEMPLATE"):
|
||||||
while '{' not in find_open_bracket:
|
line = srcfile.readline()
|
||||||
find_open_bracket = srcfile.readline()
|
line_no += 1
|
||||||
line_no += 1
|
# Name comes after // comment
|
||||||
|
name = line[2:].strip()
|
||||||
|
|
||||||
recinfo = syminfo.get_recompiled_address(srcfilename, line_no)
|
recinfo = syminfo.get_recompiled_address_from_name(name)
|
||||||
if not recinfo:
|
if not recinfo:
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
|
find_open_bracket = line
|
||||||
|
while '{' not in find_open_bracket:
|
||||||
|
find_open_bracket = srcfile.readline()
|
||||||
|
line_no += 1
|
||||||
|
|
||||||
|
recinfo = syminfo.get_recompiled_address(srcfilename, line_no)
|
||||||
|
if not recinfo:
|
||||||
|
continue
|
||||||
|
|
||||||
# The effective_ratio is the ratio when ignoring differing register
|
# The effective_ratio is the ratio when ignoring differing register
|
||||||
# allocation vs the ratio is the true ratio.
|
# allocation vs the ratio is the true ratio.
|
||||||
|
@ -511,14 +532,14 @@ def can_resolve_register_differences(original_asm, new_asm):
|
||||||
print("\n%s is only %s similar to the original, diff above" % (recinfo.name, percenttext))
|
print("\n%s is only %s similar to the original, diff above" % (recinfo.name, percenttext))
|
||||||
|
|
||||||
# If html, record the diffs to an HTML file
|
# If html, record the diffs to an HTML file
|
||||||
if html:
|
if html_path:
|
||||||
escaped = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '<').replace('>', '>')
|
escaped = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '<').replace('>', '>')
|
||||||
htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(effective_ratio), escaped))
|
htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), html.escape(recinfo.name), str(effective_ratio), escaped))
|
||||||
|
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
break
|
break
|
||||||
|
|
||||||
def gen_html(html, data):
|
def gen_html(html_path, data):
|
||||||
templatefile = open(get_file_in_script_dir('template.html'), 'r')
|
templatefile = open(get_file_in_script_dir('template.html'), 'r')
|
||||||
if not templatefile:
|
if not templatefile:
|
||||||
print('Failed to find HTML template file, can\'t generate HTML summary')
|
print('Failed to find HTML template file, can\'t generate HTML summary')
|
||||||
|
@ -529,9 +550,9 @@ def gen_html(html, data):
|
||||||
|
|
||||||
templatedata = templatedata.replace('/* INSERT DATA HERE */', ','.join(data), 1)
|
templatedata = templatedata.replace('/* INSERT DATA HERE */', ','.join(data), 1)
|
||||||
|
|
||||||
htmlfile = open(html, 'w')
|
htmlfile = open(html_path, 'w')
|
||||||
if not htmlfile:
|
if not htmlfile:
|
||||||
print('Failed to write to HTML file %s' % html)
|
print('Failed to write to HTML file %s' % html_path)
|
||||||
return
|
return
|
||||||
|
|
||||||
htmlfile.write(templatedata)
|
htmlfile.write(templatedata)
|
||||||
|
@ -580,8 +601,8 @@ def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy):
|
||||||
svgfile.write(templatedata)
|
svgfile.write(templatedata)
|
||||||
svgfile.close()
|
svgfile.close()
|
||||||
|
|
||||||
if html:
|
if html_path:
|
||||||
gen_html(html, htmlinsert)
|
gen_html(html_path, htmlinsert)
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
if not found_verbose_target:
|
if not found_verbose_target:
|
||||||
|
|
Loading…
Reference in a new issue