Quellcode durchsuchen

Enable MacOS binutils test. (#322)

Alexey Alexandrov vor 7 Jahren
Ursprung
Commit
20ceacaff6

+ 4
- 3
.travis.yml Datei anzeigen

@@ -47,10 +47,11 @@ addons:
47 47
   apt:
48 48
     packages:
49 49
       - graphviz
50
-      
50
+
51 51
 before_install:
52
-  - go get -u github.com/golang/lint/golint honnef.co/go/tools/cmd/...   
53
-  - if [[ "$TRAVIS_OS_NAME" == "osx" && -z $SKIP_GRAPHVIZ ]]; then brew update          ; fi
52
+  - go get -u github.com/golang/lint/golint honnef.co/go/tools/cmd/...
53
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
54
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install binutils ; fi
54 55
   - if [[ "$TRAVIS_OS_NAME" == "osx" && -z $SKIP_GRAPHVIZ ]]; then brew install graphviz; fi
55 56
 
56 57
 script:

+ 16
- 9
internal/binutils/addr2liner.go Datei anzeigen

@@ -41,9 +41,11 @@ type addr2Liner struct {
41 41
 	rw   lineReaderWriter
42 42
 	base uint64
43 43
 
44
-	// nm holds an NM based addr2Liner which can provide
45
-	// better full names compared to addr2line, which often drops
46
-	// namespaces etc. from the names it returns.
44
+	// nm holds an addr2Liner using nm tool. Certain versions of addr2line
45
+	// produce incomplete names due to
46
+	// https://sourceware.org/bugzilla/show_bug.cgi?id=17541. As a workaround,
47
+	// the names from nm are used when they look more complete. See addrInfo()
48
+	// code below for the exact heuristic.
47 49
 	nm *addr2LinerNM
48 50
 }
49 51
 
@@ -215,17 +217,22 @@ func (d *addr2Liner) addrInfo(addr uint64) ([]plugin.Frame, error) {
215 217
 		return nil, err
216 218
 	}
217 219
 
218
-	// Get better name from nm if possible.
220
+	// Certain versions of addr2line produce incomplete names due to
221
+	// https://sourceware.org/bugzilla/show_bug.cgi?id=17541. Attempt to replace
222
+	// the name with a better one from nm.
219 223
 	if len(stack) > 0 && d.nm != nil {
220 224
 		nm, err := d.nm.addrInfo(addr)
221 225
 		if err == nil && len(nm) > 0 {
222
-			// Last entry in frame list should match since
223
-			// it is non-inlined. As a simple heuristic,
224
-			// we only switch to the nm-based name if it
225
-			// is longer.
226
+			// Last entry in frame list should match since it is non-inlined. As a
227
+			// simple heuristic, we only switch to the nm-based name if it is longer
228
+			// by 2 or more characters. We consider nm names that are longer by 1
229
+			// character insignificant to avoid replacing foo with _foo on MacOS (for
230
+			// unknown reasons read2line produces the former and nm produces the
231
+			// latter on MacOS even though both tools are asked to produce mangled
232
+			// names).
226 233
 			nmName := nm[len(nm)-1].Func
227 234
 			a2lName := stack[len(stack)-1].Func
228
-			if len(nmName) > len(a2lName) {
235
+			if len(nmName) > len(a2lName)+1 {
229 236
 				stack[len(stack)-1].Func = nmName
230 237
 			}
231 238
 		}

+ 8
- 3
internal/binutils/binutils.go Datei anzeigen

@@ -111,6 +111,11 @@ func initTools(b *binrep, config string) {
111 111
 	defaultPath := paths[""]
112 112
 	b.llvmSymbolizer, b.llvmSymbolizerFound = findExe("llvm-symbolizer", append(paths["llvm-symbolizer"], defaultPath...))
113 113
 	b.addr2line, b.addr2lineFound = findExe("addr2line", append(paths["addr2line"], defaultPath...))
114
+	if !b.addr2lineFound {
115
+		// On MacOS, brew installs addr2line under gaddr2line name, so search for
116
+		// that if the tool is not found by its default name.
117
+		b.addr2line, b.addr2lineFound = findExe("gaddr2line", append(paths["addr2line"], defaultPath...))
118
+	}
114 119
 	b.nm, b.nmFound = findExe("nm", append(paths["nm"], defaultPath...))
115 120
 	b.objdump, b.objdumpFound = findExe("objdump", append(paths["objdump"], defaultPath...))
116 121
 }
@@ -306,9 +311,9 @@ func (f *fileNM) SourceLine(addr uint64) ([]plugin.Frame, error) {
306 311
 }
307 312
 
308 313
 // fileAddr2Line implements the binutils.ObjFile interface, using
309
-// 'addr2line' to map addresses to symbols (with file/line number
310
-// information). It can be slow for large binaries with debug
311
-// information.
314
+// llvm-symbolizer, if that's available, or addr2line to map addresses to
315
+// symbols (with file/line number information). It can be slow for large
316
+// binaries with debug information.
312 317
 type fileAddr2Line struct {
313 318
 	once sync.Once
314 319
 	file

+ 1
- 3
internal/binutils/binutils_test.go Datei anzeigen

@@ -265,8 +265,6 @@ func TestObjFile(t *testing.T) {
265 265
 func TestMachoFiles(t *testing.T) {
266 266
 	skipUnlessDarwinAmd64(t)
267 267
 
268
-	t.Skip("Disabled because of issues with addr2line (see https://github.com/google/pprof/pull/313#issuecomment-364073010)")
269
-
270 268
 	// Load `file`, pretending it was mapped at `start`. Then get the symbol
271 269
 	// table. Check that it contains the symbol `sym` and that the address
272 270
 	// `addr` gives the `expected` stack trace.
@@ -291,7 +289,7 @@ func TestMachoFiles(t *testing.T) {
291 289
 		{"lib normal mapping", "lib_mac_64", 0, math.MaxUint64, 0,
292 290
 			0xfa0, "_bar",
293 291
 			[]plugin.Frame{
294
-				{Func: "bar", File: "/tmp/lib.c", Line: 6},
292
+				{Func: "bar", File: "/tmp/lib.c", Line: 5},
295 293
 			}},
296 294
 	} {
297 295
 		t.Run(tc.desc, func(t *testing.T) {

+ 31
- 0
internal/binutils/testdata/build_mac.sh Datei anzeigen

@@ -0,0 +1,31 @@
1
+#!/bin/bash -x
2
+
3
+# This is a script that generates the test MacOS executables in this directory.
4
+# It should be needed very rarely to run this script. It is mostly provided
5
+# as a future reference on how the original binary set was created.
6
+
7
+set -o errexit
8
+
9
+cat <<EOF >/tmp/hello.cc
10
+#include <stdio.h>
11
+
12
+int main() {
13
+  printf("Hello, world!\n");
14
+  return 0;
15
+}
16
+EOF
17
+
18
+cat <<EOF >/tmp/lib.c
19
+int foo() {
20
+  return 1;
21
+}
22
+
23
+int bar() {
24
+  return 2;
25
+}
26
+EOF
27
+
28
+cd $(dirname $0)
29
+rm -rf exe_mac_64* lib_mac_64*
30
+clang -g -o exe_mac_64 /tmp/hello.c
31
+clang -g -o lib_mac_64 -dynamiclib /tmp/lib.c

BIN
internal/binutils/testdata/exe_mac_64 Datei anzeigen


+ 20
- 0
internal/binutils/testdata/exe_mac_64.dSYM/Contents/Info.plist Datei anzeigen

@@ -0,0 +1,20 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+	<dict>
5
+		<key>CFBundleDevelopmentRegion</key>
6
+		<string>English</string>
7
+		<key>CFBundleIdentifier</key>
8
+		<string>com.apple.xcode.dsym.exe_mac_64</string>
9
+		<key>CFBundleInfoDictionaryVersion</key>
10
+		<string>6.0</string>
11
+		<key>CFBundlePackageType</key>
12
+		<string>dSYM</string>
13
+		<key>CFBundleSignature</key>
14
+		<string>????</string>
15
+		<key>CFBundleShortVersionString</key>
16
+		<string>1.0</string>
17
+		<key>CFBundleVersion</key>
18
+		<string>1</string>
19
+	</dict>
20
+</plist>

BIN
internal/binutils/testdata/exe_mac_64.dSYM/Contents/Resources/DWARF/exe_mac_64 Datei anzeigen


BIN
internal/binutils/testdata/lib_mac_64 Datei anzeigen


+ 20
- 0
internal/binutils/testdata/lib_mac_64.dSYM/Contents/Info.plist Datei anzeigen

@@ -0,0 +1,20 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+	<dict>
5
+		<key>CFBundleDevelopmentRegion</key>
6
+		<string>English</string>
7
+		<key>CFBundleIdentifier</key>
8
+		<string>com.apple.xcode.dsym.lib_mac_64</string>
9
+		<key>CFBundleInfoDictionaryVersion</key>
10
+		<string>6.0</string>
11
+		<key>CFBundlePackageType</key>
12
+		<string>dSYM</string>
13
+		<key>CFBundleSignature</key>
14
+		<string>????</string>
15
+		<key>CFBundleShortVersionString</key>
16
+		<string>1.0</string>
17
+		<key>CFBundleVersion</key>
18
+		<string>1</string>
19
+	</dict>
20
+</plist>

BIN
internal/binutils/testdata/lib_mac_64.dSYM/Contents/Resources/DWARF/lib_mac_64 Datei anzeigen