GP-272 - Gnu Demangler - fixed demangler failure on variable name when

the parent namespace is an operator function
This commit is contained in:
dragonmacher
2020-11-13 12:51:33 -05:00
parent c75491d70a
commit 118372d3ce
3 changed files with 117 additions and 4 deletions

View File

@@ -25,6 +25,7 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import utility.function.Dummy;
public class DemangledThunk extends DemangledObject {
@@ -176,8 +177,7 @@ public class DemangledThunk extends DemangledObject {
}
Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(program,
mangled, err -> Msg.warn(this, err));
mangled, Dummy.consumer());
if (s == null) {
Address thunkedAddr =
CreateThunkFunctionCmd.getThunkedAddr(program, thunkAddress, false);
@@ -185,11 +185,13 @@ public class DemangledThunk extends DemangledObject {
s = program.getSymbolTable().getPrimarySymbol(thunkedAddr);
}
}
if (s == null || !block.contains(s.getAddress())) {
Msg.warn(this, "Unable to find or create thunk for " + mangled + " at " + thunkAddress);
return null;
}
Address addr = s.getAddress();
Address addr = s.getAddress();
DemanglerOptions subOptions = new DemanglerOptions(options);
subOptions.setApplySignature(true);

View File

@@ -1004,6 +1004,81 @@ public class GnuDemanglerParser {
return findBalancedStart(string, templateEnd, '<', '>');
}
/**
* Walks backward from the given start position to find the next namespace separator. This
* allows clients to determine if a given position is inside of a namespace.
*
* @param text the text to search
* @param start the start position
* @param stop the stop position
* @return the start index of the namespace entry containing the current {@code start}
* index; -1 if no namespace start is found
*/
private int findNamespaceStart(String text, int start, int stop) {
if (!text.contains(Namespace.DELIMITER)) {
return -1;
}
int nsCount = 0;
int parenDepth = 0;
int templateDepth = 0;
int braceDepth = 0;
boolean isNested = false;
for (int i = start; i >= stop; i--) {
char c = text.charAt(i);
switch (c) {
case ':': {
nsCount++;
if (nsCount == 2) {
if (!isNested) {
return i + 2;
}
nsCount = 0;
}
break;
}
case ' ': {
if (!isNested) {
return -1; // a space implies a return type when not nested
}
break;
}
case '(': {
isNested = --parenDepth > 0 || templateDepth > 0 || braceDepth > 0;
break;
}
case ')': {
isNested = ++parenDepth > 0 || templateDepth > 0 || braceDepth > 0;
break;
}
case '<': {
isNested = parenDepth > 0 || --templateDepth > 0 || braceDepth > 0;
break;
}
case '>': {
isNested = parenDepth > 0 || ++templateDepth > 0 || braceDepth > 0;
break;
}
case '{': {
isNested = parenDepth > 0 || templateDepth > 0 || --braceDepth > 0;
break;
}
case '}': {
isNested = parenDepth > 0 || templateDepth > 0 || ++braceDepth > 0;
break;
}
default:
continue;
}
}
return -1;
}
private DemangledDataType createTypeInNamespace(String name) {
List<String> names = SymbolPathParser.parse(name, false);
DemangledType namespace = null;
@@ -1342,7 +1417,17 @@ public class GnuDemanglerParser {
@Override
boolean matches(String text) {
matcher = OVERLOAD_OPERATOR_NAME_PATTERN.matcher(text);
return matcher.matches();
if (!matcher.matches()) {
return false;
}
int operatorStart = matcher.start(2);
int leafStart = findNamespaceStart(demangled, text.length() - 1, operatorStart);
if (leafStart > operatorStart) {
return false; // operator is inside of a non-leaf namespace entry
}
return true;
}
@Override

View File

@@ -842,6 +842,32 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals("Magick::Coordinate const &", parameters.get(1).getSignature());
}
@Test
public void testOperatorAsNamespace() throws Exception {
//
// Mangled: __ZN3WTF15__visitor_tableINS_7VisitorIZZN7WebCore12SubtleCrypto11generateKeyERN3JSC9ExecStateEONS_7VariantIJNS4_6StrongINS4_8JSObjectEEENS_6StringEEEEbONS_6VectorINS2_14CryptoKeyUsageELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEEONS_3RefINS2_15DeferredPromiseENS_13DumbPtrTraitsISL_EEEEEN4$_10clEONS7_IJNS_6RefPtrINS2_9CryptoKeyENSM_ISS_EEEENS2_13CryptoKeyPairEEEEEUlRSU_E_JZZNS3_11generateKeyES6_SD_bSJ_SP_ENSQ_clESX_EUlRSV_E_EEEJSU_SV_EE12__trampolineE
//
// Demangled: WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>::__trampoline
//
DemangledObject object = parser.parse(
"__ZN3WTF15__visitor_tableINS_7VisitorIZZN7WebCore12SubtleCrypto11generateKeyERN3JSC9ExecStateEONS_7VariantIJNS4_6StrongINS4_8JSObjectEEENS_6StringEEEEbONS_6VectorINS2_14CryptoKeyUsageELm0ENS_15CrashOnOverflowELm16ENS_10FastMallocEEEONS_3RefINS2_15DeferredPromiseENS_13DumbPtrTraitsISL_EEEEEN4$_10clEONS7_IJNS_6RefPtrINS2_9CryptoKeyENSM_ISS_EEEENS2_13CryptoKeyPairEEEEEUlRSU_E_JZZNS3_11generateKeyES6_SD_bSJ_SP_ENSQ_clESX_EUlRSV_E_EEEJSU_SV_EE12__trampolineE",
"WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >&)#1}, WebCore::SubtleCrypto::generateKey(JSC::ExecState&, WTF::Variant<JSC::Strong<JSC::JSObject>, WTF::String>&&, bool, WTF::Vector<WebCore::CryptoKeyUsage, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&, WTF::Ref<WebCore::DeferredPromise, WTF::DumbPtrTraits<WebCore::DeferredPromise> >&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>, WTF::RefPtr<WebCore::CryptoKey, WTF::DumbPtrTraits<WebCore::CryptoKey> >, WebCore::CryptoKeyPair>::__trampoline");
assertNotNull(object);
assertType(object, DemangledVariable.class);
String name = "__trampoline";
assertName(object, name, "WTF",
"__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>");
String signature = object.getSignature(false);
assertEquals(
"WTF::__visitor_table<WTF::Visitor<WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>&)#1},WebCore::SubtleCrypto::generateKey(JSC::ExecState&,WTF::Variant<JSC::Strong<JSC::JSObject>,WTF::String>&&,bool,WTF::Vector<WebCore::CryptoKeyUsage,0ul,WTF::CrashOnOverflow,16ul,WTF::FastMalloc>&&,WTF::Ref<WebCore::DeferredPromise,WTF::DumbPtrTraits<WebCore::DeferredPromise>>&&)::$_10::operator()(WTF::Variant<WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>&&)::{lambda(WebCore::CryptoKeyPair&)#1}>,WTF::RefPtr<WebCore::CryptoKey,WTF::DumbPtrTraits<WebCore::CryptoKey>>,WebCore::CryptoKeyPair>::__trampoline",
signature);
}
@Test
public void testOverloadedShiftOperatorTemplated_RightShift() {
parser = new GnuDemanglerParser();