mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-272 - Gnu Demangler - updated to handle a lambda function as a
function parameter
This commit is contained in:
@@ -47,6 +47,7 @@ public class GnuDemanglerParser {
|
||||
|
||||
private static final String OPERATOR = "operator";
|
||||
private static final String LAMBDA = "lambda";
|
||||
private static final String LAMBDA_START = "{lambda";
|
||||
private static final String VAR_ARGS = "...";
|
||||
private static final String THUNK = "thunk";
|
||||
private static final String CONST = " const";
|
||||
@@ -60,7 +61,7 @@ public class GnuDemanglerParser {
|
||||
*
|
||||
* Parts: -optional spaces
|
||||
* -optional (const) (non-capture group)
|
||||
* -followed by '()' with optinal parameter text (capture group 1)
|
||||
* -followed by '()' with optional parameter text (capture group 1)
|
||||
*
|
||||
* Note: this pattern is used for matching the arguments string, in the above examples it
|
||||
* would be:
|
||||
@@ -191,16 +192,18 @@ public class GnuDemanglerParser {
|
||||
* Pattern for newer C++ lambda syntax:
|
||||
*
|
||||
* Sample: {lambda(void const*, unsigned int)#1}
|
||||
* {lambda(NS1::Class1 const&, int, int)#1} const&
|
||||
*
|
||||
* Pattern: [optional text] brace lambda([parameters])#digits brace
|
||||
* Pattern: [optional text] brace lambda([parameters])#digits brace [optional modifiers]
|
||||
*
|
||||
* Parts:
|
||||
* -full text without leading characters (capture group 1)
|
||||
* -parameters of the lambda function (capture group 2)
|
||||
* -trailing id (capture group 3)
|
||||
* -trailing modifiers (e.g., const, &) (capture group 4)
|
||||
*/
|
||||
private static final Pattern LAMBDA_PATTERN =
|
||||
Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})");
|
||||
Pattern.compile(".*(\\{" + LAMBDA + "\\((.*)\\)(#\\d+)\\})(\\s*(?:const|\\*|\\&)*){0,1}");
|
||||
|
||||
/*
|
||||
* Sample: {unnamed type#1}
|
||||
@@ -396,7 +399,7 @@ public class GnuDemanglerParser {
|
||||
if (lambdaName != null) {
|
||||
String uniqueName = lambdaName.getFullText();
|
||||
String escapedLambda = removeBadSpaces(uniqueName);
|
||||
simpleName = simpleName.replace("{lambda", escapedLambda);
|
||||
simpleName = simpleName.replace(LAMBDA_START, escapedLambda);
|
||||
function = new DemangledLambda(mangledSource, demangled, null);
|
||||
function.setSignature(lambdaName.getFullText());
|
||||
}
|
||||
@@ -440,6 +443,7 @@ public class GnuDemanglerParser {
|
||||
}
|
||||
|
||||
private LambdaName getLambdaName(String name) {
|
||||
|
||||
Matcher matcher = LAMBDA_PATTERN.matcher(name);
|
||||
if (!matcher.matches()) {
|
||||
return null;
|
||||
@@ -448,7 +452,8 @@ public class GnuDemanglerParser {
|
||||
String fullText = matcher.group(1);
|
||||
String params = matcher.group(2);
|
||||
String trailing = matcher.group(3);
|
||||
return new LambdaName(fullText, params, trailing);
|
||||
String modifiers = matcher.group(4);
|
||||
return new LambdaName(fullText, params, trailing, modifiers);
|
||||
}
|
||||
|
||||
private String stripOffTemplates(String string) {
|
||||
@@ -699,7 +704,11 @@ public class GnuDemanglerParser {
|
||||
// e.g., unsigned long (*)(long const &)
|
||||
// array pointer/refs
|
||||
// e.g., short (&)[7]
|
||||
//
|
||||
// lambda function
|
||||
// e.g., {lambda(NS1::Class1 const&, int, int)#1} const&
|
||||
//
|
||||
|
||||
LambdaName lambdaName = getLambdaName(datatype);
|
||||
|
||||
// check for array case
|
||||
Matcher arrayMatcher = ARRAY_POINTER_REFERENCE_PATTERN.matcher(datatype);
|
||||
@@ -710,6 +719,13 @@ public class GnuDemanglerParser {
|
||||
ddt.setNamespace(namespace);
|
||||
i = arrayMatcher.end();
|
||||
}
|
||||
else if (lambdaName != null) {
|
||||
String fullText = lambdaName.getFullText();
|
||||
ddt.setName(fullText);
|
||||
int offset = fullText.indexOf('(');
|
||||
int remaining = fullText.length() - offset;
|
||||
i = i + remaining;
|
||||
}
|
||||
else {
|
||||
int startParenCount =
|
||||
StringUtilities.countOccurrences(datatype.substring(i), '(');
|
||||
@@ -1003,7 +1019,8 @@ public class GnuDemanglerParser {
|
||||
List<DemangledDataType> parameters = parseParameters(paramerterString);
|
||||
|
||||
DemangledFunctionPointer dfp = new DemangledFunctionPointer(mangledSource, demangledSource);
|
||||
dfp.setReturnType(parseDataType(returnType));
|
||||
DemangledDataType returnDataType = parseDataType(returnType);
|
||||
dfp.setReturnType(returnDataType);
|
||||
for (DemangledDataType parameter : parameters) {
|
||||
dfp.addParameter(parameter);
|
||||
}
|
||||
@@ -1486,11 +1503,13 @@ public class GnuDemanglerParser {
|
||||
private String fullText;
|
||||
private String params;
|
||||
private String trailing;
|
||||
private String modifiers;
|
||||
|
||||
LambdaName(String fullText, String params, String trailing) {
|
||||
LambdaName(String fullText, String params, String trailing, String modifiers) {
|
||||
this.fullText = fullText;
|
||||
this.params = params;
|
||||
this.trailing = trailing;
|
||||
this.modifiers = modifiers == null ? "" : modifiers;
|
||||
}
|
||||
|
||||
String getFullText() {
|
||||
@@ -1503,6 +1522,7 @@ public class GnuDemanglerParser {
|
||||
return builder.append("fullText", fullText)
|
||||
.append("params", params)
|
||||
.append("trailing", trailing)
|
||||
.append("modifiers", modifiers)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1460,6 +1460,40 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionWithLambdaParameter() throws Exception {
|
||||
|
||||
//
|
||||
// Mangled: _ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_
|
||||
//
|
||||
// Demangled: int
|
||||
// JSC::Structure::add<
|
||||
// (JSC::Structure::ShouldPin)1,
|
||||
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}
|
||||
// >(
|
||||
// JSC::VM&, JSC::PropertyName,
|
||||
// unsigned int,
|
||||
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const&
|
||||
// )
|
||||
//
|
||||
//
|
||||
|
||||
DemangledObject object = parser.parse(
|
||||
"_ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_",
|
||||
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1, JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}>(JSC::VM&, JSC::PropertyName, unsigned int, JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const&)");
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledFunction.class);
|
||||
|
||||
String name =
|
||||
"add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>";
|
||||
assertName(object, name, "JSC", "Structure");
|
||||
|
||||
String signature = object.getSignature(false);
|
||||
assertEquals(
|
||||
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>(JSC::VM &,JSC::PropertyName,unsigned int,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const &)",
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionInLambdaNamespace() throws Exception {
|
||||
|
||||
|
||||
@@ -101,6 +101,37 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
|
||||
assertNotNull(cmd.getDemangledObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingFunctionWithLambdaParameter() throws Exception {
|
||||
|
||||
//
|
||||
// This shows a bug when applying a function that has as one of its parameters a lambda function
|
||||
//
|
||||
|
||||
String mangled =
|
||||
"_ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_";
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this performs initialization
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
options = options.withDeprecatedDemangler();
|
||||
DemangledObject result = demangler.demangle(mangled, options);
|
||||
assertNotNull(result);
|
||||
assertEquals(
|
||||
"int JSC::Structure::add<(JSC::Structure::ShouldPin)1,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker_const&,int,int)#1}>(JSC::VM &,JSC::PropertyName,unsigned int,JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&,JSC::PropertyName,unsigned_int,unsigned_int,JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const &)",
|
||||
result.getSignature(false));
|
||||
|
||||
DemanglerCmd cmd = new DemanglerCmd(addr("01001000"), mangled, options);
|
||||
|
||||
// this used to trigger an exception
|
||||
boolean success = applyCmd(program, cmd);
|
||||
assertTrue("Demangler command failed: " + cmd.getStatusMsg(), success);
|
||||
|
||||
assertNotNull(cmd.getDemangledObject());
|
||||
}
|
||||
|
||||
private Address addr(String address) {
|
||||
return program.getAddressFactory().getAddress(address);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user