Merge remote-tracking branch 'origin/GP-6703_ghizard_Minor_MDMang_tweaks'

This commit is contained in:
Ryan Kurtz
2026-06-02 13:39:16 -04:00
4 changed files with 176 additions and 27 deletions

View File

@@ -192,4 +192,10 @@ public class MDCharacterIterator {
public boolean positionStartsWith(String substring) {
return string.regionMatches(index, substring, 0, substring.length());
}
@Override
public String toString() {
return string + "\n" + " ".repeat(index) + "^";
}
}

View File

@@ -637,7 +637,8 @@ public class MDSpecialName extends MDParsableItem {
}
break;
case 'F': {
dmang.parseInfoPush(3, "dynamic atexit destructor operator");
dmang.parseInfoPush(3,
"dynamic atexit destructor operator for [Object]");
StringBuilder builder = new StringBuilder();
// TODO... 20160812: This looks like new ObjectCPP and ObjectC
if (dmang.peek() == '?') {
@@ -672,17 +673,17 @@ public class MDSpecialName extends MDParsableItem {
}
break;
case 'G':
dmang.parseInfoPush(3, "vector copy constructor");
dmang.parseInfoPush(3, "vector copy constructor iterator");
name = "`vector copy constructor iterator'";
dmang.parseInfoPop();
break;
case 'H':
dmang.parseInfoPush(3, "vector vbase copy constructor");
dmang.parseInfoPush(3, "vector vbase copy constructor iterator");
name = "`vector vbase copy constructor iterator'";
dmang.parseInfoPop();
break;
case 'I':
dmang.parseInfoPush(3, "managed vector copy constructor");
dmang.parseInfoPush(3, "managed vector copy constructor iterator");
name = "`managed vector copy constructor iterator'";
dmang.parseInfoPop();
break;
@@ -692,7 +693,7 @@ public class MDSpecialName extends MDParsableItem {
dmang.parseInfoPop();
break;
case 'K':
dmang.parseInfoPush(3, "udl");
dmang.parseInfoPush(3, "user defined literal");
// Our test has manufactured symbol "??__Kabc@def@@3HA"
// 20170329: Confirmed that this is not a MDReusableName with
// manufactured symbol "??__Kabc@def@0@3HA"

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.
@@ -16,9 +16,13 @@
package mdemangler.template;
import mdemangler.*;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDDataTypeParser;
import mdemangler.naming.MDFragmentName;
import mdemangler.object.MDObject;
import mdemangler.object.MDObjectCPP;
import mdemangler.typeinfo.MDTypeInfo;
import mdemangler.typeinfo.MDTypeInfoParser;
/**
* This class represents a the template constant portion of a
@@ -66,24 +70,17 @@ public class MDTemplateConstant extends MDParsableItem {
// name = "&" + object;
}
break;
case '2': // TODO: Currently, we have no test data for this.
a = new MDSignedEncodedNumber(dmang);
a.parse();
String aStr = a.toString();
// 20140630: seems that '\'' is not there in $2a'b (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
b = new MDSignedEncodedNumber(dmang);
b.parse();
if (aStr.charAt(0) == '-') {
name = "-";
aStr = aStr.substring(1, aStr.length());
case '2':
// This is not perect. The newer encoding might not get tripped
// up by attempting to demangle with the older scheme or vice versa.
int currentIndex = dmang.getIndex();
try {
name = parseFloatingPointConstant();
}
name += aStr.charAt(0) + ".";
if (aStr.length() > 1) {
name += aStr.substring(1, aStr.length());
catch (MDException e) {
dmang.setIndex(currentIndex);
name = parseInitializedTemplateConstant();
}
name += "e" + b;
break;
case 'D':
a = new MDSignedEncodedNumber(dmang);
@@ -102,7 +99,7 @@ public class MDTemplateConstant extends MDParsableItem {
case 'F':
// 20140630: seems that '\'' is not there in $Fa'b (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
// mangled string)
a = new MDSignedEncodedNumber(dmang);
a.parse();
b = new MDSignedEncodedNumber(dmang);
@@ -112,7 +109,7 @@ public class MDTemplateConstant extends MDParsableItem {
case 'G':
// 20140630: seems that '\'' is not there in $Ga'b'c (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
// mangled string)
a = new MDSignedEncodedNumber(dmang);
a.parse();
b = new MDSignedEncodedNumber(dmang);
@@ -140,7 +137,7 @@ public class MDTemplateConstant extends MDParsableItem {
case 'I': { // Used in some cases ($$issue!!!!!!)
// 20140630: seems that '\'' is not there in $Ix'y (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
// mangled string)
// It also seems that the second parameter CAN be negative: $Ixa, where
// x is some object, and a is some signed number
// Do not do a pushModifierContext here.
@@ -165,7 +162,7 @@ public class MDTemplateConstant extends MDParsableItem {
case 'J': { // Used in some cases ($$issue!!!!!!)
// 20140630: seems that '\'' is not there in $Jx'y'z (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
// mangled string)
// It also seems that the second, third, and fourth parameters CAN be
// negative: $Jxabc, where x is some object, and a, b, and care some
// signed numbers
@@ -221,6 +218,65 @@ public class MDTemplateConstant extends MDParsableItem {
}
}
private String parseFloatingPointConstant() throws MDException {
String str = "";
MDSignedEncodedNumber a = new MDSignedEncodedNumber(dmang);
a.parse();
String aStr = a.toString();
// 20140630: seems that '\'' is not there in $2a'b (documentation
// notation failure--the single quote (any type) is not really in the
// mangled string)
MDSignedEncodedNumber b = new MDSignedEncodedNumber(dmang);
b.parse();
if (aStr.charAt(0) == '-') {
str = "-";
aStr = aStr.substring(1, aStr.length());
}
str += aStr.charAt(0) + ".";
if (aStr.length() > 1) {
str += aStr.substring(1, aStr.length());
}
str += "e" + b;
return str;
}
// Not sure that I like the name of this method, as I'm not sure what the full scope of
// encodings/initializations are at this time.
private String parseInitializedTemplateConstant() throws MDException {
String str = "";
// I don't know if we need to push and pop context before and after this
// (to have correct back references if needed).
MDDataType t = MDDataTypeParser.parseDataType(dmang, true);
t.parse();
str += t.toString() + "{";
char code = dmang.peek();
while (code != '@') {
//From MDDataTypeParser:
// MDParsableItem item = new MDObjectCPP(dmang);
// dmang.pushContext();
// item.parse();
// dmang.popContext();
// I don't know if we need to push and pop context before and after this
// (to have correct back references if needed).
//From MDObjectCpp
//int RTTINum = qualifiedName.getRTTINumber();
MDTypeInfo typeInfo = MDTypeInfoParser.parse(dmang, -1);
//if (qualifiedName.isTypeCast()) {
// typeInfo.setTypeCast();
//}
typeInfo.parse();
str += typeInfo.toString();
}
dmang.next(); // skip the '@' character
str += "}";
return str;
}
@Override
public void insert(StringBuilder builder) {
dmang.insertString(builder, name);

View File

@@ -3243,6 +3243,26 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
//=====================
// $2 template constants
//
// We seem to have two different encodings for $2 template constant. An older form that
// encodes floating point numbers that works in undname from vs2017 and a newer form that
// encodes type constants with initializers that works in undname from vs2022. The 2017
// mangled strings do not demangle under 2022 and the 2022 strings do not demangle under
// 2017. I have not checked other VS versions. Probably no longer need to encode floating
// point type the same way, as they could probably be encoded with the newer format, which
// should offer a broader encoding scheme. We don't know if both encoding styles can
// coexist or whether we need to offer different demangling versions (e.g., see MDMangVS2015).
// We haven't pursued fleshing out the differences between versions, but if we did, then we
// could offer the user the options of choosing or we could detect from PE header, PDB, or
// other analysis. Probably best if we can make all coexist. (Note: we still have other
// issues where LLVM or Clang don't adhere exactly to some MSFT encoding standards; this
// was partially worked around, but is still a mess.)
//
// ALSO... gaining evidence that there are many more $ codes for template constants than
// what we have implemented. Seems like it might be a lot of work to tackle all of them.
//manufactured symbol: $2 Blank (zero) exponent
@Test
public void testSpecialTemplateParameters_dollar2_blankzeroexp() throws Exception {
@@ -3366,6 +3386,56 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
// Newer $2 template constant encodings below. See note at top of $2 section
// real symbol with $2 non-floating point template constant with initializers
// From template_op_lit/tol64
// mstruth here is from vs2022 undname
@Category(MDMangFailingTestCategory.class)
@Test
public void testTemplateConstantParameterWithInitializers1() throws Exception {
mangled =
"??$?__K_x2@$2U?$DoubleString@$03@@3D0GB@@0GC@@0GD@@0GB@@0GC@@0GD@@0A@@@@@@YA?A_PXZ";
msTruth =
"auto __cdecl operator \"\" _x2<struct DoubleString<4>{char{97,98,99,97,98,99,0}}>(void)";
mdTruth = msTruth;
demangleAndTest16Bit();
}
// This is fuzzed counterpoint to the real $2 template constant, above
// mstruth here is from vs2022 undname
@Category(MDMangFailingTestCategory.class)
@Test
public void testTemplateConstantParameterWithInitializers1_counterpoint1() throws Exception {
mangled = "??$?M$2H@@@YA?AXXZ";
msTruth = "void __cdecl operator<<int{}>(void)";
mdTruth = msTruth;
demangleAndTest16Bit();
}
// This is fuzzed counterpoint to the real $2 template constant, above. This does not have $2
// mstruth here is from both vs2022 and vs2017 undname
@Test
public void testTemplateConstantParameterWithInitializers1_counterpoint2() throws Exception {
mangled = "??$?MH@@YAXXZ";
msTruth = "void __cdecl operator<<int>(void)";
mdTruth = msTruth;
demangleAndTest16Bit();
}
// This is fuzzed counterpoint to the real $2 template constant, above. This does not have $2
// probably don't need since we just figured out ?A (we already process)
// mstruth here is from both vs2022 and vs2017 undname
@Test
public void testTemplateConstantParameterWithInitializers1_counterpoint3() throws Exception {
mangled = "??$?MH@@YA?AXXZ";
msTruth = "void __cdecl operator<<int>(void)";
mdTruth = msTruth;
demangleAndTest16Bit();
}
//=====================
//real symbol: $D
@Test
public void testSpecialTemplateParameters_dollarD() throws Exception {
@@ -5050,6 +5120,22 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
//manufactured symbol
// We have no real symbols and haven't been able to get undname to produce results,
// which means that we might not have all the right pieces for a ??_W symbol to parse.
// If we find/produce a symbol that undname works on, the we should delete and
// replace this test and change the demangler to properly parse the symbol (which should
// also cause this current test to fail).
@Test
public void testSpecialNames_W() throws Exception {
mangled = "??_WAA@@QAAXXZ";
msTruth = "";
mdTruth = "public: void __cdecl AA::`omni callsig'(void)";
demangleAndTest();
}
// ??_WAA@@QAAXXZ
// public: void __cdecl AA::`omni callsig'(void)
//manufactured symbol
@Test
public void testSpecialNames_X() throws Exception {