initial commit
This commit is contained in:
131
src/jehanne/cmd/profile/profile.go
Normal file
131
src/jehanne/cmd/profile/profile.go
Normal file
@ -0,0 +1,131 @@
|
||||
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")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user