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:
ghizard 2024-06-11 08:06:42 -04:00
parent d1b0828af9
commit 3c36666600
27 changed files with 960 additions and 208 deletions

View File

@ -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);
}
/**

View File

@ -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 +

View File

@ -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) {

View File

@ -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.

View File

@ -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();

View File

@ -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());
}
}
}

View File

@ -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;
}
}

View File

@ -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_";
}
}

View File

@ -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_";
}
}

View File

@ -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;
}
}

View File

@ -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");
}

View File

@ -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();

View File

@ -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();

View File

@ -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:

View File

@ -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 {

View File

@ -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);
}
}
}
}
/******************************************************************************/

View File

@ -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.

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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.

View File

@ -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();
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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 '?'

View File

@ -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.
}

View File

@ -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 {