GP-6526 - MicrosoftDemangler - fix logic and tests for argument tags

This commit is contained in:
ghizard
2026-03-02 17:46:36 -05:00
parent 8adc6bb567
commit 52a2425e3f
7 changed files with 90 additions and 25 deletions
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -227,6 +227,14 @@ public class MDDataType extends MDType {
}
// super.insert(builder);
}
/**
* Insert this type as though it is an template or function argument
* @param the builder to which the insertion is made
*/
public void insertAsArg(StringBuilder builder) {
insert(builder);
}
}
/******************************************************************************/
@@ -65,12 +65,16 @@ public class MDComplexType extends MDDataType {
super.insert(builder);
}
public void insertWithoutComplexTag(StringBuilder builder) {
@Override
public void insertAsArg(StringBuilder builder) {
// TODO: look at what needs to be done to get rid of this?
if ((builder.length() != 0) && (builder.charAt(0) != ' ')) {
dmang.insertString(builder, " ");
}
qualifiedName.insert(builder);
if (dmang.getOutputOptions().applyUdtArgumentTypeTag()) {
super.insert(builder);
}
}
}
@@ -44,7 +44,7 @@ public class MDArrayBasicType extends MDModifierType {
}
@Override
protected void insertReferredType(StringBuilder builder) {
protected void insertReferredType(StringBuilder builder, boolean isArg) {
StringBuilder arrayBuilder = new StringBuilder();
arrayBuilder.append("[]");
MDType dt = this.refType;
@@ -204,12 +204,27 @@ public abstract class MDModifierType extends MDDataType {
dmang.cleanOutput(builder); // 20170714
}
protected void insertReferredType(StringBuilder builder) {
refType.insert(builder);
protected void insertReferredType(StringBuilder builder, boolean asArg) {
// LATER: Investigate weather we can change refType definition from MDType to MDDataType
if (refType instanceof MDDataType mdt && asArg) {
mdt.insertAsArg(builder);
}
else {
refType.insert(builder);
}
}
@Override
public void insert(StringBuilder builder) {
insertInternal(builder, false);
}
@Override
public void insertAsArg(StringBuilder builder) {
insertInternal(builder, true);
}
private void insertInternal(StringBuilder builder, boolean asArg) {
// Added 20170412 to try have available to get MSFT affect on this
// "invalid" condition.
// if (cvMod.isBasedPtrBased()) {
@@ -274,12 +289,12 @@ public abstract class MDModifierType extends MDDataType {
// builder.insertString(" "); //20160701
if (refType instanceof MDArrayReferencedType) {
// 20170714 refType.insert(builder);
insertReferredType(builder);// 20170714
insertReferredType(builder, asArg);// 20170714
}
else if (cvMod.isPinPointer()) {
StringBuilder refBuilder = new StringBuilder();
// 20170714 refType.insert(refBuilder);
insertReferredType(refBuilder);// 20170714
insertReferredType(refBuilder, asArg);// 20170714
dmang.appendString(refBuilder, " ");
if (!(cvMod.isQuestionType() ||
(cvMod.isPointerType() && (refType instanceof MDVoidDataType)))) {
@@ -296,7 +311,7 @@ public abstract class MDModifierType extends MDDataType {
else if (cvMod.isCLIArray()) {
StringBuilder refBuilder = new StringBuilder();
// 20170714 refType.insert(refBuilder);
insertReferredType(refBuilder);// 20170714
insertReferredType(refBuilder, asArg);// 20170714
if (!(refType instanceof MDVoidDataType)) {
cvMod.insertManagedPropertiesPrefix(refBuilder);
// cvMod.insertManagedProperties(refBuilder);
@@ -319,7 +334,7 @@ public abstract class MDModifierType extends MDDataType {
// }
// //Could be function (function pointer or function) or data.
// 20170714 refType.insert(builder);
insertReferredType(builder);// 20170714
insertReferredType(builder, asArg);// 20170714
}
}
}
@@ -119,13 +119,7 @@ public class MDArgumentsList extends MDParsableItem {
}
firstArgDone = true;
StringBuilder argBuilder = new StringBuilder();
if (arg instanceof MDComplexType ct &&
!dmang.getOutputOptions().applyUdtArgumentTypeTag()) {
ct.insertWithoutComplexTag(argBuilder);
}
else {
arg.insert(argBuilder);
}
arg.insertAsArg(argBuilder);
dmang.appendString(builder, argBuilder.toString().trim());
// doing toString() allows the Based5 "bug" to be cleaned per parameter.
// possible: dmang.appendString(builder, arg.toString().trim());
@@ -202,19 +202,13 @@ public class MDTemplateArgumentsList extends MDParsableItem {
if (args.size() > 0) {
// boolean firstArgDone = false;
Iterator<Boolean> delimIter = commaDelimiter.iterator();
for (MDType arg : args) {
for (MDDataType arg : args) {
if (delimIter.next()) {
dmang.appendString(builder, ",");
}
// firstArgDone = true;
StringBuilder argBuilder = new StringBuilder();
if (arg instanceof MDComplexType ct &&
!dmang.getOutputOptions().applyUdtArgumentTypeTag()) {
ct.insertWithoutComplexTag(argBuilder);
}
else {
arg.insert(argBuilder);
}
arg.insertAsArg(argBuilder);
dmang.appendString(builder, argBuilder.toString());
}
}
@@ -299,6 +299,56 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
String className =
"F<E::D::G<E::D::H<bool_(__cdecl*const)(C::B_const&),0>,bool,C::B_const&>_>";
String functionName = className + "<E::D::A<bool,C::B_const&>_>";
Function function = assertFunction(functionName, addr);
assertNoBookmarkAt(addr);
Symbol[] symbols = symbolTable.getSymbols(addr);
assertEquals(2, symbols.length);
assertEquals(functionName, symbols[0].getName());
assertEquals(mangled, symbols[1].getName());
// Check for the Class 'this' pointer
Parameter[] parameters = function.getParameters();
assertEquals(2, parameters.length);
Parameter p1 = parameters[0];
assertEquals("this", p1.getName());
assertEquals(className + " *", p1.getDataType().toString());
Namespace ns = symbols[0].getParentNamespace();
assertEquals(className, ns.getName(false));
ns = ns.getParentNamespace();
assertEquals("E", ns.getName(false));
}
@Test
public void testFunctionThisPointerWithTags() throws Exception {
//
// Test a function within a class that has a 'this' pointer
//
String mangled =
"??$?0V?$A@_NABW4B@C@@@D@E@@@?$F@V?$G@U?$H@Q6A_NABW4B@C@@@Z$0A@@D@E@@_NABW4B@C@@@D@E@@@E@@QAE@ABV?$F@V?$A@_NABW4B@C@@@D@E@@@1@@Z";
Address addr = addr("0x0101");
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled,
MicrosoftDemanglerOptions.DEFAULT_UNDERLYING_OUTPUT, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
String className =
"F<class_E::D::G<struct_E::D::H<bool_(__cdecl*const)(enum_C::B_const&),0>,bool,enum_C::B_const&>_>";
String functionName = className + "<class_E::D::A<bool,enum_C::B_const&>_>";