From d3e8f08f54994635e71af01cc926b10d9103e0a4 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sat, 7 Jul 2018 22:22:57 +0100 Subject: [PATCH] Initial work to get full output format working --- entry.go | 20 ++++++ heap_dump.go | 71 +++++++++++++++++--- heap_entry.go | 9 --- main.go | 22 +++--- object.go | 21 ++++++ heap_entry_easyjson.go => object_easyjson.go | 20 +++--- 6 files changed, 124 insertions(+), 39 deletions(-) create mode 100644 entry.go delete mode 100644 heap_entry.go create mode 100644 object.go rename heap_entry_easyjson.go => object_easyjson.go (72%) diff --git a/entry.go b/entry.go new file mode 100644 index 0000000..498df0e --- /dev/null +++ b/entry.go @@ -0,0 +1,20 @@ +package main + +func NewEntry(inputJSON []byte) (*Entry, error) { + obj, err := NewObject(inputJSON) + if err != nil { + return nil, err + } + + return &Entry{ + Object: obj, + Index: obj.Index(), + }, err +} + +// Entry is a parsed heap item object +type Entry struct { + Object *Object + Offset int64 + Index string +} diff --git a/heap_dump.go b/heap_dump.go index 39053f4..636a74a 100644 --- a/heap_dump.go +++ b/heap_dump.go @@ -1,9 +1,11 @@ package main import ( - "encoding/json" + "bufio" + "fmt" "io" "os" + "sort" ) func NewHeapDump(file string) (*HeapDump, error) { @@ -16,7 +18,7 @@ func NewHeapDump(file string) (*HeapDump, error) { type HeapDump struct { File string Index []string - Entries map[string]*HeapEntry + Entries map[string]*Entry } // Process processes the heap dump @@ -28,20 +30,71 @@ func (s *HeapDump) Process() error { return err } - s.Entries = map[string]*HeapEntry{} + s.Entries = map[string]*Entry{} - d := json.NewDecoder(file) + reader := bufio.NewReader(file) + var offset int64 = -1 for { - var e HeapEntry - if err := d.Decode(&e); err == io.EOF { + offset++ + line, err := reader.ReadBytes(byte('\n')) + if err == io.EOF { break } else if err != nil { return err } - index := e.Address + ":" + e.Type - s.Entries[index] = &e - s.Index = append(s.Index, index) + + entry, err := NewEntry(line) + if err != nil { + return err + } + + entry.Offset = offset + s.Entries[entry.Index] = entry + s.Index = append(s.Index, entry.Index) } return nil } + +func (s *HeapDump) PrintMatchingJSON(indexes *[]string) error { + file, err := os.Open(s.File) + defer file.Close() + + if err != nil { + return err + } + + reader := bufio.NewReader(file) + offsets := s.matchingOffsets(indexes) + + var current int64 = 0 + var offset int64 = -1 + + for { + offset++ + line, err := reader.ReadBytes(byte('\n')) + if err == io.EOF { + break + } else if err != nil { + return err + } + + if offset == offsets[current] { + current++ + fmt.Print(string(line)) + } + } + + return nil +} + +func (s *HeapDump) matchingOffsets(indexes *[]string) []int64 { + var offsets []int64 + + for _, index := range *indexes { + offsets = append(offsets, s.Entries[index].Offset) + } + + sort.Slice(offsets, func(i, j int) bool { return offsets[i] < offsets[j] }) + return offsets +} diff --git a/heap_entry.go b/heap_entry.go deleted file mode 100644 index 0b26170..0000000 --- a/heap_entry.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -//go:generate easyjson -all heap_entry.go - -// HeapEntry is a parsed heap item object -type HeapEntry struct { - Address string `json:"address"` - Type string `json:"type"` -} diff --git a/main.go b/main.go index 0b9c6d4..6bb5a5a 100644 --- a/main.go +++ b/main.go @@ -49,14 +49,6 @@ func versionString() string { return buffer.String() } -func printHexDiff(leaked *[]string, dump *HeapDump) { - for _, index := range *leaked { - if item, ok := dump.Entries[index]; ok { - fmt.Printf("%s\n", item.Address) - } - } -} - func logMsg(msg string) { if !*silentFlag { fmt.Println(msg) @@ -70,6 +62,14 @@ func loadDump(filePath string) (*HeapDump, error) { return dump, err } +func printHexDiff(leaked *[]string, dump *HeapDump) { + for _, index := range *leaked { + if entry, ok := dump.Entries[index]; ok { + fmt.Println(entry.Object.Address) + } + } +} + func main() { kingpin.Version(versionString()) kingpin.Parse() @@ -93,7 +93,7 @@ func main() { if *formatFlag == "hex" { printHexDiff(leaked, dump2) - } // else if *formatFlag == 'full' { - // printFullDiff(leaked, dump2) - // } + } else if *formatFlag == "full" { + dump2.PrintMatchingJSON(leaked) + } } diff --git a/object.go b/object.go new file mode 100644 index 0000000..3da23d2 --- /dev/null +++ b/object.go @@ -0,0 +1,21 @@ +package main + +import "encoding/json" + +//go:generate easyjson -all object.go + +func NewObject(inputJSON []byte) (*Object, error) { + var obj Object + err := json.Unmarshal(inputJSON, &obj) + + return &obj, err +} + +type Object struct { + Address string `json:"address"` + Type string `json:"type"` +} + +func (s *Object) Index() string { + return s.Address + ":" + s.Type +} diff --git a/heap_entry_easyjson.go b/object_easyjson.go similarity index 72% rename from heap_entry_easyjson.go rename to object_easyjson.go index 4fa57bd..27605d1 100644 --- a/heap_entry_easyjson.go +++ b/object_easyjson.go @@ -17,7 +17,7 @@ var ( _ easyjson.Marshaler ) -func easyjson48125c2bDecodeGithubComJimehRbheapleak(in *jlexer.Lexer, out *HeapEntry) { +func easyjsonE44bcf2dDecodeGithubComJimehRbheapleak(in *jlexer.Lexer, out *Object) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -50,7 +50,7 @@ func easyjson48125c2bDecodeGithubComJimehRbheapleak(in *jlexer.Lexer, out *HeapE in.Consumed() } } -func easyjson48125c2bEncodeGithubComJimehRbheapleak(out *jwriter.Writer, in HeapEntry) { +func easyjsonE44bcf2dEncodeGithubComJimehRbheapleak(out *jwriter.Writer, in Object) { out.RawByte('{') first := true _ = first @@ -78,25 +78,25 @@ func easyjson48125c2bEncodeGithubComJimehRbheapleak(out *jwriter.Writer, in Heap } // MarshalJSON supports json.Marshaler interface -func (v HeapEntry) MarshalJSON() ([]byte, error) { +func (v Object) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjson48125c2bEncodeGithubComJimehRbheapleak(&w, v) + easyjsonE44bcf2dEncodeGithubComJimehRbheapleak(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface -func (v HeapEntry) MarshalEasyJSON(w *jwriter.Writer) { - easyjson48125c2bEncodeGithubComJimehRbheapleak(w, v) +func (v Object) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonE44bcf2dEncodeGithubComJimehRbheapleak(w, v) } // UnmarshalJSON supports json.Unmarshaler interface -func (v *HeapEntry) UnmarshalJSON(data []byte) error { +func (v *Object) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjson48125c2bDecodeGithubComJimehRbheapleak(&r, v) + easyjsonE44bcf2dDecodeGithubComJimehRbheapleak(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface -func (v *HeapEntry) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson48125c2bDecodeGithubComJimehRbheapleak(l, v) +func (v *Object) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonE44bcf2dDecodeGithubComJimehRbheapleak(l, v) }