diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/datatype/modifier/MDBasedAttribute.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/datatype/modifier/MDBasedAttribute.java index d91a32eead..eeadc8a215 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/datatype/modifier/MDBasedAttribute.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/datatype/modifier/MDBasedAttribute.java @@ -37,7 +37,7 @@ import mdemangler.naming.MDQualifiedName; // that String at the appropriate time in the processing of // outputting a demangled String. So, we first, purposefully // insert this null character, and later look for it in order -// to properly truncate the substring in question, in order to +// to properly truncate the substring in question, in order to // mimic what we believe is happening in Microsoft demangler // code.... but this is true only if we care to mimic Microsoft // code, which we do and do not want to do, depending on which @@ -69,7 +69,8 @@ public class MDBasedAttribute extends MDParsableItem { protected void parseInternal() throws MDException { parsed = true; // TODO: Provide mechanism to turn on/off (move this boolean into MDMang?) - boolean boolean32BitSymbols = true; + // Guessing that this is correct. We do not yet have real demangled output to test against + boolean boolean32BitSymbols = dmang.getArchitectureSize() != 16; if (boolean32BitSymbols) { switch (dmang.getAndIncrement()) { case '0': // UINFO: void @@ -124,7 +125,7 @@ public class MDBasedAttribute extends MDParsableItem { bn.parse(); StringBuilder bnBuilder = new StringBuilder(); bn.insert(bnBuilder); - dmang.appendString(bnBuilder, "\""); + dmang.appendString(bnBuilder, "\")"); dmang.insertString(bnBuilder, "__segmname(\""); basedName = bnBuilder.toString(); break; diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.java index 726afc56f1..bcc7fa84e5 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.java @@ -59,19 +59,21 @@ public class MDVCall extends MDMemberFunctionInfo { @Override public String getModifier() { - // TODO: Future specialization on 16-bit or 32plus + if (dmang.getArchitectureSize() == 16) { + return getNameModifier_16BitModel(); + } return getNameModifier_32PlusBitModel(); } @Override public void insert(StringBuilder builder) { - // TODO: Future specialization on 16-bit or 32plus - // dmang.appendString(builder, getNameModifier_32PlusBitModel()); super.insert(builder); } public String getNameModifier_16BitModel() { - String modifier = "{" + callIndex + ","; + // 20250625: added brace after comma to somewhat match the 32-bit+ model, though both + // still have a mismatched number of braces. + String modifier = "{" + callIndex + ",{"; if (myThisModel == ThisModel.NEAR) { modifier += NEAR_STRING; } @@ -93,7 +95,10 @@ public class MDVCall extends MDMemberFunctionInfo { modifier += FAR_STRING; } else { - modifier += basedType; // TODO based value. + String baseStr = basedType.toString(); + if (!baseStr.isEmpty()) { + modifier += baseStr + " "; + } } modifier += "vfptr}}' }'"; return modifier; @@ -170,6 +175,7 @@ public class MDVCall extends MDMemberFunctionInfo { myThisModel = ThisModel.NEAR; myCallModel = CallModel.NEAR; myVfptrModel = VfptrModel.BASED; + basedType = new MDBasedAttribute(dmang); basedType.parse(); // TODO: check this // nameModifier += "__near this, __near call, " + basedType + " // vfptr}}' }'"; @@ -178,6 +184,7 @@ public class MDVCall extends MDMemberFunctionInfo { myThisModel = ThisModel.NEAR; myCallModel = CallModel.FAR; myVfptrModel = VfptrModel.BASED; + basedType = new MDBasedAttribute(dmang); basedType.parse(); // TODO: check this // nameModifier += "__near this, __far call, " + basedType + " // vfptr}}' }'"; @@ -186,6 +193,7 @@ public class MDVCall extends MDMemberFunctionInfo { myThisModel = ThisModel.FAR; myCallModel = CallModel.NEAR; myVfptrModel = VfptrModel.BASED; + basedType = new MDBasedAttribute(dmang); basedType.parse(); // TODO: check this // nameModifier += "__far this, __near call, " + basedType + " // vfptr}}' }'"; @@ -194,6 +202,7 @@ public class MDVCall extends MDMemberFunctionInfo { myThisModel = ThisModel.FAR; myCallModel = CallModel.FAR; myVfptrModel = VfptrModel.BASED; + basedType = new MDBasedAttribute(dmang); basedType.parse(); // TODO: check this // nameModifier += "__far this, __far call, " + basedType + " // vfptr}}' }'"; diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java index c81d33aa2e..8dcdb535ad 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java @@ -45,6 +45,7 @@ public class MDBaseTestConfiguration { protected String mangled; protected MDParsableItem demangItem; protected boolean isFunction = false; + protected int archSize = 64; protected String demangled; protected String truth; @@ -66,6 +67,10 @@ public class MDBaseTestConfiguration { isFunction = isFunctionArg; } + public void setArchitectureSize(int size) { + archSize = size; + } + /** * Runs through the process of creating a demangler, demangling a symbol string, * testing the output, and performing other ancillary outputs and tests. @@ -91,6 +96,8 @@ public class MDBaseTestConfiguration { } mdm.setIsFunction(isFunction); + mdm.setArchitectureSize(archSize); + // Meant to be overridden, as needed by extended classes demangItem = doDemangleSymbol(mdm, mangled); demangled = (demangItem == null) ? "" : demangItem.toString(); diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java index 466f76d788..98d42c92c1 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java @@ -194,8 +194,15 @@ public class MDMangBaseTest extends AbstractGenericTest { ms2013Truth); } - private void demangleAndTestFunction() throws Exception { + private void demangleAndTestFunction32Bit() throws Exception { testConfiguration.setIsFunction(true); + testConfiguration.setArchitectureSize(32); + testConfiguration.demangleAndTest(testName, mangled, mdTruth, msTruth, ghTruth, + ms2013Truth); + } + + private void demangleAndTest16Bit() throws Exception { + testConfiguration.setArchitectureSize(16); testConfiguration.demangleAndTest(testName, mangled, mdTruth, msTruth, ghTruth, ms2013Truth); } @@ -15362,7 +15369,7 @@ public class MDMangBaseTest extends AbstractGenericTest { mangled = "_name"; mdTruth = "name"; msTruth = ""; - demangleAndTestFunction(); + demangleAndTestFunction32Bit(); } @Test @@ -15378,7 +15385,7 @@ public class MDMangBaseTest extends AbstractGenericTest { mangled = "_name@12"; mdTruth = "__stdcall name,12"; msTruth = ""; - demangleAndTestFunction(); + demangleAndTestFunction32Bit(); } @Test @@ -15394,7 +15401,7 @@ public class MDMangBaseTest extends AbstractGenericTest { mangled = "@name@12"; mdTruth = "__fastcall name,12"; msTruth = ""; - demangleAndTestFunction(); + demangleAndTestFunction32Bit(); } @Test @@ -15410,7 +15417,7 @@ public class MDMangBaseTest extends AbstractGenericTest { mangled = "name@@12"; mdTruth = "__vectorcall name,12"; msTruth = ""; - demangleAndTestFunction(); + demangleAndTestFunction32Bit(); } @Test @@ -15421,6 +15428,247 @@ public class MDMangBaseTest extends AbstractGenericTest { demangleAndTest(); } + //===================== + /* + * Following are tests involving functions and function pointers for functions that take and + * return function pointers + */ + + @Test + public void testFunctionWithFunctionPointers1() throws Exception { + mangled = "?fxa@@3PAP6AP6AHH@ZP6ADD@Z@ZA"; + msTruth = "int (__cdecl*(__cdecl** fxa)(char (__cdecl*)(char)))(int)"; + mdTruth = msTruth; + demangleAndTest(); + } + + @Test + public void testFunctionWithFunctionPointers2() throws Exception { + mangled = "?f2@@YAP6AP6AHH@ZP6ADD@Z@ZAAP6AP6AHH@Z0@Z@Z"; + msTruth = + "int (__cdecl*(__cdecl*__cdecl f2(int (__cdecl*(__cdecl*&)(char (__cdecl*)(char)))(int)))(char (__cdecl*)(char)))(int)"; + mdTruth = msTruth; + demangleAndTest(); + } + + //===================== + /* + * Follow are hand-crafted vcall modifiers with 16-bit architecture. + * These use the architectures size for parsing both the vcall modifier as well as the + * __based() attributes for those that use a based attribute + */ + + // hand-crafted... this test is a 32-bit counterpoint test for the 16-bit test after it + @Test + public void testVCallA32() throws Exception { + mangled = "??_9name0@@$BBII@AA"; + msTruth = "[thunk]: __cdecl name0::`vcall'{392,{flat}}' }'"; + mdTruth = msTruth; + demangleAndTest(); + } + + // hand-crafted + @Test + public void testVCallA16() throws Exception { + mangled = "??_9name0@@$BBII@AA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __near call, __near vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + @Test + public void testVCallB16() throws Exception { + mangled = "??_9name0@@$BBII@BA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __far call, __near vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallC16() throws Exception { + mangled = "??_9name0@@$BBII@CA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __near call, __near vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallD16() throws Exception { + mangled = "??_9name0@@$BBII@DA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __near vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallE16() throws Exception { + mangled = "??_9name0@@$BBII@EA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __near call, __far vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallF16() throws Exception { + mangled = "??_9name0@@$BBII@FA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __far call, __far vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallG16() throws Exception { + mangled = "??_9name0@@$BBII@GA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __near call, __far vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallH16() throws Exception { + mangled = "??_9name0@@$BBII@HA"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __far vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallI016() throws Exception { + mangled = "??_9name0@@$BBII@I0A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __near call, __based(void) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallJ016() throws Exception { + mangled = "??_9name0@@$BBII@J0A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__near this, __far call, __based(void) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallK016() throws Exception { + mangled = "??_9name0@@$BBII@K0A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __near call, __based(void) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL016() throws Exception { + mangled = "??_9name0@@$BBII@L0A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(void) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL116() throws Exception { + mangled = "??_9name0@@$BBII@L1A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(__self) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL216() throws Exception { + mangled = "??_9name0@@$BBII@L2A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(NYI:__near*) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL316() throws Exception { + mangled = "??_9name0@@$BBII@L3A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(NYI:__far*) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL416() throws Exception { + mangled = "??_9name0@@$BBII@L4A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(NYI:__huge*) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL516() throws Exception { + mangled = "??_9name0@@$BBII@L5A"; + // This expected result is even more questionable... need real output for based 5 code with + // 16-bit model + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL616() throws Exception { + mangled = "??_9name0@@$BBII@L6A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(NYI:__segment) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL716() throws Exception { + mangled = "??_9name0@@$BBII@L7name1@A"; + // Need special attention to mangled and demangled for this hand-crafted test + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(__segmname(\"name1\")) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + + // hand-crafted + @Test + public void testVCallL816() throws Exception { + mangled = "??_9name0@@$BBII@L8A"; + mdTruth = + "[thunk]: __cdecl name0::`vcall'{392,{__far this, __far call, __based(NYI:) vfptr}}' }'"; + msTruth = mdTruth; // TODO: Need a 16-bit machine to determine actual mdTruth + demangleAndTest16Bit(); + } + //===================== //TODO: ignore for now.