3131import ghidra .program .model .data .Undefined ;
3232import ghidra .program .model .data .VoidDataType ;
3333import ghidra .program .model .listing .Function .FunctionUpdateType ;
34+ import ghidra .program .model .listing .Parameter ;
35+ import ghidra .program .model .listing .ParameterImpl ;
3436import ghidra .program .model .listing .Variable ;
3537import ghidra .program .model .listing .VariableStorage ;
3638import ghidra .program .model .symbol .SourceType ;
@@ -279,8 +281,11 @@ private SignatureImport importSignatureFromBroma(Address addr, Broma.Function fu
279281 ) {
280282 signatureConflict = true ;
281283 }
282- // Keep existing Ghidra name for args without names in Broma
283- else if (bromaParam .getName () == null && param .getName () != null ) {
284+ // Keep existing Ghidra name for args without names in Broma (Making sure to not include any duplicates)
285+ else if (
286+ bromaParam .getName () == null && param .getName () != null &&
287+ !bromaSig .parameters .subList (0 , i ).stream ().anyMatch (p -> p .getName () != null && p .getName ().equals (param .getName ()))
288+ ) {
284289 bromaParam .setName (param .getName (), SourceType .USER_DEFINED );
285290 }
286291 }
@@ -390,10 +395,24 @@ else if (conv == CConv.OPTCALL && i == 1 && !(type instanceof Composite)) {
390395 updateType = FunctionUpdateType .DYNAMIC_STORAGE_ALL_PARAMS ;
391396 }
392397
398+ // Check for already-existing parameter names
399+ for (var existingParam : data .getParameters ()) {
400+ for (var bromaParam : bromaSig .parameters ) {
401+ if (!existingParam .isAutoParameter () && existingParam .getName () != null && existingParam .getName ().equals (bromaParam .getName ())) {
402+ existingParam .setName (null , SourceType .USER_DEFINED );
403+ }
404+ }
405+ }
406+
407+ var conventionName = conv .getGhidraName ();
408+ if (bromaSig .returnsStruct && bromaSig .memberFunction && (args .platform == Platform .ANDROID32 || args .platform == Platform .MAC_INTEL )) {
409+ conventionName = args .platform == Platform .MAC_INTEL ? "__stdcall" : "__cdecl" ;
410+ }
411+
393412 // Apply new signature
394413 try {
395414 data .updateFunction (
396- conv . getGhidraName () ,
415+ conventionName ,
397416 bromaSig .returnType .orElse (null ),
398417 updateType ,
399418 true ,
@@ -404,6 +423,35 @@ else if (conv == CConv.OPTCALL && i == 1 && !(type instanceof Composite)) {
404423 throw new Error ("Died on: " + fullName + " with " + e .getMessage ());
405424 }
406425
426+ // Set struct return storage for ARM64
427+ if (bromaSig .returnsStruct && (args .platform == Platform .ANDROID64 || args .platform == Platform .MAC_ARM || args .platform == Platform .IOS )) {
428+ var newParams = new ArrayList <Parameter >(List .of (data .getParameters ()));
429+ var foundReturn = newParams .stream ().filter (p -> p .getName () != null && p .getName ().equals ("__return" )).findFirst ();
430+ if (foundReturn .isPresent ()) {
431+ foundReturn .get ().setName (null , SourceType .USER_DEFINED );
432+ }
433+ newParams .add (0 , new ParameterImpl (
434+ "__return" ,
435+ data .getReturnType (),
436+ new VariableStorage (currentProgram , currentProgram .getRegister ("x8" )),
437+ currentProgram ,
438+ SourceType .USER_DEFINED
439+ ));
440+ try {
441+ data .updateFunction (
442+ "__cdecl" ,
443+ bromaSig .returnType .orElse (null ),
444+ FunctionUpdateType .CUSTOM_STORAGE ,
445+ true ,
446+ SourceType .USER_DEFINED ,
447+ newParams .toArray (Variable []::new )
448+ );
449+ } catch (Exception e ) {
450+ throw new Error ("Died on: " + fullName + " with " + e .getMessage ());
451+ }
452+ data .setReturn (data .getReturnType (), new VariableStorage (currentProgram , currentProgram .getRegister ("x0" )), SourceType .USER_DEFINED );
453+ }
454+
407455 // Set return type storage for custom cconvs
408456 if (shouldReorderParams && bromaSig .returnType .isPresent ()) {
409457 var ret = bromaSig .returnType .get ();
0 commit comments