-
Notifications
You must be signed in to change notification settings - Fork 645
Prototype(symbolization): Add symbolization in Pyroscope read path #3799
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
base: main
Are you sure you want to change the base?
Changes from all commits
268d7f1
2024309
ad040af
deb91ca
8754fc9
9c26ec5
7918c09
362cabd
f0a9e7b
a76010f
f4c869e
3130e2a
2a4b163
98ec7f9
91a4bb2
a054f58
c38dac7
8628f33
c650907
af13cfb
fa1ff76
73a48aa
95f8a6f
0008486
ca335b8
762a596
13c2659
3522cd0
a6bd5c9
61d2b41
1ca0b6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
|
||
log2 "github.com/go-kit/log" | ||
|
||
googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" | ||
"github.com/grafana/pyroscope/pkg/experiment/symbolizer" | ||
) | ||
|
||
const ( | ||
// buildID = "c047672cae7964324658491e7dee26748ae5d2f8" | ||
//buildID = "2fa2055ef20fabc972d5751147e093275514b142" | ||
buildID = "6d64b17fbac799e68da7ebd9985ddf9b5cb375e6" | ||
invalidName = "<invalid>" | ||
) | ||
|
||
func main() { | ||
client := &localDebuginfodClient{debugFilePath: "/usr/lib/debug/.build-id/6d/64b17fbac799e68da7ebd9985ddf9b5cb375e6.debug"} | ||
logger := log2.NewLogfmtLogger(os.Stdout) | ||
s, err := symbolizer.NewProfileSymbolizer(logger, client, nil, symbolizer.NewMetrics(nil), 10, 10) | ||
|
||
if err != nil { | ||
log.Fatalf("Failed to create debuginfod client: %v", err) | ||
} | ||
|
||
ctx := context.Background() | ||
_, err = client.FetchDebuginfo(ctx, buildID) | ||
if err != nil { | ||
log.Fatalf("Failed to fetch debug info: %v", err) | ||
} | ||
|
||
profile := &googlev1.Profile{ | ||
Mapping: []*googlev1.Mapping{{ | ||
MemoryStart: 0x28000, | ||
MemoryLimit: 0x1b0000, | ||
FileOffset: 0x28000, | ||
}}, | ||
Location: []*googlev1.Location{ | ||
{ | ||
MappingId: 1, | ||
Address: 0x2a28a, | ||
}, | ||
{ | ||
MappingId: 1, | ||
Address: 0x124dec, | ||
}, | ||
{ | ||
MappingId: 1, | ||
Address: 0x2a1c9, | ||
}, | ||
}, | ||
StringTable: []string{"", buildID}, | ||
} | ||
|
||
if err := s.SymbolizePprof(ctx, profile); err != nil { | ||
log.Fatalf("Failed to symbolize: %v", err) | ||
} | ||
|
||
printResults(profile) | ||
} | ||
|
||
func printResults(p *googlev1.Profile) { | ||
fmt.Println("Symbolization Results:") | ||
|
||
fmt.Println("\nFunction Table:") | ||
for i, fn := range p.Function { | ||
name := invalidName | ||
if fn.Name >= 0 && int(fn.Name) < len(p.StringTable) { | ||
name = p.StringTable[fn.Name] | ||
} | ||
|
||
filename := invalidName | ||
if fn.Filename >= 0 && int(fn.Filename) < len(p.StringTable) { | ||
filename = p.StringTable[fn.Filename] | ||
} | ||
|
||
fmt.Printf(" Function[%d]: ID=%d, Name=%s, File=%s, StartLine=%d\n", | ||
i, fn.Id, name, filename, fn.StartLine) | ||
} | ||
|
||
fmt.Println("\nLocations:") | ||
for _, loc := range p.Location { | ||
fmt.Printf("\nAddress: 0x%x\n", loc.Address) | ||
if len(loc.Line) == 0 { | ||
fmt.Println(" No symbolization information found") | ||
continue | ||
} | ||
|
||
for i, line := range loc.Line { | ||
fmt.Printf(" Line %d (FunctionID=%d):\n", i+1, line.FunctionId) | ||
|
||
var fn *googlev1.Function | ||
for _, function := range p.Function { | ||
if function.Id == line.FunctionId { | ||
fn = function | ||
break | ||
} | ||
} | ||
|
||
if fn != nil { | ||
name := invalidName | ||
if fn.Name >= 0 && int(fn.Name) < len(p.StringTable) { | ||
name = p.StringTable[fn.Name] | ||
} | ||
|
||
filename := invalidName | ||
if fn.Filename >= 0 && int(fn.Filename) < len(p.StringTable) { | ||
filename = p.StringTable[fn.Filename] | ||
} | ||
|
||
fmt.Printf(" Function: %s\n", name) | ||
fmt.Printf(" File: %s\n", filename) | ||
fmt.Printf(" Line: %d\n", line.Line) | ||
fmt.Printf(" StartLine: %d\n", fn.StartLine) | ||
} else { | ||
fmt.Printf(" ERROR: Cannot find function with ID %d\n", line.FunctionId) | ||
} | ||
} | ||
} | ||
fmt.Println("\nSymbolization completed successfully.") | ||
} | ||
|
||
type localDebuginfodClient struct { | ||
debugFilePath string | ||
} | ||
|
||
func (c *localDebuginfodClient) FetchDebuginfo(ctx context.Context, buildID string) (io.ReadCloser, error) { | ||
return os.Open(c.debugFilePath) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package lidia | ||
|
||
// BinaryLayoutInfo represents the layout information of the binary | ||
type BinaryLayoutInfo struct { | ||
Type uint16 // e_type from ELF header | ||
ProgramHeaders []ProgramHeaderInfo | ||
} | ||
|
||
// ProgramHeaderInfo represents a program header from the ELF file | ||
type ProgramHeaderInfo struct { | ||
Type uint32 | ||
Flags uint32 | ||
Offset uint64 | ||
VirtualAddr uint64 | ||
PhysAddr uint64 | ||
FileSize uint64 | ||
MemSize uint64 | ||
Align uint64 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,11 +11,14 @@ const ( | |
version uint32 = 1 | ||
|
||
// Size of the file header in bytes | ||
headerSize = 0x80 | ||
headerSize = 0x98 | ||
|
||
// Number of fields in a line table entry | ||
lineTableFieldsCount = 2 | ||
|
||
// Size of each line table entry (2 uint16s or 2 uint32s) | ||
lineTableFieldsSize = 4 | ||
|
||
Comment on lines
13
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just in case: does such change invalidate existing objects? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll remove the constant to properly calculate this dynamically as: entrySize := 4
if hdr.lineTablesHeader.fieldSize == 4 {
entrySize = 8
}
hdr.binaryLayoutHeader.offset = hdr.lineTablesHeader.offset + uint64(len(rc.lb.entries)*entrySize) But answer your question, no, this should only affect the offset calculation when writing a new file, ensuring that the binary layout section starts at the correct position. It has no impact on how we read existing files. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. N/A anymore since we removed |
||
// Number of fields in a range entry | ||
fieldsCount = 8 | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not as of now.