Sfoglia il codice sorgente

Prefer nm based function names to addr2line based names.

The names produced by addr2line are often incomplete.  Fix this by
falling back to nm to get function names and using the nm-provided
name if it is longer.
Raul Silvera 9 anni fa
parent
commit
d933d09123

+ 22
- 0
internal/binutils/addr2liner.go Vedi File

@@ -38,6 +38,11 @@ const (
38 38
 type addr2Liner struct {
39 39
 	rw   lineReaderWriter
40 40
 	base uint64
41
+
42
+	// nm holds an NM based addr2Liner which can provide
43
+	// better full names compared to addr2line, which often drops
44
+	// namespaces etc. from the names it returns.
45
+	nm *addr2LinerNM
41 46
 }
42 47
 
43 48
 // lineReaderWriter is an interface to abstract the I/O to an addr2line
@@ -193,5 +198,22 @@ func (d *addr2Liner) addrInfo(addr uint64) ([]plugin.Frame, error) {
193 198
 			stack = append(stack, frame)
194 199
 		}
195 200
 	}
201
+
202
+	// Get better name from nm if possible.
203
+	if len(stack) > 0 && d.nm != nil {
204
+		nm, err := d.nm.addrInfo(addr)
205
+		if err == nil && len(nm) > 0 {
206
+			// Last entry in frame list should match since
207
+			// it is non-inlined.  As a simple heuristic,
208
+			// we only switch to the nm-based name if it
209
+			// is longer.
210
+			nmName := nm[len(nm)-1].Func
211
+			a2lName := stack[len(stack)-1].Func
212
+			if len(nmName) > len(a2lName) {
213
+				stack[len(stack)-1].Func = nmName
214
+			}
215
+		}
216
+	}
217
+
196 218
 	return stack, nil
197 219
 }

+ 7
- 0
internal/binutils/binutils.go Vedi File

@@ -245,6 +245,13 @@ func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) {
245 245
 			return nil, err
246 246
 		}
247 247
 		f.addr2liner = addr2liner
248
+
249
+		// When addr2line encounters some gcc compiled binaries, it
250
+		// drops interesting parts of names in anonymous namespaces.
251
+		// Fallback to NM for better function names.
252
+		if nm, err := newAddr2LinerNM(f.b.nm, f.name, f.base); err == nil {
253
+			f.addr2liner.nm = nm
254
+		}
248 255
 	}
249 256
 	return f.addr2liner.addrInfo(addr)
250 257
 }

+ 1
- 1
internal/binutils/binutils_test.go Vedi File

@@ -37,7 +37,7 @@ func functionName(level int) (name string) {
37 37
 func TestAddr2Liner(t *testing.T) {
38 38
 	const offset = 0x500
39 39
 
40
-	a := addr2Liner{&mockAddr2liner{}, offset}
40
+	a := addr2Liner{&mockAddr2liner{}, offset, nil}
41 41
 	for i := 1; i < 8; i++ {
42 42
 		addr := i*0x1000 + offset
43 43
 		s, err := a.addrInfo(uint64(addr))