Skip to content

Instantly share code, notes, and snippets.

@salvatore-abello
Created June 17, 2023 22:19
Show Gist options
  • Save salvatore-abello/16b68348e5e38176aabc71cf66098251 to your computer and use it in GitHub Desktop.
Save salvatore-abello/16b68348e5e38176aabc71cf66098251 to your computer and use it in GitHub Desktop.
A Haskell Demangler. Attempts to demangle all mangled symbols in the current program. https://gitlab.haskell.org/ghc/ghc/-/snippets/1535
#Demangle haskell function/symbol names.
#@author salvatore.abello
#@category haskellscripts
#@keybinding
#@menupath
#@toolbar
# Thanks to: https://gitlab.haskell.org/bgamari -> https://gitlab.haskell.org/ghc/ghc/-/snippets/1535
from ghidra.program.model.symbol.SourceType import *
def run():
functions = currentProgram.getFunctionManager().getFunctions(True)
for function in functions:
demangled_name = ghc_demangle_sym(function.getName())
if demangled_name:
try:
new_name = demangled_name[0]
function.setName(new_name, USER_DEFINED)
print("Function: %s => %s" % (function.getName(), new_name))
except Exception as e:
print("Failed to rename function: %s" % function.getName())
symbol_table = currentProgram.getSymbolTable()
symbols = symbol_table.getAllSymbols(True)
for symbol in symbols:
if symbol.isExternal():
continue
demangled_name = ghc_demangle_sym(symbol.getName())
if demangled_name:
try:
new_name = demangled_name[0]
symbol.setName(new_name, USER_DEFINED)
print("Symbol: %s => %s" % (symbol.getName(), new_name))
except Exception as e:
print("Failed to rename symbol: %s" % symbol.getName())
count = 0
def ghc_demangle_sym(sym):
global count
out = []
def push(c):
global count
if out is not None:
out.append(c)
count += 1
index = 0
while index < len(sym):
c = sym[index]
if c == 'Z':
index += 1
if index >= len(sym):
return 0
inner_c = sym[index]
if inner_c == '\0':
return 0
elif inner_c == 'L':
push('(')
index += 1
elif inner_c == 'R':
push(')')
index += 1
elif inner_c == 'M':
push('[')
index += 1
elif inner_c == 'N':
push(']')
index += 1
elif inner_c == 'C':
push(':')
index += 1
elif inner_c == 'Z':
push('Z')
index += 1
else:
tmp = ''
while index < len(sym) and sym[index].isdigit():
tmp += sym[index]
index += 1
if not tmp:
return 0
arity = int(tmp)
if index >= len(sym):
return 0
inner_inner_c = sym[index]
if inner_inner_c == '\0':
return 0
elif inner_inner_c == 'T':
push('(')
if arity > 0:
for i in range(arity - 1):
push(',')
push(')')
index += 1
elif inner_inner_c == 'H':
push('(')
push('#')
if arity == 1:
push(' ')
else:
for i in range(arity - 1):
push(',')
push('#')
push(')')
index += 1
else:
return 0
elif c == 'z':
index += 1
if index >= len(sym):
return 0
inner_c = sym[index]
if inner_c == '\0':
return 0
elif inner_c == 'a':
push('&')
index += 1
elif inner_c == 'b':
push('|')
index += 1
elif inner_c == 'c':
push('^')
index += 1
elif inner_c == 'd':
push('$')
index += 1
elif inner_c == 'e':
push('=')
index += 1
elif inner_c == 'g':
push('>')
index += 1
elif inner_c == 'h':
push('#')
index += 1
elif inner_c == 'i':
push('.')
index += 1
elif inner_c == 'l':
push('<')
index += 1
elif inner_c == 'm':
push('-')
index += 1
elif inner_c == 'n':
push('!')
index += 1
elif inner_c == 'p':
push('+')
index += 1
elif inner_c == 'q':
push("'")
index += 1
elif inner_c == 'r':
push('\\')
index += 1
elif inner_c == 's':
push('/')
index += 1
elif inner_c == 't':
push('*')
index += 1
elif inner_c == 'u':
push('_')
index += 1
elif inner_c == 'v':
push('%')
index += 1
else:
tmp = ''
while index < len(sym) and sym[index] in '0123456789abcdefABCDEF':
tmp += sym[index]
index += 1
if not tmp or index >= len(sym) or sym[index] != 'U':
return 0
index += 1
codepoint = int(tmp, 16)
if codepoint > 255:
codepoint = '~'
push(chr(codepoint))
else:
push(c)
index += 1
return ''.join(out), count
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment