Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use simplified demangled symbol names in disassembly report #449

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions internal/binutils/binutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([]
"--line-numbers", fmt.Sprintf("--start-address=%#x", start),
fmt.Sprintf("--stop-address=%#x", end)}

if runtime.GOOS == "darwin" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So without this disasm doesn't work on Mac at all? If that's the case perhaps we should put this on its own PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

args = []string{"-disassemble-all", "-no-show-raw-insn",
"-line-numbers", fmt.Sprintf("-start-address=%#x", start),
fmt.Sprintf("-stop-address=%#x", end)}
}

if intelSyntax {
if b.isLLVMObjdump {
args = append(args, "--x86-asm-syntax=intel")
Expand Down
14 changes: 12 additions & 2 deletions internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/google/pprof/internal/measurement"
"github.com/google/pprof/internal/plugin"
"github.com/google/pprof/profile"
"github.com/ianlancetaylor/demangle"
)

// Output formats.
Expand Down Expand Up @@ -432,6 +433,9 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e
}
}

// demangle symbols by default for disassembly report
options := []demangle.Option{demangle.NoParams, demangle.NoTemplateParams}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've preferred to have a way to control this, (eg with symbolize=demangle=xxx). Sometimes having the mangled name is useful


// Correlate the symbols from the binary with the profile samples.
for _, s := range syms {
sns := symNodes[s]
Expand All @@ -447,7 +451,13 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e

ns := annotateAssembly(insts, sns, s.base)

fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0])
if strings.HasPrefix(s.sym.Name[0], "__Z") {
// Workaround to handle double leading underscores on Mac
// which are not properly handled by the demangle.Filter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we open an issue against the demangle package for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fmt.Fprintf(w, "ROUTINE ======================== %s\n", demangle.Filter(s.sym.Name[0][1:], options...))
} else {
fmt.Fprintf(w, "ROUTINE ======================== %s\n", demangle.Filter(s.sym.Name[0], options...))
}
for _, name := range s.sym.Name[1:] {
fmt.Fprintf(w, " AKA ======================== %s\n", name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we demangle these ones too?

}
Expand All @@ -462,7 +472,7 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e
if n.function != function || n.file != file || n.line != line {
function, file, line = n.function, n.file, n.line
if n.function != "" {
locStr = n.function + " "
locStr = demangle.Filter(n.function, options...) + " "
}
if n.file != "" {
locStr += n.file
Expand Down
111 changes: 111 additions & 0 deletions internal/report/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ package report
import (
"bytes"
"io/ioutil"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"testing"

"github.com/google/pprof/internal/binutils"
Expand Down Expand Up @@ -105,6 +108,15 @@ var testM = []*profile.Mapping{
HasLineNumbers: true,
HasInlineFrames: true,
},
{
// Entry for disassembly demangle test
ID: 2,
File: "testdata/disasm.bin",
HasFunctions: true,
HasFilenames: true,
HasLineNumbers: true,
HasInlineFrames: true,
},
}

var testF = []*profile.Function{
Expand All @@ -128,6 +140,12 @@ var testF = []*profile.Function{
Name: "tee",
Filename: "/some/path/testdata/source2",
},
{
// Entry for disassembly demangle test
ID: 5,
Name: "_ZStL8__ioinit",
Filename: "testdata/sample/disasm.cc",
},
}

var testL = []*profile.Location{
Expand Down Expand Up @@ -181,6 +199,19 @@ var testL = []*profile.Location{
},
},
},
{
// Entry for disassembly demangle test
ID: 6,
Mapping: testM[1],
// Update the following address if the binary disasm.bin is rebuilt
Address: 2101617,
Line: []profile.Line{
{
Function: testF[4],
Line: 2,
},
},
},
}

var testProfile = &profile.Profile{
Expand Down Expand Up @@ -218,6 +249,86 @@ var testProfile = &profile.Profile{
Mapping: testM,
}

func TestPrintAssembly(t *testing.T) {

if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
t.Skip("This test only works on Linux or Mac")
}

demangled := "ioinit"

if runtime.GOOS == "darwin" {
// get objdump version and skip test if < 9.0
// binutils does not export get(). Try to get objdump version on our own.
// only works if objdump is in path.
cmdOut, err := exec.Command("objdump", "-version").Output()
if err != nil {
t.Skip("cannot determine objdump version.", err)
}

re := regexp.MustCompile(`.*version (([0-9]*)\.([0-9]*)\.([0-9]*)).*$`)
fields := re.FindStringSubmatch(strings.Split(string(cmdOut), "\n")[0])
if len(fields) != 5 {
t.Skip("cannot determine objdump version.", fields)
}

if ver, _ := strconv.Atoi(fields[2]); ver < 9 {
t.Skip("objdump version too old. ", fields[0])
}

testM[1].File = "testdata/disasm.mac.bin"
testM[1].Start = 0x100000000
testL[5].Address = 0
testF[4].Name = "__ZNSt3__111char_traitsIcE11eq_int_typeEii"
// Update the following address if the binary, disasm.mac.bin is rebuilt
testL[5].Address = 0x100001cd0
demangled = "eq_int_type"
}

sampleValue1 := func(v []int64) int64 {
return v[1]
}

asmProfile := testProfile.Copy()
asmProfile.Sample = []*profile.Sample{
{
Location: []*profile.Location{testL[5]},
Value: []int64{1, 1000},
},
}

tc := testcase{
rpt: New(
asmProfile,
&Options{
OutputFormat: Dis,
Symbol: regexp.MustCompile(`.`),
TrimPath: "/some/path",
SampleValue: sampleValue1,
},
),
want: demangled,
}

var b bytes.Buffer
if err := Generate(&b, tc.rpt, &binutils.Binutils{}); err != nil {
t.Fatalf("%s: %v", tc.want, err)
}

r := regexp.MustCompile(`( *ROUTINE.*={24} )(.*)`)
fields := r.FindStringSubmatch(b.String())
if len(fields) != 3 {
t.Fatalf("want: %s\n got: %s\n", tc.want, string(b.String()))
}

demangledName := fields[2]

if !(strings.Contains(demangledName, tc.want)) ||
(strings.Contains(demangledName, "_Z")) {
t.Fatalf("want: %s\n got: %s\n", tc.want, string(b.String()))
}
}

func TestDisambiguation(t *testing.T) {
parent1 := &graph.Node{Info: graph.NodeInfo{Name: "parent1"}}
parent2 := &graph.Node{Info: graph.NodeInfo{Name: "parent2"}}
Expand Down
8 changes: 8 additions & 0 deletions internal/report/testdata/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ To update the binary and profile:
go build -o sample.bin ./sample
./sample.bin -cpuprofile sample.cpu
```

To update the binary used for PrintAssembly test:
```shell
g++ -o disasm[.mac].bin disasm.cc
```

The address for testL[5] need to be manually updated
with the new adddess for the corresponding symbols
Binary file added internal/report/testdata/disasm.bin
Binary file not shown.
Binary file added internal/report/testdata/disasm.mac.bin
Binary file not shown.
24 changes: 24 additions & 0 deletions internal/report/testdata/sample/disasm.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// sample program that is used to produce some of the files in
// pprof/internal/report/testdata.

#include <iostream>

using namespace std;
int main(int argc, char** argv) {
cout << "Hello World!" << endl;
return 0;
}