Skip to content

Commit

Permalink
GP-4627 - MDMangUtils methods to get SymbolPaths
Browse files Browse the repository at this point in the history
  • Loading branch information
ghizard committed Jun 7, 2024
1 parent 127f567 commit 5f3de98
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* ###
* 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 java.util.ArrayList;
import java.util.List;

import ghidra.app.util.SymbolPath;
import mdemangler.datatype.complex.MDComplexType;
import mdemangler.datatype.modifier.MDModifierType;
import mdemangler.naming.*;
import mdemangler.object.MDObjectCPP;

/**
* Utility class for MDMang users (and perhaps internal)
*/
public class MDMangUtils {

private MDMangUtils() {
// purposefully empty
}

/**
* Returns SymbolPath for the demangled item
* @param parsableItem the demangled item
* @return the symbol path
*/
public static SymbolPath getSymbolPath(MDParsableItem parsableItem) {
return getSymbolPath(parsableItem, false);
}

/**
* Returns a more simple SymbolPath for the demangled item. Any embedded object found at
* the main namespace level will have its namespace components retrieved and inserted
* appropriately in the main SymbolPath namespace. However, embedded objects that are more
* deeply placed (such as when used for a template argument) don't and shouldn't take part
* in this simplification
* @param parsableItem the demangled item
* @return the symbol path
*/
public static SymbolPath getSimpleSymbolPath(MDParsableItem parsableItem) {
return getSymbolPath(parsableItem, true);
}

private static SymbolPath getSymbolPath(MDParsableItem parsableItem, boolean simple) {
List<String> parts = new ArrayList<>();
// When simple is true, we need to recurse the nested hierarchy to pull the names
// up to the main namespace level, so we set recurse = true
recurseNamespace(parts, parsableItem, simple);
SymbolPath sp = null;
for (String part : parts) {
sp = new SymbolPath(sp, part);
}
return sp;
}

private static void recurseNamespace(List<String> parts, MDParsableItem item,
boolean recurseNested) {
item = getReferencedType(item);
String name;
MDQualification qualification;
if (item instanceof MDComplexType complexType) {
MDQualifiedName qualName = complexType.getNamespace();
name = qualName.getName();
qualification = qualName.getQualification();
}
else if (item instanceof MDObjectCPP objCpp) {
MDObjectCPP embeddedObj = objCpp.getEmbeddedObject();
name = embeddedObj.getName();
qualification = embeddedObj.getQualification();
}
else {
return;
}

List<String> myParts = new ArrayList<>();
// the qualification comes in reverse order... the last is nearest to namespace root
for (MDQualifier qual : qualification) {
if (qual.isNested() && recurseNested) {
MDNestedName nestedName = qual.getNested();
MDObjectCPP nestedObjCpp = nestedName.getNestedObject();
List<String> nestedParts = new ArrayList<>();
recurseNamespace(nestedParts, nestedObjCpp, recurseNested);
myParts.addAll(0, nestedParts);
}
else if (qual.isAnon()) {
myParts.add(0, qual.getAnonymousName());
}
else {
myParts.add(0, qual.toString());
}
}
myParts.add(name);
parts.addAll(myParts);
}

// This method recurses
private static MDParsableItem getReferencedType(MDParsableItem item) {
if (item instanceof MDModifierType m) {
return getReferencedType(m.getReferencedType());
}
return item;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public void insert(StringBuilder builder) {
public String getMangled() {
return mangled;
}

public MDObjectCPP getNestedObject() {
return objectCPP;
}

}

/******************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -138,6 +138,10 @@ protected void parseInternal() throws MDException {
// }
}

/**
* Provides iterator of MDQualifiers, where the last iteration is the namespace root
* @return the iterator
*/
@Override
public Iterator<MDQualifier> iterator() {
return quals.iterator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ public boolean isNested() {
return (nameNested != null);
}

public boolean isAnon() {
return (nameAnonymous != null);
}

public MDNestedName getNested() {
return nameNested;
}

public MDReusableName getAnonymousName() {
return nameAnonymous;
public String getAnonymousName() {
return nameAnonymous.getName();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public MDObjectCPP getEmbeddedObject() {
*/
public String getName() {
if (hashedObjectFlag) {
return hashedObject.toString();
return hashedObject.getName();
}
return getQualifiedName().getBasicName().toString();
}
Expand Down Expand Up @@ -267,10 +267,19 @@ protected void parseInternal() throws MDException {
hashString = builder.toString();
}

/**
* Returns the name representation
* @return the name
*/
public String getName() {
// We have made up the name representation with the encompassing tick marks (similar
// to other types). Nothing is sacrosanct about this output.
return "`" + hashString + "'";
}

@Override
public void insert(StringBuilder builder) {
// We have made up the output format. Nothing is sacrosanct about this output.
builder.append("`" + hashString + "'");
builder.append(getName());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,11 @@ public static MDTypeInfo parse(MDMang dmang, int rttiNum) throws MDException {
dmang.increment();
typeInfo = new MDMemberFunctionInfo(dmang);
typeInfo.setPrivate();
// When considering code 'A' to be at index 0, then for this and other processing
// below, those that have an *even* index are *near* pointers and those with
// an *odd* index are *far* pointers
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'C':
case 'D':
Expand All @@ -172,15 +175,15 @@ public static MDTypeInfo parse(MDMang dmang, int rttiNum) throws MDException {
typeInfo = new MDVFAdjustor(dmang);
typeInfo.setPrivate();
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'I': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment
case 'J':
dmang.increment();
typeInfo = new MDMemberFunctionInfo(dmang);
typeInfo.setProtected();
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'K':
case 'L':
Expand All @@ -202,15 +205,15 @@ public static MDTypeInfo parse(MDMang dmang, int rttiNum) throws MDException {
typeInfo = new MDVFAdjustor(dmang);
typeInfo.setProtected();
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'Q': // A, B, I, J, Q, R: These might be "this adjustment" with no adjustment
case 'R':
dmang.increment();
typeInfo = new MDMemberFunctionInfo(dmang);
typeInfo.setPublic();
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'S':
case 'T':
Expand All @@ -232,7 +235,7 @@ public static MDTypeInfo parse(MDMang dmang, int rttiNum) throws MDException {
typeInfo = new MDVFAdjustor(dmang);
typeInfo.setPublic();
typeInfo.setPointerFormat(
(code % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((code - 'A') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case 'Y':
case 'Z':
Expand Down Expand Up @@ -277,27 +280,30 @@ public static MDTypeInfo parseSpecialHandlingFunction(MDMang dmang, int rttiNum)
char ch = dmang.getAndIncrement();
switch (ch) {
// UINFO: (0-5) isFunction, isMember, isvtordisp (0-5)
// UINFO: val%2==0: near; val%2==0: far;
// UINFO: val%2==0: near; val%2==1: far;
case '0':
case '1':
typeInfo = new MDVtordisp(dmang);
typeInfo.setPrivate();
// When considering code '0' to be at index 0, then for this and other processing
// below, those that have an *even* index are *near* pointers and those with
// an *odd* index are *far* pointers
typeInfo.setPointerFormat(
(ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((ch - '0') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case '2':
case '3':
typeInfo = new MDVtordisp(dmang);
typeInfo.setProtected();
typeInfo.setPointerFormat(
(ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((ch - '0') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case '4':
case '5':
typeInfo = new MDVtordisp(dmang);
typeInfo.setPublic();
typeInfo.setPointerFormat(
(ch % 2 == 0) ? PointerFormat._NEAR : PointerFormat._NEAR);
((ch - '0') % 2 == 0) ? PointerFormat._NEAR : PointerFormat._FAR);
break;
case '$':
char ch2 = dmang.getAndIncrement();
Expand Down
Loading

0 comments on commit 5f3de98

Please sign in to comment.