Skip to content

Commit 0206645

Browse files
committed
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).
1 parent 2d6d9eb commit 0206645

File tree

2 files changed

+42
-20
lines changed

2 files changed

+42
-20
lines changed

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
936936

937937
// Configure stdout/stderr. The stdout may go to a buffer, not a real
938938
// stdout.
939-
cmd.Stdout = stdout
939+
cmd.Stdout = newOutputWriter(stdout, result.Executable)
940940
cmd.Stderr = os.Stderr
941941
if config.EmulatorName() == "simavr" {
942942
cmd.Stdout = nil // don't print initial load commands

monitor.go

+41-19
Original file line numberDiff line numberDiff line change
@@ -197,31 +197,14 @@ func Monitor(executable, port string, config *compileopts.Config) error {
197197

198198
go func() {
199199
buf := make([]byte, 100*1024)
200-
var line []byte
200+
writer := newOutputWriter(os.Stdout, executable)
201201
for {
202202
n, err := serialConn.Read(buf)
203203
if err != nil {
204204
errCh <- fmt.Errorf("read error: %w", err)
205205
return
206206
}
207-
start := 0
208-
for i, c := range buf[:n] {
209-
if c == '\n' {
210-
os.Stdout.Write(buf[start : i+1])
211-
start = i + 1
212-
address := extractPanicAddress(line)
213-
if address != 0 {
214-
loc, err := addressToLine(executable, address)
215-
if err == nil && loc.IsValid() {
216-
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
217-
}
218-
}
219-
line = line[:0]
220-
} else {
221-
line = append(line, c)
222-
}
223-
}
224-
os.Stdout.Write(buf[start:n])
207+
writer.Write(buf[:n])
225208
}
226209
}()
227210

@@ -400,3 +383,42 @@ func readDWARF(executable string) (*dwarf.Data, error) {
400383
return nil, errors.New("unknown binary format")
401384
}
402385
}
386+
387+
type outputWriter struct {
388+
out io.Writer
389+
executable string
390+
line []byte
391+
}
392+
393+
// newOutputWriter returns an io.Writer that will intercept panic addresses and
394+
// will try to insert a source location in the output if the source location can
395+
// be found in the executable.
396+
func newOutputWriter(out io.Writer, executable string) *outputWriter {
397+
return &outputWriter{
398+
out: out,
399+
executable: executable,
400+
}
401+
}
402+
403+
func (w *outputWriter) Write(p []byte) (n int, err error) {
404+
start := 0
405+
for i, c := range p {
406+
if c == '\n' {
407+
w.out.Write(p[start : i+1])
408+
start = i + 1
409+
address := extractPanicAddress(w.line)
410+
if address != 0 {
411+
loc, err := addressToLine(w.executable, address)
412+
if err == nil && loc.Filename != "" {
413+
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
414+
}
415+
}
416+
w.line = w.line[:0]
417+
} else {
418+
w.line = append(w.line, c)
419+
}
420+
}
421+
w.out.Write(p[start:])
422+
n = len(p)
423+
return
424+
}

0 commit comments

Comments
 (0)