132 lines
2.4 KiB
Go
132 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"debug/elf"
|
|
"encoding/binary"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"sort"
|
|
)
|
|
|
|
type Header struct {
|
|
Sz byte
|
|
_ byte
|
|
Core uint16
|
|
_ uint16
|
|
Ver byte
|
|
Sig byte
|
|
Time uint64
|
|
}
|
|
|
|
type pc uint64
|
|
|
|
type Record struct {
|
|
Header
|
|
pcs []pc
|
|
}
|
|
|
|
|
|
type Symbol struct {
|
|
Addr uint64
|
|
Name string
|
|
}
|
|
|
|
type Symbols []*Symbol
|
|
|
|
func (s Symbols) Len() int { return len(s) }
|
|
func (s Symbols) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
type ByAddress struct{ Symbols }
|
|
|
|
func (s ByAddress) Less(i, j int) bool { return s.Symbols[i].Addr < s.Symbols[j].Addr }
|
|
|
|
var (
|
|
profile = flag.String("profile", "", "name of file containing profile data")
|
|
debug = flag.Bool("d", false, "Debug printing")
|
|
kernel = flag.String("kernel", "", "kernel to profile against")
|
|
symbolTable []*Symbol
|
|
)
|
|
|
|
func loadSymbols(kernel *elf.File) {
|
|
syms, err := kernel.Symbols()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
for _, sym := range syms {
|
|
value := sym.Value | 0xffffffff00000000
|
|
symbolTable = append(symbolTable, &Symbol{value, sym.Name})
|
|
}
|
|
sort.Sort(ByAddress{symbolTable})
|
|
}
|
|
|
|
func findFunction(pc pc) string {
|
|
addr := uint64(pc)
|
|
var prevSym *Symbol
|
|
for _, sym := range symbolTable {
|
|
if sym.Addr > addr && prevSym != nil {
|
|
return prevSym.Name
|
|
}
|
|
prevSym = sym
|
|
}
|
|
return "*** Not Found ***"
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
kernelElf, err := elf.Open(*kernel)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
loadSymbols(kernelElf)
|
|
|
|
backtraces, err := ioutil.ReadFile(*profile)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
b := bytes.NewBuffer(backtraces)
|
|
var numRecords int
|
|
var records []Record
|
|
for {
|
|
var h Header
|
|
if err := binary.Read(b, binary.LittleEndian, &h); err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
fmt.Fprintf(os.Stderr, "header: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if *debug {
|
|
fmt.Fprintf(os.Stderr, "%d: %v\n", numRecords, h)
|
|
}
|
|
|
|
if h.Sig != 0xee {
|
|
fmt.Fprintf(os.Stderr, "Record %d: sig is 0x%x, not 0xee", numRecords, h.Sig)
|
|
os.Exit(1)
|
|
}
|
|
pcs := make([]pc, h.Sz)
|
|
if err := binary.Read(b, binary.LittleEndian, pcs); err != nil {
|
|
fmt.Fprintf(os.Stderr, "data: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
numRecords++
|
|
records = append(records, Record{Header: h, pcs: pcs})
|
|
}
|
|
|
|
for _, r := range records {
|
|
fmt.Printf("0x%x: ", r.Time)
|
|
for _, pc := range r.pcs {
|
|
fmt.Printf("[0x%x, %s] ", pc, findFunction(pc))
|
|
}
|
|
fmt.Printf("\n")
|
|
}
|
|
}
|