mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
main: show runtime panic addresses for tinygo run
This adds the same panic locations that are already present for
`tinygo flash -monitor`, but for `tinygo run` and `tinygo test`.
For example, this is the output that I get while working on some GC
code. It now shows the source location instead of just an address:
$ tinygo test -v archive/zip
=== RUN TestReader
=== RUN TestReader/test.zip
panic: runtime error at 0x000000000024d9b4: goroutine stack overflow
[tinygo: panic at /home/ayke/src/tinygo/tinygo/src/internal/task/task_stack.go:58:15]
FAIL archive/zip 0.139s
(This particular location isn't all that useful, but it shows that the
feature works).
This commit is contained in:
@@ -936,7 +936,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
|
||||
// Configure stdout/stderr. The stdout may go to a buffer, not a real
|
||||
// stdout.
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stdout = newOutputWriter(stdout, result.Executable)
|
||||
cmd.Stderr = os.Stderr
|
||||
if config.EmulatorName() == "simavr" {
|
||||
cmd.Stdout = nil // don't print initial load commands
|
||||
|
||||
+41
-19
@@ -197,31 +197,14 @@ func Monitor(executable, port string, config *compileopts.Config) error {
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 100*1024)
|
||||
var line []byte
|
||||
writer := newOutputWriter(os.Stdout, executable)
|
||||
for {
|
||||
n, err := serialConn.Read(buf)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("read error: %w", err)
|
||||
return
|
||||
}
|
||||
start := 0
|
||||
for i, c := range buf[:n] {
|
||||
if c == '\n' {
|
||||
os.Stdout.Write(buf[start : i+1])
|
||||
start = i + 1
|
||||
address := extractPanicAddress(line)
|
||||
if address != 0 {
|
||||
loc, err := addressToLine(executable, address)
|
||||
if err == nil && loc.IsValid() {
|
||||
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
|
||||
}
|
||||
}
|
||||
line = line[:0]
|
||||
} else {
|
||||
line = append(line, c)
|
||||
}
|
||||
}
|
||||
os.Stdout.Write(buf[start:n])
|
||||
writer.Write(buf[:n])
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -400,3 +383,42 @@ func readDWARF(executable string) (*dwarf.Data, error) {
|
||||
return nil, errors.New("unknown binary format")
|
||||
}
|
||||
}
|
||||
|
||||
type outputWriter struct {
|
||||
out io.Writer
|
||||
executable string
|
||||
line []byte
|
||||
}
|
||||
|
||||
// newOutputWriter returns an io.Writer that will intercept panic addresses and
|
||||
// will try to insert a source location in the output if the source location can
|
||||
// be found in the executable.
|
||||
func newOutputWriter(out io.Writer, executable string) *outputWriter {
|
||||
return &outputWriter{
|
||||
out: out,
|
||||
executable: executable,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *outputWriter) Write(p []byte) (n int, err error) {
|
||||
start := 0
|
||||
for i, c := range p {
|
||||
if c == '\n' {
|
||||
w.out.Write(p[start : i+1])
|
||||
start = i + 1
|
||||
address := extractPanicAddress(w.line)
|
||||
if address != 0 {
|
||||
loc, err := addressToLine(w.executable, address)
|
||||
if err == nil && loc.Filename != "" {
|
||||
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
|
||||
}
|
||||
}
|
||||
w.line = w.line[:0]
|
||||
} else {
|
||||
w.line = append(w.line, c)
|
||||
}
|
||||
}
|
||||
w.out.Write(p[start:])
|
||||
n = len(p)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user