-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Debugger: Improve symbol search performance
Signed-off-by: iipeace <[email protected]>
- Loading branch information
Showing
1 changed file
with
166 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
__credits__ = "Peace Lee" | ||
__license__ = "GPLv2" | ||
__version__ = "3.9.8" | ||
__revision__ = "240519" | ||
__revision__ = "240520" | ||
__maintainer__ = "Peace Lee" | ||
__email__ = "[email protected]" | ||
__repository__ = "https://github.com/iipeace/guider" | ||
|
@@ -6654,7 +6654,7 @@ def isElfFile(path=None, fd=None): | |
ord("F"), | ||
) | ||
except IOError: | ||
SysMgr.printOpenErr(path) | ||
SysMgr.printOpenWarn(path) | ||
return False | ||
except SystemExit: | ||
sys.exit(0) | ||
|
@@ -62202,6 +62202,7 @@ def _doCommonJobs(pids, procList): | |
targetBpList.setdefault(pid, {}) | ||
targetBpFileList.setdefault(pid, {}) | ||
exceptBpFileList.setdefault(pid, {}) | ||
objectList.setdefault(pid, {}) | ||
|
||
# create object # | ||
procObj = Debugger(pid=pid, mode="break") | ||
|
@@ -62234,6 +62235,7 @@ def _doCommonJobs(pids, procList): | |
exceptBpFileList[pid] = UtilMgr.deepcopy( | ||
procObj.exceptBpFileList | ||
) | ||
objectList[pid] = UtilMgr.deepcopy(procObj.objectList) | ||
|
||
# create a lock for the multi-threaded process # | ||
if SysMgr.getTids(pid, sibling=True): | ||
|
@@ -62268,6 +62270,7 @@ def _doCommonJobs(pids, procList): | |
targetBpList = {} | ||
targetBpFileList = {} | ||
exceptBpFileList = {} | ||
objectList = {} | ||
|
||
# get argument # | ||
if tid: | ||
|
@@ -62563,6 +62566,8 @@ def _doCommonJobs(pids, procList): | |
targetBpFileList = targetBpFileList[ppid] | ||
if ppid in exceptBpFileList: | ||
exceptBpFileList = exceptBpFileList[ppid] | ||
if ppid in objectList: | ||
objectList = objectList[ppid] | ||
if ppid in lockList: | ||
lockObj = lockList[ppid] | ||
else: | ||
|
@@ -62584,6 +62589,7 @@ def _doCommonJobs(pids, procList): | |
targetBpList=targetBpList, | ||
targetBpFileList=targetBpFileList, | ||
exceptBpFileList=exceptBpFileList, | ||
objectList=objectList, | ||
) | ||
elif mode == "hook": | ||
Debugger.hookFunc(pid, SysMgr.customCmd) | ||
|
@@ -62748,20 +62754,23 @@ def _printRes(procInfo, resInfo, maxSymLen): | |
|
||
# load android JIT caches # | ||
try: | ||
if not SysMgr.isAndroid: | ||
raise Exception("not android") | ||
if SysMgr.isAndroid: | ||
# remove on-memory caches # | ||
ElfAnalyzer.cachedFiles = {} | ||
|
||
# remove on-memory caches # | ||
ElfAnalyzer.cachedFiles = {} | ||
|
||
# load android JIT symbols # | ||
dobj = Debugger(pid=pid, attach=False) | ||
dobj.updateProcMap(onlyExec=False) | ||
dobj.loadAndroidJITSymbols() | ||
|
||
if SysMgr.isAndroid: | ||
# load android JIT symbols # | ||
dobj.loadAndroidJITSymbols() | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
pass | ||
SysMgr.printErr("failed to analyze %s" % procInfo, True) | ||
continue | ||
|
||
# TODO: remove useless map info to improve search performance # | ||
|
||
for addr in addrList: | ||
ret = dobj.getSymbolInfo( | ||
|
@@ -63861,11 +63870,16 @@ def getProcAddrBySymbol(pid, symbolList, fileFilter=None, errExit=False): | |
if not FileAnalyzer.isValidFile(filePath, special=True): | ||
continue | ||
|
||
# check symbol strings # | ||
origFilePath = filePath.rsplit(SysMgr.magicStr, 1)[0] | ||
if UtilMgr.isElfFile( | ||
origFilePath | ||
) and not ElfAnalyzer.getObjectStr(origFilePath, symbolList): | ||
continue | ||
|
||
for sym in symbolList: | ||
# create an ELF object # | ||
try: | ||
origFilePath = filePath.rsplit(SysMgr.magicStr, 1)[0] | ||
|
||
res = ElfAnalyzer.getSymOffset(sym, origFilePath) | ||
if not res: | ||
continue | ||
|
@@ -83889,6 +83903,7 @@ def __init__(self, pid=None, execCmd=None, attach=True, mode=None): | |
self.targetBpList = {} | ||
self.targetBpFileList = {} | ||
self.exceptBpFileList = {} | ||
self.objectList = {} | ||
self.symbolCacheList = {} | ||
self.failedAddrList = {} | ||
self.ldInjected = False | ||
|
@@ -86902,8 +86917,17 @@ def loadAndroidJITSymbols(self): | |
# get JITDescriptor # | ||
decChar = "Q" if wordSize == 8 else "I" | ||
varAddr = list(addrInfo.values())[0][2] | ||
desc = self.readMem(long(varAddr, 16), (8 + wordSize * 2)) | ||
version, action, rel, head = struct.unpack("II" + (decChar * 2), desc) | ||
desc = self.readMem(long(varAddr, 16), (8 + wordSize * 2 + 32)) | ||
ret = struct.unpack( | ||
"II" + (decChar * 2) + "8B" + ("I" * 4) + "Q", desc | ||
) | ||
version, action, rel, head = ret[:4] | ||
magic = ret[4:12] | ||
flags, szdesc, szentry, seqlock, ts = ret[12:] | ||
|
||
# check timestamp # | ||
last = self.objectList.get("__jit_debug_descriptor", 0) | ||
self.objectList["__jit_debug_descriptor"] = ts | ||
|
||
# enable DWARF flag # | ||
origDwarfEnable = SysMgr.dwarfEnable | ||
|
@@ -86912,7 +86936,7 @@ def loadAndroidJITSymbols(self): | |
# get code entry # | ||
codeCnt = 0 | ||
codep = head | ||
while 1: | ||
while ts > last: | ||
# get JITCodeEntry # | ||
code = self.readMem(codep, (wordSize * 3) + 8) | ||
next_, prev_, sfaddr, sfsize = struct.unpack( | ||
|
@@ -86944,7 +86968,7 @@ def loadAndroidJITSymbols(self): | |
|
||
# merge symbols and DWARFs # | ||
for n, v in elfObj.attr.items(): | ||
if n in ("symTable", "dymsymTable"): | ||
if n in ("symTable", "dynsymTable"): | ||
symInfo = origElfObj.attr.get(n, {}) | ||
for sym, attrs in sorted( | ||
v.items(), key=lambda x: x[1]["value"] | ||
|
@@ -86984,6 +87008,9 @@ def loadAndroidJITSymbols(self): | |
# recover DWARF flag # | ||
SysMgr.dwarfEnable = origDwarfEnable | ||
|
||
# skip dex parsing # | ||
return | ||
|
||
# -------------------- __dex_debug_descriptor -------------------- # | ||
""" | ||
// Public/stable binary interface. | ||
|
@@ -87124,7 +87151,7 @@ def loadAndroidJITSymbols(self): | |
|
||
# merge symbols and DWARFs # | ||
for n, v in elfObj.attr.items(): | ||
if n in ("symTable", "dymsymTable"): | ||
if n in ("symTable", "dynsymTable"): | ||
for sym, attrs in sorted( | ||
v.items(), key=lambda x: x[1]["value"] | ||
): | ||
|
@@ -96537,9 +96564,25 @@ def _getOneItem(): | |
return [] | ||
|
||
# search symbols from all memory-mapped files # | ||
checkList = {} | ||
realSym = symbol.strip("* ") | ||
for mfile in list(self.pmap): | ||
mfile = mfile.split(SysMgr.magicStr)[0] | ||
|
||
if binary and not mfile in binary: | ||
continue | ||
elif mfile in checkList: | ||
continue | ||
elif ( | ||
realSym | ||
and not mfile in ElfAnalyzer.cachedFiles | ||
and UtilMgr.isElfFile(mfile) | ||
and not ElfAnalyzer.getObjectStr(mfile, symbol) | ||
): | ||
continue | ||
|
||
# save check list # | ||
checkList[mfile] = None | ||
|
||
# get ELF object # | ||
try: | ||
|
@@ -96867,6 +96910,7 @@ def restartTrace(self, initStatus=None): | |
dobj.targetBpList = self.targetBpList | ||
dobj.targetBpFileList = self.targetBpFileList | ||
dobj.exceptBpFileList = self.exceptBpFileList | ||
dobj.objectList = self.objectList | ||
|
||
# initialize variables # | ||
if dobj.mode == "break": | ||
|
@@ -97546,6 +97590,7 @@ def trace( | |
targetBpList={}, | ||
targetBpFileList={}, | ||
exceptBpFileList={}, | ||
objectList={}, | ||
initStatus=None, | ||
): | ||
# initialize variables # | ||
|
@@ -97558,6 +97603,8 @@ def trace( | |
self.targetBpFileList = targetBpFileList | ||
if not self.exceptBpFileList: | ||
self.exceptBpFileList = exceptBpFileList | ||
if not self.objectList: | ||
self.objectList = objectList | ||
|
||
# context variables # | ||
self.cmd = None | ||
|
@@ -102549,6 +102596,30 @@ def getFilterFlags(symbol): | |
|
||
return symbol, inc, start, end | ||
|
||
@staticmethod | ||
def getObjectStr(fpath, symbol): | ||
candSymList = {} | ||
try: | ||
if type(symbol) != list: | ||
symbol = [symbol] | ||
condSym = [s.strip("*") for s in symbol] | ||
|
||
# check real path # | ||
p = fpath.split(SysMgr.magicStr)[0] | ||
|
||
# get and check symbols # | ||
eobj = ElfAnalyzer(p, onlyStr=True) | ||
for s in eobj.strTable: | ||
if UtilMgr.isValidStr(s, condSym, inc=True): | ||
candSymList[s] = None | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
SysMgr.printWarn( | ||
"failed to get string table of '%s'" % fpath, reason=True | ||
) | ||
return candSymList | ||
|
||
@staticmethod | ||
def getSymOffset( | ||
symbol, binPath, objdumpPath=None, loadAddr=False, cache=False | ||
|
@@ -103332,6 +103403,7 @@ def __init__( | |
path=None, | ||
debug=False, | ||
onlyHdr=False, | ||
onlyStr=False, | ||
fd=None, | ||
size=sys.maxsize, | ||
incArg=False, | ||
|
@@ -103746,6 +103818,7 @@ def _printer(item): | |
self.attr = {} | ||
self.is32Bit = True | ||
self.saved = False | ||
self.strTable = {} | ||
self.sortedSymTable = [] | ||
self.sortedAddrTable = [] | ||
self.sortedLineTable = [] | ||
|
@@ -103961,18 +104034,28 @@ def _isValidSect(name): | |
% (debugPath, self.path) | ||
) | ||
|
||
dobj = ElfAnalyzer(debugPath, debug=debug, origPath=self.path) | ||
dobj = ElfAnalyzer( | ||
debugPath, | ||
debug=debug, | ||
onlyHdr=onlyHdr, | ||
onlyStr=onlyStr, | ||
origPath=self.path, | ||
) | ||
if dobj: | ||
# merge tables # | ||
dobj.mergeSymTable() | ||
self.addrTable.update(dobj.addrTable) | ||
dobj.addrTable.clear() | ||
self.attr["symTable"] = UtilMgr.deepcopy(dobj.attr["symTable"]) | ||
self.attr["dynsymTable"] = UtilMgr.deepcopy( | ||
dobj.attr["dynsymTable"] | ||
) | ||
if "dwarf" in dobj.attr: | ||
self.attr["dwarf"] = UtilMgr.deepcopy(dobj.attr["dwarf"]) | ||
del dobj | ||
self.strTable = UtilMgr.deepcopy(dobj.strTable) | ||
|
||
# copy tables # | ||
for tname in ("symTable", "dynsymTable", "dwarf"): | ||
if not tname in dobj.attr: | ||
continue | ||
self.attr[tname] = UtilMgr.deepcopy(dobj.attr[tname]) | ||
|
||
# remove object # | ||
del dobj | ||
|
||
# check file # | ||
if not os.path.exists(path): | ||
|
@@ -104746,6 +104829,54 @@ def _printStrSect(sh_name, strtab): | |
if onlyHdr: | ||
return None | ||
|
||
# return only string table # | ||
if onlyStr: | ||
for x in (e_shstrndx, e_shdynstr, e_shdbgstr): | ||
if x < 0: | ||
continue | ||
|
||
# section info # | ||
( | ||
sh_name, | ||
sh_type, | ||
sh_flags, | ||
sh_addr, | ||
sh_offset, | ||
sh_size, | ||
sh_link, | ||
sh_info, | ||
sh_addralign, | ||
sh_entsize, | ||
) = self.getSectionInfo(fd, e_shoff + e_shentsize * x) | ||
|
||
# read str data # | ||
fd.seek(sh_offset) | ||
strtable = fd.read(sh_size) | ||
try: | ||
strtable_decoded = strtable.decode() | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
strtable_decoded = strtable | ||
|
||
lastnull = 0 | ||
symTable = {} | ||
for i, s in enumerate(strtable_decoded): | ||
if s != "\0": | ||
continue | ||
try: | ||
sd = strtable[lastnull:i].decode() | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
sd = strtable[lastnull:i] | ||
lastnull = i + 1 | ||
|
||
sd = ElfAnalyzer.demangleSymbol(sd) | ||
self.strTable[sd] = None | ||
|
||
return None | ||
|
||
# define versym info # | ||
self.attr["versymList"] = [] | ||
|
||
|
@@ -104813,16 +104944,15 @@ def _printStrSect(sh_name, strtab): | |
lastnull = 0 | ||
dynsymTable = {} | ||
for i, s in enumerate(dynstr_section_decoded): | ||
if s == "\0": | ||
try: | ||
dynsymTable[lastnull] = dynstr_section[ | ||
lastnull:i | ||
].decode() | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
dynsymTable[lastnull] = dynstr_section[lastnull:i] | ||
lastnull = i + 1 | ||
if s != "\0": | ||
continue | ||
try: | ||
dynsymTable[lastnull] = dynstr_section[lastnull:i].decode() | ||
except SystemExit: | ||
sys.exit(0) | ||
except: | ||
dynsymTable[lastnull] = dynstr_section[lastnull:i] | ||
lastnull = i + 1 | ||
|
||
# parse .gnu.version_d table # | ||
if e_shverdef >= 0: | ||
|
@@ -105115,7 +105245,7 @@ def _printStrSect(sh_name, strtab): | |
and self.attr["sectionHeader"][".symtab"]["type"] != "NOBITS" | ||
and self.attr["sectionHeader"][".strtab"]["type"] != "NOBITS" | ||
): | ||
# get .symtab section info # | ||
# get .strtab section info # | ||
( | ||
sh_name, | ||
sh_type, | ||
|