mirror of
https://github.com/awgil/ffxiv_reverse.git
synced 2025-04-20 06:07:46 +00:00
Fixes
- bumped CS version to contain a bunch of fixes - correctly strip namespace element if it is the last one - do not export types marked as obsolete - removed test.yml generation - added a pass to dump nested unions - a bunch of TODOs on python side
This commit is contained in:
parent
2c2f94d591
commit
1d4f9ff7f3
6 changed files with 37 additions and 18 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@ obj/
|
||||||
bin/
|
bin/
|
||||||
*.user
|
*.user
|
||||||
logs/
|
logs/
|
||||||
|
idbtoolkit/info.yml
|
||||||
|
idbtoolkit/__pycache__/
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b67538d428032c0fab9bce8062f2c2b79bc6e7fc
|
Subproject commit 9375140795326c929c5eaeb5283082f1eb1909a1
|
|
@ -10,7 +10,7 @@ namespace idapopulate;
|
||||||
|
|
||||||
internal static class CSImportExt
|
internal static class CSImportExt
|
||||||
{
|
{
|
||||||
public static string WithoutPrefix(this string str, string prefix) => str.StartsWith(prefix) ? str.Substring(prefix.Length) : str;
|
public static string WithoutPrefix(this string str, string prefix, string sep) => str == prefix ? "" : str.StartsWith(prefix + sep) ? str.Substring(prefix.Length + sep.Length) : str;
|
||||||
|
|
||||||
// if [FieldOffset] is not specified, assume sequential layout...
|
// if [FieldOffset] is not specified, assume sequential layout...
|
||||||
public static int GetFieldOffset(this FieldInfo fi) => fi.GetCustomAttribute<FieldOffsetAttribute>()?.Value ?? Marshal.OffsetOf(fi.DeclaringType!, fi.Name).ToInt32();
|
public static int GetFieldOffset(this FieldInfo fi) => fi.GetCustomAttribute<FieldOffsetAttribute>()?.Value ?? Marshal.OffsetOf(fi.DeclaringType!, fi.Name).ToInt32();
|
||||||
|
@ -64,6 +64,8 @@ internal class CSImport
|
||||||
{
|
{
|
||||||
if (type.FullName == null)
|
if (type.FullName == null)
|
||||||
return false;
|
return false;
|
||||||
|
if (type.GetCustomAttribute<ObsoleteAttribute>() != null)
|
||||||
|
return false;
|
||||||
if (!type.FullName.StartsWith("FFXIVClientStructs.FFXIV.") && !type.FullName.StartsWith("FFXIVClientStructs.Havok."))
|
if (!type.FullName.StartsWith("FFXIVClientStructs.FFXIV.") && !type.FullName.StartsWith("FFXIVClientStructs.Havok."))
|
||||||
return false;
|
return false;
|
||||||
if (type.DeclaringType != null && (type.Name is "Addresses" or "MemberFunctionPointers" or "StaticAddressPointers" || type.Name == type.DeclaringType.Name + "VTable"))
|
if (type.DeclaringType != null && (type.Name is "Addresses" or "MemberFunctionPointers" or "StaticAddressPointers" || type.Name == type.DeclaringType.Name + "VTable"))
|
||||||
|
@ -266,7 +268,7 @@ internal class CSImport
|
||||||
|
|
||||||
private string TypeNameComplex(Type type)
|
private string TypeNameComplex(Type type)
|
||||||
{
|
{
|
||||||
var baseName = type.DeclaringType != null ? TypeNameComplex(type.DeclaringType) : type.Namespace?.WithoutPrefix("FFXIVClientStructs.").WithoutPrefix("FFXIV.").WithoutPrefix("Havok.").Replace(".", "::") ?? "";
|
var baseName = type.DeclaringType != null ? TypeNameComplex(type.DeclaringType) : type.Namespace?.WithoutPrefix("FFXIVClientStructs", ".").WithoutPrefix("FFXIV", ".").WithoutPrefix("Havok", ".").Replace(".", "::") ?? "";
|
||||||
var leafName = type.Name;
|
var leafName = type.Name;
|
||||||
if (type.IsGenericType)
|
if (type.IsGenericType)
|
||||||
{
|
{
|
||||||
|
@ -281,7 +283,7 @@ internal class CSImport
|
||||||
// hack for std
|
// hack for std
|
||||||
if (fullName.StartsWith("STD::Std"))
|
if (fullName.StartsWith("STD::Std"))
|
||||||
{
|
{
|
||||||
fullName = fullName.WithoutPrefix("STD::Std");
|
fullName = fullName.WithoutPrefix("STD::Std", "");
|
||||||
fullName = "std::"+ fullName.Substring(0, 1).ToLower() + fullName.Substring(1);
|
fullName = "std::"+ fullName.Substring(0, 1).ToLower() + fullName.Substring(1);
|
||||||
}
|
}
|
||||||
return fullName;
|
return fullName;
|
||||||
|
|
|
@ -8,25 +8,12 @@ if (outDir == null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var testRes = new Result();
|
|
||||||
var testEnum1 = new Result.Enum() { IsSigned = true, Width = 2 };
|
|
||||||
testEnum1.Values.Add(new() { Name = "E1V1", Value = 1 });
|
|
||||||
testEnum1.Values.Add(new() { Name = "E1V1dup", Value = 1 });
|
|
||||||
testEnum1.Values.Add(new() { Name = "E1V2", Value = 2 });
|
|
||||||
testEnum1.Values.Add(new() { Name = "E1V3", Value = 10 });
|
|
||||||
testRes.Enums["test::Enum1"] = testEnum1;
|
|
||||||
var testEnum2 = new Result.Enum() { IsBitfield = true, IsSigned = false, Width = 4 };
|
|
||||||
testEnum2.Values.Add(new() { Name = "E2V1", Value = 0x1 });
|
|
||||||
testEnum2.Values.Add(new() { Name = "E2V2", Value = 0x4 });
|
|
||||||
testRes.Enums["test::Enum2"] = testEnum2;
|
|
||||||
testRes.Enums["test::Enum3"] = new() { Width = 1 };
|
|
||||||
testRes.Write(outDir.FullName + "/test.yml");
|
|
||||||
|
|
||||||
var gameRoot = PathUtils.FindGameRoot();
|
var gameRoot = PathUtils.FindGameRoot();
|
||||||
var resolver = new SigResolver(gameRoot + "\\ffxiv_dx11.exe");
|
var resolver = new SigResolver(gameRoot + "\\ffxiv_dx11.exe");
|
||||||
|
|
||||||
var res = new Result();
|
var res = new Result();
|
||||||
new CSImport().Populate(res, resolver);
|
new CSImport().Populate(res, resolver);
|
||||||
|
res.DumpNestedUnions();
|
||||||
|
|
||||||
var dataYml = PathUtils.FindFileAmongParents("/FFXIVClientStructs/ida/data.yml");
|
var dataYml = PathUtils.FindFileAmongParents("/FFXIVClientStructs/ida/data.yml");
|
||||||
if (dataYml != null)
|
if (dataYml != null)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace idapopulate;
|
namespace idapopulate;
|
||||||
|
|
||||||
|
@ -144,6 +145,28 @@ internal class Result
|
||||||
File.WriteAllText(path, data);
|
File.WriteAllText(path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DumpNestedUnions()
|
||||||
|
{
|
||||||
|
foreach (var (name, s) in Structs)
|
||||||
|
{
|
||||||
|
if (s.Fields.All(f => f.Offset == 0))
|
||||||
|
continue; // it's a simple union, we handle that on IDA side
|
||||||
|
|
||||||
|
foreach (var g in s.Fields.GroupBy(f => f.Offset))
|
||||||
|
{
|
||||||
|
if (g.Count() > 1)
|
||||||
|
{
|
||||||
|
var firstType = g.First().Type;
|
||||||
|
if (!g.All(f => f.Type == firstType))
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"Nested union found at {name}+0x{g.Key:X}: {string.Join(", ", g.Select(f => f.Name))}");
|
||||||
|
}
|
||||||
|
// else: all elements of the same type, we don't create union for that on IDA side
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool ValidateUniqueEaName()
|
public bool ValidateUniqueEaName()
|
||||||
{
|
{
|
||||||
Dictionary<ulong, string> uniqueEAs = new();
|
Dictionary<ulong, string> uniqueEAs = new();
|
||||||
|
|
|
@ -145,6 +145,7 @@ def populate_function_names(data):
|
||||||
ensure_function_at(ea, "function") # if function is not referenced from anywhere, define one manually
|
ensure_function_at(ea, "function") # if function is not referenced from anywhere, define one manually
|
||||||
set_custom_name(ea, g['name'], g['address'])
|
set_custom_name(ea, g['name'], g['address'])
|
||||||
|
|
||||||
|
# TODO: calculate masks for bitfield values properly
|
||||||
def populate_enums(data):
|
def populate_enums(data):
|
||||||
msg('** Populating exported enums **')
|
msg('** Populating exported enums **')
|
||||||
|
|
||||||
|
@ -170,6 +171,7 @@ def populate_enums(data):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg(f'Enum error: {e}')
|
msg(f'Enum error: {e}')
|
||||||
|
|
||||||
|
# TODO: have c# app generate correctly ordered list
|
||||||
def populate_vtables(data):
|
def populate_vtables(data):
|
||||||
# vtable population is done in several passes
|
# vtable population is done in several passes
|
||||||
Vtable = collections.namedtuple("VTable", "primaryEA secondaryEAs vFuncs base")
|
Vtable = collections.namedtuple("VTable", "primaryEA secondaryEAs vFuncs base")
|
||||||
|
@ -316,6 +318,9 @@ def populate_vtables(data):
|
||||||
pass3()
|
pass3()
|
||||||
return vtables
|
return vtables
|
||||||
|
|
||||||
|
# TODO: if all fields are at offset 0, just create union directly
|
||||||
|
# TODO: if all fields in the nested union are of the same type, don't create a union, instead just add member comment with alt names
|
||||||
|
# TODO: have c# app generate correctly ordered list
|
||||||
def populate_structs(data):
|
def populate_structs(data):
|
||||||
# structure creation is done in two passes
|
# structure creation is done in two passes
|
||||||
res = {} # base/substruct always ordered before referencing struct; key = class name
|
res = {} # base/substruct always ordered before referencing struct; key = class name
|
||||||
|
|
Loading…
Add table
Reference in a new issue