; -------------------------------------------------------------------------------- ; @Title: Ramdump generation script for NuttX ; @Description: ; This is a generic awareness script specially adapted for NuttX . ; You can use this script to generate a OS ramdump of the debug/trace ; scenario. ; ; The resulting scripts can be used to restore the scenario in the TRACE32 ; instruction set simulator. ; ; Usage: ; - Interactive: ; DO /ramdump.cmm ; Edit the settings in the dialog and then hit "STORE". ; - Script based: ; DO /ramdump.cmm \ ; MEM="" \ ; SYMBOLFILE="" \ ; TRACESAVE=<0|1> \ ; STOREFORMAT=<0|1> ; ; Example: ; - Interactive: ; DO ramdump.cmm ; - Script based: store 0x0--0xffff & 0x20000000++0xfff ; DO ramdump.cmm MEM="AD:0x0--0xffff,AD:0x20000000++0xfff" ; ; Parameters: ; - MEM="" ; comma separated list of absolute memory ranges ; AD:--,AD:..,AD:++ ; - SYMBOLFILE="" ; path to the used symbolfile ; - TRACESAVE=<0|1> ; enable/disable storage of the off-/onchip trace, default: 0 ; - STOREFORMAT=<0|1> ; 0: binary (zipped), 1: SRecord (robust against busfaults), default: 0 ; ; @Keywords: RAMDump ; @Author: AME ; @Copyright: (C) 1989-2023 Lauterbach GmbH, licensed for use with TRACE32(R) only ; -------------------------------------------------------------------------------- ; $Id: ramdump.cm 9324 2023-08-03 06:49:05Z amerkle $ PRIVATE &sArguments PRIVATE &bDialog &sMemoryRanges &sSymbolFile &bTraceSave &nStoreFormat ENTRY %LINE &sArguments GOSUB checkSanity GOSUB parseArguments "&sArguments" RETURNVALUES &bDialog &sMemoryRanges &sSymbolFile &bTraceSave &nStoreFormat IF (&bDialog) ( GOSUB showDialog ENDDO ) PRIVATE &nTime &i &sRestoreCmm &sRange &sTmp &sFilename &sFilename2 &sProgressText ; check arguments - function does only return on success GOSUB checkArguments "&sMemoryRanges" "&nStoreFormat" ; the real magic starts here &nTime=DATE.UnixTime() SPRINTF &sRestoreCmm "./restore_%u.cmm" &nTime IF OS.FILE("&sRestoreCmm") DEL "&sRestoreCmm" SPRINTF &sProgressText "Step: deployments will be saved to %s, %u_*" "&sRestoreCmm" &nTime GOSUB progress "&sProgressText" &sTmp=OS.PPF() SPRINTF &sTmp "; Created by %s %s - %s" "NuttX" OS.FILE.NAME("&sTmp") "$Id: ramdump.cm 9324 2023-08-03 06:49:05Z amerkle $" APPEND "&sRestoreCmm" "&sTmp" SPRINTF &sTmp "; %s on %s" DATE.DATE() OS.NAME() APPEND "&sRestoreCmm" "&sTmp" APPEND "&sRestoreCmm" "" APPEND "&sRestoreCmm" "IF !SIMULATOR()" APPEND "&sRestoreCmm" "(" APPEND "&sRestoreCmm" " PRINT %ERROR ""Please execute this script in a TRACE32 Simulator!""" APPEND "&sRestoreCmm" " ENDDO" APPEND "&sRestoreCmm" ")" APPEND "&sRestoreCmm" "" APPEND "&sRestoreCmm" "RESet" APPEND "&sRestoreCmm" "SYStem.RESet" APPEND "&sRestoreCmm" "SYStem.CPU " CPU() IF PRACTICE.FUNCtion.AVAILable(SYStem.Option.MMUSPACES) ( IF SYStem.Option.MMUSPACES() APPEND "&sRestoreCmm" "SYStem.Option MMUSPACES ON" ) IF PRACTICE.FUNCtion.AVAILable(SYStem.Option.ZONESPACES) ( IF SYStem.Option.ZONESPACES() APPEND "&sRestoreCmm" "SYStem.Option ZONESPACES ON" ) IF PRACTICE.FUNCtion.AVAILable(SYStem.Option.MACHINESPACES) ( IF SYStem.Option.MACHINESPACES() APPEND "&sRestoreCmm" "SYStem.Option MACHINESPACES ON" ) IF CONFIGNUMBER()>1. ( GOSUB getCoreAssignment RETURNVALUES &sTmp APPEND "&sRestoreCmm" "CORE.ASSIGN &sTmp" ) APPEND "&sRestoreCmm" "SYStem.Up" APPEND "&sRestoreCmm" "" GOSUB progress "Step: flush caches" GOSUB cacheClean IF CORE.NUMBER()>1. CORE.select 0. APPEND "&sRestoreCmm" "; Restore memory contents" &i=0. &sRange=STRing.TOKEN("&sMemoryRanges",",;",&i) WHILE ("&sRange"!="") ( IF (STRing.ComPare(STRing.LoWeR("&sRange"),"")&&(sYmbol.List.SECtion.COUNT()!=0.)) ( PRIVATE &j SPRINTF &sProgressText "Step: save memory ranges based on Section Table" GOSUB progress "&sProgressText" &j=1. RePeaT sYmbol.List.SECtion.COUNT() ( IF (sYmbol.List.SECtion.SIZE(&j)>0.) ( SPRINTF &sRange "%#!A++0x%X" sYmbol.List.SECtion.BEGIN(&j) sYmbol.List.SECtion.SIZE(&j)-1. SPRINTF &sProgressText "Step: save section %s memory range %s" STRing.SPLIT(sYmbol.List.SECtion.PATH(&j),"\",-1.) "&sRange" GOSUB progress "&sProgressText" GOSUB storeMemoryRange "&sRestoreCmm" "&nTime" "&nStoreFormat" "&sRange" ) &j=&j+1. ) ) ELSE ( SPRINTF &sProgressText "Step: save memory range %s" "&sRange" GOSUB progress "&sProgressText" GOSUB storeMemoryRange "&sRestoreCmm" "&nTime" "&nStoreFormat" "&sRange" ) &i=&i+1. &sRange=STRing.TOKEN("&sMemoryRanges",",;",&i) ) APPEND "&sRestoreCmm" "" APPEND "&sRestoreCmm" "; Restore registers per logical core" &i=0. RePeaT CORE.NUMBER() ( PRIVATE &sPerfile &sTree &sCoreText IF CORE.NUMBER()>1. ( CORE.select &i APPEND "&sRestoreCmm" "CORE.select &i" SPRINTF &sCoreText "Core %2u/%-2u: " &i CORE.NUMBER()-1. ) SPRINTF &sProgressText "Step: %sstore GPRs" "&sCoreText" GOSUB progress "&sProgressText" SPRINTF &sFilename "%u_reg_core%u.cmm" &nTime &i STOre "./&(sFilename)" Register APPEND "&sRestoreCmm" "DO ~~~~/&(sFilename)" GOSUB getCorePerfilePath RETURNVALUES &sPerfile &sTree IF "&sPerfile"!="" ( PRIVATE &sPerFilterList &sPerFilterList="*" IF CPU.FEATURE(C15)||CPU.FEATURE(SPR) ( ; -A/-R profile ; switch to highest required PL and store PRIVATE &nRegM &sMode &nRegM=Register(M) IF !CPU.FEATURE(SPR) ( ; AARCH32 IF SYStem.Option.ZONESPACES() ( Register.Set M 0x16 // mon SPRINTF &sTmp "Register.Set M %#x /CORE %u" 0x16 &i APPEND "&sRestoreCmm" "&sTmp" ) ELSE IF SYStem.Option.MACHINESPACES() ( Register.Set M 0x1a // hyp SPRINTF &sTmp "Register.Set M %#x /CORE %u" 0x1a &i APPEND "&sRestoreCmm" "&sTmp" ) ) ELSE ( ; AARCH64 PRIVATE &nHighestEl &nEl &nHighestEl=&nRegM &nEl=&nRegM IF CPU.FEATURE(NONSECURE)&&CPU.FEATURE(SECURE) &nHighestEl=0xD // EL3 ELSE IF CPU.FEATURE(HYPERVISOR) &nHighestEl=0x9 // EL2 IF SYStem.Option.ZONESPACES() &nEl=0xD // EL3 ELSE IF SYStem.Option.MACHINESPACES()||(ARMARCHVERSION()>=0x81) &nEl=0x9 // EL2 IF (&nEl>&nHighestEl) &nEl=&nHighestEl Register.Set M &nEl SPRINTF &sTmp "Register.Set M %#x /CORE %u" &nEl &i APPEND "&sRestoreCmm" "&sTmp" ) GOSUB getModeString "Register(M)" RETURNVALUES &sMode GOSUB getPerFilter "Register(M)" "FALSE()" RETURNVALUES &sPerFilterList SPRINTF &sProgressText "Step: %sstore SPR/C15 registers, Mode %s" "&sCoreText" "&sMode" GOSUB progress "&sProgressText" SPRINTF &sFilename2 "%u_spr_core%u_%s.orig.cmm" &nTime &i "&sMode" SPRINTF &sFilename "%u_spr_core%u_%s.cmm" &nTime &i "&sMode" IF (CPU.FEATURE(C15)&&CPU.FEATURE(SPR)) ( IF ((Register(M)&0x10)==0) PER.STOre "./&(sFilename2)" "&(sPerfile)" "AArch64" /CORE &i ELSE PER.STOre "./&(sFilename2)" "&(sPerfile)" "AArch32" /CORE &i ) ELSE ( PER.STOre "./&(sFilename2)" "&(sPerfile)" /CORE &i ) GOSUB perStoreFilter "&sFilename2" "&sFilename" "&sPerFilterList" APPEND "&sRestoreCmm" "DO ~~~~/&(sFilename)" Register.Set M &nRegM /CORE &i SPRINTF &sTmp "Register.Set M %#x /CORE %u" &nRegM &i APPEND "&sRestoreCmm" "&sTmp" ; in current EL store AArch registers again GOSUB getModeString "Register(M)" RETURNVALUES &sMode GOSUB getPerFilter "Register(M)" "TRUE()" RETURNVALUES &sPerFilterList SPRINTF &sProgressText "Step: %sstore SPR/C15 registers, Mode %s" "&sCoreText" "&sMode" GOSUB progress "&sProgressText" SPRINTF &sFilename2 "%u_spr_core%u_%s.orig.cmm" &nTime &i "current" SPRINTF &sFilename "%u_spr_core%u_%s.cmm" &nTime &i "current" ) ELSE ( ; -M profile SPRINTF &sProgressText "Step: %sstore PPB registers, Mode %s" "&sCoreText" "&sMode" GOSUB progress "&sProgressText" SPRINTF &sFilename2 "%u_ppb_core%u_%s.orig.cmm" &nTime &i "current" SPRINTF &sFilename "%u_ppb_core%u_%s.cmm" &nTime &i "current" ) IF (CPU.FEATURE(C15)&&CPU.FEATURE(SPR)) ( IF (Register(M)&0x10)==0 PER.STOre "./&(sFilename2)" "&(sPerfile)" "AArch64" /CORE &i ELSE PER.STOre "./&(sFilename2)" "&(sPerfile)" "AArch32" /CORE &i ) ELSE ( PER.STOre "./&(sFilename2)" "&(sPerfile)" /CORE &i ) GOSUB perStoreFilter "&sFilename2" "&sFilename" "&sPerFilterList" APPEND "&sRestoreCmm" "DO ~~~~/&(sFilename)" SPRINTF &sFilename "%u_reg_core%u.cmm" &nTime &i APPEND "&sRestoreCmm" "DO ~~~~/&(sFilename)" ) ELSE ( PRIVATE &sText SPRINTF &sText "Error: No core-perfile detected for CPU=%s. Please contact support@lauterbach.com ." CPU() GOSUB progress "&sText" ) APPEND "&sRestoreCmm" "" &i=&i+1. ) IF CORE.NUMBER()>1. ( CORE.select 0. APPEND "&sRestoreCmm" "CORE.select 0." APPEND "&sRestoreCmm" "" ) IF CORE.NUMBER()>1. CORE.select 0. IF PRACTICE.FUNCtion.AVAILable(SYStem.Option.MACHINESPACES) ( IF SYStem.Option.MACHINESPACES() ( APPEND "&sRestoreCmm" "; Storing of iAMP/Hypervisor environments is not yet supported." APPEND "&sRestoreCmm" "; The stored MMU.<>, TRANSlation.<>, TASK.<> commands will be incomplete and/or misleading!" APPEND "&sRestoreCmm" "; Sorry for the inconvenience." ) ) IF ("&sSymbolFile"!="") ( GOSUB progress "Step: handle sYmbol files" PRIVATE &sFormat &sParameters GOSUB getDataLoadParameters "&sSymbolFile" RETURNVALUES &sFormat &sParameters APPEND "&sRestoreCmm" "Data.LOAD.&(sFormat) ""&(sSymbolFile)"" &(sParameters) /NoCODE" APPEND "&sRestoreCmm" "" ) IF (TASK.CONFIGFILE()!="") ( PRIVATE &sAwarenessFile &sMenuFile &sTaskOptionAccess &sAwarenessFile=STRing.Replace(TASK.CONFIGFILE(),OS.PSD(),"~~",1.) &sAwarenessFile=STRing.Replace("&sAwarenessFile","\","/",0.) &sMenuFile=STRing.CUT("&sAwarenessFile",-STRing.LENgth(OS.FILE.EXTENSION("&sAwarenessFile")))+".men" IF (TASK.ACCESS()!="") SPRINTF &sTaskOptionAccess "/ACCESS %s" TASK.ACCESS() APPEND "&sRestoreCmm" "TASK.CONFIG ""&sAwarenessFile"" &sTaskOptionAccess" IF (OS.FILE("&sMenuFile")) APPEND "&sRestoreCmm" "MENU.ReProgram ""&sMenuFile""" APPEND "&sRestoreCmm" "" ) ELSE IF (TASK.ORTIFILE()!="") ( PRIVATE &sOrtiFile &sOrtiFile=STRing.Replace(TASK.ORTIFILE(),"\","/",0.) APPEND "&sRestoreCmm" "TASK.ORTI ""&sOrtiFile""" APPEND "&sRestoreCmm" "" ) IF (&bTraceSave)&&(Trace.METHOD.Analyzer()||Trace.METHOD.CAnalyzer()||Trace.METHOD.Onchip())&&(Trace.RECORDS()>=256.) ( GOSUB progress "Step: store flowtrace" APPEND "&sRestoreCmm" "; Restore flowtrace" SPRINTF &sFilename "%u_trace.ad" &nTime Trace.SAVE "./&(sFilename)" APPEND "&sRestoreCmm" "Trace.LOAD ~~~~/&(sFilename)" APPEND "&sRestoreCmm" "" ) APPEND "&sRestoreCmm" "ENDDO" PRINT "Step: FINISHED" ENDDO "&sRestoreCmm" ; -------------------------------------------------------------------------------- ; Subroutines ; -------------------------------------------------------------------------------- checkSanity: ;() ( IF (VERSION.BUILD()<158636.) ( PRINT %ERROR "Software version too old. Please use more recent software. Exiting..." ENDDO ) IF ((ARMARCHVERSION()<7.)&&!((ARMARCHVERSION()==6.)&&STRing.ComPare(CORENAME(),"CORTEXM*"))) ( PRINT %ERROR "Feature is only supported for ARM Architecture v6m/v7 onwards. Exiting..." ENDDO ) ) ; -------------------------------------------------------------------------------- parseArguments: ;(args) ( PRIVATE &sArguments &bDialog &sMemoryRanges &sSymbolFile &bTraceSave &sTmp &nStoreFormat PARAMETERS &sArguments &bDialog=("&sArguments"=="") &bDialog=&bDialog||(STRing.SCAN("&sArguments","/DIALOG",0.)>=0.) &sMemoryRanges=STRing.SCANAndExtract("&sArguments","MEM=","") &sMemoryRanges=STRing.Replace("&sMemoryRanges","""","",0.) &sSymbolFile=STRing.SCANAndExtract("&sArguments","SYMBOLFILE=","") &sSymbolFile=STRing.Replace("&sSymbolFile","""","",0.) &bTraceSave=STRing.SCANAndExtract("&sArguments","TRACESAVE=","0")!="0" &sTmp=STRing.SCANAndExtract("&sArguments","STOREFORMAT=","0") EVAL &sTmp IF EVAL.TYPE()==(0x4||0x8) &nStoreFormat=&sTmp+0. RETURN "&bDialog" "&sMemoryRanges" "&sSymbolFile" "&bTraceSave" "&nStoreFormat" ) ; -------------------------------------------------------------------------------- checkArguments: ;(memoryRanges, storeFormat) ( PRIVATE &sMemoryRanges &nStoreFormat &i &sRange PARAMETERS &sMemoryRanges &nStoreFormat ; sanity check - memory ranges &i=0. &sRange=STRing.TOKEN("&sMemoryRanges",",;",&i) WHILE ("&sRange"!="") ( LOCAL &bRangeValid &bRangeValid=TRUE() IF (STRing.ComPare("&sRange","<*>")) ( &bRangeValid=(&bRangeValid)&&STRing.ComPare(STRing.LoWeR("&sRange"),"") ) ELSE ( ON ERROR GOSUB ( &bRangeValid=FALSE() RETURN ) &bRangeValid=(&bRangeValid)&&ADDRESS.isPHYSICAL(ADDRESS.RANGE.BEGIN(&sRange)) ON ERROR inherit ) IF !(&bRangeValid) ( DIALOG.OK "Invalid Range *&sRange* detected."+CONVERT.CHAR(0xa)+"Valid formats: A:--, A:++"+CONVERT.CHAR(0xa)+"e.g. A:0x80000000++0x1fffffff" ENDDO "" ) &i=&i+1. &sRange=STRing.TOKEN("&sMemoryRanges",",;",&i) ) ; sanity check - store format IF (&nStoreFormat!=(0.||1.)) ( DIALOG.OK "Invalid argument detected." ENDDO "" ) RETURN ) ; -------------------------------------------------------------------------------- showDialog: ( PMACRO.LOCK ( PRIVATE &sPpfDialog &sPpfDialog=OS.PPF() DIALOG.view (&+ HEADER "RAMDUMP" NAME "DLGRAMDUMP" POS 1. 1. 16. TEXT "Memory Range(s):" POS 17. 1. 39. 5. MEMR: MEDIT "" "DIALOG.ENABLE START" POS 58. 1. 5. 1. GUESS: BUTTON "guess" (&- PRIVATE &sRanges IF ("&sRanges"=="") ( GOSUB updateProgress "Using OS-Specific method to detect ranges..." GOSUB guessRange RETURNVALUES &sRanges IF ("&sRanges"=="") GOSUB updateProgress "Using OS-Specific method to detect ranges...failed." ) IF ("&sRanges"=="") ( GOSUB updateProgress "Using Section Table to detect ranges..." GOSUB guessRange_sectionTable RETURNVALUES &sRanges IF ("&sRanges"=="") GOSUB updateProgress "Using Section Table to detect ranges...failed." ) DIALOG.SET MEMR "&sRanges" IF ("&sRanges"=="") ( GOSUB updateProgress "Failed to guess memory ranges. Please set ranges manually." DIALOG.OK "Failed to guess memory ranges. Please set ranges manually." ) ELSE ( DIALOG.ENABLE START IF STRing.ComPare(STRing.LoWeR("&sRanges"),"**") ( DIALOG.OK "Too many sections detected."+CONV.CHAR(0xa)+"The placeholder """" will store all sections part of the sYmbol.List.SECtion window." GOSUB updateProgress "Warning: Detected too many sections while guess memory ranges." GOSUB updateProgress "Placeholder """" will store all sections." ) ELSE ( DIALOG.OK "Please check if the guessed memory range(s) are correct." GOSUB updateProgress "Succeeded to guess memory ranges." ) ) ) POS 1. 7. 16. TEXT "Kernel Symbol File:" POS 17. 7. 42. SYM: EDIT "" "" POS 61. 7. 2. BUTTON "..." (&- PRIVATE &sTmp &sTmp=DIALOG.STRing(SYM) &sTmp=OS.FILE.PATH("&sTmp") IF "&sTmp"!="" ( &sTmp=OS.FILE.JOINPATH("&sTmp","*.*") ) DIALOG.File "&sTmp" ENTRY %LINE &sTmp IF "&sTmp"!="" ( &sTmp="&sTmp" DIALOG.Set SYM "&sTmp" ) ) POS 1. 9. 15. TEXT "Save dump to:" POS 17. 9. 42. CMM: EDIT "./" "" POS 61. 9. 2. BUTTON "..." (&- PRIVATE &sDir DIALOG.DIR ENTRY &sDir IF "&sDir"!="" DIALOG.Set CMM "&sDir" ) POS 1. 11. 1. TBOX: CHECKBOX "" "" POS 3. 11. 10. TEXT "Store Flowtrace" POS 16. 11. 10. TEXT "Store format:" POS 26. 11. 16. SFMT: PULLDOWN "Binary,S3Record (ECC robust)" "" POS 53. 11. 10. 1. START: BUTTON "STORE" ( PRIVATE &sPpf &sPpf="&sPpfDialog" (&- PRIVATE &sMemoryRanges &sSymbolFile &sDestinationPath &nStoreFormat &sArguments &sReturn &sMemoryRanges=STRing.Replace(DIALOG.STRing(MEMR),""+CONVert.CHAR(0xa),",",0.) &sSymbolFile=DIALOG.STRing(SYM) &sDestinationPath=DIALOG.STRing(CMM) &nStoreFormat=0. IF (DIALOG.STRing(SFMT)=="S3Record (ECC robust)") ( &nStoreFormat=1. ) IF (!OS.DIR("&sDestinationPath")) ( DIALOG.OK "Destination path doesn't exist." GOSUB updateProgress "Destination path doesn't exist." ENDDO ) SPRINTF &sArguments "MEM=""%s"" SYMBOLFILE=""%s"" TRACESAVE=%u STOREFORMAT=%u" "&sMemoryRanges" "&sSymbolFile" CONVERT.BOOLTOINT(DIALOG.BOOLEAN(TBOX)) &nStoreFormat GOSUB updateProgress "Generate ramdump... this might take a while" GOSUB updateProgress "run: CD ""&sDestinationPath""" GOSUB updateProgress "run: DO ""&sPpf"" &sArguments" CD "&sDestinationPath" DO "&sPpf" &sArguments RETURNVALUES &sReturn IF ("&sReturn"!="") ( GOSUB updateProgress "Generate ramdump...succeeded." GOSUB updateProgress "Please run script ""&sReturn"" in TRACE32 Simulator." ) ELSE ( GOSUB updateProgress "Start to generate ramdump...failed." ) ) ) POS 1. 13. 61. 5. ITEXT: INFOTEXT "" GR SI INIT (&- DIALOG.STORAGE.define &sLog PRIVATE &sSymbolFile &sWelcomeText DIALOG.DISable START IF !((Trace.METHOD.Analyzer()||Trace.METHOD.CAnalyzer()||Trace.METHOD.Onchip())&&(Trace.RECORDS()>=256.)) ( DIALOG.DISable TBOX ) IF sYmbol.List.PROGRAM.COUNT()==1. ( DIALOG.Set SYM sYmbol.List.PROGRAM.FILE(1.) ) &sWelcomeText="Welcome to Ramdump Generator for "+"NuttX"+"." GOSUB updateProgress "&sWelcomeText" ) CLOSE (&- DIALOG.END ) SUBROUTINE updateProgress (&- PRIVATE &sPrefix &sText PARAMETERS &sText SPRINTF &sPrefix "[%02u:%02u:%02u]: " DATE.SECONDS()/60./60. (DATE.SECONDS()/60.)%60. DATE.SECONDS()%60. &sLog=STRing.MID("&sLog",0.,2048.-STRing.LENgth("&(sPrefix)&(sText)")-1.) &sLog="&(sPrefix)&(sText)"+CONV.CHAR(0xa)+"&(sLog)" DIALOG.SET ITEXT "&sLog" RETURN ) SUBROUTINE guessRange_sectionTable (&- PRIVATE &i &sRanges Var.NEWLOCAL void*[100] \nStart Var.NEWLOCAL void*[100] \nEnd Var.NEWLOCAL int \count Var.NEWLOCAL int \i IF (sYmbol.List.SECtion.COUNT()==0.) RETURN "" &i=1. RePeaT sYmbol.List.SECtion.COUNT() ( PRIVATE &sRange &nStart &nEnd &nStart=ADDRESS.OFFSET(sYmbol.List.SECtion.BEGIN(&i)) &nEnd=&nStart+sYmbol.List.SECtion.SIZE(&i)-0x1 IF (&nStart<&nEnd) ( PRIVATE &bMerge &bMerge=FALSE() Var.IF \count>=1 ( Var.IF (\nEnd[\count-1]+0xf)>=&nStart ( ; merge Var.Assign \nEnd[\count-1]=&nEnd &bMerge=TRUE() ) ) IF (!&bMerge) ( Var.Assign \nStart[\count]=&nStart Var.Assign \nEnd[\count]=&nEnd Var.Assign \count++ ) ) &i=&i+1. ; abort merged add when we reach 100 sections Var.IF \count>=100. RETURN "" ) Var.Assign \i=0 Var.WHILE \i<\count ( Var.IF \i==0 SPRINTF &sRanges "%sAD:0x%x--0x%x" "&sRanges" Var.VALUE(\nStart[\i]) Var.VALUE(\nEnd[\i]) ELSE SPRINTF &sRanges "%s%cAD:0x%x--0x%x" "&sRanges" 0xa Var.VALUE(\nStart[\i]) Var.VALUE(\nEnd[\i]) Var.Assign \i++ ) RETURN "&sRanges" ) SUBROUTINE guessRange ( PRIVATE &sRanges GOSUB guessRange_sectionTable RETURNVALUES &sRanges IF ("&sRanges"=="") RETURN "&sRanges" IF Var.EXIST(g_mmheap) ( LOCAL &nHeapStart &nHeapEnd &nHeapStart=0. &nHeapEnd=-1. ON ERROR GOSUB ( &nHeapStart=0. &nHeapEnd=-1. RETURN ) IF Var.VALUE(g_mmheap)!=0x0 ( &nHeapStart=Var.VALUE(g_mmheap->mm_heapstart[0]) &nHeapEnd=Var.VALUE(g_mmheap->mm_heapend[0]) ) ON ERROR inherit IF (&nHeapStart<&nHeapEnd) ( SPRINTF &sRanges "%s%cAD:0x%x--0x%x" "&sRanges" 0xa &nHeapStart &nHeapEnd-1. ) ) RETURN "&sRanges" ) ) ) PMACRO.UNLOCK RETURN ) ; -------------------------------------------------------------------------------- progress: ;(sText) ( PARAMETERS &sText PRINT "&sText" IF WINdow.EXIST(DLGRAMDUMP) ( DIALOG.SELect DLGRAMDUMP GOSUB updateProgress "&sText" ) ) ; -------------------------------------------------------------------------------- getCoreAssignment: ;() ( PRIVATE &sAssignment &i &sAssignment="" &i=0. RePeaT CORE.NUMBER() ( SPRINTF &sAssignment "%s%u. " "&sAssignment" CORE.LOGICALTOPHYSICAL(&i) &i=&i+1. ) &sAssignment=STRing.TRIM("&sAssignment") RETURN "&sAssignment" ) ; -------------------------------------------------------------------------------- cacheClean: ;() ( PRIVATE &i &i=0. IF PRACTICE.CoMmanD.AVAILable(CACHE.FLUSH.FULL) ( IF CORE.NUMBER()>1. CORE.select &i CACHE.FLUSH FULL &i=&i+1. ) ELSE ( &i=0. IF PRACTICE.CoMmanD.AVAILable(CACHE.FLUSH.DC) ( RePeaT CORE.NUMBER() ( IF CORE.NUMBER()>1. CORE.select &i CACHE.FLUSH DC &i=&i+1. ) ) &i=0. IF PRACTICE.CoMmanD.AVAILable(CACHE.FLUSH.L2) ( RePeaT CORE.NUMBER() ( IF CORE.NUMBER()>1. CORE.select &i CACHE.FLUSH L2 &i=&i+1. ) ) &i=0. IF PRACTICE.CoMmanD.AVAILable(CACHE.FLUSH.L3) ( RePeaT CORE.NUMBER() ( IF CORE.NUMBER()>1. CORE.select &i CACHE.FLUSH L3 &i=&i+1. ) ) ) IF CORE.NUMBER()>1. CORE.select 0. RETURN ) storeMemoryRange: ; (file, time, format, range) ( PRIVATE &sRestoreCmm &nTime &nStoreFormat &sRange &sFilename PARAMETERS &sRestoreCmm &nTime &nStoreFormat &sRange IF (&nStoreFormat==0.) ( IF (ADDRESS.RANGE.SIZE(&sRange)>16384.) ( SPRINTF &sFilename "%u_mem_%s.bin.gz" &nTime STRing.Replace(STRing.LoWeR("&sRange"),":","_",0.) SILENT.Data.SAVE.Binary "./&(sFilename)" &(sRange) /ZIP APPEND "&sRestoreCmm" "Data.LOAD.Binary ~~~~/&(sFilename) &(sRange) /UNZIP /NosYmbol" ) ELSE ( SPRINTF &sFilename "%u_mem_%s.bin" &nTime STRing.Replace(STRing.LoWeR("&sRange"),":","_",0.) SILENT.Data.SAVE.Binary "./&(sFilename)" &(sRange) APPEND "&sRestoreCmm" "Data.LOAD.Binary ~~~~/&(sFilename) &(sRange) /NosYmbol" ) ) ELSE IF (&nStoreFormat==1.) ( SPRINTF &sFilename "%u_mem_%s.srec" &nTime STRing.Replace(STRing.LoWeR("&sRange"),":","_",0.) SILENT.Data.SAVE.S3Record "./&(sFilename)" &(sRange) /SkipErrors APPEND "&sRestoreCmm" "Data.LOAD.S3Record ~~~~/&(sFilename) &(sRange) /NosYmbol" ) RETURN ) ; -------------------------------------------------------------------------------- getDataLoadParameters: ;(file) ( PRIVATE &sSymbolFile &i &bFound PRIVATE &sDataLoadFormat &sLoadOptions PARAMETERS &sSymbolFile &sDataLoadFormat="auto" IF (sYmbol.List.PROGRAM.COUNT()==0.) RETURN "&sDataLoadFormat" "" IF ("&sSymbolFile"=="") RETURN "&sDataLoadFormat" "" &i=0. &bFound=FALSE() RePeaT ( PRIVATE &sFile &i=&i+1. &sFile=sYmbol.List.Program.FILE(&i) &bFound=(OS.FILE.ABSPATH("&sFile")==OS.FILE.ABSPATH("&sSymbolFile")) ) WHILE (!&bFound&&((&i+1.)<=sYmbol.List.PROGRAM.COUNT())) IF (&bFound) ( PRIVATE &sFormat &sCommand &sToken &bOptionFound &sCommand=sYmbol.List.PROGRAM.COMMAND(&i) &sFormat=sYmbol.List.PROGRAM.FORMAT(&i) IF (STRing.ComPare("&sFormat","ELF/*")) &sDataLoadFormat="Elf" ELSE IF (STRing.ComPare("&sFormat","EXE/*")) &sDataLoadFormat="eXe" &i=2. &bOptionFound=FALSE() &sToken=STRing.TOKEN("&sCommand"," ",&i,"QUOTEDSTRINGS=ON") WHILE ("&sToken"!="") ( &bOptionFound=&(bOptionFound)||STRing.ComPare("&sToken","/*") IF ((&i==(2.||3.))&&!&bOptionFound) ( ; it's an offset/address/accessclass EVAL &sToken IF (EVAL.TYPE()==(0x2||0x4||0x8)) ; binary/hex/decimal ( SPRINTF &sLoadOptions "%s %#x" "&sLoadOptions" &sToken ) ELSE IF (EVAL.TYPE()==(0x80||0x200)) ; numeric range/address range ( ; evaluate possibly embedded functions in token ; accidentally converts numeric range to address range C: &sToken=&sToken SPRINTF &sLoadOptions "%s %#!R" "&sLoadOptions" &sToken ) ELSE IF (EVAL.TYPE()==0x100) ; address ( ; evaluate possibly embedded functions in token &sToken=&sToken SPRINTF &sLoadOptions "%s %#!A" "&sLoadOptions" &sToken ) ELSE IF STRing.ComPare("&(sToken)","*?:") ( ; only access class? e.g. NS: EVAL &(sToken)0 IF (EVAL.TYPE()==0x100) ( SPRINTF &sLoadOptions "%s %#!A" "&sLoadOptions" &(sToken)0 ) ) ) ELSE IF STRing.ComPare("&sToken","/*") ( ; it's an option PRIVATE &bOptionNoParam &bOptionWithParam &bOptionNoParam=STRing.ComPare(",/GNU,/GHS,/RVCT,/DWARF,/DWARF2,/STABS,",STRing.UPper("*,&(sToken),*")) &bOptionWithParam=STRing.ComPare(",/NAME,/ABI,",STRing.UPper("*,&(sToken),*")) IF (&bOptionNoParam) ( SPRINTF &sLoadOptions "%s %s" "&sLoadOptions" "&sToken" ) ELSE IF (&bOptionWithParam) ( SPRINTF &sLoadOptions "%s %s" "&sLoadOptions" "&sToken" &i=&i+1. &sToken=STRing.TOKEN("&sCommand"," ",&i,"QUOTEDSTRINGS=ON") SPRINTF &sLoadOptions "%s %s" "&sLoadOptions" "&sToken" ) ) &i=&i+1. &sToken=STRing.TOKEN("&sCommand"," ",&i,"QUOTEDSTRINGS=ON") ) ) RETURN "&sDataLoadFormat" "&sLoadOptions" ) ; -------------------------------------------------------------------------------- perStoreFilter: ;(sInFile, sOutFile) ( PRIVATE &sInFile &sOutFile &sFilter &nHandle &sHandle &sLine PARAMETERS &sInFile &sOutFile &sFilter ; detect available filehandle &nHandle=0. RePeaT ( &nHandle=&nHandle+1. ) WHILE FILE.OPEN(&nHandle) SPRINTF &sHandle "#%u" &nHandle ; count lines, detect maximum length PRIVATE &nLineCount &nLineLength &nLineCount=0. &nLineLength=0. OPEN &sHandle "&sInFile" /Read READ &sHandle %LINE &sLine WHILE !FILE.EOF(&nHandle) ( PRIVATE &nLength &nLength=STRing.LENgth("&sLine") IF (&nLineLength<&nLength) &nLineLength=&nLength &nLineCount=&nLineCount+1. READ &sHandle %LINE &sLine ) CLOSE &sHandle IF (&nLineCount==0) RETURN ; read all lines into an hll-array PRIVATE &nLineCount2 &nLineLength2 &nLineCount2=&nLineCount+1. &nLineLength2=&nLineLength+1. Var.NEWLOCAL char[&nLineCount2][&nLineLength2] \ppLines Var.NEWLOCAL int \i OPEN &sHandle "&sInFile" /Read READ &sHandle %LINE &sLine Var.Assign \i = 0 RePeaT &nLineCount ( Var.Assign \ppLines[\i++] = "&sLine" READ &sHandle %LINE &sLine ) CLOSE &sHandle ; apply semicolon separated filters to register names PRIVATE &j &sFilterToken &j=0. IF ("&sFilter"=="") &sFilter="*" RePeaT ( &sFilterToken=STRing.TOKEN("&sFilter",";",&j) IF ("&sFilterToken"!="") GOSUB perStoreFilter_process "&sOutFile" "\ppLines" "&nLineCount" "&sFilterToken" &j=&j+1. ) WHILE ("&sFilterToken"!="") RETURN ) ; -------------------------------------------------------------------------------- perStoreFilter_process: ;(sOutFile, sHllLines, nLineCount, sCompareExpr) ( PRIVATE &sOutFile &sHllLines &nLineCount &sFilter PARAMETERS &sOutFile &sHllLines &nLineCount &sFilter PRIVATE &sLine &sLineOut &bHeading &bRoRegister &bOnErrorInheritPending Var.NEWLOCAL int \i Var.Assign \i = 0 &bHeading=FALSE() &bRoRegister=FALSE() &bOnErrorInheritPending=FALSE() &sLineOut="" Var.WHILE \i<&nLineCount ( &sLine=Var.STRing(&sHllLines[\i]) IF ("&sLine"=="") ( ; empty line - nothing todo ) ELSE IF STRing.ComPare("&sLine","// *") ( ; a heading / tree is signaled via a comment line without an indent ; e.g. `// Virtualization Extensions` &sLineOut="&sLine" &bHeading=TRUE() ) ELSE ( PRIVATE &sLineTrim &sComment &sRegisterName &sReason ; example lines: ; `PER.Set.simple SPR:0x34111 %Quad 0x8 // MDCR_EL2` ; `// PER.Set.simple SPR:0x30012 %Quad 0x17011099 // ID_DFR0_EL1; reason=read-only` ; `// PER.Set.simple SPR:0x34316 %Quad 0x0 // HAFGRTR_EL2; reason=access_error` &sLineTrim=STRing.TRIM("&sLine") &sComment=STRing.TRIM(STRing.TOKEN("&sLineTrim","//",-1.,"DELIMITER=STRING")) &sRegisterName=STRing.TRIM(STRing.TOKEN("&sComment","; ",0.)) &sReason=STRing.SCANAndExtract("&sComment","reason=","") IF STRing.ComPare("&sRegisterName","&(sFilter)") ( &bRoRegister=("&sReason"=="read-only") IF (&bRoRegister) ( ; remove comment markers from `reason=read-only` registers ; - try to restore them but ignore errors &sLineOut=" "+STRing.TRIM(STRing.CUT("&sLineTrim",2.)) ) ELSE ( &sLineOut=" &sLineTrim" ) ) ) IF ("&sLineOut"!="") ( IF ((&bRoRegister)&&(!&bOnErrorInheritPending)) APPEND "&sOutFile" " ON ERROR CONTinue" ELSE IF ((&bOnErrorInheritPending)&&(!&bRoRegister)) APPEND "&sOutFile" " ON ERROR inherit" APPEND "&sOutFile" "&sLineOut" &bOnErrorInheritPending=&bRoRegister IF (!&bHeading) Var.Assign &sHllLines[\i] = "" &bHeading=FALSE() &bRoRegister=FALSE() &sLineOut="" ) Var.Assign \i++ ) IF (&bOnErrorInheritPending) APPEND "&sOutFile" " ON ERROR inherit" RETURN ) ; -------------------------------------------------------------------------------- getModeString: ;(regM) ( PRIVATE &nRegM &sStr PARAMETERS &nRegM Var.NEWLOCAL char[32][5] \ppModes Var.Assign \ppModes[0]="EL0t" Var.Assign \ppModes[1]="EL0h" Var.Assign \ppModes[2]="0x2" Var.Assign \ppModes[3]="0x3" Var.Assign \ppModes[4]="EL1t" Var.Assign \ppModes[5]="EL1h" Var.Assign \ppModes[6]="0x6" Var.Assign \ppModes[7]="0x7" Var.Assign \ppModes[8]="EL2t" Var.Assign \ppModes[9]="EL2h" Var.Assign \ppModes[10]="0xa" Var.Assign \ppModes[11]="0xb" Var.Assign \ppModes[12]="EL3t" Var.Assign \ppModes[13]="EL3h" Var.Assign \ppModes[14]="0xe" Var.Assign \ppModes[15]="0xf" Var.Assign \ppModes[16]="Usr" Var.Assign \ppModes[17]="Fiq" Var.Assign \ppModes[18]="Irq" Var.Assign \ppModes[19]="Svc" Var.Assign \ppModes[20]="0x14" Var.Assign \ppModes[21]="0x15" Var.Assign \ppModes[22]="Mon" Var.Assign \ppModes[23]="Abt" Var.Assign \ppModes[24]="0x18" Var.Assign \ppModes[25]="0x19" Var.Assign \ppModes[26]="Hyp" Var.Assign \ppModes[27]="Und" Var.Assign \ppModes[28]="0x1c" Var.Assign \ppModes[29]="0x1d" Var.Assign \ppModes[30]="0x1e" Var.Assign \ppModes[31]="Sys" &nRegM=&nRegM &sStr=Var.STRing(\ppModes[&nRegM]) RETURN "&sStr" ) ; -------------------------------------------------------------------------------- getPerFilter: ;(regM, current) ( PRIVATE &nRegM &bCurrent &sFilter PARAMETERS &nRegM &bCurrent IF ((&nRegM&0x10)!=0x0) // Aarch32? RETURN "*" IF !(CPU.FEATURE(C15)||CPU.FEATURE(SPR)) // -A/-R profile? RETURN "*" &sFilter="" IF (&nRegM>=(0xc)) // EL3t, EL3h &sFilter=OS.FILE.JOINPATH("&sFilter","*?_EL3") IF (&nRegM>=(0x8)) // EL2t, EL2h &sFilter=OS.FILE.JOINPATH("&sFilter","*?_EL2","*?_EL12","*?_EL02") IF (&nRegM>=(0x4)) // EL1t, EL1h &sFilter=OS.FILE.JOINPATH("&sFilter","*?_EL1") &sFilter=OS.FILE.JOINPATH("&sFilter","*?_EL0") IF (!&bCurrent) &sFilter=OS.FILE.JOINPATH("&sFilter","*") &sFilter=STRing.Replace("&sFilter","/",";",0.) &sFilter=STRing.Replace("&sFilter","\",";",0.) RETURN "&sFilter" ) ; -------------------------------------------------------------------------------- getCorePerfilePath: ;() ( PRIVATE &sFile &sTree &sPath &c0 &c1 GOSUB getCorePerfile RETURNVALUES &sFile &sTree &c0=STRing.MID("&sFile",0.,1.) &c1=STRing.MID("&sFile",1.,1.) IF ("&c0"=="") &sPath="" ELSE IF ("&c0"=="~")||("&c0"=="/")||("&c1"==":")||(("&c0"=="\")&&("&c1"=="\")) &sPath="&sFile" ELSE &sPath="~~/&(sFile)" RETURN "&sPath" "&sTree" ) getCorePerfile: ;() ( PRIVATE &i &sFile &sCsvFileList &i=0. &sCsvFileList=PER.FILENAME() IF (PRACTICE.FUNCtion.AVAILable(CPU.FILELIST)) &sCsvFileList="&(sCsvFileList),"+CPU.FILELIST("PER") &sFile=STRing.TOKEN("&sCsvFileList",",",&i) WHILE ("&sFile"!="") ( IF STRing.ComPare(OS.FILE.BASENAME("&sFile"),"percortex*") RETURN "&sFile" "" IF STRing.ComPare(OS.FILE.BASENAME("&sFile"),"perneoverse*") RETURN "&sFile" "" &i=&i+1. &sFile=STRing.TOKEN("&sCsvFileList",",",&i) ) IF ((ARMARCHVERSION("major")>=8.)&&CPU.FEATURE("MMU")&&!CPU.FEATURE("MPU")&&(CPU.FEATURE("C15")||CPU.FEATURE("SPR"))) ( ; A- profile IF (ARMARCHVERSION("minor")==0.) SPRINTF &sFile "perarmv%ua.per" ARMARCHVERSION("major") ELSE SPRINTF &sFile "perarmv%xa.per" ARMARCHVERSION() RETURN "&sFile" "" ) RETURN "" "" )