kpdump.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package main
  2. import (
  3. "debug/elf"
  4. "encoding/binary"
  5. "flag"
  6. "fmt"
  7. "io"
  8. "os"
  9. "math"
  10. )
  11. const LRES = 3
  12. var kernel = flag.String("k", "9k", "kernel name")
  13. func main() {
  14. flag.Parse()
  15. n := flag.Args()[0]
  16. d, err := os.Open(n)
  17. if err != nil {
  18. fmt.Fprintf(os.Stderr, "%v\n", err)
  19. os.Exit(1)
  20. }
  21. f, err := elf.Open(*kernel)
  22. if err != nil {
  23. fmt.Fprintf(os.Stderr, "%v\n", err)
  24. os.Exit(1)
  25. }
  26. var codeend uint64
  27. var codestart uint64 = math.MaxUint64
  28. for _, v := range f.Progs {
  29. if v.Type != elf.PT_LOAD {
  30. continue
  31. }
  32. fmt.Fprintf(os.Stderr, "processing %v\n", v)
  33. // MUST alignt to 2M page boundary.
  34. // then MUST allocate a []byte that
  35. // is the right size. And MUST
  36. // see if by some off chance it
  37. // joins to a pre-existing segment.
  38. // It's easier than it seems. We produce ONE text
  39. // array and ONE data array. So it's a matter of creating
  40. // a virtual memory space with an assumed starting point of
  41. // 0x200000, and filling it. We just grow that as needed.
  42. curstart := v.Vaddr
  43. curend := v.Vaddr + v.Memsz
  44. // magic numbers, BAH!
  45. if curstart < uint64(0xffffffff00000000) {
  46. curstart += 0xfffffffff0000000
  47. curend += 0xfffffffff0000000
  48. }
  49. fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
  50. if v.Flags&elf.PF_X == elf.PF_X {
  51. if curstart < codestart {
  52. codestart = curstart
  53. }
  54. if curend > codeend {
  55. codeend = curend
  56. }
  57. fmt.Fprintf(os.Stderr, "code s %x e %x\n", codestart, codeend)
  58. }
  59. }
  60. fmt.Fprintf(os.Stderr, "code s %x e %x\n", codestart, codeend)
  61. s, err := f.Symbols()
  62. if err != nil {
  63. fmt.Fprintf(os.Stderr, "%v\n", err)
  64. os.Exit(1)
  65. }
  66. // maybe we should stop doing LRES ...
  67. symname := make([]string, codeend - codestart)
  68. for i := range symname {
  69. symname[i] = fmt.Sprintf("[0x%x]", codestart + uint64(i))
  70. }
  71. for _, v := range s {
  72. vstart := v.Value
  73. vend := v.Value + v.Size
  74. if v.Value > codeend {
  75. continue
  76. }
  77. if v.Value + v.Size < codestart {
  78. continue
  79. }
  80. if vstart < codestart {
  81. v.Value = codestart
  82. }
  83. if vend > codeend {
  84. vend = codeend
  85. }
  86. for i := vstart; i < vend; i++ {
  87. symname[i-codestart] = v.Name
  88. }
  89. }
  90. symname[0] = "Total ms"
  91. symname[1<<LRES] = "Unknown"
  92. // now dump the info ...
  93. count := uint32(0)
  94. pc := codestart
  95. for {
  96. if err := binary.Read(d, binary.BigEndian, &count); err != nil {
  97. if err != io.EOF {
  98. fmt.Fprintf(os.Stderr, "%v\n", err)
  99. }
  100. break
  101. }
  102. if count > 0 {
  103. fmt.Printf("%s %d\n", symname[pc-codestart], count)
  104. }
  105. pc += (1 << LRES)
  106. }
  107. }