mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
GP-4663 - MDMang - add calling convs; custom type; end, empty param, unnamed template types; mod reference modifiers; mod guard name proc; fixed member ptr qual name; work around llvm object nesting issue
This commit is contained in:
parent
d1b0828af9
commit
3c36666600
@ -40,16 +40,16 @@ public class MDMang {
|
||||
|
||||
protected String mangled;
|
||||
protected MDCharacterIterator iter;
|
||||
protected String errorMessage = "";
|
||||
protected String errorMessage;
|
||||
protected MDParsableItem item;
|
||||
|
||||
protected List<MDContext> contextStack = new ArrayList<>();
|
||||
protected List<MDContext> contextStack;
|
||||
|
||||
public enum ProcessingMode {
|
||||
DEFAULT_STANDARD, LLVM
|
||||
}
|
||||
|
||||
private ProcessingMode processingMode = ProcessingMode.DEFAULT_STANDARD;
|
||||
private ProcessingMode processingMode;
|
||||
|
||||
public void setProcessingMode(ProcessingMode processingMode) {
|
||||
this.processingMode = processingMode;
|
||||
@ -59,14 +59,12 @@ public class MDMang {
|
||||
return processingMode;
|
||||
}
|
||||
|
||||
public boolean isProcessingModeActive(ProcessingMode mode) {
|
||||
switch (mode) {
|
||||
case LLVM:
|
||||
return processingMode == mode && (getIndex() == 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return processingMode == mode;
|
||||
public boolean isLlvmProcessingModeIndex0() {
|
||||
return processingMode == ProcessingMode.LLVM && (getIndex() == 0);
|
||||
}
|
||||
|
||||
public boolean isLlvmProcessingMode() {
|
||||
return processingMode == ProcessingMode.LLVM;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,6 +87,28 @@ public class MDMang {
|
||||
return demangle(errorOnRemainingChars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables that get set at the very beginning.
|
||||
* @throws MDException if mangled name is not set
|
||||
*/
|
||||
protected void initState() throws MDException {
|
||||
if (mangled == null) {
|
||||
throw new MDException("MDMang: Mangled string is null.");
|
||||
}
|
||||
errorMessage = "";
|
||||
processingMode = ProcessingMode.DEFAULT_STANDARD;
|
||||
iter = new MDCharacterIterator(mangled);
|
||||
resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables that can get reset for a second (or more?) passes with different modes.
|
||||
*/
|
||||
public void resetState() {
|
||||
contextStack = new ArrayList<>();
|
||||
setIndex(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demangles the string already stored and returns a parsed item.
|
||||
*
|
||||
@ -99,17 +119,13 @@ public class MDMang {
|
||||
* @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();
|
||||
initState();
|
||||
item = MDMangObjectParser.determineItemAndParse(this);
|
||||
if (item instanceof MDObjectCPP) {
|
||||
// MDMANG SPECIALIZATION USED.
|
||||
item = getEmbeddedObject((MDObjectCPP) item);
|
||||
}
|
||||
int numCharsRemaining = getNumCharsRemaining();
|
||||
popContext();
|
||||
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
|
||||
throw new MDException(
|
||||
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");
|
||||
@ -176,7 +192,6 @@ public class MDMang {
|
||||
*/
|
||||
public void setMangledSymbol(String mangledIn) {
|
||||
this.mangled = mangledIn;
|
||||
iter = new MDCharacterIterator(mangled);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,12 +29,21 @@ public class MDMangGenericize extends MDMang {
|
||||
/*
|
||||
* Used for creating a copy-with-substitutes of the original string
|
||||
*/
|
||||
private StringBuilder genericizedString = new StringBuilder();
|
||||
// uniqueCount must start at -1 as nextUnique() pre-creates a potential
|
||||
// fragment for use.
|
||||
private int uniqueCount = -1;
|
||||
private String nextUnique = nextUnique();
|
||||
private Map<String, String> uniqueFragments = new HashMap<>();
|
||||
private StringBuilder genericizedString;
|
||||
private int uniqueCount;
|
||||
private String nextUnique;
|
||||
private Map<String, String> uniqueFragments;
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
super.resetState();
|
||||
genericizedString = new StringBuilder();
|
||||
// uniqueCount must start at -1 as nextUnique() pre-creates a potential
|
||||
// fragment for use.
|
||||
uniqueCount = -1;
|
||||
nextUnique = nextUnique();
|
||||
uniqueFragments = new HashMap<>();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public MDParsableItem demangle_orig(Boolean errorOnRemainingChars) {
|
||||
@ -59,14 +68,10 @@ public class MDMangGenericize extends MDMang {
|
||||
// }
|
||||
@Override
|
||||
public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException {
|
||||
// ignoring the parameter (for now)
|
||||
if (mangled == null) {
|
||||
throw new MDException("MDMang: Mangled string is null.");
|
||||
}
|
||||
pushContext();
|
||||
// ignoring the 'errorOnRemainingChars' parameter (for now)
|
||||
initState();
|
||||
item = MDMangObjectParser.determineItemAndParse(this);
|
||||
appendRemainder();
|
||||
popContext();
|
||||
// if (errorOnRemainingChars && (numCharsRemaining > 0)) {
|
||||
// throw new MDException(
|
||||
// "MDMang: characters remain after demangling: " + numCharsRemaining +
|
||||
|
@ -44,10 +44,19 @@ public class MDMangParseInfo extends MDMang {
|
||||
}
|
||||
}
|
||||
|
||||
private Stack<MDParseInfo> infoStack = new Stack<>();
|
||||
private List<MDParseInfo> infoList = new ArrayList<>();
|
||||
private int parseInfoMangledIndex = 0;
|
||||
private StringBuilder parseInfoBuilder = new StringBuilder();
|
||||
private Stack<MDParseInfo> infoStack;
|
||||
private List<MDParseInfo> infoList;
|
||||
private int parseInfoMangledIndex;
|
||||
private StringBuilder parseInfoBuilder;
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
super.resetState();
|
||||
infoStack = new Stack<>();
|
||||
infoList = new ArrayList<>();
|
||||
parseInfoMangledIndex = 0;
|
||||
parseInfoBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override // Override might be temporary, depending on how we answer questions in MDMang
|
||||
public void parseInfoPushPop(int startIndexOffset, String itemName) {
|
||||
|
@ -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.
|
||||
|
@ -79,10 +79,6 @@ public class MDDataTypeParser {
|
||||
MDDataType dt;
|
||||
char code = dmang.peek();
|
||||
switch (code) {
|
||||
case '$':
|
||||
dmang.increment();
|
||||
dt = parseSpecialExtendedType(dmang, isHighest);
|
||||
break;
|
||||
case 'A':
|
||||
dmang.increment();
|
||||
dt = new MDReferenceType(dmang, isHighest, false, false);
|
||||
@ -139,9 +135,15 @@ public class MDDataTypeParser {
|
||||
break;
|
||||
case 'Y': // UINFO: QualifiedName only (no type)
|
||||
// TODO: implementation. Try symbol like "?var@@3$$Yabc@@"
|
||||
case 'S': // invalid (UINFO)
|
||||
dt = new MDNamedUnspecifiedType(dmang);
|
||||
break;
|
||||
case 'V': // Empty type parameter pack?
|
||||
dt = new MDEmptyParameterType(dmang);
|
||||
break;
|
||||
case 'Z': // End template parameter pack?
|
||||
dt = new MDEndParameterType(dmang);
|
||||
break;
|
||||
case 'S': // invalid (UINFO)
|
||||
case 'F': // Investigate $$F in CVMod processing... does it belong here?
|
||||
default:
|
||||
throw new MDException("SpecialDataType: unrecognized code: " + code);
|
||||
@ -162,6 +164,14 @@ public class MDDataTypeParser {
|
||||
MDDataType dt;
|
||||
char code = dmang.getAndIncrement();
|
||||
switch (code) {
|
||||
case '?':
|
||||
// Not sure if this should be here or other place. I suppose could have a
|
||||
// reference to one of these, so wouldn't want it in "Primary" data types
|
||||
dt = new MDCustomType(dmang);
|
||||
break;
|
||||
case '$':
|
||||
dt = parseSpecialExtendedType(dmang, isHighest);
|
||||
break;
|
||||
case 'C':
|
||||
dt = new MDCharDataType(dmang);
|
||||
dt.setSigned();
|
||||
|
@ -18,7 +18,7 @@ package mdemangler.datatype.modifier;
|
||||
import java.util.*;
|
||||
|
||||
import mdemangler.*;
|
||||
import mdemangler.naming.MDQualification;
|
||||
import mdemangler.naming.MDQualifiedName;
|
||||
|
||||
/**
|
||||
* This class represents a Const/Volatile modifier (and extra stuff) of a modifier
|
||||
@ -89,7 +89,10 @@ public class MDCVMod extends MDParsableItem {
|
||||
// TODO: Name this better once understood. For now, special pointer.
|
||||
String special;
|
||||
|
||||
private MDQualification qual;
|
||||
// Changed from MDQualification to support an empty name ("@@"), for which parsing
|
||||
// gets challenging for a number of symbols, even with our trying to change the looping
|
||||
// and end-of-list strategy of MDQualification
|
||||
private MDQualifiedName qual;
|
||||
private MDCVMod thisPointerCVMod; // TODO: check if EFI or CV portion
|
||||
// private String basedName;
|
||||
private MDBasedAttribute basedType;
|
||||
@ -689,7 +692,7 @@ public class MDCVMod extends MDParsableItem {
|
||||
throw new MDException("CV code not expected: " + code);
|
||||
}
|
||||
if (isMember) {
|
||||
qual = new MDQualification(dmang);
|
||||
qual = new MDQualifiedName(dmang);
|
||||
qual.parse();
|
||||
if (isFunction) {
|
||||
// TODO: check if EFI or CV portion-->I think might be any all
|
||||
@ -1066,9 +1069,11 @@ public class MDCVMod extends MDParsableItem {
|
||||
// if ((modType != cvModifierType.plain) && (modType !=
|
||||
// cvModifierType.question)) {
|
||||
if (modType != CvModifierType.plain) {
|
||||
if (qual.hasContent()) {
|
||||
dmang.insertString(builder, "::");
|
||||
qual.insert(builder);
|
||||
StringBuilder qualBuilder = new StringBuilder();
|
||||
qual.insert(qualBuilder);
|
||||
if (!qualBuilder.isEmpty()) {
|
||||
qualBuilder.append("::");
|
||||
dmang.insertString(builder, qualBuilder.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/* ###
|
||||
* 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.datatype.modifier;
|
||||
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
import mdemangler.datatype.extended.MDExtendedType;
|
||||
import mdemangler.naming.MDQualifiedName;
|
||||
|
||||
/**
|
||||
* This class represents an unspecified type with a name. (The ? code; not sure how this
|
||||
* should be different from an MDNamedUnspecifiedType.)
|
||||
* Currently putting this in the "extended" data types parsing section.
|
||||
*/
|
||||
public class MDCustomType extends MDExtendedType {
|
||||
|
||||
// Not sure what is allowed... not sure if it can have basic or special names... need to test
|
||||
// However, I've seen it closed with the "@@" which seems to indicate that it has
|
||||
// a qualified name... an MDQualification seems fit, as we probably do not want basic/special
|
||||
// names... not sure if it can be back-referenced, but should test this.
|
||||
private MDQualifiedName qualifiedName;
|
||||
|
||||
public MDCustomType(MDMang dmang) {
|
||||
super(dmang);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return qualifiedName.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
qualifiedName = new MDQualifiedName(dmang);
|
||||
qualifiedName.parse();
|
||||
}
|
||||
|
||||
public MDQualifiedName getQualifiedName() {
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* ###
|
||||
* 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.datatype.modifier;
|
||||
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
import mdemangler.datatype.extended.MDExtendedType;
|
||||
|
||||
/**
|
||||
* This class represents an empty parameter. (The $$V code.) Not sure what/how it fits into
|
||||
* everything, but coding it up for now.
|
||||
* It is one of a number of "extended" data types not originally planned by Microsoft.
|
||||
*/
|
||||
public class MDEmptyParameterType extends MDExtendedType {
|
||||
|
||||
public MDEmptyParameterType(MDMang dmang) {
|
||||
super(dmang, 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
// probably a do-nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "_EMPTY_PARAMETER_TYPE_";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* ###
|
||||
* 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.datatype.modifier;
|
||||
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
import mdemangler.datatype.extended.MDExtendedType;
|
||||
|
||||
/**
|
||||
* This class represents an end parameter (maybe signifying the last parameter is complete).
|
||||
* (The $$Z code.) It is one of a number of "extended" data types not originally planned by
|
||||
* Microsoft.
|
||||
*/
|
||||
public class MDEndParameterType extends MDExtendedType {
|
||||
|
||||
public MDEndParameterType(MDMang dmang) {
|
||||
super(dmang, 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
// probably a do-nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "_END_PARAMETER_TYPE_";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* ###
|
||||
* 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.datatype.modifier;
|
||||
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
import mdemangler.datatype.extended.MDExtendedType;
|
||||
import mdemangler.naming.MDQualifiedName;
|
||||
|
||||
/**
|
||||
* This class represents an unspecified type with a name. (The $$Y code.)
|
||||
* It is one of a number of "extended" data types not originally planned by Microsoft.
|
||||
*/
|
||||
public class MDNamedUnspecifiedType extends MDExtendedType {
|
||||
|
||||
// Not sure what is allowed... not sure if it can have basic or special names... need to test
|
||||
|
||||
// Not sure what is allowed... not sure if it can have basic or special names... need to test
|
||||
// However, I've seen it closed with the "@@" which seems to indicate that it has
|
||||
// a qualified name... an MDQualification seems fit, as we probably do not want basic/special
|
||||
// names... not sure if it can be back-referenced, but should test this.
|
||||
private MDQualifiedName qualifiedName;
|
||||
|
||||
public MDNamedUnspecifiedType(MDMang dmang) {
|
||||
super(dmang, 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return qualifiedName.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
qualifiedName = new MDQualifiedName(dmang);
|
||||
qualifiedName.parse();
|
||||
}
|
||||
|
||||
public MDQualifiedName getQualifiedName() {
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
}
|
@ -90,7 +90,7 @@ public class MDCallingConvention extends MDParsableItem {
|
||||
break;
|
||||
case 'K':
|
||||
case 'L':
|
||||
dmang.parseInfoPush(1, "(blank convention)");
|
||||
dmang.parseInfoPush(1, "(KL blank convention)");
|
||||
convention = "";
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
@ -107,10 +107,41 @@ public class MDCallingConvention extends MDParsableItem {
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'Q':
|
||||
case 'R':
|
||||
dmang.parseInfoPush(1, "__vectorcall");
|
||||
convention = "__vectorcall";
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'S':
|
||||
case 'T':
|
||||
// MSFT is as shown
|
||||
// LLVM is "__attribute__((__swiftcall__))" for code S and blank for T
|
||||
dmang.parseInfoPush(1, "__swift_1");
|
||||
convention = "__swift_1";
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'U':
|
||||
case 'V':
|
||||
// MSFT is as shown for U, but blank for V
|
||||
// LLVM is blank for both
|
||||
dmang.parseInfoPush(1, "__swift_2");
|
||||
convention = "__swift_2";
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'W':
|
||||
case 'X':
|
||||
// MSFT is blank
|
||||
// LLVM is "__attribute__((__swiftasynccall__))" for code W and blank for X
|
||||
dmang.parseInfoPush(1, "__swiftasynccall");
|
||||
convention = "__swiftasynccall"; // we made up... maybe MSFT will do an _1 suffix?
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
dmang.parseInfoPush(1, "(YZ blank convention)");
|
||||
convention = "";
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
default:
|
||||
throw new MDException("Unknown calling convention " + ch + "\n");
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package mdemangler.naming;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import mdemangler.*;
|
||||
import mdemangler.MDMang.ProcessingMode;
|
||||
import mdemangler.object.MDObjectCPP;
|
||||
import mdemangler.template.MDTemplateNameAndArguments;
|
||||
|
||||
@ -111,7 +110,7 @@ public class MDBasicName extends MDParsableItem {
|
||||
|
||||
/**
|
||||
* Return the embedded object (essentially what could stand on its own as a mangled
|
||||
* symbol) that is used as part of the name of mangled object
|
||||
* symbol) that is used as part of the name of mangled object
|
||||
* @return The embedded object that essentially represents this MDBasicName.
|
||||
*/
|
||||
public MDObjectCPP getEmbeddedObject() {
|
||||
@ -172,12 +171,7 @@ public class MDBasicName extends MDParsableItem {
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
// First pass can only have name fragment of special name
|
||||
if (dmang.isProcessingModeActive(ProcessingMode.LLVM)) {
|
||||
specialName = new MDSpecialName(dmang, 0);
|
||||
specialName.parse();
|
||||
}
|
||||
else if (dmang.peek() == '?') {
|
||||
if (dmang.peek() == '?') {
|
||||
if (dmang.peek(1) == '$') {
|
||||
templateNameAndArguments = new MDTemplateNameAndArguments(dmang);
|
||||
templateNameAndArguments.parse();
|
||||
|
@ -36,7 +36,12 @@ public class MDNestedName extends MDParsableItem {
|
||||
if (dmang.peek() != '?') {
|
||||
throw new MDException("Missing '?' in MDNestedName parsing");
|
||||
}
|
||||
dmang.increment(); // Skip the first '?'
|
||||
// We include the mode check because we want to control this special case as much as
|
||||
// possible... not wanting the missing question mark to be overlooked unless we are
|
||||
// expecting the condition.
|
||||
if (dmang.peek(1) == '?' && !dmang.isLlvmProcessingMode()) {
|
||||
dmang.increment(); // Skip the first '?'
|
||||
}
|
||||
int beginIndex = dmang.getIndex();
|
||||
objectCPP = new MDObjectCPP(dmang); // There is another '?' processed here.
|
||||
objectCPP.parse();
|
||||
|
@ -96,6 +96,17 @@ public class MDQualification extends MDParsableItem implements Iterable<MDQualif
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
// TODO: consider a do-while loop so we do not need this initial test for an empty
|
||||
// qualification, but also need to make sure MDQualifier logic also handles the first
|
||||
// '@' in the qualifier, which might not be possible at this time with the immediate
|
||||
// qualifier creation below (probably should wait to do this until when we refactor
|
||||
// MDMang to use factory models). The other solution is to look for any place that an
|
||||
// MDQualification is used (but not as part of a MDQualfiedName or MDBasicName)
|
||||
// if (dmang.peek() == '@' && dmang.peek(1) == '@') {
|
||||
// // We have an empty qualification. Remove the first '@' and the second one will
|
||||
// // be handled below.
|
||||
// dmang.increment();
|
||||
// }
|
||||
// We currently have a check to see if the index has moved (loc) to know to abort the
|
||||
// processing of this loop. We could have also done a loop check on the '`' character
|
||||
// from an LLVM suffix on mangled "type" name that looks like:
|
||||
|
@ -107,7 +107,7 @@ public class MDQualifier extends MDParsableItem {
|
||||
nameAnonymous.parse();
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
case 'I': // Believe this is interface namespace
|
||||
case 'I': // Believe this is interface namespace
|
||||
// 20140522: See note for 'A' anonymous namespace; for 'I' there is no
|
||||
// evidence to include the 'I' in the fragment (investigation seems to have
|
||||
// it removed).
|
||||
@ -188,7 +188,19 @@ public class MDQualifier extends MDParsableItem {
|
||||
dmang.parseInfoPop();
|
||||
break;
|
||||
default: // special name
|
||||
throw new MDException("SpecialName not expected in qualification list");
|
||||
if (!dmang.isLlvmProcessingMode()) {
|
||||
throw new MDException("SpecialName not expected in qualification list");
|
||||
}
|
||||
// Working around LLVM non-compliance with MSFT mangling standard (See
|
||||
// MDNestedName too). LLVM does not follow the double question mark ("??")
|
||||
// convention, but is only using one "?" (which we got above). Maybe this
|
||||
// is not a nested object, but it has attributes of a nested object other than
|
||||
// not adhering to what MSFT does. There is no test we can do such as checking
|
||||
// for lower-case letter because an embedded object name could start with
|
||||
// one of the capital letters that have meaning in the above switch cases.
|
||||
nameNested = new MDNestedName(dmang);
|
||||
nameNested.parse();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -26,12 +26,16 @@ import mdemangler.template.MDTemplateNameAndArguments;
|
||||
public class MDReusableName extends MDParsableItem {
|
||||
MDFragmentName fragment;
|
||||
MDTemplateNameAndArguments templateName;
|
||||
String specialName;
|
||||
|
||||
public MDReusableName(MDMang dmang) {
|
||||
super(dmang);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (specialName != null) {
|
||||
return specialName;
|
||||
}
|
||||
if (fragment != null) {
|
||||
return fragment.getName();
|
||||
}
|
||||
@ -41,6 +45,10 @@ public class MDReusableName extends MDParsableItem {
|
||||
return "";
|
||||
}
|
||||
|
||||
// This method is currently not called... But if it is, then we might need to consider
|
||||
// crafting the specialName on-the-fly, but would also want a flag that signifies it was
|
||||
// at dmang offset 1 in the mangled string so we would have to know whether to use
|
||||
// the crafted special name or the regular name.
|
||||
public void setName(String name) {
|
||||
if (fragment != null) {
|
||||
fragment.setName(name);
|
||||
@ -57,7 +65,10 @@ public class MDReusableName extends MDParsableItem {
|
||||
|
||||
@Override
|
||||
public void insert(StringBuilder builder) {
|
||||
if (fragment != null) {
|
||||
if (specialName != null) {
|
||||
dmang.insertString(builder, specialName);
|
||||
}
|
||||
else if (fragment != null) {
|
||||
fragment.insert(builder);
|
||||
}
|
||||
else {
|
||||
@ -95,11 +106,68 @@ public class MDReusableName extends MDParsableItem {
|
||||
break;
|
||||
default:
|
||||
fragment = new MDFragmentName(dmang);
|
||||
int loc = dmang.getIndex();
|
||||
fragment.parse();
|
||||
dmang.addBackrefName(fragment.getName());
|
||||
if (loc == 1) {
|
||||
processSpecialName(fragment.getName());
|
||||
}
|
||||
dmang.addBackrefName(fragment.getName()); // note that back-ref gets standard name
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MOVED/ADAPTED FROM MDSpecialName class (where will this eventually land?)
|
||||
//
|
||||
// Neither MSFT nor LLVM output these special names.
|
||||
// Breaks the "norm" of MSFT model we have been following.
|
||||
// The output format is our creation (trying to follow MSFT convention with ticks and braces).
|
||||
// The "?$" prefix on these are templates in MSFT's reserved space and could collide
|
||||
// with a template symbol under the MSFT 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 processSpecialName(String inputName) throws MDException {
|
||||
if (inputName.startsWith("$TSS")) {
|
||||
//dmang.parseInfoPush(0, "thread safe static guard");
|
||||
String guardNumberString = inputName.substring("$TSS".length());
|
||||
validateNumberString(guardNumberString);
|
||||
//dmang.parseInfoPop();
|
||||
specialName = "`thread safe static guard{" + guardNumberString + "}'";
|
||||
}
|
||||
else if (inputName.equals("$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");
|
||||
specialName = "`nonvisible static guard{1}'";
|
||||
//dmang.parseInfoPop();
|
||||
}
|
||||
else if (inputName.startsWith("$RT")) {
|
||||
//dmang.parseInfoPush(0, "reference temporary");
|
||||
String manglingNumberString = inputName.substring("$RT".length());
|
||||
validateNumberString(manglingNumberString);
|
||||
//dmang.parseInfoPop();
|
||||
specialName = "`reference temporary{" + manglingNumberString + "}'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates Number (it is output as Number << '@' where Number is an unsigned int, so we are
|
||||
* capturing it as a string of digits.
|
||||
* Built for what seems to be LLVM-specific mangling. Does not follow MSFT model.
|
||||
* @throws MDException Upon invalid character sequence or out of characters.
|
||||
*/
|
||||
private void validateNumberString(String numberString) throws MDException {
|
||||
numberString.getBytes();
|
||||
for (int c : numberString.getBytes()) {
|
||||
if (!Character.isDigit(c)) { // includes end of string (MDMang.DONE)
|
||||
throw new MDException("Illegal character in Number: " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -16,7 +16,6 @@
|
||||
package mdemangler.naming;
|
||||
|
||||
import mdemangler.*;
|
||||
import mdemangler.MDMang.ProcessingMode;
|
||||
import mdemangler.datatype.MDDataTypeParser;
|
||||
import mdemangler.object.MDObjectCPP;
|
||||
|
||||
@ -118,15 +117,6 @@ 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':
|
||||
@ -699,45 +689,6 @@ public class MDSpecialName extends MDParsableItem {
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -27,49 +27,31 @@ import mdemangler.template.MDTemplateNameAndArguments;
|
||||
public class MDMangObjectParser {
|
||||
|
||||
public static MDParsableItem determineItemAndParse(MDMang dmang) throws MDException {
|
||||
boolean retry = false;
|
||||
MDException firstException = null;
|
||||
MDParsableItem myItem = null;
|
||||
int index = dmang.getIndex();
|
||||
|
||||
dmang.setProcessingMode(ProcessingMode.DEFAULT_STANDARD);
|
||||
try {
|
||||
myItem = parseDefaultStandard(dmang);
|
||||
if (myItem != null) {
|
||||
myItem.parse();
|
||||
myItem = parse(dmang);
|
||||
}
|
||||
catch (MDException e1) {
|
||||
dmang.resetState();
|
||||
dmang.setProcessingMode(ProcessingMode.LLVM);
|
||||
try {
|
||||
myItem = parse(dmang);
|
||||
}
|
||||
else {
|
||||
retry = true;
|
||||
catch (MDException e2) {
|
||||
throw new MDException(
|
||||
"Reason1: " + e1.getMessage().trim() + "; Reason2: " + e2.getMessage().trim());
|
||||
}
|
||||
}
|
||||
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 {
|
||||
/**
|
||||
* This method is only intended to be called with dmang at a fresh state (including index = 0)
|
||||
*/
|
||||
private static MDParsableItem parse(MDMang dmang) throws MDException {
|
||||
MDParsableItem item;
|
||||
dmang.setProcessingMode(ProcessingMode.DEFAULT_STANDARD);
|
||||
|
||||
// We believe this should adequately distinguish between a mangled "type" name vs. a
|
||||
// dot-separated mangled "symbol" name.
|
||||
@ -80,47 +62,77 @@ public class MDMangObjectParser {
|
||||
// // item = new MDDotSeparatedItem(dmang); // for research purposes; might not keep
|
||||
// item = null;
|
||||
// }
|
||||
// Moved the following up for now because we failed (above) to properly distinguish
|
||||
// dot-separated names for three tests. Ultimately, it might be better to not have
|
||||
// a separate MDDotSeparatedItem, but to be able to set some attributes on a main item.
|
||||
// Moved the check for data type processing up in the set of checks because we failed
|
||||
// (above) to properly distinguish dot-separated names for three tests. Ultimately,
|
||||
// it might be better to not have a separate MDDotSeparatedItem, but to be able to set
|
||||
// some attributes on a main item.
|
||||
if (dmang.peek() == '.' && !dmang.getMangledSymbol().substring(1).contains(".")) {
|
||||
dmang.increment();
|
||||
item = MDDataTypeParser.parseDataType(dmang, false);
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
return item;
|
||||
}
|
||||
else if (dmang.peek() == '?') {
|
||||
|
||||
if (dmang.peek() == '?') {
|
||||
if (dmang.peek(1) == '@') {
|
||||
item = new MDObjectCodeView(dmang);
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
return item;
|
||||
}
|
||||
else if (dmang.peek(1) == '$') {
|
||||
if (dmang.peek(1) == '$') {
|
||||
item = new MDTemplateNameAndArguments(dmang);
|
||||
// If we had no exception and there were zero characters remaining, then we
|
||||
// assume that the item is a template. Otherwise, we fall through and attempt
|
||||
// to process as a CPP object.
|
||||
try {
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
if (dmang.getNumCharsRemaining() == 0) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
catch (MDException e) {
|
||||
// trying again...
|
||||
}
|
||||
// Must reset the demangler state in order to attempt to process as a CPP item
|
||||
dmang.resetState();
|
||||
}
|
||||
else {
|
||||
item = new MDObjectCPP(dmang);
|
||||
}
|
||||
item = new MDObjectCPP(dmang);
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
return item;
|
||||
}
|
||||
else if ((dmang.peek() == '_') &&
|
||||
|
||||
if ((dmang.peek() == '_') &&
|
||||
((dmang.peek(1) == '_') || ((dmang.peek(1) >= 'A') && (dmang.peek(1) <= 'Z')))) {
|
||||
item = parseObjectReserved(dmang);
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
return item;
|
||||
}
|
||||
// else if (dmang.peek() == '.' ) {
|
||||
// Might move the test of types back here once we get the dot-separted symbol processing
|
||||
// logic figured out... for now, it was moved up closer to the start of this function
|
||||
// if (dmang.peek() == '.' ) {
|
||||
// // Dot-separated will not enter here, as they are distinguished earlier.
|
||||
// dmang.increment();
|
||||
// item = MDDataTypeParser.parseDataType(dmang, false);
|
||||
// dmang.pushContext();
|
||||
// item.parse();
|
||||
// dmang.popContext();
|
||||
// return item;
|
||||
// }
|
||||
else {
|
||||
item = new MDObjectC(dmang);
|
||||
}
|
||||
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);
|
||||
item = new MDObjectC(dmang);
|
||||
dmang.pushContext();
|
||||
item.parse();
|
||||
dmang.popContext();
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,10 @@ import mdemangler.naming.MDFragmentName;
|
||||
* I created, but undname does not support the symbol. I do not know what to call this type
|
||||
* of object, so the name is descriptive for now. Some bracketed prefix have been
|
||||
* <b><code>[T2M]</code></b> and <b><code>[MEP]</code></b>, which we have gleaned by searching
|
||||
* the Internet to possibly mean "Transition to Managed (code)" and "Managed Entry Point."
|
||||
* the Internet to possibly mean "Transition to Managed (code)" and "Managed Entry Point."
|
||||
*/
|
||||
// TODO: Not sure what this is, so:
|
||||
// - if it really is an object, then it probably needs a better name;
|
||||
// - if it really is an object, then it probably needs a better name;
|
||||
// - if it doesn't belong here (i.e., might be part of MDObjectCPP), then it should be moved there.
|
||||
public class MDObjectBracket extends MDObjectReserved {
|
||||
private MDFragmentName fragmentName;
|
||||
@ -65,7 +65,7 @@ public class MDObjectBracket extends MDObjectReserved {
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
if ((dmang.peek() != '_') && (dmang.peek(1) != '_')) {
|
||||
if ((dmang.peek() != '_') || (dmang.peek(1) != '_')) {
|
||||
throw new MDException("Missing prefix in MDObjectBracket parsing");
|
||||
}
|
||||
dmang.increment(2); // Skip the two underscores.
|
||||
|
@ -17,7 +17,6 @@ package mdemangler.object;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import mdemangler.*;
|
||||
import mdemangler.MDMang.ProcessingMode;
|
||||
import mdemangler.functiontype.MDFunctionType;
|
||||
import mdemangler.naming.*;
|
||||
import mdemangler.typeinfo.MDTypeInfo;
|
||||
@ -120,17 +119,10 @@ public class MDObjectCPP extends MDObject {
|
||||
if (dmang.peek() != '?') {
|
||||
throw new MDException("Invalid ObjectCPP");
|
||||
}
|
||||
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();
|
||||
}
|
||||
dmang.increment();
|
||||
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '?')) { //??? prefix
|
||||
embeddedObjectFlag = true;
|
||||
}
|
||||
|
||||
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '@')) { //??@ prefix
|
||||
// MDMANG SPECIALIZATION USED.
|
||||
dmang.processHashedObject(this);
|
||||
@ -241,7 +233,7 @@ public class MDObjectCPP extends MDObject {
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
|
||||
if ((dmang.peek() != '?') && (dmang.peek(1) != '@')) {
|
||||
if ((dmang.peek() != '?') || (dmang.peek(1) != '@')) {
|
||||
throw new MDException("Invalid HashedObject");
|
||||
}
|
||||
dmang.increment(2);
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package mdemangler.object;
|
||||
|
||||
import mdemangler.*;
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
|
||||
/**
|
||||
* This class represents a MSFT <b><code>__catch$</code></b> (prefix) symbol. We have created
|
||||
@ -29,7 +30,7 @@ import mdemangler.*;
|
||||
*/
|
||||
public class MDObjectCatch extends MDObjectReserved {
|
||||
private String digits;
|
||||
private MDParsableItem internalItem;
|
||||
private MDObjectCPP objCpp;
|
||||
|
||||
public MDObjectCatch(MDMang dmang) {
|
||||
super(dmang);
|
||||
@ -38,12 +39,13 @@ public class MDObjectCatch extends MDObjectReserved {
|
||||
@Override
|
||||
public void insert(StringBuilder builder) {
|
||||
super.insert(builder);
|
||||
dmang.appendString(builder, "[Catch," + digits + "]{" + internalItem + "}");
|
||||
dmang.appendString(builder, "[Catch," + digits + "]{" + objCpp + "}");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
internalItem = MDMangObjectParser.determineItemAndParse(dmang);
|
||||
objCpp = new MDObjectCPP(dmang);
|
||||
objCpp.parse();
|
||||
dmang.increment(); // '$'
|
||||
//We are assuming that we can have more than one digit.
|
||||
//TODO: forward programming to test beyond one digit.
|
||||
|
@ -24,7 +24,7 @@ import mdemangler.MDMang;
|
||||
* a CodeView compiler (older version of compiler?).
|
||||
*/
|
||||
// TODO: Not sure what this is, so:
|
||||
// - if it really is an object, then it probably needs a better name;
|
||||
// - if it really is an object, then it probably needs a better name;
|
||||
// - if it doesn't belong here (i.e., might be part of MDObjectCPP), then it should be moved
|
||||
// there.
|
||||
public class MDObjectCodeView extends MDObjectCPP {
|
||||
@ -45,11 +45,14 @@ public class MDObjectCodeView extends MDObjectCPP {
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
if ((dmang.peek() != '?') && (dmang.peek(1) != '@')) {
|
||||
if ((dmang.peek() != '?') || (dmang.peek(1) != '@')) {
|
||||
throw new MDException("Missing prefix in MDObjectCodeView parsing");
|
||||
}
|
||||
dmang.increment(); // Skip the ?.
|
||||
dmang.increment(); // Skip the @.
|
||||
if ((dmang.peek() == '?') && (dmang.peek(1) == '@')) {
|
||||
throw new MDException("Cannot nest a MDObjectCodeView");
|
||||
}
|
||||
super.parseInternal();
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package mdemangler.object;
|
||||
|
||||
import mdemangler.*;
|
||||
import mdemangler.MDException;
|
||||
import mdemangler.MDMang;
|
||||
|
||||
/**
|
||||
* This class represents a MSFT <b><code>__unwindfunclet$</code></b> (prefix) symbol. We have
|
||||
@ -28,7 +29,7 @@ import mdemangler.*;
|
||||
*/
|
||||
public class MDObjectUnwindFunclet extends MDObjectReserved {
|
||||
private String digits;
|
||||
private MDParsableItem internalItem;
|
||||
private MDObjectCPP objCpp;
|
||||
|
||||
public MDObjectUnwindFunclet(MDMang dmang) {
|
||||
super(dmang);
|
||||
@ -37,12 +38,13 @@ 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 + "]{" + objCpp + "}");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
internalItem = MDMangObjectParser.determineItemAndParse(dmang);
|
||||
objCpp = new MDObjectCPP(dmang);
|
||||
objCpp.parse();
|
||||
dmang.increment(); // '$'
|
||||
//Here, we have seen $9 and $10 (two digits for $10).
|
||||
//TODO: forward programming to test beyond one digit.
|
||||
|
@ -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.
|
||||
@ -21,7 +21,7 @@ import mdemangler.*;
|
||||
import mdemangler.datatype.*;
|
||||
import mdemangler.datatype.complex.MDComplexType;
|
||||
import mdemangler.datatype.extended.MDExtendedType;
|
||||
import mdemangler.datatype.modifier.MDModifierType;
|
||||
import mdemangler.datatype.modifier.*;
|
||||
|
||||
/**
|
||||
* This class represents the template arguments list portion of a
|
||||
@ -116,6 +116,12 @@ public class MDTemplateArgumentsList extends MDParsableItem {
|
||||
if (dmang.peek(1) == '$') { // This is the same as the "default" case below
|
||||
dt = MDDataTypeParser.parsePrimaryDataType(dmang, true);
|
||||
dt.parse();
|
||||
if (dt instanceof MDEmptyParameterType ||
|
||||
dt instanceof MDEndParameterType) {
|
||||
// These two do not get added to the arguments list and they don't
|
||||
// count as or change the indices of backreferences.
|
||||
break;
|
||||
}
|
||||
commaDelimiter.add(needsComma);
|
||||
needsComma = true;
|
||||
args.add(dt);
|
||||
|
@ -76,7 +76,7 @@ public class MDTemplateNameAndArguments extends MDParsableItem {
|
||||
|
||||
@Override
|
||||
protected void parseInternal() throws MDException {
|
||||
if (dmang.peek() != '?' && dmang.peek(1) != '$') {
|
||||
if (dmang.peek() != '?' || dmang.peek(1) != '$') {
|
||||
throw new MDException("Invalid TemplateNameandArguments");
|
||||
}
|
||||
dmang.increment(); // skip the '?'
|
||||
|
@ -0,0 +1,38 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import org.junit.experimental.categories.Categories;
|
||||
import org.junit.experimental.categories.Categories.IncludeCategory;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
|
||||
@RunWith(Categories.class)
|
||||
@IncludeCategory(MDMangFailingTestCategory.class)
|
||||
@SuiteClasses(MDMangBaseTest.class)
|
||||
/**
|
||||
* This test suite has the purpose of driving the tests in MDMangBaseTest and
|
||||
* only testing those that are known not to be failing at this time. Failing
|
||||
* tests exist because I have not yet crafted an effective way to deal with them
|
||||
* yet that does not also cause other tests to fail... or they might be failing
|
||||
* for other reasons that I will not get into here. Essentially this suite
|
||||
* exists for the purpose of providing a suite of tests that will not fail
|
||||
* during nightly or continuous testing. The MDMangBaseTest class is not located
|
||||
* in a folder that will be seen by these tests.
|
||||
*/
|
||||
public class MDMangBaseFailingTests {
|
||||
// Purposefully empty.
|
||||
}
|
@ -631,7 +631,10 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
public void testPointerToQuestionToData() throws Exception {
|
||||
mangled = "?var@@3PD?BHC";
|
||||
msTruth = "";
|
||||
mdTruth = msTruth;
|
||||
// This is a non-sensical result, but the end result we get from our current processing
|
||||
// model. I believe this was probably a symbol I created to see if a pointer to a '?'
|
||||
// modifier to data could happen (from undname perspective vs. a real world perspective).
|
||||
mdTruth = "BHC const volatile * var";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@ -655,7 +658,10 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
public void testReferenceToQuestionToData() throws Exception {
|
||||
mangled = "?var@@3AD?BHC";
|
||||
msTruth = "";
|
||||
mdTruth = msTruth;
|
||||
// This is a non-sensical result, but the end result we get from our current processing
|
||||
// model. I believe this was probably a symbol I created to see if a reference to a '?'
|
||||
// modifier to data could happen (from undname perspective vs. a real world perspective).
|
||||
mdTruth = "BHC const volatile & var";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@ -678,8 +684,11 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
@Test
|
||||
public void testQuestionToQuestionToData() throws Exception {
|
||||
mangled = "?var@@3?D?BHC";
|
||||
msTruth = "";
|
||||
mdTruth = msTruth;
|
||||
msTruth = ""; //fails
|
||||
// This is a non-sensical result, but the end result we get from our current processing
|
||||
// model. I believe this was probably a symbol I created to see if '?' modifiers could
|
||||
// be nested (from undname perspective vs. a real world perspective).
|
||||
mdTruth = "BHC const volatile var";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@ -1382,6 +1391,20 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// $$T was found to be the reference type of a right-reference, and we needed to change
|
||||
// special extended types to be reached from basic data types instead of from primary data
|
||||
// types. Primary data types used to send out to extended and basic handling. Now extended
|
||||
// is sent out by basic. See MDDataTypeParser.
|
||||
// MDStdNullPtrType "$$T" referenced by RRef (any reference type)
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testStdNullPtrReferencedByRRef() throws Exception {
|
||||
mangled = "?fn@@3P6AH$$QA$$T@ZA";
|
||||
msTruth = "int (__cdecl* fn)(std::nullptr_t &&)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStdNullptrArgReal() throws Exception { //std::nullptr_t
|
||||
mangled =
|
||||
@ -3697,7 +3720,7 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//Q: __vectorcall block
|
||||
//Q,R: __vectorcall block
|
||||
@Test
|
||||
public void testFunctionCallingConventions_Q__vectorcall() throws Exception {
|
||||
mangled = "?fnii@@YQHH@Z";
|
||||
@ -3706,6 +3729,114 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_R__vectorcall() throws Exception {
|
||||
mangled = "?fnii@@YRHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int __vectorcall fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//S,T: __swift_1 block
|
||||
// MSFT is as shown
|
||||
// LLVM is "__attribute__((__swiftcall__))" for code S and blank for T
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_S__swift_1() throws Exception {
|
||||
mangled = "?fnii@@YSHH@Z";
|
||||
String llTruth = "int __attribute__((__swiftcall__)) fnii(int)\n";
|
||||
msTruth = "int __swift_1 fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MSFT is as shown
|
||||
// LLVM is "__attribute__((__swiftcall__))" for code S and blank for T
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_T__swift_1() throws Exception {
|
||||
mangled = "?fnii@@YTHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int __swift_1 fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//U,V: __swift_2 block
|
||||
// MSFT is as shown for U, but blank for V
|
||||
// LLVM is blank for both
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_U__swift_2() throws Exception {
|
||||
mangled = "?fnii@@YUHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int __swift_2 fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MSFT is as shown for U, but blank for V
|
||||
// LLVM is blank for both
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_V__blank() throws Exception {
|
||||
mangled = "?fnii@@YVHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int fnii(int)";
|
||||
mdTruth = "int __swift_2 fnii(int)";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//W,X: __swiftasynccall block
|
||||
// MSFT is blank
|
||||
// LLVM is "__attribute__((__swiftasynccall__))" for code W and blank for X
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_W__swiftasynccall() throws Exception {
|
||||
mangled = "?fnii@@YWHH@Z";
|
||||
String llTruth = "int __attribute__((__swiftasynccall__)) fnii(int)";
|
||||
msTruth = "int fnii(int)";
|
||||
mdTruth = "int __swiftasynccall fnii(int)";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MSFT is blank
|
||||
// LLVM is "__attribute__((__swiftasynccall__))" for code W and blank for X
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_X__blank() throws Exception {
|
||||
mangled = "?fnii@@YXHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int fnii(int)";
|
||||
mdTruth = "int __swiftasynccall fnii(int)";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//Y,Z: blank block
|
||||
// I suspect this is blank only unless/until the standard accepts a new convention for it
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_Y__blank() throws Exception {
|
||||
mangled = "?fnii@@YYHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// I suspect this is blank only unless/until the standard accepts a new convention for it
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testFunctionCallingConventions_Z__blank() throws Exception {
|
||||
mangled = "?fnii@@YZHH@Z";
|
||||
String llTruth = "int fnii(int)";
|
||||
msTruth = "int fnii(int)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionNoExcept() throws Exception {
|
||||
mangled = "?fnii@@YAHH@_E";
|
||||
@ -14532,10 +14663,13 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
public void testThreadSafeStaticGuard_1() throws Exception {
|
||||
mangled =
|
||||
"?$TSS0@?1??GetCategoryMap@CDynamicRegistrationInfoSource@XPerfAddIn@@SAPEBU_ATL_CATMAP_ENTRY@ATL@@XZ@4HA";
|
||||
String llTruth =
|
||||
"int `public: static struct ATL::_ATL_CATMAP_ENTRY const * __cdecl XPerfAddIn::CDynamicRegistrationInfoSource::GetCategoryMap(void)'::`2'::$TSS0";
|
||||
//TODO: Create MDMangVS2015 Specialization for this problem and then remove "mstruth = mdtruth"
|
||||
msTruth =
|
||||
"int `public: static struct ATL::_ATL_CATMAP_ENTRY const * __ptr64 __cdecl XPerfAddIn::CDynamicRegistrationInfoSource::GetCategoryMap(void)'::`2'::$TSS0";
|
||||
mdTruth =
|
||||
"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();
|
||||
}
|
||||
|
||||
@ -14558,10 +14692,13 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
@Test
|
||||
public void testNonvisibleStaticGuard() throws Exception {
|
||||
mangled = "?$S1@?1??name0@name1@name2@@KAHPEBGAEAG@Z@4HA";
|
||||
String llTruth =
|
||||
"int `protected: static int __cdecl name2::name1::name0(unsigned short const *, unsigned short &)'::`2'::$S1";
|
||||
//TODO: Create MDMangVS2015 Specialization
|
||||
msTruth =
|
||||
"int `protected: static int __cdecl name2::name1::name0(unsigned short const * __ptr64,unsigned short & __ptr64)'::`2'::$S1";
|
||||
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();
|
||||
}
|
||||
|
||||
@ -14584,10 +14721,13 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
@Test
|
||||
public void testReferenceTemporary() throws Exception {
|
||||
mangled = "?$RT1@?1??name0@name1@name2@@KAHPEBGAEAG@Z@4HA";
|
||||
String llTruth =
|
||||
"int `protected: static int __cdecl name2::name1::name0(unsigned short const *, unsigned short &)'::`2'::$RT1";
|
||||
//TODO: Create MDMangVS2015 Specialization
|
||||
msTruth =
|
||||
"int `protected: static int __cdecl name2::name1::name0(unsigned short const * __ptr64,unsigned short & __ptr64)'::`2'::$RT1";
|
||||
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();
|
||||
}
|
||||
|
||||
@ -14868,7 +15008,7 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
//=====================
|
||||
|
||||
@Test
|
||||
public void testLLVMType1WithSuffix() throws Exception {
|
||||
public void testLlvmQuestionModifierType1WithSuffix() throws Exception {
|
||||
mangled =
|
||||
".?AVname0@?1??name1@name2@name3@name4@@AEAA?AU?$name5@V?$name6@V?$name7@U?$name8@Uname9@name2@name3@name4@@@name4@@@name4@@@name4@@E@4@_K0@Z@`fedcba98";
|
||||
//llTruth = ""; // fails
|
||||
@ -14881,7 +15021,7 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLLVMType1MinusSuffix() throws Exception {
|
||||
public void testLlvmQuestionModifierType1CounterPointMinusSuffix() throws Exception {
|
||||
mangled =
|
||||
".?AVname0@?1??name1@name2@name3@name4@@AEAA?AU?$name5@V?$name6@V?$name7@U?$name8@Uname9@name2@name3@name4@@@name4@@@name4@@@name4@@E@4@_K0@Z@";
|
||||
//llTruth = "";
|
||||
@ -14894,7 +15034,7 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
//=====================
|
||||
|
||||
@Test
|
||||
public void testLLVMType2WithSuffix() throws Exception {
|
||||
public void testLlvmQuestionModifierType2WithSuffix() throws Exception {
|
||||
mangled =
|
||||
".?AVname0@?1???$name1@Vname0@?3??name2@name3@?Aname4@@QEAA_KQEBXQEAX_KQ6A_K2PEAX3P6A_KPEAD23@_E@Z@Z@@?Aname4@@YA_KQ6A_K_KPEAX1P6A_KPEAD01@_E@Z_KQEAXV0?3??name2@name3@1@QEAA_KQEBX604@Z@@Z@`fedcba98";
|
||||
msTruth = "";
|
||||
@ -14906,7 +15046,7 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLLVMType2MinusSuffix() throws Exception {
|
||||
public void testLlvmQuestionModifierType2CounterPointMinusSuffix() throws Exception {
|
||||
mangled =
|
||||
".?AVname0@?1???$name1@Vname0@?3??name2@name3@?Aname4@@QEAA_KQEBXQEAX_KQ6A_K2PEAX3P6A_KPEAD23@_E@Z@Z@@?Aname4@@YA_KQ6A_K_KPEAX1P6A_KPEAD01@_E@Z_KQEAXV0?3??name2@name3@1@QEAA_KQEBX604@Z@@Z@";
|
||||
msTruth = "";
|
||||
@ -14917,6 +15057,250 @@ public class MDMangBaseTest extends AbstractGenericTest {
|
||||
|
||||
//=====================
|
||||
|
||||
// This one had been getting "SpecialName not expected in qualification list" because of there
|
||||
// only being one '?' for the embedded object.... this is one of the situations where LLVM
|
||||
// appears to fail to adhere to the MSFT mangling scheme. So we had to put in special
|
||||
// processing after catching the exception on the MSFT processing pass
|
||||
@Test
|
||||
public void testLlvmBadObjectNesting() throws Exception {
|
||||
mangled = ".?AW4name0@?name1@name2@@YAX_N@Z@";
|
||||
//llTruth = ""; // fails
|
||||
msTruth = ""; // fails
|
||||
mdTruth = msTruth = "enum `void __cdecl name2::name1(bool)'::name0";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// Since MSFT undname does not process mangled "type" names, we create a mangled "symbol"
|
||||
// name to test against. This one is a symbol "x" that is a pointer to the type in question
|
||||
// above. We also inject the second '?' to show MSFT being able to process the mangled
|
||||
// symbol name when it follows the MSFT mangling scheme
|
||||
@Test
|
||||
public void testLlvmBadObjectNestingCounterPoint1() throws Exception {
|
||||
mangled = "?x@@3PAW4name0@??name1@name2@@YAX_N@Z@A";
|
||||
//llTruth = ""; // fails whether it has ?, ??, or ??? at the embedding point
|
||||
msTruth = "enum `void __cdecl name2::name1(bool)'::name0 * x";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// Second counterpoint to the above where we properly follow the MSFT embedding scheme,
|
||||
// but where this is only a type name, which MSFT cannot process
|
||||
@Test
|
||||
public void testLlvmBadObjectNestingCounterPoint2() throws Exception {
|
||||
mangled = ".?AW4name0@??name1@name2@@YAX_N@Z@";
|
||||
//llTruth = ""; // fails whether it has ?, ??, or ??? at the embedding point
|
||||
msTruth = ""; //fails
|
||||
mdTruth = "enum `void __cdecl name2::name1(bool)'::name0";
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
// This one had been getting "CV code not expected: @" because of the second '@' was not
|
||||
// getting pulled when there was an empty MDQualification... we changed to MDQualifiedName
|
||||
// to fix this.
|
||||
@Test
|
||||
public void testCVModMemberPointerEmptyQualifiedName() throws Exception {
|
||||
mangled = "?name0@@3P8@@AAXH@ZA";
|
||||
String llTruth = ""; // fails
|
||||
msTruth = "void (__cdecl* name0)(int)";
|
||||
mdTruth = msTruth;
|
||||
}
|
||||
|
||||
// CounterPoint1 is same mangled name, but with a qualified name for the member pointer.
|
||||
@Test
|
||||
public void testCVModMemberPointerEmptyQualifiedNameCounterPoint1() throws Exception {
|
||||
mangled = "?name0@@3P8name1@name2@@AAXH@ZA";
|
||||
String llTruth = ""; // fails
|
||||
msTruth = "void (__cdecl name2::name1::* name0)(int)";
|
||||
mdTruth = msTruth;
|
||||
}
|
||||
|
||||
// CounterPoint2 is same as CounterPoint1, but being a pointer to the member pointer...
|
||||
// this allows LLVM to present a reasonable result.
|
||||
@Test
|
||||
public void testCVModMemberPointerEmptyQualifiedNameCounterPoint2() throws Exception {
|
||||
mangled = "?name0@@3PAP8name1@name2@@AAXH@ZA";
|
||||
String llTruth = "void (__cdecl name2::name1::**name0)(int)";
|
||||
msTruth = "void (__cdecl name2::name1::** name0)(int)";
|
||||
mdTruth = msTruth;
|
||||
}
|
||||
|
||||
// CounterPoint3 is same as CounterPoint2, but again with an empty qualified name...
|
||||
// this allows LLVM to present a result, but sketchy that it doesn't provdide the calling
|
||||
// convention.
|
||||
@Test
|
||||
public void testCVModMemberPointerEmptyQualifiedNameCounterPoint3() throws Exception {
|
||||
mangled = "?name0@@3PAP8@@AAXH@ZA";
|
||||
String llTruth = "void & ( **name0)(int)"; // Seems bad that llvm loses "__cdecl"
|
||||
msTruth = "void (__cdecl** name0)(int)";
|
||||
mdTruth = msTruth;
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
// MDCustomDataType "?"
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testCustomDataType() throws Exception {
|
||||
mangled = "?fn@@3P6AHVaaa@@?bbb@@Vccc@@@ZA";
|
||||
msTruth = "int (__cdecl* fn)(class aaa,bbb,class ccc)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDCustomDataType "?"
|
||||
// Manufactured to see if backref can ref the CustomDataType
|
||||
// Question is whether the backref references the CustomDataType or the one after
|
||||
@Test
|
||||
public void testCustomDataTypeBackRef0() throws Exception {
|
||||
mangled = "?fn@@3P6AHVaaa@@?bbb@@Vccc@@0@ZA";
|
||||
msTruth = "int (__cdecl* fn)(class aaa,bbb,class ccc,class aaa)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDCustomDataType "?"
|
||||
// Manufactured to see if backref can ref the CustomDataType
|
||||
// Question is whether the backref references the CustomDataType or the one after
|
||||
@Test
|
||||
public void testCustomDataTypeBackRef1() throws Exception {
|
||||
mangled = "?fn@@3P6AHVaaa@@?bbb@@Vccc@@1@ZA";
|
||||
msTruth = "int (__cdecl* fn)(class aaa,bbb,class ccc,bbb)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDCustomDataType "?"
|
||||
// Manufactured to see if backref can ref the CustomDataType
|
||||
// Question is whether the backref references the CustomDataType or the one after
|
||||
@Test
|
||||
public void testCustomDataTypeBackRef2() throws Exception {
|
||||
mangled = "?fn@@3P6AHVaaa@@?bbb@@Vccc@@2@ZA";
|
||||
msTruth = "int (__cdecl* fn)(class aaa,bbb,class ccc,class ccc)";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
// MDNamedUnspecifiedType "$$Y" (not sure how should differ from "?" code, except maybe for
|
||||
// template param vs. regular)
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testNamedUnspecifiedType() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$Ybbb@@Vccc@@@@A";
|
||||
msTruth = "class Tc<class aaa,bbb,class ccc> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDNamedUnspecifiedType "$$Y" (not sure how should differ from "?" code, except maybe for
|
||||
// template param vs. regular)
|
||||
// Manufactured to see if backref can ref the MDNamedUnspecifiedType
|
||||
// Question is whether the backref references the MDNamedUnspecifiedType or the one after
|
||||
@Test
|
||||
public void testNamedUnspecifiedTypeBackRef0() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$Ybbb@@Vccc@@0@@A";
|
||||
msTruth = "class Tc<class aaa,bbb,class ccc,class aaa> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDNamedUnspecifiedType "$$Y" (not sure how should differ from "?" code, except maybe for
|
||||
// template param vs. regular)
|
||||
// Manufactured to see if backref can ref the MDNamedUnspecifiedType
|
||||
// Question is whether the backref references the MDNamedUnspecifiedType or the one after
|
||||
@Test
|
||||
public void testNamedUnspecifiedTypeBackRef1() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$Ybbb@@Vccc@@1@@A";
|
||||
msTruth = "class Tc<class aaa,bbb,class ccc,bbb> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// MDNamedUnspecifiedType "$$Y" (not sure how should differ from "?" code, except maybe for
|
||||
// template param vs. regular)
|
||||
// Manufactured to see if backref can ref the MDNamedUnspecifiedType
|
||||
// Question is whether the backref references the MDNamedUnspecifiedType or the one after
|
||||
@Test
|
||||
public void testNamedUnspecifiedTypeBackRef2() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$Ybbb@@Vccc@@2@@A";
|
||||
msTruth = "class Tc<class aaa,bbb,class ccc,class ccc> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
// Empty Param Pack "$$V"
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testTemplateEmptyParamType() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$VVbbb@@@@";
|
||||
msTruth = "class Tc<class aaa,class bbb> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// Empty Param Pack "$$V"
|
||||
// Manufactured to see if backref can ref the $$V... counterpoint to the next test
|
||||
// This one should have expected results
|
||||
@Test
|
||||
public void testTemplateEmptyParamTypeBackRef0() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$VVbbb@@0@@";
|
||||
msTruth = "class Tc<class aaa,class bbb,class aaa> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// Empty Param Pack "$$V"
|
||||
// Manufactured to see if backref can ref the $$V
|
||||
// Question is whether the backref references the $$V or the one after
|
||||
@Test
|
||||
public void testTemplateEmptyParamTypeBackRef1() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$VVbbb@@1@@";
|
||||
msTruth = "class Tc<class aaa,class bbb,class bbb> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
// End Template Param Pack "$$Z"
|
||||
// Manufactured
|
||||
@Test
|
||||
public void testTemplateEndParamType() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$ZVbbb@@@@";
|
||||
msTruth = "class Tc<class aaa,class bbb> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// End Template Param Pack "$$Z"
|
||||
// Manufactured to see if backref can ref the $$Z... counterpoint to the next test
|
||||
// This one should have expected results
|
||||
@Test
|
||||
public void testTemplateEndParamTypeBackRef0() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$ZVbbb@@0@@";
|
||||
msTruth = "class Tc<class aaa,class bbb,class aaa> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
// End Template Param Pack "$$Z"
|
||||
// Manufactured to see if backref can ref the $$Z
|
||||
// Question is whether the backref references the $$Z or the one after
|
||||
@Test
|
||||
public void testTemplateEndParamTypeBackRef1() throws Exception {
|
||||
mangled = "?Ti@@3V?$Tc@Vaaa@@$$ZVbbb@@1@@";
|
||||
msTruth = "class Tc<class aaa,class bbb,class bbb> Ti";
|
||||
mdTruth = msTruth;
|
||||
demangleAndTest();
|
||||
}
|
||||
|
||||
//=====================
|
||||
|
||||
//TODO: ignore for now.
|
||||
@Ignore
|
||||
public void testFuzzyFit() throws Exception {
|
||||
|
Loading…
Reference in New Issue
Block a user