GP-4703 - MDMang - retry on demangleType

This commit is contained in:
ghizard 2024-06-20 14:02:37 +00:00
parent 0e33958c76
commit 8336bdde74
4 changed files with 75 additions and 13 deletions

View File

@ -162,22 +162,10 @@ public class MDMang {
* @throws MDException upon parsing error
*/
public MDDataType demangleType(boolean errorOnRemainingChars) throws MDException {
if (mangled == null) {
throw new MDException("MDMang: Mangled string is null.");
}
initState();
pushContext();
if (peek() != '.') {
throw new MDException("MDMang: Mangled string is not that of a type.");
}
increment();
MDDataType mdDataType = MDDataTypeParser.parseDataType(this, false);
MDDataType mdDataType = MDDataTypeParser.determineAndParseDataType(this, false);
item = mdDataType;
if (mdDataType != null) {
mdDataType.parse();
}
int numCharsRemaining = getNumCharsRemaining();
popContext();
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
throw new MDException(
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");

View File

@ -17,6 +17,7 @@ package mdemangler.datatype;
import mdemangler.MDException;
import mdemangler.MDMang;
import mdemangler.MDMang.ProcessingMode;
import mdemangler.datatype.complex.*;
import mdemangler.datatype.extended.*;
import mdemangler.datatype.modifier.*;
@ -31,6 +32,52 @@ import mdemangler.object.MDObjectCPP;
* by calling the appropriate parser at the appropriate place in the code.
*/
public class MDDataTypeParser {
/**
* This method is only to be used by MDMang itself for the highest level type parsing where
* there is not already a multi-retry. This method checks for the '.' starting character,
* determines the type by calling the {@link #parseDataType(MDMang, boolean)}, parses the type,
* and does the multi-mode retry if there is an exception on the first pass as
* MDMangObjectParser does for generic mangled objects
* @param dmang - the MDMang driver
* @param isHighest - boolean indicating whether something else modifies or names the data
* type to be parsed, which impacts when certain overloaded CV modifiers can be applied.
* @return - a type derived from MDDataType
* @throws MDException on parsing error
*/
public static MDDataType determineAndParseDataType(MDMang dmang, boolean isHighest)
throws MDException {
MDDataType dt = null;
if (dmang.peek() != '.') {
throw new MDException("MDMang: Mangled string is not that of a type.");
}
dmang.setProcessingMode(ProcessingMode.DEFAULT_STANDARD);
try {
dmang.pushContext();
dmang.increment(); // skip the '.'
dt = parseDataType(dmang, isHighest);
dt.parse();
dmang.popContext();
}
catch (MDException e1) {
dmang.resetState();
dmang.setProcessingMode(ProcessingMode.LLVM);
try {
dmang.pushContext();
dmang.increment(); // skip the '.'
dt = parseDataType(dmang, isHighest);
dt.parse();
dmang.popContext();
}
catch (MDException e2) {
throw new MDException(
"Reason1: " + e1.getMessage().trim() + "; Reason2: " + e2.getMessage().trim());
}
}
return dt;
}
/**
* This method parses all data types. Specifically, it parses void, data indirect types,
* function indirect types, and all types parsed by parsePrimaryDataType().

View File

@ -14992,6 +14992,19 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
// Note the suffix seems like an already or partially demangled name. Note that name0
// seems like a plain tag (no closing '@'), there is a regular namespace delimiter "::",
// the suffix "3@" is almost like a backreference tag with the '@' closing the full
// qualified name... except... we've seen numbers that are beyond the backref range as
// here, but also have seen numbers like 18.
@Ignore
public void testMangledTypeWithNamespaceSuffix() throws Exception {
mangled = ".?AT<unnamed-tag>@name0::3@";
msTruth = "";
mdTruth = msTruth;
demangleAndTest();
}
//=====================
@Test

View File

@ -80,4 +80,18 @@ public class MDMangExtraTest extends AbstractGenericTest {
assertEquals("k::j::i", qualifications.get(2).toString());
}
// Need to test the demangleType() method to make sure it does the retry with LLVM mode
@Test
public void testDemangleTypeWithRetry() throws Exception {
// Test string taken from MDMangBaseTest
String mangled = ".?AW4name0@?name1@name2@@YAX_N@Z@";
String truth = "enum `void __cdecl name2::name1(bool)'::name0";
MDMangGhidra demangler = new MDMangGhidra();
MDParsableItem item = demangler.demangleType(mangled, true); // note demangleType()
String demangled = item.toString();
assertEquals(truth, demangled);
}
}