mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
GP-5101 - MDMang - Properly process anon NS in vxtables owner and parentage; start work on OutputOptions, as needed for anon NS
This commit is contained in:
parent
710e2a8ba3
commit
9c942026b5
@ -66,7 +66,13 @@ public class MicrosoftDemangler implements Demangler {
|
|||||||
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
||||||
try {
|
try {
|
||||||
item = demangler.demangle();
|
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) {
|
if (object != null) {
|
||||||
object.setMangledContext(context);
|
object.setMangledContext(context);
|
||||||
}
|
}
|
||||||
@ -103,7 +109,13 @@ public class MicrosoftDemangler implements Demangler {
|
|||||||
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
||||||
try {
|
try {
|
||||||
mdType = demangler.demangleType();
|
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) {
|
if (dataType != null) {
|
||||||
dataType.setMangledContext(context);
|
dataType.setMangledContext(context);
|
||||||
}
|
}
|
||||||
|
@ -50,22 +50,27 @@ public class MicrosoftDemanglerUtil {
|
|||||||
* is not appropriate for {@link MDDataType} and some other types of {@link MDParsableItem}
|
* is not appropriate for {@link MDDataType} and some other types of {@link MDParsableItem}
|
||||||
* @param item the item to convert
|
* @param item the item to convert
|
||||||
* @param mangled the original mangled string
|
* @param mangled the original mangled string
|
||||||
|
* @param originalDemangled the original demangled string
|
||||||
* @return the {@link DemangledObject} result
|
* @return the {@link DemangledObject} result
|
||||||
* @throws DemangledException up issue converting to a {@link DemangledObject}
|
* @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 {
|
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 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
|
* @return the result
|
||||||
*/
|
*/
|
||||||
static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled) {
|
static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled,
|
||||||
return processDataType(null, type, mangled, type.toString());
|
String originalDemangled) {
|
||||||
|
return processDataType(null, type, mangled, originalDemangled);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
@ -121,14 +126,8 @@ public class MicrosoftDemanglerUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (qual.isAnon()) {
|
else if (qual.isAnon()) {
|
||||||
// Instead of using the standard qual.toString() method, which returns
|
String orig = qual.getAnonymousName();
|
||||||
// "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName()
|
demangled = new DemangledNamespaceNode(mangled, orig, qual.toString());
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
else if (qual.isInterface()) {
|
else if (qual.isInterface()) {
|
||||||
// TODO: need to do better; setting namespace for now
|
// TODO: need to do better; setting namespace for now
|
||||||
|
@ -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
|
@Test
|
||||||
//This test checks that we can provide a mangled string for a function namespace.
|
//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
|
// The return String from getOriginalMangled() is not null only for this special
|
||||||
|
@ -40,6 +40,8 @@ import mdemangler.template.MDTemplateArgumentsList;
|
|||||||
public class MDMang {
|
public class MDMang {
|
||||||
public static final char DONE = MDCharacterIterator.DONE;
|
public static final char DONE = MDCharacterIterator.DONE;
|
||||||
|
|
||||||
|
private MDOutputOptions outputOptions = new MDOutputOptions();
|
||||||
|
|
||||||
protected int architectureSize = 32;
|
protected int architectureSize = 32;
|
||||||
protected boolean isFunction = false;
|
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.
|
* Controls whether an exception is thrown if there are remaining characters after demangling.
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,13 +30,13 @@ public class MDBasicName extends MDParsableItem {
|
|||||||
MDReusableName reusableName;
|
MDReusableName reusableName;
|
||||||
MDObjectCPP embeddedObject;
|
MDObjectCPP embeddedObject;
|
||||||
MDQualification embeddedObjectQualification;
|
MDQualification embeddedObjectQualification;
|
||||||
String nameModifier;
|
MDNameModifier nameModifier;
|
||||||
|
|
||||||
public MDBasicName(MDMang dmang) {
|
public MDBasicName(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNameModifier(String nameModifier) {
|
public void setNameModifier(MDNameModifier nameModifier) {
|
||||||
this.nameModifier = nameModifier;
|
this.nameModifier = nameModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ public class MDBasicName extends MDParsableItem {
|
|||||||
templateNameAndArguments.insert(builder);
|
templateNameAndArguments.insert(builder);
|
||||||
}
|
}
|
||||||
if (nameModifier != null) {
|
if (nameModifier != null) {
|
||||||
builder.append(nameModifier);
|
builder.append(nameModifier.getModifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +34,13 @@ public class MDFragmentName extends MDParsableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
|
if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) {
|
||||||
|
dmang.insertString(builder, MDMangUtils.createStandardAnonymousNamespaceNode(name));
|
||||||
|
}
|
||||||
|
else {
|
||||||
dmang.insertString(builder, name);
|
dmang.insertString(builder, name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -93,7 +93,7 @@ public class MDQualifiedBasicName extends MDParsableItem {
|
|||||||
return qualification;
|
return qualification;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNameModifier(String nameModifier) {
|
public void setNameModifier(MDNameModifier nameModifier) {
|
||||||
basicName.setNameModifier(nameModifier);
|
basicName.setNameModifier(nameModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +91,14 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
name.insert(builder);
|
name.insert(builder);
|
||||||
}
|
}
|
||||||
else if (nameAnonymous != null) {
|
else if (nameAnonymous != null) {
|
||||||
|
if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) {
|
||||||
|
dmang.insertString(builder,
|
||||||
|
MDMangUtils.createStandardAnonymousNamespaceNode(nameAnonymous.getName()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
dmang.insertString(builder, ANONYMOUS_NAMESPACE);
|
dmang.insertString(builder, ANONYMOUS_NAMESPACE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (nameInterface != null) {
|
else if (nameInterface != null) {
|
||||||
nameInterface.insert(builder);
|
nameInterface.insert(builder);
|
||||||
}
|
}
|
||||||
|
@ -148,9 +148,7 @@ public class MDObjectCPP extends MDObject {
|
|||||||
typeInfo.setTypeCast();
|
typeInfo.setTypeCast();
|
||||||
}
|
}
|
||||||
typeInfo.parse();
|
typeInfo.parse();
|
||||||
if (!typeInfo.getNameModifier().isEmpty()) {
|
qualifiedName.setNameModifier(typeInfo);
|
||||||
qualifiedName.setNameModifier(typeInfo.getNameModifier());
|
|
||||||
}
|
|
||||||
if (qualifiedName.isTypeCast()) {
|
if (qualifiedName.isTypeCast()) {
|
||||||
applyFunctionReturnTypeToTypeCastOperatorName();
|
applyFunctionReturnTypeToTypeCastOperatorName();
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,19 @@ import mdemangler.*;
|
|||||||
*/
|
*/
|
||||||
public class MDGuard extends MDTypeInfo {
|
public class MDGuard extends MDTypeInfo {
|
||||||
|
|
||||||
|
private MDEncodedNumber guardNumber;
|
||||||
|
|
||||||
public MDGuard(MDMang dmang) {
|
public MDGuard(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
|
guardNumber = new MDEncodedNumber(dmang);
|
||||||
mdtype = new MDType(dmang);
|
mdtype = new MDType(dmang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
return "{" + guardNumber + "}'";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
super.insert(builder);
|
super.insert(builder);
|
||||||
@ -35,9 +43,7 @@ public class MDGuard extends MDTypeInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseInternal() throws MDException {
|
protected void parseInternal() throws MDException {
|
||||||
MDEncodedNumber guardNumber = new MDEncodedNumber(dmang);
|
|
||||||
guardNumber.parse();
|
guardNumber.parse();
|
||||||
nameModifier = "{" + guardNumber + "}'";
|
|
||||||
super.parseInternal();
|
super.parseInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
package mdemangler.typeinfo;
|
package mdemangler.typeinfo;
|
||||||
|
|
||||||
import mdemangler.*;
|
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 PRIVATE = "private: ";
|
||||||
private static final String PROTECTED = "protected: ";
|
private static final String PROTECTED = "protected: ";
|
||||||
private static final String PUBLIC = "public: ";
|
private static final String PUBLIC = "public: ";
|
||||||
@ -61,14 +62,13 @@ public class MDTypeInfo extends MDParsableItem {
|
|||||||
protected MDType mdtype;
|
protected MDType mdtype;
|
||||||
protected boolean isTypeCast;
|
protected boolean isTypeCast;
|
||||||
|
|
||||||
protected String nameModifier = "";
|
|
||||||
|
|
||||||
public MDTypeInfo(MDMang dmang) {
|
public MDTypeInfo(MDMang dmang) {
|
||||||
super(dmang, 1);
|
super(dmang, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNameModifier() {
|
@Override
|
||||||
return nameModifier;
|
public String getModifier() {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPrivate() {
|
public void setPrivate() {
|
||||||
|
@ -57,6 +57,12 @@ public class MDVCall extends MDMemberFunctionInfo {
|
|||||||
callIndex = new MDEncodedNumber(dmang);
|
callIndex = new MDEncodedNumber(dmang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
// TODO: Future specialization on 16-bit or 32plus
|
||||||
|
return getNameModifier_32PlusBitModel();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
// TODO: Future specialization on 16-bit or 32plus
|
// TODO: Future specialization on 16-bit or 32plus
|
||||||
@ -197,8 +203,6 @@ public class MDVCall extends MDMemberFunctionInfo {
|
|||||||
}
|
}
|
||||||
// TODO evaluate whether parseInternal() or parse.
|
// TODO evaluate whether parseInternal() or parse.
|
||||||
super.parseInternal();
|
super.parseInternal();
|
||||||
// TODO: Future specialization on 16-bit or 32plus
|
|
||||||
nameModifier = getNameModifier_32PlusBitModel();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,21 +24,27 @@ import mdemangler.functiontype.MDFunctionType;
|
|||||||
*/
|
*/
|
||||||
public class MDVFAdjustor extends MDMemberFunctionInfo {
|
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
|
// 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
|
// used to represent the logical "this" adjustor property, which means an offset to the
|
||||||
// true "this" value in some multiple inheritance situations.
|
// true "this" value in some multiple inheritance situations.
|
||||||
public MDVFAdjustor(MDMang dmang) {
|
public MDVFAdjustor(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
mdtype = new MDFunctionType(dmang);
|
mdtype = new MDFunctionType(dmang);
|
||||||
|
adjustment = new MDEncodedNumber(dmang);
|
||||||
setVirtual();
|
setVirtual();
|
||||||
setThunk();
|
setThunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
return "`adjustor{" + adjustment + "}' ";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseInternal() throws MDException {
|
protected void parseInternal() throws MDException {
|
||||||
MDEncodedNumber adjustment = new MDEncodedNumber(dmang);
|
|
||||||
adjustment.parse();
|
adjustment.parse();
|
||||||
nameModifier = "`adjustor{" + adjustment + "}' ";
|
|
||||||
super.parseInternal(); // TODO evaluate whether parseInternal() or parse.
|
super.parseInternal(); // TODO evaluate whether parseInternal() or parse.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,31 @@ import mdemangler.functiontype.MDFunctionType;
|
|||||||
*/
|
*/
|
||||||
public class MDVtordisp extends MDMemberFunctionInfo {
|
public class MDVtordisp extends MDMemberFunctionInfo {
|
||||||
|
|
||||||
|
// 20200507: Believe this to be <offset-to-vtordisp>
|
||||||
|
private MDEncodedNumber vtorDisplacement;
|
||||||
|
// 20200507: Believe this to be <static-offset>
|
||||||
|
private MDEncodedNumber adjustment;
|
||||||
|
|
||||||
public MDVtordisp(MDMang dmang) {
|
public MDVtordisp(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
mdtype = new MDFunctionType(dmang);
|
mdtype = new MDFunctionType(dmang);
|
||||||
|
vtorDisplacement = new MDEncodedNumber(dmang);
|
||||||
|
adjustment = new MDEncodedNumber(dmang);
|
||||||
setVirtual();
|
setVirtual();
|
||||||
setThunk();
|
setThunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
return "`vtordisp{" + vtorDisplacement + "," + adjustment + "}' ";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseInternal() throws MDException {
|
protected void parseInternal() throws MDException {
|
||||||
// 20200507: Believe this to be <offset-to-vtordisp>
|
// 20200507: Believe this to be <offset-to-vtordisp>
|
||||||
MDEncodedNumber vtorDisplacement = new MDEncodedNumber(dmang);
|
|
||||||
vtorDisplacement.parse();
|
vtorDisplacement.parse();
|
||||||
// 20200507: Believe this to be <static-offset>
|
// 20200507: Believe this to be <static-offset>
|
||||||
MDEncodedNumber adjustment = new MDEncodedNumber(dmang);
|
|
||||||
adjustment.parse();
|
adjustment.parse();
|
||||||
nameModifier = "`vtordisp{" + vtorDisplacement + "," + adjustment + "}' ";
|
|
||||||
super.parseInternal();
|
super.parseInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,15 @@ import mdemangler.functiontype.MDFunctionType;
|
|||||||
*/
|
*/
|
||||||
public class MDVtordispex extends MDMemberFunctionInfo {
|
public class MDVtordispex extends MDMemberFunctionInfo {
|
||||||
|
|
||||||
|
// 20200507: Believe this to be <offset-to-vptr>
|
||||||
|
private MDEncodedNumber a = new MDEncodedNumber(dmang);
|
||||||
|
// 20200507: Believe this to be <vbase-offset-offset>
|
||||||
|
private MDEncodedNumber b = new MDEncodedNumber(dmang);
|
||||||
|
// 20200507: Believe this to be <offset-to-vtordisp>
|
||||||
|
private MDEncodedNumber c = new MDEncodedNumber(dmang);
|
||||||
|
// 20200507: Believe this to be <static-offset>
|
||||||
|
private MDEncodedNumber d = new MDEncodedNumber(dmang);
|
||||||
|
|
||||||
public MDVtordispex(MDMang dmang) {
|
public MDVtordispex(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
mdtype = new MDFunctionType(dmang);
|
mdtype = new MDFunctionType(dmang);
|
||||||
@ -31,21 +40,21 @@ public class MDVtordispex extends MDMemberFunctionInfo {
|
|||||||
setThunk();
|
setThunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
return "`vtordispex{" + a + "," + b + "," + c + "," + d + "}' ";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseInternal() throws MDException {
|
protected void parseInternal() throws MDException {
|
||||||
// 20200507: Believe this to be <offset-to-vptr>
|
// 20200507: Believe this to be <offset-to-vptr>
|
||||||
MDEncodedNumber a = new MDEncodedNumber(dmang);
|
|
||||||
a.parse();
|
a.parse();
|
||||||
// 20200507: Believe this to be <vbase-offset-offset>
|
// 20200507: Believe this to be <vbase-offset-offset>
|
||||||
MDEncodedNumber b = new MDEncodedNumber(dmang);
|
|
||||||
b.parse();
|
b.parse();
|
||||||
// 20200507: Believe this to be <offset-to-vtordisp>
|
// 20200507: Believe this to be <offset-to-vtordisp>
|
||||||
MDEncodedNumber c = new MDEncodedNumber(dmang);
|
|
||||||
c.parse();
|
c.parse();
|
||||||
// 20200507: Believe this to be <static-offset>
|
// 20200507: Believe this to be <static-offset>
|
||||||
MDEncodedNumber d = new MDEncodedNumber(dmang);
|
|
||||||
d.parse();
|
d.parse();
|
||||||
nameModifier = "`vtordispex{" + a + "," + b + "," + c + "," + d + "}' ";
|
|
||||||
super.parseInternal();
|
super.parseInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ public class MDVxTable extends MDTypeInfo {
|
|||||||
goodNestedTermination = false;
|
goodNestedTermination = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModifier() {
|
||||||
|
return generateNameModifier();
|
||||||
|
}
|
||||||
|
|
||||||
public MDCVMod getCVMod() {
|
public MDCVMod getCVMod() {
|
||||||
return cvmod;
|
return cvmod;
|
||||||
}
|
}
|
||||||
@ -94,10 +99,9 @@ public class MDVxTable extends MDTypeInfo {
|
|||||||
dmang.increment();
|
dmang.increment();
|
||||||
goodNestedTermination = true;
|
goodNestedTermination = true;
|
||||||
}
|
}
|
||||||
nameModifier = generateNameModifier();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateNameModifier() {
|
private String generateNameModifier() {
|
||||||
if (!goodNestedTermination) {
|
if (!goodNestedTermination) {
|
||||||
return "{for ??}";
|
return "{for ??}";
|
||||||
}
|
}
|
||||||
|
@ -4664,6 +4664,25 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
|||||||
demangleAndTest();
|
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
|
@Test
|
||||||
public void testSpecialNames_R() throws Exception {
|
public void testSpecialNames_R() throws Exception {
|
||||||
mangled = "??_R0X@8";
|
mangled = "??_R0X@8";
|
||||||
|
@ -78,6 +78,64 @@ public class MDMangExtraTest extends AbstractGenericTest {
|
|||||||
assertEquals("b::a", qualifications.get(0).toString());
|
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<MDQualification> 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<MDQualification> 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
|
// Need to test the demangleType() method to make sure it does the retry with LLVM mode
|
||||||
@Test
|
@Test
|
||||||
public void testDemangleTypeWithRetry() throws Exception {
|
public void testDemangleTypeWithRetry() throws Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user