From e5fee6babe505acce032885a7122eb8f66b0a3cb Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Thu, 3 Feb 2022 14:08:15 -0500 Subject: [PATCH] GP-1725 - MDMang process some nonstandard mangling forms Closes #1162 --- .../main/java/mdemangler/MDEncodedNumber.java | 3 +- .../src/main/java/mdemangler/MDMang.java | 39 ++++++++- .../java/mdemangler/MDMangGenericize.java | 12 +-- .../java/mdemangler/naming/MDBasicName.java | 7 +- .../java/mdemangler/naming/MDSpecialName.java | 75 ++++++++++++++++- .../mdemangler/object/MDMangObjectParser.java | 58 ++++++++++++- .../java/mdemangler/object/MDObjectCPP.java | 9 ++- .../java/mdemangler/object/MDObjectCatch.java | 3 +- .../object/MDObjectUnwindFunclet.java | 6 +- .../java/mdemangler/typeinfo/MDTypeInfo.java | 20 +++++ .../mdemangler/typeinfo/MDTypeInfoParser.java | 25 +++++- .../java/mdemangler/typeinfo/MDVtordisp.java | 2 + .../mdemangler/typeinfo/MDVtordispex.java | 8 +- .../mdemangler/MDBaseTestConfiguration.java | 5 +- .../test/java/mdemangler/MDMangBaseTest.java | 81 ++++++++++++++++--- 15 files changed, 312 insertions(+), 41 deletions(-) diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDEncodedNumber.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDEncodedNumber.java index 1f0458b93f..deaedb2b3d 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDEncodedNumber.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDEncodedNumber.java @@ -100,7 +100,8 @@ public class MDEncodedNumber extends MDParsableItem { } } else { - throw new MDException("Illegal character in MDEncodedNumber: " + dmang.peek()); + throw new MDException("Illegal character at index " + dmang.getIndex() + + " in MDEncodedNumber: " + dmang.peek()); } } } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java index 5473e99b13..d4b1c7e1e1 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java @@ -45,6 +45,30 @@ public class MDMang { protected List contextStack = new ArrayList<>(); + public enum ProcessingMode { + DEFAULT_STANDARD, LLVM + } + + private ProcessingMode processingMode = ProcessingMode.DEFAULT_STANDARD; + + public void setProcessingMode(ProcessingMode processingMode) { + this.processingMode = processingMode; + } + + public ProcessingMode getProcessingMode() { + return processingMode; + } + + public boolean isProcessingModeActive(ProcessingMode mode) { + switch (mode) { + case LLVM: + return processingMode == mode && (getIndex() == 0); + default: + break; + } + return processingMode == mode; + } + /** * Demangles the string passed in. * @@ -69,14 +93,15 @@ public class MDMang { * @param errorOnRemainingChars * boolean flag indicating whether remaining characters causes an * error. + * @return item detected and parsed + * @throws MDException upon error parsing item */ public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException { if (mangled == null) { throw new MDException("MDMang: Mangled string is null."); } pushContext(); - item = MDMangObjectParser.parse(this); - item.parse(); + item = MDMangObjectParser.determineItemAndParse(this); if (item instanceof MDObjectCPP) { // MDMANG SPECIALIZATION USED. item = getEmbeddedObject((MDObjectCPP) item); @@ -163,13 +188,21 @@ public class MDMang { /** * Returns the current index. - * * @return the current index. */ public int getIndex() { return iter.getIndex(); } + /** + * Sets the current index. + * @param index the position to set. + * @throws IllegalArgumentException if index is not in range from 0 to string.length()-1 + */ + public void setIndex(int index) { + iter.setIndex(index); + } + /** * Returns the next character without incrementing the current index. * diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java index e98181ac9b..6148be6b3d 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java @@ -64,11 +64,7 @@ public class MDMangGenericize extends MDMang { throw new MDException("MDMang: Mangled string is null."); } pushContext(); - item = MDMangObjectParser.parse(this); - if (item != null) { - item.parse(); - } - int numCharsRemaining = getNumCharsRemaining(); + item = MDMangObjectParser.determineItemAndParse(this); appendRemainder(); popContext(); // if (errorOnRemainingChars && (numCharsRemaining > 0)) { @@ -108,7 +104,7 @@ public class MDMangGenericize extends MDMang { * genericizedString. Suggested use is to use peek() and next() when not * wanting to add the character, but to use getAndIncrement() when wanting * to add the character. - * + * * @return the character at the new position or DONE */ @Override @@ -121,7 +117,7 @@ public class MDMangGenericize extends MDMang { * by one. If the resulting index is greater or equal to the end index, the * current index is reset to the end index and a value of DONE is returned. * Also adds the character to the genericizedString. - * + * * @return the character at the new position or DONE */ @Override @@ -145,7 +141,7 @@ public class MDMangGenericize extends MDMang { * Increments the index by count. Does no testing for whether the index * surpasses the length of the string. Also does internal processing * for creating a genericized String. - * + * * @param count * number of characters to move ahead */ diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.java index 30dc921bef..5d0d6173d5 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.java @@ -17,6 +17,7 @@ package mdemangler.naming; import ghidra.util.Msg; import mdemangler.*; +import mdemangler.MDMang.ProcessingMode; import mdemangler.object.MDObjectCPP; import mdemangler.template.MDTemplateNameAndArguments; @@ -172,7 +173,11 @@ public class MDBasicName extends MDParsableItem { @Override protected void parseInternal() throws MDException { // First pass can only have name fragment of special name - if (dmang.peek() == '?') { + if (dmang.isProcessingModeActive(ProcessingMode.LLVM)) { + specialName = new MDSpecialName(dmang, 0); + specialName.parse(); + } + else if (dmang.peek() == '?') { if (dmang.peek(1) == '$') { templateNameAndArguments = new MDTemplateNameAndArguments(dmang); templateNameAndArguments.parse(); diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDSpecialName.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDSpecialName.java index 37798d3224..182dc878d0 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDSpecialName.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDSpecialName.java @@ -16,6 +16,7 @@ package mdemangler.naming; import mdemangler.*; +import mdemangler.MDMang.ProcessingMode; import mdemangler.datatype.MDDataTypeParser; import mdemangler.object.MDObjectCPP; @@ -117,6 +118,15 @@ public class MDSpecialName extends MDParsableItem { @Override protected void parseInternal() throws MDException { + if (dmang.isProcessingModeActive(ProcessingMode.LLVM)) { + parseLLVM(); + } + else { + parseDefaultStandard(); + } + } + + protected void parseDefaultStandard() throws MDException { isQualified = true; switch (dmang.getAndIncrement()) { case '0': @@ -650,7 +660,7 @@ public class MDSpecialName extends MDParsableItem { dmang.parseInfoPop(); break; case 'J': - dmang.parseInfoPush(3, "thread guard"); + dmang.parseInfoPush(3, "local static thread guard"); name = "`local static thread guard'"; dmang.parseInfoPop(); break; @@ -688,6 +698,69 @@ public class MDSpecialName extends MDParsableItem { break; } } + + // Seemingly LLVM-specific. Breaks the "norm" of MSFT model we have been following. + // The output format is our creation (trying to follow MSFT convention). + // The "?$" prefix on these are templates in MSFT's reserved space and could collide + // the a template symbol under the MSFT scheme. Maybe LLVM will eventually fix these??? + // I could be wrong in that MSFT also honors this scheme, but it seems whacked in that it + // doesn't conform to the rest of their scheme. + // Following the model of MSFT Guard output strings even though the mangled form does not + // follow MSFT's scheme. Change is that we are not outputting the extraneous tick as is seen + // in the middle of `local static guard'{2}', but we are still increasing the string value + // that is in braces by one from the coded value. Thus, we are outputting + // `thread safe static guard{1}' for "?$TSS0@". We can reconsider this later. + public void parseLLVM() throws MDException { + if (dmang.positionStartsWith("?$TSS")) { + dmang.parseInfoPush(0, "thread safe static guard"); + dmang.increment("?$TSS".length()); + String guardNumberString = getNumberString(); + dmang.parseInfoPop(); + name = "`thread safe static guard{" + guardNumberString + "}'"; + } + else if (dmang.positionStartsWith("?$S1@")) { + // The '1' in "?$S1" is currently hard-coded in the LLVM code, but I believe we + // should still enclose it in braces... subject to change. + dmang.parseInfoPush(0, "nonvisible static guard"); + dmang.increment("?$S1@".length()); + name = "`nonvisible static guard{1}'"; + dmang.parseInfoPop(); + } + else if (dmang.positionStartsWith("?$RT")) { + dmang.parseInfoPush(0, "reference temporary"); + dmang.increment("?$RT".length()); + String manglingNumberString = getNumberString(); + dmang.parseInfoPop(); + name = "`reference temporary{" + manglingNumberString + "}'"; + } + else { + throw new MDException("Could not match NonStandard Special Name"); + } + } + + /** + * Get Number (it is output as Number << '@' where Number is an unsigned int, so we are + * capturing it as a string of digits, terminated with an '@' character. + * Built for what seems to be LLVM-specific mangling. Does not follow MSFT model. + * @return a the Number represented by a String (decimal). + * @throws MDException Upon invalid character sequence or out of characters. + */ + private String getNumberString() throws MDException { + char ch; + StringBuilder builder = new StringBuilder(); + dmang.parseInfoPush(0, "Number"); + while ((ch = dmang.peek()) != '@') { + if (!Character.isDigit(ch)) { // includes end of string (MDMang.DONE) + throw new MDException("Illegal character in Number: " + ch); + } + builder.append(ch); + dmang.next(); + } + dmang.next(); // '@' + dmang.parseInfoPop(); + return builder.toString(); + } + } /******************************************************************************/ diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDMangObjectParser.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDMangObjectParser.java index d656154db3..720498c47b 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDMangObjectParser.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDMangObjectParser.java @@ -16,6 +16,7 @@ package mdemangler.object; import mdemangler.*; +import mdemangler.MDMang.ProcessingMode; import mdemangler.datatype.MDDataTypeParser; import mdemangler.template.MDTemplateNameAndArguments; @@ -25,8 +26,50 @@ import mdemangler.template.MDTemplateNameAndArguments; */ public class MDMangObjectParser { - public static MDParsableItem parse(MDMang dmang) throws MDException { + public static MDParsableItem determineItemAndParse(MDMang dmang) throws MDException { + boolean retry = false; + MDException firstException = null; + MDParsableItem myItem = null; + int index = dmang.getIndex(); + try { + myItem = parseDefaultStandard(dmang); + if (myItem != null) { + myItem.parse(); + } + else { + retry = true; + } + } + catch (MDException e) { + retry = true; + myItem = null; + firstException = e; + } + if (!retry) { + return myItem; + } + try { + dmang.setIndex(index); + myItem = parseLlvm(dmang); + if (myItem != null) { + myItem.parse(); + } + } + catch (MDException e) { + if (firstException != null) { + throw firstException; + } + throw e; + } + if (myItem == null && firstException != null) { + throw firstException; + } + return myItem; + } + + public static MDParsableItem parseDefaultStandard(MDMang dmang) throws MDException { MDParsableItem item; + dmang.setProcessingMode(ProcessingMode.DEFAULT_STANDARD); if (dmang.peek() == '?') { if (dmang.peek(1) == '@') { item = new MDObjectCodeView(dmang); @@ -52,6 +95,17 @@ public class MDMangObjectParser { return item; } + public static MDParsableItem parseLlvm(MDMang dmang) { + // Might eliminate next test if we create other "non-standard" processing + // that does not begin with "?$". + if (dmang.peek() != '?' && dmang.peek(1) != '$') { + return null; + } + dmang.setProcessingMode(ProcessingMode.LLVM); + MDObjectCPP item = new MDObjectCPP(dmang); + return item; + } + // Thus far, we have seen (created from forward code example): // __mep => [MEP], which is presumably "Managed Entry Point" // __t2m => [T2M], which is presumably "Transition to Managed (code)" @@ -96,7 +150,7 @@ public class MDMangObjectParser { * @throws MDException Upon MDMang parsing issues that cause us to fail * processing. */ - public static MDParsableItem parseObjectReserved(MDMang dmang) throws MDException { + public static MDParsableItem parseObjectReserved(MDMang dmang) { MDParsableItem item; if (dmang.positionStartsWith("__TI")) { dmang.increment("__TI".length()); diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java index efbc42e233..1daa04a36a 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java @@ -17,6 +17,7 @@ package mdemangler.object; import ghidra.util.Msg; import mdemangler.*; +import mdemangler.MDMang.ProcessingMode; import mdemangler.functiontype.MDFunctionType; import mdemangler.naming.*; import mdemangler.typeinfo.MDTypeInfo; @@ -119,7 +120,13 @@ public class MDObjectCPP extends MDObject { if (dmang.peek() != '?') { throw new MDException("Invalid ObjectCPP"); } - dmang.increment(); + if (!dmang.isProcessingModeActive(ProcessingMode.LLVM)) { + // If not LLVM mode, then the '?' seen above is valid as being part of this MDObjectCPP + // parsing, so we should consume it. If, on the other hand, we are in LLVM mode, then + // this '?' is currently part of the possible nonstandard mangling forms that are + // output by LLVM mangling and they are consumed there. + dmang.increment(); + } if ((dmang.peek(0) == '?') && (dmang.peek(1) == '?')) { //??? prefix embeddedObjectFlag = true; } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCatch.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCatch.java index 44cb9c708d..a042ab5acd 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCatch.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCatch.java @@ -43,8 +43,7 @@ public class MDObjectCatch extends MDObjectReserved { @Override protected void parseInternal() throws MDException { - internalItem = MDMangObjectParser.parse(dmang); - internalItem.parse(); + internalItem = MDMangObjectParser.determineItemAndParse(dmang); dmang.increment(); // '$' //We are assuming that we can have more than one digit. //TODO: forward programming to test beyond one digit. diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectUnwindFunclet.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectUnwindFunclet.java index f07bc2dd69..0337efbf2f 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectUnwindFunclet.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectUnwindFunclet.java @@ -37,14 +37,12 @@ public class MDObjectUnwindFunclet extends MDObjectReserved { @Override public void insert(StringBuilder builder) { super.insert(builder); - dmang.appendString(builder, - "[UnwindFunclet," + digits + "]{" + internalItem + "}"); + dmang.appendString(builder, "[UnwindFunclet," + digits + "]{" + internalItem + "}"); } @Override protected void parseInternal() throws MDException { - internalItem = MDMangObjectParser.parse(dmang); - internalItem.parse(); + internalItem = MDMangObjectParser.determineItemAndParse(dmang); dmang.increment(); // '$' //Here, we have seen $9 and $10 (two digits for $10). //TODO: forward programming to test beyond one digit. diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.java index 8109724fb2..cbb3dcd5bd 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.java @@ -43,8 +43,16 @@ public class MDTypeInfo extends MDParsableItem { _NOT_SPECIFIED, _STATIC, _VIRTUAL } + /** + * Enum representing pointer format. + */ + enum PointerFormat { + _NOT_SPECIFIED, _NEAR, _FAR //HUGE not present in mangling. + } + private StorageClass storage = StorageClass._NOT_SPECIFIED; private AccessSpecifier access = AccessSpecifier._NOT_SPECIFIED; + private PointerFormat pointerFormat = PointerFormat._NOT_SPECIFIED; private boolean isThunk = false; private boolean isMember = true; private boolean isExternC = false; @@ -103,6 +111,18 @@ public class MDTypeInfo extends MDParsableItem { return (storage == StorageClass._VIRTUAL); } + public void setPointerFormat(PointerFormat pointerFormat) { + this.pointerFormat = pointerFormat; + } + + public boolean isNear() { + return (pointerFormat == PointerFormat._NEAR); + } + + public boolean isFar() { + return (pointerFormat == PointerFormat._FAR); + } + public void setThunk() { isThunk = true; } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfoParser.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfoParser.java index 9c1943e5c3..cc8de823bb 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfoParser.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfoParser.java @@ -18,6 +18,7 @@ package mdemangler.typeinfo; import mdemangler.MDException; import mdemangler.MDMang; import mdemangler.datatype.modifier.MDBasedAttribute; +import mdemangler.typeinfo.MDTypeInfo.PointerFormat; /** * This class parses the mangled string at the current offset to determine and @@ -143,11 +144,13 @@ public class MDTypeInfoParser { // hasArgs = false; //no reason to have set true // dmang.parseInfoPop(); break; - case 'A': + case 'A': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment case 'B': dmang.increment(); typeInfo = new MDMemberFunctionInfo(dmang); typeInfo.setPrivate(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case 'C': case 'D': @@ -168,12 +171,16 @@ public class MDTypeInfoParser { dmang.increment(); typeInfo = new MDVFAdjustor(dmang); typeInfo.setPrivate(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; - case 'I': + case 'I': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment case 'J': dmang.increment(); typeInfo = new MDMemberFunctionInfo(dmang); typeInfo.setProtected(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case 'K': case 'L': @@ -194,12 +201,16 @@ public class MDTypeInfoParser { dmang.increment(); typeInfo = new MDVFAdjustor(dmang); typeInfo.setProtected(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; - case 'Q': + case 'Q': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment case 'R': dmang.increment(); typeInfo = new MDMemberFunctionInfo(dmang); typeInfo.setPublic(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case 'S': case 'T': @@ -220,6 +231,8 @@ public class MDTypeInfoParser { dmang.increment(); typeInfo = new MDVFAdjustor(dmang); typeInfo.setPublic(); + typeInfo.setPointerFormat( + (code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case 'Y': case 'Z': @@ -269,16 +282,22 @@ public class MDTypeInfoParser { case '1': typeInfo = new MDVtordisp(dmang); typeInfo.setPrivate(); + typeInfo.setPointerFormat( + (ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case '2': case '3': typeInfo = new MDVtordisp(dmang); typeInfo.setProtected(); + typeInfo.setPointerFormat( + (ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case '4': case '5': typeInfo = new MDVtordisp(dmang); typeInfo.setPublic(); + typeInfo.setPointerFormat( + (ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR); break; case '$': char ch2 = dmang.getAndIncrement(); diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.java index fb62010303..25b1825f6e 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.java @@ -33,8 +33,10 @@ public class MDVtordisp extends MDMemberFunctionInfo { @Override protected void parseInternal() throws MDException { + // 20200507: Believe this to be MDEncodedNumber vtorDisplacement = new MDEncodedNumber(dmang); vtorDisplacement.parse(); + // 20200507: Believe this to be MDEncodedNumber adjustment = new MDEncodedNumber(dmang); adjustment.parse(); nameModifier = "`vtordisp{" + vtorDisplacement + "," + adjustment + "}' "; diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.java index c661b8a248..3a9aecf2e0 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.java @@ -33,16 +33,16 @@ public class MDVtordispex extends MDMemberFunctionInfo { @Override protected void parseInternal() throws MDException { - // TODO: what is this? Possibly the displacement? + // 20200507: Believe this to be MDEncodedNumber a = new MDEncodedNumber(dmang); a.parse(); - // TODO: what is this? Possibly the adjustment? + // 20200507: Believe this to be MDEncodedNumber b = new MDEncodedNumber(dmang); b.parse(); - // TODO: what is this? + // 20200507: Believe this to be MDEncodedNumber c = new MDEncodedNumber(dmang); c.parse(); - // TODO: what is this? + // 20200507: Believe this to be MDEncodedNumber d = new MDEncodedNumber(dmang); d.parse(); nameModifier = "`vtordispex{" + a + "," + b + "," + c + "," + d + "}' "; diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java index adcf4beab1..83c04ab181 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java @@ -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. @@ -198,6 +198,7 @@ public class MDBaseTestConfiguration { demangled = demangItem.toString(); } catch (MDException e) { + Msg.info(this, "Could not demangle: " + mangled, e); demangItem = null; demangled = ""; } diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java index f463e575ef..c667beac20 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java @@ -14487,24 +14487,87 @@ public class MDMangBaseTest extends AbstractGenericTest { demangleAndTest(); } - //TODO: considering for Issue 1162 - @Ignore + // real symbol (Issue #1162) + // Following the model of MSFT Guard output strings even though the mangled form does not + // follow MSFT's scheme. Change is that we are not outputting the extraneous tick as is seen + // in the middle of `local static guard'{2}', and we are not increasing the string value + // that is in braces by one from the coded "GuardNum" value. Thus, we are outputting + // `thread safe static guard{0}' for "?$TSS0@". We can reconsider this later. + @Test public void testThreadSafeStaticGuard_1() throws Exception { mangled = "?$TSS0@?1??GetCategoryMap@CDynamicRegistrationInfoSource@XPerfAddIn@@SAPEBU_ATL_CATMAP_ENTRY@ATL@@XZ@4HA"; -// mangled = -// "?xTSS0@?1??GetCategoryMap@CDynamicRegistrationInfoSource@XPerfAddIn@@SAPEBU_ATL_CATMAP_ENTRY@ATL@@XZ@4HA"; - //TODO: investigate and consider what we should have as outputs. - msTruth = ""; mdTruth = - "int `public: static struct ATL::_ATL_CATMAP_ENTRY const * __ptr64 __cdecl XPerfAddIn::CDynamicRegistrationInfoSource::GetCategoryMap(void)'::`2'::`thread safe local static guard'"; + "int `public: static struct ATL::_ATL_CATMAP_ENTRY const * __ptr64 __cdecl XPerfAddIn::CDynamicRegistrationInfoSource::GetCategoryMap(void)'::`2'::`thread safe static guard{0}'"; + //TODO: Create MDMangVS2015 Specialization for this problem and then remove "mstruth = mdtruth" + msTruth = mdTruth; + demangleAndTest(); + } + + @Test + public void testSimpleMainTemplateAsCounterpointToThreadSafeStaticGuard() throws Exception { + mangled = "?$TSS0@HH"; // Begins with same pattern as ThreadSafeStaticGuard + msTruth = "TSS0"; + mdTruth = msTruth; + demangleAndTest(); + } + + // Manufactured by modifying "??_B?1??name0@name1@name2@@KAHPEBGAEAG@Z@51" which is a + // `local static guard'{2}'. We eliminated the closing 51 that makes it an MDGuard typeinfo + // with value of 2 (1+1). We are also eliminating the extraneous middle closing tick (single + // quote) that MSFT has in their output. We are not incrementing the value of ManglingNumber + // that we are putting in braces (unlike other MSFT guard numbers). Thus, we will output + // `nonvisible static guard{1}' for "?$S1@". We can reconsider this later. We also tacked + // on the "4HA" as is done for the `thread safe static guard' so that it is an "int". + // TODO: Watch for real symbol of this type "?$S1@". + @Test + public void testNonvisibleStaticGuard() throws Exception { + mangled = "?$S1@?1??name0@name1@name2@@KAHPEBGAEAG@Z@4HA"; + mdTruth = + "int `protected: static int __cdecl name2::name1::name0(unsigned short const * __ptr64,unsigned short & __ptr64)'::`2'::`nonvisible static guard{1}'"; + //TODO: Create MDMangVS2015 Specialization for this problem and then remove "mstruth = mdtruth" + msTruth = mdTruth; + demangleAndTest(); + } + + @Test + public void testSimpleMainTemplateAsCounterpointToNonvisibleStaticGuard() throws Exception { + mangled = "?$S1@HH"; // Begins with same pattern as ThreadSafeStaticGuard + msTruth = "S1"; + mdTruth = msTruth; + demangleAndTest(); + } + + // Manufactured by modifying "??_B?1??name0@name1@name2@@KAHPEBGAEAG@Z@51" which is a + // `local static guard'{2}'. We eliminated the closing 51 that makes it an MDGuard typeinfo + // with value of 2 (1+1). We are also eliminating the extraneous middle closing tick (single + // quote) that MSFT has in their output. We are not incrementing the value of "number" + // that we are putting in braces (unlike other MSFT guard numbers). Thus, we will output + // `reference temporary{1}'" for the "?$RT1@". We can reconsider this later. We also tacked + // on the "4HA" as is done for the `thread safe static guard' so that it is an "int". + // TODO: Watch for real symbol of this type "?$RTnum@". + @Test + public void testReferenceTemporary() throws Exception { + mangled = "?$RT1@?1??name0@name1@name2@@KAHPEBGAEAG@Z@4HA"; + mdTruth = + "int `protected: static int __cdecl name2::name1::name0(unsigned short const * __ptr64,unsigned short & __ptr64)'::`2'::`reference temporary{1}'"; + //TODO: Create MDMangVS2015 Specialization for this problem and then remove "mstruth = mdtruth" + msTruth = mdTruth; + demangleAndTest(); + } + + @Test + public void testSimpleMainTemplateAsCounterpointToReferenceTemporary() throws Exception { + mangled = "?$RT1@HH"; // Begins with same pattern as ThreadSafeStaticGuard + msTruth = "RT1"; + mdTruth = msTruth; demangleAndTest(); } //Issue 1344: Long symbols get MD5-hashed. // We have made up the output format. Nothing is sacrosanct about this output. @Test - public void testHashedSymbolComponentsLongerThan5096_1() throws Exception { + public void testHashedSymbolComponentsLongerThan4096_1() throws Exception { mangled = "??@f4873c94f485cd6716c2319fc51ac714@"; msTruth = ""; mdTruth = "`f4873c94f485cd6716c2319fc51ac714'"; @@ -14514,7 +14577,7 @@ public class MDMangBaseTest extends AbstractGenericTest { //Issue 1344: Long symbols get MD5-hashed. // We have made up the output format. Nothing is sacrosanct about this output. @Test - public void testHashedSymbolComponentsLongerThan5096_2() throws Exception { + public void testHashedSymbolComponentsLongerThan4096_2() throws Exception { mangled = "?catch$0@?0???@f4873c94f485cd6716c2319fc51ac714@@4HA"; msTruth = ""; mdTruth = "int ``f4873c94f485cd6716c2319fc51ac714''::`1'::catch$0";