From a502cd93b13235b7539557a91328de00b7c51bc3 Mon Sep 17 00:00:00 2001 From: Peace Lee Date: Fri, 26 Mar 2021 16:33:47 +0900 Subject: [PATCH] ElfAnalyzer: Support DWARF v4 Signed-off-by: Peace Lee --- guider/guider.py | 145 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 45 deletions(-) diff --git a/guider/guider.py b/guider/guider.py index 79b3585c..494dfd74 100755 --- a/guider/guider.py +++ b/guider/guider.py @@ -7,7 +7,7 @@ __credits__ = "Peace Lee" __license__ = "GPLv2" __version__ = "3.9.8" -__revision__ = "210324" +__revision__ = "210326" __maintainer__ = "Peace Lee" __email__ = "iipeace5@gmail.com" __repository__ = "https://github.com/iipeace/guider" @@ -3588,9 +3588,24 @@ def convHtmlChar(string): @staticmethod - def printTime(): - diff = time.time() - UtilMgr.curTime - print('\n[Elapsed: %f]' % diff) + def printTime(name=None, update=False): + # get current time # + now = time.time() + diff = now - UtilMgr.curTime + + # update timestamp # + if update: + UtilMgr.current = now + + # add name # + if name: + prefix = '[%s]' % name + else: + prefix = '' + + # print time diff # + string = '\n%s[Elapsed: %f]' % (prefix, diff) + print(UtilMgr.convColor(string, 'RED')) @@ -19249,6 +19264,9 @@ def printHelp(force=False): - Print all call contexts except for wait status for a specific thread # {0:1} {1:1} a.out -g a.out -q EXCEPTWAIT + - Print all call contexts except for register info for a specific thread + # {0:1} {1:1} a.out -g a.out -q NOCONTEXT + - Print all call contexts for a specific thread after loading all symbols in stop status # {0:1} {1:1} a.out -g a.out -q STOPTARGET @@ -20013,6 +20031,9 @@ def printHelp(force=False): - Monitor function calls except for wait status for a specific thread # {0:1} {1:1} a.out -g a.out -q EXCEPTWAIT + - Monitor function calls except for register info for a specific thread + # {0:1} {1:1} a.out -g a.out -q NOCONTEXT + - Monitor function calls except for no symbol functions for a specific thread # {0:1} {1:1} a.out -g a.out -q EXCEPTNOSYM @@ -44718,6 +44739,7 @@ def __init__(self, pid=None, execCmd=None, attach=True, mode=None): self.status = 'enter' self.traceStatus = False self.runStatus = False + self.sampleStatus = True self.attached = attach self.execCmd = execCmd self.arch = arch = SysMgr.getArch() @@ -48781,7 +48803,8 @@ def makeSvgString(callTree, callCnt): palette = Timeline.Config().PALETTE def _iterNode(array, target, callCnt, depth=0, pos=0, height=36): - for node, value in target.items(): + for node, value in sorted(target.items(), + key=lambda x:x[1]['cnt'], reverse=True): # get stats # totalCnt = callCnt[0] cnt = value['cnt'] @@ -49090,12 +49113,16 @@ def _finishPrint(): # check samples # if not self.callTable: - SysMgr.printWarn( - "no sample data for %s(%s)" % \ - (self.comm, self.pid), True) + if not self.sampleStatus: + SysMgr.printWarn( + "no sample data for %s(%s)" % \ + (self.comm, self.pid), True) _resetStats() return + # update status for sample collection # + self.sampleStatus = True + # check user input # SysMgr.waitUserInput( wait=0.000001, msg="press enter key...") @@ -49350,7 +49377,7 @@ def clearArgs(self): - def getAnonVrangeByOffset(self, offset, fname=None): + def getAnonRangeByOffset(self, offset, fname=None): if not fname in self.pmap: return @@ -49378,7 +49405,7 @@ def getAnonVrangeByOffset(self, offset, fname=None): - def getVrangeBySymbol(self, symbol, fname=None): + def getRangeBySym(self, symbol, fname=None): if not fname in self.pmap: return @@ -49568,10 +49595,10 @@ def getSymbolInfo(self, vaddr, onlyFunc=True, onlyExec=True): self.needMapScan = True # print error message and return # - procInfo = '%s(%s)' % (self.comm, self.pid) SysMgr.printWarn( - 'fail to get file name via addr %s for %s' % \ - (hex(vaddr).rstrip('L'), procInfo)) + 'fail to get symbol via %s for %s(%s)' % \ + (hex(vaddr).rstrip('L'), self.comm, self.pid)) + return None # get real offset for memory hole # @@ -49592,12 +49619,11 @@ def getSymbolInfo(self, vaddr, onlyFunc=True, onlyExec=True): self.needMapScan = True # print error message and return # - procInfo = '%s(%s)' % (self.comm, self.pid) - SysMgr.printWarn(( - 'fail to get offset in %s via %s for %s ' - 'because of wrong memory map') % \ - (fname, hex(vaddr).rstrip('L'), procInfo)) - return ['??', fname, '??', '??', '??', '??'] + SysMgr.printWarn( + 'fail to get symbol via %s for %s(%s)' % \ + (hex(vaddr).rstrip('L'), self.comm, self.pid)) + + return None # remove suffix in file name # fname = fname.rsplit(SysMgr.magicStr, 1)[0] @@ -49623,10 +49649,12 @@ def getSymbolInfo(self, vaddr, onlyFunc=True, onlyExec=True): sys.exit(0) except: SysMgr.printWarn( - 'fail to get symbol from %s for %s(%s)' % \ + 'fail to get symbol via %s for %s(%s)' % \ (hex(offset).rstrip('L'), self.comm, self.pid), reason=True) - return ['??', fname, '??', '??', '??', '??'] + + # return # + return [hex(offset).rstrip('L'), fname, '??', '??', '??', '??'] @@ -49678,10 +49706,13 @@ def printContext( self, regs=True, bt=True, sig=True, deref=True, args=None, newline=False): + # check skip condition # if not regs and not bt: return elif not SysMgr.printEnable: return + elif 'NOCONTEXT' in SysMgr.environList: + return if newline: prefix = '\n' @@ -50028,13 +50059,19 @@ def getBacktraceStr(self, bt, default=20, maximum=0, force=False): indentStr = ' ' * default for item in bt: + if item[1] == item[2] == '??': + sym = hex(item[0]).rstrip('L') + else: + sym = item[1] + fname = item[2] + # remove redundant symbols # - if prevSym == item[1] and prevFile == item[2]: + if prevSym == sym and prevFile == fname: cnt += 1 continue else: - prevSym = item[1] - prevFile = item[2] + prevSym = sym + prevFile = fname # check redundant symbols # if cnt > 0: @@ -50044,7 +50081,7 @@ def getBacktraceStr(self, bt, default=20, maximum=0, force=False): cntStr = '' # build a new string # - newStr = ' <- %s[%s]%s' % (item[1], item[2], cntStr) + newStr = ' <- %s[%s]%s' % (sym, fname, cntStr) if btStr and len(newStr) + pos > maximum: newStr = '\n%s%s' % (indentStr, newStr) pos = len(newStr) - 1 @@ -51323,10 +51360,12 @@ def handleUsercall(self, update=True): # print unknown call address # if fname == '??': + sym = hex(self.pc).rstrip('L') + if self.isRealtime: - self.addSample('??', fname, realtime=True, bt=backtrace) + self.addSample(sym, fname, realtime=True, bt=backtrace) elif SysMgr.outPath: - self.addSample('??', fname, bt=backtrace) + self.addSample(sym, fname, bt=backtrace) return # check contiguous unknown symbol # @@ -51351,10 +51390,10 @@ def handleUsercall(self, update=True): try: # symbol range # if sym != '??': - vstart, vend = self.getVrangeBySymbol(sym, fname) + vstart, vend = self.getRangeBySym(sym, fname) # anon range # else: - vstart, vend = self.getAnonVrangeByOffset(offset, fname) + vstart, vend = self.getAnonRangeByOffset(offset, fname) except SystemExit: sys.exit(0) except: @@ -52277,6 +52316,7 @@ def initValues(self): self.comm = SysMgr.getComm(self.pid, cache=True) self.exe = SysMgr.getExeName(self.pid) self.start = self.last = time.time() + self.sampleStatus = True self.statFd = None self.kernelFd = None self.prevStat = None @@ -52698,28 +52738,30 @@ def runEventLoop(self): self.ptraceEvent(self.traceEventList) self.ptrace(self.cmd) - # KILL / SEGV signal # + # KILL / SEGV / ABRT signal # elif SysMgr.isTermSignal(stat): + # print status # + SysMgr.printErr( + 'detected %s for %s(%s)' % \ + (ConfigMgr.SIG_LIST[stat], self.comm, self.pid)) + # print context info # - self.printContext(newline=True) + if SysMgr.showAll: + self.printContext(newline=True) - SysMgr.printErr( - 'terminated %s(%s) because of %s' % \ - (self.comm, self.pid, ConfigMgr.SIG_LIST[stat])) + # deliver signal # + if self.cont(check=True, sig=stat) < 0: + sys.exit(0) # set fault flag to shared memory # self.setFaultFlag() - if SysMgr.isTopMode(): - SysMgr.waitEvent() - - sys.exit(0) - # exit # elif stat == -1: if self.status == 'exit': SysMgr.printPipe(' ') + # print status # SysMgr.printErr( 'terminated %s(%s)' % (self.comm, self.pid)) @@ -52762,7 +52804,7 @@ def runEventLoop(self): 'detected %s(%s) with error' % \ (self.comm, self.pid), reason=True) - # continue target # + # deliver signal # if self.mode == 'break': if self.cont(check=True) < 0: sys.exit(0) @@ -58986,10 +59028,14 @@ def _convRegName(arg, regList): else: ehdata = fd.read(8) + # size for address and segment in DWARF v4 # if ver >= 4: - # address size (uint8) is added in DWARF v4 # - # segment size (uint8) is added in DWARF v4 # - pass + addrSize = struct.unpack('B', table[pos:pos+1])[0] + pos += 1 + segmentSize = struct.unpack('B', table[pos:pos+1])[0] + pos += 1 + else: + addrSize = segmentSize = -1 # Call Alignment Factor # data = table[pos:].decode('latin-1') @@ -59033,6 +59079,8 @@ def _convRegName(arg, regList): 'length': size, 'id': cid, 'version': ver, + 'addrsize': addrSize, + 'segmentsize': segmentSize, 'caf': caf, 'daf': daf, 'rar': rar, @@ -59051,14 +59099,21 @@ def _convRegName(arg, regList): (offset, size, cid) printStr += ' %-22s %s\n' % ('Version:', ver) printStr += ' %-22s "%s"\n' % ('Augmentation:', augstr) + if addrSize >= 0: + printStr += ' %-22s %s\n' % \ + ('Pointer Size:', addrSize) + if segmentSize >= 0: + printStr += ' %-22s %s\n' % \ + ('Segment Size:', segmentSize) printStr += ' %-22s %x\n' % \ ('Code alignment factor:', caf) printStr += ' %-22s %x\n' % \ ('Data alignment factor:', daf) printStr += ' %-22s %d\n' % \ ('Return address column:', rar) - printStr += ' %-22s %s\n\n' % \ - ('Augmentation data: ', augdatastr) + if augdatastr: + printStr += ' %-22s %s\n\n' % \ + ('Augmentation data: ', augdatastr) SysMgr.printPipe(printStr) #-------------------- FDE --------------------#