[symbolize] Add info msg to backtraces
This change adds support for adding an additional message to the end
of backtraces. This can be used for instance to add information about
stack pointers and other such information.
Bug: TC-303
Test: New unit tests + CQ
Change-Id: I9c4538a97b9668eeaae23f699284454d5c0ed550
diff --git a/symbolize/ast.go b/symbolize/ast.go
index 6374548..4c9d9b8 100644
--- a/symbolize/ast.go
+++ b/symbolize/ast.go
@@ -72,6 +72,7 @@
type BacktraceElement struct {
vaddr uint64
num uint64
+ msg string
info addressInfo
}
diff --git a/symbolize/demuxer_test.go b/symbolize/demuxer_test.go
index ae6ee90..ebbb916 100644
--- a/symbolize/demuxer_test.go
+++ b/symbolize/demuxer_test.go
@@ -233,6 +233,53 @@
//[131.604] 01234.05678> Error at atan2 at atan2.c:49
}
+func TestMsgSimpleBacktrace(t *testing.T) {
+ msg := "{{{bt:0:0xdeadbeef:this is a message}}}\n"
+ symbo := newMockSymbolizer([]mockModule{})
+ demuxer := NewDemuxer(testBinaries, symbo)
+ ctx := context.Background()
+ in := StartParsing(ctx, strings.NewReader(msg))
+ out := demuxer.Start(ctx, in)
+ buf := new(bytes.Buffer)
+ Consume(ComposePostProcessors(ctx, out, &FilterContextElements{},
+ NewBacktracePresenter(buf, NewBasicPresenter(buf, false))))
+ expected := " #0 0x00000000deadbeee in <>+0xdeadbeee this is a message\n"
+ actual := buf.String()
+ if actual != expected {
+ t.Errorf("want %q got %q", expected, actual)
+ }
+}
+
+func ExampleMsgBacktrace() {
+ // mock the input and outputs of llvm-symbolizer
+ symbo := newMockSymbolizer([]mockModule{
+ {"testdata/libc.elf", map[uint64][]SourceLocation{
+ 0x43680: {{NewOptStr("pow.c"), 23, NewOptStr("pow")}},
+ }},
+ })
+
+ // make a demuxer
+ demuxer := NewDemuxer(testBinaries, symbo)
+
+ // define a little message that will need to be parsed
+ msg := "{{{module:1:libc.so:elf:4fcb712aa6387724a9f465a32cd8c14b}}}\n" +
+ "{{{mmap:0x12345000:0xcf6bc:load:1:rx:0x0}}}\n" +
+ "{{{bt:0:0x12388681:sp 0xdeadbaaf bp 0xdeadbeef}}}\n"
+
+ // start sending InputLines to the demuxer
+ ctx := context.Background()
+ in := StartParsing(ctx, strings.NewReader(msg))
+ // start the demuxer which will cause filters to send output lines to 'out'
+ out := demuxer.Start(ctx, in)
+
+ Consume(ComposePostProcessors(ctx, out,
+ &FilterContextElements{},
+ NewBacktracePresenter(os.Stdout, NewBasicPresenter(os.Stdout, false))))
+
+ //Output:
+ // #0 0x0000000012388680 in pow pow.c:23 <libc.so>+0x43680 sp 0xdeadbaaf bp 0xdeadbeef
+}
+
func ExampleNoHeaderBacktrace() {
// mock the input and outputs of llvm-symbolizer
symbo := newMockSymbolizer([]mockModule{
diff --git a/symbolize/parser.go b/symbolize/parser.go
index 31b8f6a..eb14950 100644
--- a/symbolize/parser.go
+++ b/symbolize/parser.go
@@ -71,10 +71,11 @@
ptr := ptrRegexp
str := strRegexp
num := fmt.Sprintf("(?:%s|%s)", dec, ptr)
- b.addRule(fmt.Sprintf("{{{bt:(%s):(%s)}}}", dec, ptr), func(args ...string) {
+ b.addRule(fmt.Sprintf("{{{bt:(%s):(%s)(?::(%s))?}}}", dec, ptr, str), func(args ...string) {
out = append(out, &BacktraceElement{
num: str2dec(args[1]),
vaddr: str2int(args[2]),
+ msg: args[3],
})
})
b.addRule(fmt.Sprintf("{{{pc:(%s)}}}", ptr), func(args ...string) {
diff --git a/symbolize/presenter.go b/symbolize/presenter.go
index 5b93205..3430b78 100644
--- a/symbolize/presenter.go
+++ b/symbolize/presenter.go
@@ -27,14 +27,14 @@
}
}
-func printBacktrace(out io.Writer, hdr LineHeader, frame uint64, info addressInfo) {
+func printBacktrace(out io.Writer, hdr LineHeader, frame uint64, msg string, info addressInfo) {
modRelAddr := info.addr - info.seg.Vaddr + info.seg.ModRelAddr
var hdrString string
if hdr != nil {
hdrString = hdr.Present()
}
if len(info.locs) == 0 {
- fmt.Fprintf(out, "%s #%-4d %#016x in <%s>+%#x\n", hdrString, frame, info.addr, info.mod.Name, modRelAddr)
+ fmt.Fprintf(out, "%s #%-4d %#016x in <%s>+%#x %s\n", hdrString, frame, info.addr, info.mod.Name, modRelAddr, msg)
return
}
for i, loc := range info.locs {
@@ -54,7 +54,11 @@
if !loc.file.IsEmpty() {
fmt.Fprintf(out, " %s:%d", loc.file, loc.line)
}
- fmt.Fprintf(out, " <%s>+%#x\n", info.mod.Name, modRelAddr)
+ fmt.Fprintf(out, " <%s>+%#x", info.mod.Name, modRelAddr)
+ if msg != "" {
+ fmt.Fprintf(out, " %s", msg)
+ }
+ fmt.Fprintf(out, "\n")
}
}
@@ -70,7 +74,7 @@
func (b *BacktracePresenter) Process(line OutputLine, out chan<- OutputLine) {
if len(line.line) == 1 {
if bt, ok := line.line[0].(*BacktraceElement); ok {
- printBacktrace(b.out, line.header, bt.num, bt.info)
+ printBacktrace(b.out, line.header, bt.num, bt.msg, bt.info)
// Don't process a backtrace we've already output.
return
}
@@ -79,7 +83,7 @@
// Note that we're going to discard the text in front.
if txt, ok := line.line[0].(*Text); ok && isSpace(txt.text) {
if bt, ok := line.line[1].(*BacktraceElement); ok {
- printBacktrace(b.out, line.header, bt.num, bt.info)
+ printBacktrace(b.out, line.header, bt.num, bt.msg, bt.info)
// Don't process a backtrace we've already output.
return
}
diff --git a/symbolize/regextokenizer.go b/symbolize/regextokenizer.go
index c629e02..f94a871 100644
--- a/symbolize/regextokenizer.go
+++ b/symbolize/regextokenizer.go
@@ -93,7 +93,12 @@
for i := 0; i < regex.groupCount; i++ {
groupBeginIdx := locs[2*(regex.index+i)]
groupEndIdx := locs[2*(regex.index+i)+1]
- groups = append(groups, input[groupBeginIdx:groupEndIdx])
+ // When a group is optional it may not be included. Check for that.
+ if groupBeginIdx == -1 || groupEndIdx == -1 {
+ groups = append(groups, "")
+ } else {
+ groups = append(groups, input[groupBeginIdx:groupEndIdx])
+ }
}
// Pass the regex's groups to it
regex.action(groups...)