From 9c942026b59ae9c3524bee40eb22ad04ff81f132 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:48:38 -0500 Subject: [PATCH] GP-5101 - MDMang - Properly process anon NS in vxtables owner and parentage; start work on OutputOptions, as needed for anon NS --- .../microsoft/MicrosoftDemangler.java | 16 ++++- .../microsoft/MicrosoftDemanglerUtil.java | 27 +++++---- .../MicrosoftDemanglerExtraTest.java | 23 ++++++++ .../src/main/java/mdemangler/MDMang.java | 10 +++- .../main/java/mdemangler/MDOutputOptions.java | 51 ++++++++++++++++ .../java/mdemangler/naming/MDBasicName.java | 10 ++-- .../mdemangler/naming/MDFragmentName.java | 11 +++- .../mdemangler/naming/MDNameModifier.java | 29 ++++++++++ .../naming/MDQualifiedBasicName.java | 6 +- .../java/mdemangler/naming/MDQualifier.java | 12 +++- .../java/mdemangler/object/MDObjectCPP.java | 4 +- .../java/mdemangler/typeinfo/MDGuard.java | 14 +++-- .../java/mdemangler/typeinfo/MDTypeInfo.java | 14 ++--- .../java/mdemangler/typeinfo/MDVCall.java | 12 ++-- .../mdemangler/typeinfo/MDVFAdjustor.java | 14 +++-- .../java/mdemangler/typeinfo/MDVtordisp.java | 19 ++++-- .../mdemangler/typeinfo/MDVtordispex.java | 23 +++++--- .../java/mdemangler/typeinfo/MDVxTable.java | 12 ++-- .../test/java/mdemangler/MDMangBaseTest.java | 19 ++++++ .../test/java/mdemangler/MDMangExtraTest.java | 58 +++++++++++++++++++ 20 files changed, 315 insertions(+), 69 deletions(-) create mode 100644 Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java create mode 100644 Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDNameModifier.java diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java index 60d7fed401..0cd7171070 100644 --- a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java +++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java @@ -66,7 +66,13 @@ public class MicrosoftDemangler implements Demangler { demangler.setIsFunction(mContext.shouldInterpretAsFunction()); try { item = demangler.demangle(); - object = MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled); + if (item == null) { + return null; + } + String originalDemangled = item.toString(); + demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true); + object = + MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled, originalDemangled); if (object != null) { object.setMangledContext(context); } @@ -103,7 +109,13 @@ public class MicrosoftDemangler implements Demangler { demangler.setIsFunction(mContext.shouldInterpretAsFunction()); try { mdType = demangler.demangleType(); - dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled); + if (mdType == null) { + return null; + } + String originalDemangled = item.toString(); + demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true); + dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled, + originalDemangled); if (dataType != null) { dataType.setMangledContext(context); } diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java index d31121fe2a..39a3e792bf 100644 --- a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java +++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java @@ -50,22 +50,27 @@ public class MicrosoftDemanglerUtil { * is not appropriate for {@link MDDataType} and some other types of {@link MDParsableItem} * @param item the item to convert * @param mangled the original mangled string + * @param originalDemangled the original demangled string * @return the {@link DemangledObject} result * @throws DemangledException up issue converting to a {@link DemangledObject} */ - static DemangledObject convertToDemangledObject(MDParsableItem item, String mangled) + static DemangledObject convertToDemangledObject(MDParsableItem item, String mangled, + String originalDemangled) throws DemangledException { - return processItem(item, mangled, item.toString()); + return processItem(item, mangled, originalDemangled); } /** - * Method to convert an {@link MDDataType} into a {@link DemangledDataType} + * Method to convert an {@link MDDataType} into a {@link DemangledDataType}. Demangler + * needs to have already run to process the type before calling this method * @param type the type to convert - * @param mangled the original mangled string + * @param mangled the mangled string + * @param originalDemangled the original demangled string * @return the result */ - static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled) { - return processDataType(null, type, mangled, type.toString()); + static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled, + String originalDemangled) { + return processDataType(null, type, mangled, originalDemangled); } //============================================================================================== @@ -121,14 +126,8 @@ public class MicrosoftDemanglerUtil { } } else if (qual.isAnon()) { - // Instead of using the standard qual.toString() method, which returns - // "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName() - // which will have the underlying anonymous name of the form "A0xfedcba98" to create - // a standardized anonymous name that is distinguishable from other anonymous names. - // The standardized name comes from createStandardAnonymousNamespaceNode(). This - // is especially important when there are sibling anonymous names. - String anon = MDMangUtils.createStandardAnonymousNamespaceNode(qual.getAnonymousName()); - demangled = new DemangledNamespaceNode(mangled, qual.toString(), anon); + String orig = qual.getAnonymousName(); + demangled = new DemangledNamespaceNode(mangled, orig, qual.toString()); } else if (qual.isInterface()) { // TODO: need to do better; setting namespace for now diff --git a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java index 8cf517384f..bd2074321e 100644 --- a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java +++ b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java @@ -178,6 +178,29 @@ public class MicrosoftDemanglerExtraTest extends AbstractGenericTest { //============================================================================================== + @Test + public void testVxTableAnonymousNsInOwnerAndBackref() throws Exception { + String mangled = "??_7a@?A0xfedcba98@b@@6B012@01@@"; + String mTruth = + "const b::`anonymous namespace'::a::`vftable'{for `b::A0xfedcba98::a's `A0xfedcba98::a'}"; + String gTruth = + "const b::_anon_FEDCBA98::a::`vftable'{for `b::_anon_FEDCBA98::a's `_anon_FEDCBA98::a'}"; + + MicrosoftDemangler demangler = new MicrosoftDemangler(); + + MicrosoftMangledContext context = + demangler.createMangledContext(mangled, null, program32, address32); + DemangledObject obj = demangler.demangle(context); + + String originalDemangled = obj.getOriginalDemangled(); + assertEquals(mTruth, originalDemangled); + + String demangled = demangler.getMdItem().toString(); + assertEquals(gTruth, demangled); + } + + //============================================================================================== + @Test //This test checks that we can provide a mangled string for a function namespace. // The return String from getOriginalMangled() is not null only for this special diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java index fcc8cc4d92..e0df9e067e 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java @@ -40,6 +40,8 @@ import mdemangler.template.MDTemplateArgumentsList; public class MDMang { public static final char DONE = MDCharacterIterator.DONE; + private MDOutputOptions outputOptions = new MDOutputOptions(); + protected int architectureSize = 32; protected boolean isFunction = false; @@ -110,7 +112,13 @@ public class MDMang { } //============================================================================================== - // Control + // Output Options + public MDOutputOptions getOutputOptions() { + return outputOptions; + } + + //============================================================================================== + // Demangling options /** * Controls whether an exception is thrown if there are remaining characters after demangling. diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java new file mode 100644 index 0000000000..a2265bc532 --- /dev/null +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java @@ -0,0 +1,51 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package mdemangler; + +/** + * Options for controlling demangler output. Quick stub for now. Full implementation was planned + * for another ticket + */ +public class MDOutputOptions { + + private boolean useEncodedAnonymousNamespaceNumber; + + /** + * Constructor + */ + public MDOutputOptions() { + } + + /** + * Sets the option for whether to use or not use the numerical encoding to craft a + * unique anonymous namespace. The default {@code false} is to produce the normal anonymous + * namespace string produced by Microsoft's {@code undname} + * @param useEncodedNumber {@code true} to produce a namespace that uses the encoded number + */ + public void setUseEncodedAnonymousNamespace(boolean useEncodedNumber) { + this.useEncodedAnonymousNamespaceNumber = useEncodedNumber; + } + + /** + * Returns {@code true} if the demangler will use the encoded number in creating the + * anonymous namespace component + * @return {@code true} if the flag is set + */ + public boolean useEncodedAnonymousNamespace() { + return useEncodedAnonymousNamespaceNumber; + } + +} 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 a75ea7d6cc..9340d5ffc3 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDBasicName.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. @@ -30,13 +30,13 @@ public class MDBasicName extends MDParsableItem { MDReusableName reusableName; MDObjectCPP embeddedObject; MDQualification embeddedObjectQualification; - String nameModifier; + MDNameModifier nameModifier; public MDBasicName(MDMang dmang) { super(dmang); } - public void setNameModifier(String nameModifier) { + public void setNameModifier(MDNameModifier nameModifier) { this.nameModifier = nameModifier; } @@ -165,7 +165,7 @@ public class MDBasicName extends MDParsableItem { templateNameAndArguments.insert(builder); } if (nameModifier != null) { - builder.append(nameModifier); + builder.append(nameModifier.getModifier()); } } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDFragmentName.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDFragmentName.java index 0537e98050..61d2c589fa 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDFragmentName.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDFragmentName.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. @@ -34,7 +34,12 @@ public class MDFragmentName extends MDParsableItem { @Override public void insert(StringBuilder builder) { - dmang.insertString(builder, name); + if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) { + dmang.insertString(builder, MDMangUtils.createStandardAnonymousNamespaceNode(name)); + } + else { + dmang.insertString(builder, name); + } } public void setName(String name) { diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDNameModifier.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDNameModifier.java new file mode 100644 index 0000000000..a4d6f17778 --- /dev/null +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDNameModifier.java @@ -0,0 +1,29 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package mdemangler.naming; + +/** + * This interface is for items that provide a name modifier + */ +public interface MDNameModifier { + + /** + * Returns the modifier string for the name + * @return the modifier + */ + public String getModifier(); + +} diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifiedBasicName.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifiedBasicName.java index 77a7a59663..86d66439fb 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifiedBasicName.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifiedBasicName.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. @@ -93,7 +93,7 @@ public class MDQualifiedBasicName extends MDParsableItem { return qualification; } - public void setNameModifier(String nameModifier) { + public void setNameModifier(MDNameModifier nameModifier) { basicName.setNameModifier(nameModifier); } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifier.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifier.java index bbd69dd1da..c766580b89 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifier.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/naming/MDQualifier.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. @@ -91,7 +91,13 @@ public class MDQualifier extends MDParsableItem { name.insert(builder); } else if (nameAnonymous != null) { - dmang.insertString(builder, ANONYMOUS_NAMESPACE); + if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) { + dmang.insertString(builder, + MDMangUtils.createStandardAnonymousNamespaceNode(nameAnonymous.getName())); + } + else { + dmang.insertString(builder, ANONYMOUS_NAMESPACE); + } } else if (nameInterface != null) { nameInterface.insert(builder); 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 b61c19e994..fc8584bc6c 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java @@ -148,9 +148,7 @@ public class MDObjectCPP extends MDObject { typeInfo.setTypeCast(); } typeInfo.parse(); - if (!typeInfo.getNameModifier().isEmpty()) { - qualifiedName.setNameModifier(typeInfo.getNameModifier()); - } + qualifiedName.setNameModifier(typeInfo); if (qualifiedName.isTypeCast()) { applyFunctionReturnTypeToTypeCastOperatorName(); } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDGuard.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDGuard.java index bd8d7e0ae9..2f055b2979 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDGuard.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDGuard.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. @@ -23,11 +23,19 @@ import mdemangler.*; */ public class MDGuard extends MDTypeInfo { + private MDEncodedNumber guardNumber; + public MDGuard(MDMang dmang) { super(dmang); + guardNumber = new MDEncodedNumber(dmang); mdtype = new MDType(dmang); } + @Override + public String getModifier() { + return "{" + guardNumber + "}'"; + } + @Override public void insert(StringBuilder builder) { super.insert(builder); @@ -35,9 +43,7 @@ public class MDGuard extends MDTypeInfo { @Override protected void parseInternal() throws MDException { - MDEncodedNumber guardNumber = new MDEncodedNumber(dmang); guardNumber.parse(); - nameModifier = "{" + guardNumber + "}'"; super.parseInternal(); } } 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 cbb3dcd5bd..1e95b02013 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDTypeInfo.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. @@ -16,11 +16,12 @@ package mdemangler.typeinfo; import mdemangler.*; +import mdemangler.naming.MDNameModifier; /** * */ -public class MDTypeInfo extends MDParsableItem { +public class MDTypeInfo extends MDParsableItem implements MDNameModifier { private static final String PRIVATE = "private: "; private static final String PROTECTED = "protected: "; private static final String PUBLIC = "public: "; @@ -61,14 +62,13 @@ public class MDTypeInfo extends MDParsableItem { protected MDType mdtype; protected boolean isTypeCast; - protected String nameModifier = ""; - public MDTypeInfo(MDMang dmang) { super(dmang, 1); } - public String getNameModifier() { - return nameModifier; + @Override + public String getModifier() { + return ""; } public void setPrivate() { 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 28c2ec61c4..726afc56f1 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVCall.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. @@ -57,6 +57,12 @@ public class MDVCall extends MDMemberFunctionInfo { callIndex = new MDEncodedNumber(dmang); } + @Override + public String getModifier() { + // TODO: Future specialization on 16-bit or 32plus + return getNameModifier_32PlusBitModel(); + } + @Override public void insert(StringBuilder builder) { // TODO: Future specialization on 16-bit or 32plus @@ -197,8 +203,6 @@ public class MDVCall extends MDMemberFunctionInfo { } // TODO evaluate whether parseInternal() or parse. super.parseInternal(); - // TODO: Future specialization on 16-bit or 32plus - nameModifier = getNameModifier_32PlusBitModel(); } } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVFAdjustor.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVFAdjustor.java index ca072437c3..23264c2cdd 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVFAdjustor.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVFAdjustor.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. @@ -24,21 +24,27 @@ import mdemangler.functiontype.MDFunctionType; */ public class MDVFAdjustor extends MDMemberFunctionInfo { + private MDEncodedNumber adjustment; + // Comment from wiki page: This kind of thunk (G,H,O,P,W,X) function is always virtual, and // used to represent the logical "this" adjustor property, which means an offset to the // true "this" value in some multiple inheritance situations. public MDVFAdjustor(MDMang dmang) { super(dmang); mdtype = new MDFunctionType(dmang); + adjustment = new MDEncodedNumber(dmang); setVirtual(); setThunk(); } + @Override + public String getModifier() { + return "`adjustor{" + adjustment + "}' "; + } + @Override protected void parseInternal() throws MDException { - MDEncodedNumber adjustment = new MDEncodedNumber(dmang); adjustment.parse(); - nameModifier = "`adjustor{" + adjustment + "}' "; super.parseInternal(); // TODO evaluate whether parseInternal() or parse. } } 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 25b1825f6e..bfa3e65305 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordisp.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. @@ -24,22 +24,31 @@ import mdemangler.functiontype.MDFunctionType; */ public class MDVtordisp extends MDMemberFunctionInfo { + // 20200507: Believe this to be + private MDEncodedNumber vtorDisplacement; + // 20200507: Believe this to be + private MDEncodedNumber adjustment; + public MDVtordisp(MDMang dmang) { super(dmang); mdtype = new MDFunctionType(dmang); + vtorDisplacement = new MDEncodedNumber(dmang); + adjustment = new MDEncodedNumber(dmang); setVirtual(); setThunk(); } + @Override + public String getModifier() { + return "`vtordisp{" + vtorDisplacement + "," + adjustment + "}' "; + } + @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 + "}' "; super.parseInternal(); } } 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 3a9aecf2e0..e58549e679 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVtordispex.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. @@ -24,6 +24,15 @@ import mdemangler.functiontype.MDFunctionType; */ public class MDVtordispex extends MDMemberFunctionInfo { + // 20200507: Believe this to be + private MDEncodedNumber a = new MDEncodedNumber(dmang); + // 20200507: Believe this to be + private MDEncodedNumber b = new MDEncodedNumber(dmang); + // 20200507: Believe this to be + private MDEncodedNumber c = new MDEncodedNumber(dmang); + // 20200507: Believe this to be + private MDEncodedNumber d = new MDEncodedNumber(dmang); + public MDVtordispex(MDMang dmang) { super(dmang); mdtype = new MDFunctionType(dmang); @@ -31,21 +40,21 @@ public class MDVtordispex extends MDMemberFunctionInfo { setThunk(); } + @Override + public String getModifier() { + return "`vtordispex{" + a + "," + b + "," + c + "," + d + "}' "; + } + @Override protected void parseInternal() throws MDException { // 20200507: Believe this to be - MDEncodedNumber a = new MDEncodedNumber(dmang); a.parse(); // 20200507: Believe this to be - MDEncodedNumber b = new MDEncodedNumber(dmang); b.parse(); // 20200507: Believe this to be - MDEncodedNumber c = new MDEncodedNumber(dmang); c.parse(); // 20200507: Believe this to be - MDEncodedNumber d = new MDEncodedNumber(dmang); d.parse(); - nameModifier = "`vtordispex{" + a + "," + b + "," + c + "," + d + "}' "; super.parseInternal(); } } diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVxTable.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVxTable.java index 30e941a9d8..4b82df6986 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVxTable.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/typeinfo/MDVxTable.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. @@ -45,6 +45,11 @@ public class MDVxTable extends MDTypeInfo { goodNestedTermination = false; } + @Override + public String getModifier() { + return generateNameModifier(); + } + public MDCVMod getCVMod() { return cvmod; } @@ -94,10 +99,9 @@ public class MDVxTable extends MDTypeInfo { dmang.increment(); goodNestedTermination = true; } - nameModifier = generateNameModifier(); } - String generateNameModifier() { + private String generateNameModifier() { if (!goodNestedTermination) { return "{for ??}"; } diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java index dc46659bfa..6d664ceb94 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java @@ -4664,6 +4664,25 @@ public class MDMangBaseTest extends AbstractGenericTest { demangleAndTest(); } + // vbtable with anonymous namespace + @Test + public void testUnderscore7AnonNs() throws Exception { + mangled = "??_7a@?A0xfedcba98@b@@6B@"; + msTruth = "const b::`anonymous namespace'::a::`vftable'"; + mdTruth = msTruth; + demangleAndTest(); + } + + // vbtable with anonymous namespace + @Test + public void testUnderscore7AnonNsAndBackref() throws Exception { + mangled = "??_7a@?A0xfedcba98@b@@6B012@01@@"; + msTruth = + "const b::`anonymous namespace'::a::`vftable'{for `b::A0xfedcba98::a's `A0xfedcba98::a'}"; + mdTruth = msTruth; + demangleAndTest(); + } + @Test public void testSpecialNames_R() throws Exception { mangled = "??_R0X@8"; diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java index bfcf06d01d..0d6f31f058 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java @@ -78,6 +78,64 @@ public class MDMangExtraTest extends AbstractGenericTest { assertEquals("b::a", qualifications.get(0).toString()); } + // Anonymous namespace in owner and backref + @Test + public void testVxTableAnonymousNsInOwner() throws Exception { + String mangled = "??_7a@?A0xfedcba98@b@@6B@"; + String truth = "const b::`anonymous namespace'::a::`vftable'"; + String truth2 = "const b::_anon_FEDCBA98::a::`vftable'"; + + MDMangGhidra demangler = new MDMangGhidra(); + demangler.setMangledSymbol(mangled); + demangler.setErrorOnRemainingChars(true); + demangler.setDemangleOnlyKnownPatterns(true); + MDParsableItem item = demangler.demangle(); + + MDObjectCPP cppItem = (MDObjectCPP) item; + MDVxTable vxTable = (MDVxTable) cppItem.getTypeInfo(); + List qualifications = vxTable.getNestedQualifications(); + assertEquals(0, qualifications.size()); + + String demangled = item.toString(); + assertEquals(truth, demangled); + + demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true); + demangled = item.toString(); + assertEquals(truth2, demangled); + } + + // Anonymous namespace in owner and backref + @Test + public void testVxTableAnonymousNsInOwnerAndBackref() throws Exception { + String mangled = "??_7a@?A0xfedcba98@b@@6B012@01@@"; + String truth = + "const b::`anonymous namespace'::a::`vftable'{for `b::A0xfedcba98::a's `A0xfedcba98::a'}"; + String truth2 = + "const b::_anon_FEDCBA98::a::`vftable'{for `b::_anon_FEDCBA98::a's `_anon_FEDCBA98::a'}"; + + MDMangGhidra demangler = new MDMangGhidra(); + demangler.setMangledSymbol(mangled); + demangler.setErrorOnRemainingChars(true); + demangler.setDemangleOnlyKnownPatterns(true); + MDParsableItem item = demangler.demangle(); + + MDObjectCPP cppItem = (MDObjectCPP) item; + MDVxTable vxTable = (MDVxTable) cppItem.getTypeInfo(); + List qualifications = vxTable.getNestedQualifications(); + assertEquals(2, qualifications.size()); + + String demangled = item.toString(); + assertEquals(truth, demangled); + assertEquals("b::A0xfedcba98::a", qualifications.get(0).toString()); + assertEquals("A0xfedcba98::a", qualifications.get(1).toString()); + + demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true); + demangled = item.toString(); + assertEquals(truth2, demangled); + assertEquals("b::_anon_FEDCBA98::a", qualifications.get(0).toString()); + assertEquals("_anon_FEDCBA98::a", qualifications.get(1).toString()); + } + // Need to test the demangleType() method to make sure it does the retry with LLVM mode @Test public void testDemangleTypeWithRetry() throws Exception {