From b908331a49524c38290a60dffade78129363a775 Mon Sep 17 00:00:00 2001 From: iipeace Date: Thu, 11 Jul 2024 23:17:48 +0900 Subject: [PATCH] demangle: Add demangle command Signed-off-by: iipeace --- guider/guider.py | 148 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 40 deletions(-) diff --git a/guider/guider.py b/guider/guider.py index 3272d089..27172ef2 100755 --- a/guider/guider.py +++ b/guider/guider.py @@ -7,7 +7,7 @@ __credits__ = "Peace Lee" __license__ = "GPLv2" __version__ = "3.9.8" -__revision__ = "240710" +__revision__ = "240711" __maintainer__ = "Peace Lee" __email__ = "iipeace5@gmail.com" __repository__ = "https://github.com/iipeace/guider" @@ -36770,6 +36770,7 @@ def getCmdList(): "checkdup": ("Page", "Linux"), "comp": ("Compress", "Linux/MacOS/Windows"), "decomp": ("Decompress", "Linux/MacOS/Windows"), + "demangle": ("Demangling", "Linux/MacOS/Windows"), "dirdiff": ("Dir", "Linux/MacOS/Windows"), "dump": ("Memory", "Linux"), "exec": ("Command", "Linux/MacOS/Windows"), @@ -38502,6 +38503,13 @@ def printHelp(force=False, isExit=True): cmd, mode ) + defUsage6 = """ +Usage: + # {0:1} {1:1} [OPTIONS] [--help] + """.format( + cmd, mode + ) + # description formatter # def _getDesc(s, t=0): usages = [ @@ -38511,6 +38519,7 @@ def _getDesc(s, t=0): defUsage3, defUsage4, defUsage5, + defUsage6, ] return "%s\nDescription:\n %s\n" % (usages[t], s) @@ -40300,6 +40309,9 @@ def _getDesc(s, t=0): - {2:1} of specific processes having cmdline path including specific keywords # {0:1} {1:1} a.out -q TARGETCMD # {0:1} {1:1} "*chrome, *test*" -q TARGETCMD + + - {2:1} from stdin + # echo a.out | {0:1} {1:1} """.format( cmd, mode, @@ -41282,13 +41294,13 @@ def _getDesc(s, t=0): # {0:1} {1:1} -g a.out -q RMRECOPT:"--no-dump-kernel-symbols", RMREPOPT:"-f" - {2:1} and report to the specific output file with task filter - # {0:1} {1:1} -g a.out -q TASKFILTER:"*task" + # {0:1} {1:1} -q TASKFILTER:"*task" - {2:1} and report to per-task output files - # {0:1} {1:1} -g a.out -q EACHFILE + # {0:1} {1:1} -q EACHFILE - {2:1} and report the flame graph to a specific file - # {0:1} {1:1} -g a.out -q DRAWFLAME + # {0:1} {1:1} -q DRAWFLAME - Report from perf data # {0:1} {1:1} -I perf.data @@ -43520,6 +43532,33 @@ def _getDesc(s, t=0): cmd, mode, "Print systemd files" ) + # demangle # + elif SysMgr.checkMode("demangle"): + helpStr = ( + _getDesc("Demangle symbols", t=6) + + """ +Options: + -v verbose + -J print in JSON format + -q set environment variables + """ + ) + + helpStr += """ +Examples: + - {2:1} + # {0:1} {1:1} {3:1} + # {0:1} {1:1} "{3:1}|_ZL15__pthread_startPv" + + - {2:1} from stdin + # echo {3:1} | {0:1} {1:1} + """.format( + cmd, + mode, + "Demangle symbols", + "_ZN3art6Thread14CreateCallbackEPv", + ) + # printinfo # elif SysMgr.checkMode("printinfo"): helpStr = ( @@ -54914,6 +54953,10 @@ def _printJson(path, obj): elif SysMgr.checkMode("printinfo"): SysMgr.doPrintInfo() + # DEMANGLE MODE # + elif SysMgr.checkMode("demangle"): + SysMgr.doDemangle() + # SETAFFINITY MODE # elif SysMgr.checkMode("setafnt"): SysMgr.doSetAffinity() @@ -56428,6 +56471,7 @@ def doSimplePerfRec(): def convSimplePerfSample(path, scripts=[]): # open file # try: + realpath = os.path.realpath(path) if path else "INPUT" compressed = False if scripts: fd = None @@ -56437,10 +56481,24 @@ def convSimplePerfSample(path, scripts=[]): compressed = True else: fd = open(path) + + # get scripts # + try: + if compressed: + scripts = fd.read().decode().split("\n") + else: + scripts = fd.readlines() + except SystemExit: + sys.exit(0) + except: + SysMgr.printErr( + "failed to read samples from '%s'" % realpath, True + ) + return except SystemExit: sys.exit(0) except: - SysMgr.printErr("failed to '%s'", os.path.realpath(path), True) + SysMgr.printErr("failed to read '%s'" % realpath, True) return # init variables # @@ -56462,19 +56520,6 @@ def _getSym(call): symbol = "0x" + symbol.rsplit("[+", 1)[1].rstrip("]") return symbol - # get scripts # - if not scripts: - try: - if compressed: - scripts = fd.read().decode().split("\n") - else: - scripts = fd.readlines() - except SystemExit: - sys.exit(0) - except: - SysMgr.printErr("failed to read samples", True) - return - # get filter variables # eachFile = "EACHFILE" in SysMgr.environList onlyUser = "ONLYUSER" in SysMgr.environList @@ -56675,7 +56720,14 @@ def _getSym(call): # print task stats # taskStatStr = ", ".join( [ - "%s(%s): %s" % (v["comm"], tid, convNum(v["nrSample"])) + "%s(%s): %s" + % ( + v["comm"] + if v["comm"] != "unknown" + else SysMgr.getComm(tid), + tid, + convNum(v["nrSample"]), + ) for tid, v in sorted( taskList.items(), key=lambda x: x[1]["nrSample"], @@ -56701,13 +56753,11 @@ def _getSym(call): # draw flame graph # if "DRAWFLAME" in SysMgr.environList: - try: - # sync report file # - SysMgr.printFd.flush() - except SystemExit: - sys.exit(0) - except: - pass + # remove task filter # + SysMgr.filterGroup = [] + + # sync report file # + SysMgr.closeAllForPrint() # set output name # outFile = UtilMgr.getDrawOutputPath(SysMgr.outPath, "flamegraph") @@ -56715,7 +56765,7 @@ def _getSym(call): # draw flame graph # Debugger.drawFlame( inputFile=SysMgr.outPath, - outFile=UtilMgr.rstrip(outFile, ".gz"), + outFile=outFile, forceOutFile=True, ) @@ -62258,6 +62308,26 @@ def doPrintNs(): sys.exit(0) + @staticmethod + def doDemangle(): + # get keyword # + if SysMgr.hasMainArg(): + targetList = SysMgr.getMainArgs(False, "|") + elif SysMgr.filterGroup: + targetList = ",".join(SysMgr.filterGroup) + else: + targetList = [] + + if not targetList: + # check stdin pipe # + buf = sys.stdin.readline() + if buf: + targetList = UtilMgr.cleanItem(buf.split("|"), False) + + for symbol in targetList: + symbol = ElfAnalyzer.demangleSymbol(symbol) + SysMgr.printPipe(symbol) + @staticmethod def doPrintInfo(): SysMgr.printLogo(big=True, onlyFile=True) @@ -62283,7 +62353,7 @@ def doPrintInfo(): @staticmethod def isSilentCmd(): - if SysMgr.checkMode("getpid"): + if SysMgr.checkMode(["getpid", "demangle"]): return True else: return False @@ -93098,7 +93168,7 @@ def _loadSamples(fname, nrSamples, nrFiles): sysinfo = SysMgr.sysinfoBuffer.split("\n") for s in sysinfo: try: - if not s: + if not s or s in (twoLine): continue # add task info # @@ -101210,10 +101280,7 @@ def _printSystemStat(): pass # check mode # - if instance.isRealtime: - mtype = "Top" - else: - mtype = "Trace" + mtype = "Top" if instance.isRealtime else "Trace" suffix = "\n" # update suffix of output file name # @@ -101230,13 +101297,16 @@ def _printSystemStat(): # print System Info # _printSystemStat() - SysMgr.printInfo( - "start analyzing %ss of %s(%s)..." - % (ctype, instance.comm, instance.pid) - ) - nrTotal = float(len(instance.callList)) + convert = UtilMgr.convNum + if instance.pid == 0: + procInfo = "%s samples" % convert(nrTotal) + else: + procInfo = "%s(%s)" % (instance.comm, instance.pid) + + SysMgr.printInfo("start analyzing %ss of %s..." % (ctype, procInfo)) + # check incomplete break mode # if not Debugger.envFlags["COMPLETECALL"] and instance.mode == "break": isIncompleteBreakMode = True @@ -101291,7 +101361,6 @@ def _printSystemStat(): UtilMgr.deleteProgress() # print call table # - convert = UtilMgr.convNum try: elapsed = instance.callList[-1][1] - instance.start except: @@ -101315,7 +101384,6 @@ def _printSystemStat(): freqStr = "" # set task info # - procInfo = "%s(%s)" % (instance.comm, instance.pid) mprocInfo = "%s(%s)" % ( Debugger.tracerInstance.comm, Debugger.tracerInstance.pid,