Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorManuel Coenen <manuel@duet3d.com>2020-11-30 14:57:17 +0300
committerManuel Coenen <manuel@duet3d.com>2020-11-30 14:57:17 +0300
commit14a9c1caf6f2b080a73b48c5a2b1f9154b57be1f (patch)
treeea2d47fba2b63062141a8d4250a2d681ed211d37 /Tools
parentd096a0723f2fd6294e199dab0ef292eb49ce999b (diff)
Add stackanalyzer to find a fault location from a M122 output and a map
file
Diffstat (limited to 'Tools')
-rw-r--r--Tools/stackanalyzer/go.mod3
-rwxr-xr-xTools/stackanalyzer/linux/stackanalyzerbin0 -> 2339240 bytes
-rwxr-xr-xTools/stackanalyzer/macos/stackanalyzerbin0 -> 2344376 bytes
-rw-r--r--Tools/stackanalyzer/stackanalyzer.go172
-rwxr-xr-xTools/stackanalyzer/win/stackanalyzer.exebin0 -> 2467840 bytes
5 files changed, 175 insertions, 0 deletions
diff --git a/Tools/stackanalyzer/go.mod b/Tools/stackanalyzer/go.mod
new file mode 100644
index 00000000..735571df
--- /dev/null
+++ b/Tools/stackanalyzer/go.mod
@@ -0,0 +1,3 @@
+module github.com/Duet3D/RepRapFirmware/Tools/stackanalyzer
+
+go 1.15
diff --git a/Tools/stackanalyzer/linux/stackanalyzer b/Tools/stackanalyzer/linux/stackanalyzer
new file mode 100755
index 00000000..bd309c67
--- /dev/null
+++ b/Tools/stackanalyzer/linux/stackanalyzer
Binary files differ
diff --git a/Tools/stackanalyzer/macos/stackanalyzer b/Tools/stackanalyzer/macos/stackanalyzer
new file mode 100755
index 00000000..d00a2b1f
--- /dev/null
+++ b/Tools/stackanalyzer/macos/stackanalyzer
Binary files differ
diff --git a/Tools/stackanalyzer/stackanalyzer.go b/Tools/stackanalyzer/stackanalyzer.go
new file mode 100644
index 00000000..91581a16
--- /dev/null
+++ b/Tools/stackanalyzer/stackanalyzer.go
@@ -0,0 +1,172 @@
+package main
+
+import (
+ "bufio"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+)
+
+const (
+ assertionHeader = iota
+ assertionLineNo
+ assertionFunction
+)
+const (
+ header = iota
+ register0
+ register1
+ register2
+ register3
+ returnControl
+ returnAddress
+ faultAddress
+)
+
+func main() {
+ mapFile := flag.String("mapFile", "", "Path to .map file")
+ m122 := flag.String("m122", "-", "Path to file with M122 output (even partial) or \"-\" for stdin")
+ flag.Parse()
+
+ if *m122 == "" {
+ log.Fatal("-m122 needs to be provided")
+ }
+ if *mapFile == "" {
+ log.Fatal("-mapFile needs to be provided")
+ }
+
+ var r io.Reader
+ if *m122 == "-" {
+ r = bufio.NewReader(os.Stdin)
+ } else {
+ f, err := os.Open(*m122)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ r = f
+ }
+
+ var err error
+ faultedAddress := uint64(0)
+ scanner := bufio.NewScanner(r)
+ isAssertion := false
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+
+ if line == "" {
+ continue
+ }
+ if strings.HasPrefix(line, "Last software reset") {
+ isAssertion = strings.Contains(line, "reason: Assertion")
+ continue
+ }
+ if strings.HasPrefix(line, "Stack:") {
+ stackElems := strings.Fields(line)
+ var faultElem string
+ if isAssertion {
+ faultElem = stackElems[assertionFunction]
+ } else {
+ faultElem = stackElems[faultAddress]
+ }
+
+ // Get the fault address
+ faultedAddress, err = strconv.ParseUint(faultElem, 16, 64)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ faultLocation, lastAddress, err := getFailingBlock(*mapFile, faultedAddress)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("Faulted at:")
+ for _, l := range faultLocation {
+ fmt.Println(l)
+ }
+ if isAssertion {
+ lineNo, _ := strconv.ParseUint(stackElems[assertionLineNo], 16, 64)
+ fmt.Printf("Error is at line: %d\n", lineNo)
+ } else {
+ fmt.Printf("Error is at offset: %#x\n", (faultedAddress - lastAddress))
+ }
+ }
+ }
+}
+
+func getFailingBlock(mapFile string, faultedAddress uint64) ([]string, uint64, error) {
+ // Open the map file
+ mf, err := os.Open(mapFile)
+ if err != nil {
+ return nil, 0, err
+ }
+ defer mf.Close()
+ mapScanner := bufio.NewScanner(mf)
+
+ var faultLocation []string
+ var prevFaultFunction string
+ var faultFunction string
+ lastAddress := uint64(0)
+ foundStart := false
+ addressOfLine := uint64(0)
+ for mapScanner.Scan() {
+ mapLine := mapScanner.Text()
+
+ // Advance to the interesting section
+ if !foundStart {
+ if !strings.HasPrefix(mapLine, ".text") {
+ continue
+ }
+ foundStart = true
+ }
+ fields := strings.Fields(mapLine)
+
+ // Lines with only one field indicate the next function
+ if len(fields) < 2 {
+ prevFaultFunction = faultFunction
+ faultFunction = fields[0]
+ continue
+ }
+
+ // Get the address of the current line
+ var addressField string
+ for _, f := range fields {
+ if strings.HasPrefix(f, "0x") {
+ addressField = f[2:]
+ break
+ }
+ }
+
+ // Still no address
+ if addressField == "" {
+ continue
+ }
+
+ addressOfLine, err = strconv.ParseUint(addressField, 16, 64)
+ if err != nil {
+ return nil, 0, errors.New(fmt.Sprintf("Could not parse line: %s", mapLine))
+ }
+
+ if addressOfLine <= faultedAddress {
+
+ // Reset the slice of lines if we see a new address
+ if addressOfLine != lastAddress {
+ lastAddress = addressOfLine
+ faultLocation = make([]string, 0, 0)
+ faultLocation = append(faultLocation, prevFaultFunction)
+ }
+ faultLocation = append(faultLocation, mapLine)
+ } else {
+ // We reached the function after our fault
+ break
+ }
+ }
+
+ return faultLocation, lastAddress, nil
+}
diff --git a/Tools/stackanalyzer/win/stackanalyzer.exe b/Tools/stackanalyzer/win/stackanalyzer.exe
new file mode 100755
index 00000000..1e9c41af
--- /dev/null
+++ b/Tools/stackanalyzer/win/stackanalyzer.exe
Binary files differ