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 llvm-symbolizer's JSON output to provide function start lines #891

Merged
merged 9 commits into from
Sep 29, 2024
21 changes: 21 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,23 @@ jobs:
run: |
google-chrome --version

- name: Add LLVM 14.0 repository to ensure llvm-symbolizer 14.0.0+ on Ubuntu 20.04
if: matrix.os == 'ubuntu-20.04'
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main"
sudo apt-get update

- name: Install llvm-symbolizer
run: |
if [ "${{ matrix.os }}" = "ubuntu-20.04" ]; then
sudo apt-get install -y llvm-14 clang-14
sudo update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-14 100
else
sudo apt-get update
sudo apt-get install -y llvm clang
fi

- name: Fetch dependencies
run: |
sudo apt-get install graphviz
Expand All @@ -154,6 +171,10 @@ jobs:
# Add PATH for installed tools.
echo "$GOPATH/bin:$PATH" >> $GITHUB_PATH

- name: Check llvm-symbolizer installation
run: |
llvm-symbolizer --version

- name: Run the script
run: |
go version
Expand Down
9 changes: 5 additions & 4 deletions driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ type ObjFile interface {

// A Frame describes a single line in a source file.
type Frame struct {
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in file
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in file
StartLine int // start line of function (if available)
}

// A Sym describes a single symbol in an object file.
Expand Down
11 changes: 6 additions & 5 deletions internal/binutils/addr2liner_llvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,19 @@ func (d *llvmSymbolizer) readCodeFrames() ([]plugin.Frame, error) {
Address string `json:"Address"`
ModuleName string `json:"ModuleName"`
Symbol []struct {
Line int `json:"Line"`
Column int `json:"Column"`
FunctionName string `json:"FunctionName"`
FileName string `json:"FileName"`
Line int `json:"Line"`
Column int `json:"Column"`
FunctionName string `json:"FunctionName"`
FileName string `json:"FileName"`
StartLine int `json:"StartLine"`
} `json:"Symbol"`
}
if err := json.Unmarshal([]byte(line), &frame); err != nil {
return nil, err
}
var stack []plugin.Frame
for _, s := range frame.Symbol {
stack = append(stack, plugin.Frame{Func: s.FunctionName, File: s.FileName, Line: s.Line, Column: s.Column})
stack = append(stack, plugin.Frame{Func: s.FunctionName, File: s.FileName, Line: s.Line, Column: s.Column, StartLine: s.StartLine})
}
return stack, nil
}
Expand Down
14 changes: 7 additions & 7 deletions internal/binutils/binutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ func TestObjFile(t *testing.T) {
t.Fatalf("SourceLine: unexpected error %v", err)
}
wantFrames := []plugin.Frame{
{Func: "main", File: "/tmp/hello.c", Line: 3},
{Func: "main", File: "/tmp/hello.c", Line: 3, StartLine: 3},
}
if !reflect.DeepEqual(gotFrames, wantFrames) {
t.Fatalf("SourceLine for main: got %v; want %v\n", gotFrames, wantFrames)
Expand Down Expand Up @@ -402,17 +402,17 @@ func TestMachoFiles(t *testing.T) {
{"normal mapping", "exe_mac_64", 0x100000000, math.MaxUint64, 0,
0x100000f50, "_main",
[]plugin.Frame{
{Func: "main", File: "/tmp/hello.c", Line: 3},
{Func: "main", File: "/tmp/hello.c", Line: 3, StartLine: 3},
}},
{"other mapping", "exe_mac_64", 0x200000000, math.MaxUint64, 0,
0x200000f50, "_main",
[]plugin.Frame{
{Func: "main", File: "/tmp/hello.c", Line: 3},
{Func: "main", File: "/tmp/hello.c", Line: 3, StartLine: 3},
}},
{"lib normal mapping", "lib_mac_64", 0, math.MaxUint64, 0,
0xfa0, "_bar",
[]plugin.Frame{
{Func: "bar", File: "/tmp/lib.c", Line: 5},
{Func: "bar", File: "/tmp/lib.c", Line: 5, StartLine: 5},
}},
} {
t.Run(tc.desc, func(t *testing.T) {
Expand Down Expand Up @@ -461,8 +461,8 @@ func TestLLVMSymbolizer(t *testing.T) {
frames []plugin.Frame
}{
{0x10, false, []plugin.Frame{
{Func: "Inlined_0x10", File: "foo.h", Line: 0, Column: 0},
{Func: "Func_0x10", File: "foo.c", Line: 2, Column: 1},
{Func: "Inlined_0x10", File: "foo.h", Line: 0, Column: 0, StartLine: 0},
{Func: "Func_0x10", File: "foo.c", Line: 2, Column: 1, StartLine: 2},
}},
{0x20, true, []plugin.Frame{
{Func: "foo_0x20", File: "0x20 8"},
Expand Down Expand Up @@ -532,7 +532,7 @@ func TestPEFile(t *testing.T) {
t.Fatalf("SourceLine: unexpected error %v", err)
}
wantFrames := []plugin.Frame{
{Func: "main", File: "hello.c", Line: 3, Column: 12},
{Func: "main", File: "hello.c", Line: 3, Column: 12, StartLine: 3},
}
if !reflect.DeepEqual(gotFrames, wantFrames) {
t.Fatalf("SourceLine for main: got %v; want %v\n", gotFrames, wantFrames)
Expand Down
2 changes: 1 addition & 1 deletion internal/binutils/testdata/fake-llvm-symbolizer
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ while read line; do
addr=$3
case ${kind} in
CODE)
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Symbol\":[{\"Column\":0,\"FileName\":\"${fname}.h\",\"FunctionName\":\"Inlined_${addr}\",\"Line\":0},{\"Column\":1,\"FileName\":\"${fname}.c\",\"FunctionName\":\"Func_${addr}\",\"Line\":2}]}"
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Symbol\":[{\"Column\":0,\"FileName\":\"${fname}.h\",\"FunctionName\":\"Inlined_${addr}\",\"Line\":0,\"StartLine\":0},{\"Column\":1,\"FileName\":\"${fname}.c\",\"FunctionName\":\"Func_${addr}\",\"Line\":2,\"StartLine\":2}]}"
;;
DATA)
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Data\":{\"Name\":\"${fname}_${addr}\",\"Size\":\"0x8\",\"Start\":\"${addr}\"}}"
Expand Down
9 changes: 5 additions & 4 deletions internal/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,11 @@ type ObjFile interface {

// A Frame describes a location in a single line in a source file.
type Frame struct {
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in line (if available)
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in line (if available)
StartLine int // start line of function (if available)
}

// A Sym describes a single symbol in an object file.
Expand Down
1 change: 1 addition & 0 deletions internal/symbolizer/symbolizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ func symbolizeOneMapping(m *profile.Mapping, locs []*profile.Location, obj plugi
Name: frame.Func,
SystemName: frame.Func,
Filename: frame.File,
StartLine: int64(frame.StartLine),
})
l.Line[i] = profile.Line{
Function: f,
Expand Down
Loading