Skip to content

Commit cfb42ce

Browse files
committed
Global functions in SyncBromaScript
1 parent d3c008e commit cfb42ce

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

scripts/ghidra/Broma.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ public String getName() {
213213

214214
public CConv getCallingConvention(Platform platform) {
215215
if (platform != Platform.WINDOWS32) {
216-
if (dispatch.isEmpty() || !dispatch.get().value.contains("static")) return CConv.THISCALL;
216+
if (parent != null && (dispatch.isEmpty() || !dispatch.get().value.contains("static"))) return CConv.THISCALL;
217217

218218
switch (platform) {
219219
case WINDOWS64:
@@ -378,6 +378,7 @@ public List<Function> getFunctions(String name) {
378378
*/
379379
private final List<Patch> patches;
380380
public final List<Class> classes;
381+
public final List<Function> functions;
381382
private boolean committed = false;
382383

383384
private Matcher forkMatcher(Pattern regex, Matcher of, String group, boolean find) {
@@ -393,13 +394,19 @@ private void applyRegexes(Platform platform) {
393394
while (matcher.find()) {
394395
this.classes.add(new Class(this, platform, matcher));
395396
}
397+
398+
var funMatcher = Regexes.GRAB_GLOBAL_FUNCTION.matcher(this.data);
399+
while (funMatcher.find()) {
400+
this.functions.add(new Function(this, null, platform, funMatcher));
401+
}
396402
}
397403

398404
private Broma() {
399405
this.path = null;
400406
this.data = null;
401407
this.patches = null;
402408
this.classes = null;
409+
this.functions = null;
403410
}
404411

405412
public static Broma fake() {
@@ -416,6 +423,7 @@ public Broma(Path path, Platform platform) throws IOException {
416423
data = Files.readString(path);
417424
patches = new ArrayList<Patch>();
418425
classes = new ArrayList<Class>();
426+
functions = new ArrayList<Function>();
419427
this.applyRegexes(platform);
420428
}
421429

scripts/ghidra/Regexes.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,32 @@ public static final Pattern grabFunction(String funName) {
6969
Pattern.DOTALL | Pattern.MULTILINE
7070
);
7171
}
72+
public static final Pattern grabGlobalFunction(String funName) {
73+
return Pattern.compile(
74+
formatRegex(
75+
// Grab attributes
76+
"(?<attrs>\\[\\[.*?\\]\\]\\s*)?" +
77+
// Must match start of line (MULTILINE flag required)
78+
"(?<=^)" +
79+
// Get the dispatch modifier keyword if one is defined
80+
"(?<dispatch>(?:inline|virtual|static|callback)\\s+)?" +
81+
// Grab the return type and name of the function, or the name if it's a destructor
82+
"(?:(?:(?<return>{0})\\s+(?<name>{2}))|(?<destructor>~{2}))" +
83+
// Grab the parameters
84+
"\\(\\s*(?<params>(?:{1}\\s*,?\\s*)*)\\)" +
85+
"(?:" +
86+
// Grab the platforms
87+
"(?:\\s*=\\s*(?<platforms>(?:\\w+\\s+(?:0x[0-9a-fA-F]+|inline)\\s*,?\\s*)+))" +
88+
// Or the body
89+
"|(?<inlinebody>(?=\\s*\\'{'))" +
90+
// Or where we can add platforms
91+
"|(?<insertplatformshere>\\s*(?=;))" +
92+
")",
93+
GRAB_TYPE, GRAB_PARAM, funName
94+
),
95+
Pattern.DOTALL | Pattern.MULTILINE
96+
);
97+
}
7298
public static final Pattern grabPlatformAddress(String platformName) {
7399
return Pattern.compile(
74100
formatRegex("(?<platform>{0})\\s+0x(?<addr>[0-9a-fA-F]+)", platformName),
@@ -116,6 +142,7 @@ public static final Pattern grabMemberOrPad(String memberName) {
116142
Pattern.DOTALL
117143
);
118144
public static final Pattern GRAB_FUNCTION = grabFunction("\\w+");
145+
public static final Pattern GRAB_GLOBAL_FUNCTION = grabGlobalFunction("\\w+");
119146
public static final Pattern GRAB_MEMBER = grabMemberOrPad("\\w+");
120147
public static final Pattern GRAB_PLATFORM_ADDRESS = grabPlatformAddress("\\w+");
121148
}

scripts/ghidra/ScriptWrapper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
public class ScriptWrapper {
5454
List<String> classes = new ArrayList<String>();
5555
List<String> enums = new ArrayList<String>();
56+
List<String> functions = new ArrayList<String>();
5657
GhidraScript wrapped;
5758
Path bindingsDir;
5859

@@ -473,7 +474,7 @@ Signature getBromaSignature(Broma.Function fun, Platform platform, boolean ignor
473474
// Parse args
474475
List<Variable> bromaParams = new ArrayList<Variable>();
475476
// Add `this` arg
476-
boolean hasThis = fun.dispatch.isEmpty() || !fun.dispatch.get().value.contains("static");
477+
boolean hasThis = fun.parent != null && (fun.dispatch.isEmpty() || !fun.dispatch.get().value.contains("static"));
477478
if (hasThis && platform != Platform.ANDROID32 && platform != Platform.MAC_INTEL) {
478479
bromaParams.add(new ParameterImpl(
479480
"this",

scripts/ghidra/SyncBromaScript.java

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ public void run() throws Exception {
144144

145145
wrapper.printfmt("Found {0} classes in Broma", wrapper.classes.size());
146146

147+
// Read functions
148+
wrapper.functions.addAll(this.bromas.stream()
149+
.map(b -> b.functions.stream().map(f -> f.getName()).toList())
150+
.flatMap(List::stream)
151+
.toList());
152+
153+
wrapper.printfmt("Found {0} functions in Broma", wrapper.functions.size());
154+
147155
// Read enums
148156
var enumPath = Paths.get(wrapper.bindingsDir.toString(), "include", "Geode", "Enums.hpp");
149157
if (Files.exists(enumPath)) {
@@ -202,8 +210,8 @@ public SignatureImport promoted(SignatureImport to) {
202210

203211
private SignatureImport importSignatureFromBroma(Address addr, Broma.Function fun, boolean force) throws Exception {
204212
final var name = fun.getName();
205-
final var className = fun.parent.name.value;
206-
final var fullName = className + "::" + name;
213+
final var className = fun.parent != null ? fun.parent.name.value : null;
214+
final var fullName = className != null ? className + "::" + name : name;
207215
final var listing = currentProgram.getListing();
208216

209217
var status = SignatureImport.NOCHANGES;
@@ -219,7 +227,9 @@ private SignatureImport importSignatureFromBroma(Address addr, Broma.Function fu
219227
addr, fun.platformOffset.get().value, fullName
220228
));
221229
}
222-
data.setParentNamespace(wrapper.addOrGetNamespace(className));
230+
if (className != null) {
231+
data.setParentNamespace(wrapper.addOrGetNamespace(className));
232+
}
223233
}
224234

225235
// Check if function already has an user-provided name - in this case, it might be merged
@@ -252,7 +262,9 @@ private SignatureImport importSignatureFromBroma(Address addr, Broma.Function fu
252262
status = status.promoted(SignatureImport.ADDED);
253263
}
254264
data.getSymbol().setName(name, SourceType.USER_DEFINED);
255-
data.setParentNamespace(wrapper.addOrGetNamespace(className));
265+
if (className != null) {
266+
data.setParentNamespace(wrapper.addOrGetNamespace(className));
267+
}
256268

257269
// Get the calling convention
258270
final var conv = fun.getCallingConvention(args.platform);
@@ -521,6 +533,30 @@ private void handleImport() throws Exception {
521533
default: break;
522534
}
523535
}
536+
537+
for (var fun : bro.functions) {
538+
// Only add functions that have an offset on this platform
539+
if (fun.platformOffset.isEmpty()) {
540+
continue;
541+
}
542+
var offset = Long.parseLong(fun.platformOffset.get().value, 16);
543+
if (offset == Broma.PLACEHOLDER_ADDR) {
544+
continue;
545+
}
546+
var addr = currentProgram.getImageBase().add(offset);
547+
548+
switch (importSignatureFromBroma(addr, fun, false)) {
549+
case ADDED: {
550+
importedAddCount += 1;
551+
wrapper.printfmt("Added {0} at {1}", fun.getName(), Long.toHexString(addr.getOffset()));
552+
} break;
553+
case UPDATED: {
554+
importedUpdateCount += 1;
555+
wrapper.printfmt("Updated {0} at {1}", fun.getName(), Long.toHexString(addr.getOffset()));
556+
} break;
557+
default: break;
558+
}
559+
}
524560
}
525561
wrapper.printfmt("Added {0} functions & updated {1} functions from Broma", importedAddCount, importedUpdateCount);
526562
}

0 commit comments

Comments
 (0)