Skip to content

Commit

Permalink
test for printing demangled names in disassembly
Browse files Browse the repository at this point in the history
  • Loading branch information
kalyanac authored and Kalyana Chadalavada committed Mar 13, 2019
1 parent e71d09f commit 8a1a78d
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 1 deletion.
8 changes: 8 additions & 0 deletions internal/binutils/binutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ func (bu *Binutils) Disasm(file string, start, end uint64) ([]plugin.Inst, error
fmt.Sprintf("--start-address=%#x", start),
fmt.Sprintf("--stop-address=%#x", end),
file)

if runtime.GOOS == "darwin" {
cmd = exec.Command(b.objdump, "-disassemble-all", "-no-show-raw-insn",
"-line-numbers", fmt.Sprintf("-start-address=%#x", start),
fmt.Sprintf("-stop-address=%#x", end),
file)
}

out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("%v: %v", cmd.Args, err)
Expand Down
8 changes: 7 additions & 1 deletion internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,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", demangle.Filter(s.sym.Name[0], options...))
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
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)
}
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 @@ -100,6 +103,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 @@ -123,6 +135,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 @@ -176,6 +194,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 @@ -213,6 +244,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;
}

0 comments on commit 8a1a78d

Please sign in to comment.