Skip to content

Commit

Permalink
more work to actually output json!
Browse files Browse the repository at this point in the history
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
  • Loading branch information
vsoch committed Sep 25, 2021
1 parent c8def06 commit 7e94e60
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 221 deletions.
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@ To run and preview the output, do:

```bash
$ make
$ go run main.go parse gosmeagle
$ go run main.go parse libtest.so
```
```
...
[{a 8 long int } {b 8 long int } {c 8 long int } {d 8 long int } {e 8 long int } {f 16 __int128 }]
[{__fmt -1 }]
[]
{"library":"libtest.so","functions":[{"name":"__printf_chk"},{"parameters":[{"name":"a","type":"long int","sizes":8},{"name":"b","type":"long int","sizes":8},{"name":"c","type":"long int","sizes":8},{"name":"d","type":"long int","sizes":8},{"name":"e","type":"long int","sizes":8},{"name":"f","type":"__int128","sizes":16}],"name":"bigcall"}]}
```

Note that this library is under development, so currently I've just finished parsing functions
and formal paramters from the dwarf, and next I'm going to map that to an x86_64 parser to get more
metadata. Stay tuned!
or print pretty:

Note that I added parsing of the Type and Binding. I think I'm going to pull out using just the Dwarf wrapper and remove the internal code that isn't supposed to be accessible :)
See discussion in [this thread](https://twitter.com/vsoch/status/1437535961131352065) for the discovery of the missing variables.
```
$ go run main.go parse libtest.so --pretty
```

Note that this library is under development, so stay tuned!

## Background

I started this library after discussion (see [this thread](https://twitter.com/vsoch/status/1437535961131352065)) and wanting to extend Dwarf a bit and also reproduce [Smeagle](https://github.com/buildsi/Smeagle) in Go.

## Includes

Expand All @@ -35,3 +37,13 @@ Since I needed some functionality from [debug/dwarf](https://cs.opensource.googl
- renaming readType to ReadType so it's public.
- also renaming sigToType to SigToType so it's public
- made typeCache public (TypeCache)

## TODO

- add variable parsing
- add allocator to get allocations
- need to get registers / locations for each type

TODO: the typecache stores a TYPE and we need to also keep track of the CLASS or KIND of type, so add to that.


7 changes: 5 additions & 2 deletions cli/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
type ParserArgs struct {
Binary []string `desc:"A binary to parse."`
}
type ParserFlags struct{}
type ParserFlags struct {
Pretty bool `long:"pretty" desc:"Pretty print the json"`
}

// Parser looks at symbols and ABI in Go
var Parser = cmd.Sub{
Expand All @@ -28,6 +30,7 @@ func init() {
// RunParser reads a file and creates a corpus
func RunParser(r *cmd.Root, c *cmd.Sub) {
args := c.Args.(*ParserArgs)
flags := c.Flags.(*ParserFlags)
corpus := corpus.GetCorpus(args.Binary[0])
corpus.ToJson()
corpus.ToJson(flags.Pretty)
}
72 changes: 47 additions & 25 deletions corpus/corpus.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package corpus

import (
"encoding/json"
"fmt"
"github.com/vsoch/gosmeagle/descriptor"
"github.com/vsoch/gosmeagle/parsers/file"
"github.com/vsoch/gosmeagle/parsers/x86_64"
"log"
"reflect"
)

// A corpus holds a library name, a list of Functions and variables
// TODO should this be a list of Locations instead?
type Corpus struct {
Library string `json:"library"`
Functions []descriptor.FunctionDescription `json:"functions"`
Variables []string `json:"variables"`
Functions []descriptor.FunctionDescription `json:"functions,omitempty"`
Variables []descriptor.VariableDescription `json:"variables,omitempty"`
}

// Get a corpus from a filename
Expand All @@ -34,7 +37,7 @@ func GetCorpus(filename string) Corpus {
func (c *Corpus) Parse(f *file.File) {

// Parse dwarf for each entry to use
f.ParseDwarf()
lookup := f.ParseDwarf()

// Parse entries based on type (function or variable)
for _, e := range f.Entries {
Expand All @@ -45,44 +48,63 @@ func (c *Corpus) Parse(f *file.File) {
log.Fatalf("Issue retriving symbols from %s", c.Library)
}
for _, symbol := range symbols {
switch symbol.GetType() {
case "STT_FUNC":
entry, ok := lookup["functions"][symbol.GetName()]
if !ok {
continue
}
c.parseFunction(f, symbol, &entry)

case "STT_OBJECT":

// Do we have a variable with global linkage?
entry, ok := lookup["variables"][symbol.GetName()]
if ok && symbol.GetBinding() == "STB_GLOBAL" {
c.parseVariable(f, symbol, &entry)
}

// If we have a function, parse function
if symbol.GetType() == "STT_FUNC" {
c.parseFunction(f, symbol)
}

// TODO if it's a variable AND has global linkage, parse

//fmt.Println("Name:", symbol.Name)
//fmt.Println("Address:", symbol.Address)
//fmt.Println("Size:", symbol.Size)
//fmt.Println("Code:", symbol.Code)
//fmt.Println("Type:", symbol.Type)
//fmt.Println("Binding:", symbol.Binding)
//fmt.Println("Relocs:", symbol.Relocations)
}
}
}

// parse a dynamic function symbol
func (c *Corpus) parseFunction(f *file.File, symbol file.Symbol) {
func (c *Corpus) parseFunction(f *file.File, symbol file.Symbol, entry *file.DwarfEntry) {

switch f.GoArch() {
case "amd64":
c.Functions = append(c.Functions, x86_64.ParseFunction(f, symbol, entry))
default:
fmt.Printf("Unsupported architecture %s\n", f.GoArch())
}
}

// parse a global variable
func (c *Corpus) parseVariable(f *file.File, symbol file.Symbol, entry *file.DwarfEntry) {

//fmt.Println(symbol)
switch f.GoArch() {
case "amd64":
{
c.Functions = append(c.Functions, x86_64.ParseFunction(f, symbol))
// c.Functions = append(c.Functions, x86.ParseReturnValue(symbol)

// Don't allow variables without name or type
variable := x86_64.ParseVariable(f, symbol, entry)
if !reflect.DeepEqual(variable, descriptor.VariableDescription{}) {
c.Variables = append(c.Variables, variable)
}
default:
fmt.Printf("Unsupported architecture %s\n", f.GoArch())
}
}

// Serialize corpus to json
func (c *Corpus) ToJson() {
func (c *Corpus) ToJson(pretty bool) {

//outJson, _ := json.Marshal(c)
//output := string(outJson)
//fmt.Println(output)
var outJson []byte
if pretty {
outJson, _ = json.MarshalIndent(c, "", " ")
} else {
outJson, _ = json.Marshal(c)
}
output := string(outJson)
fmt.Println(output)
}
28 changes: 14 additions & 14 deletions descriptor/types.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package descriptor

// A Parameter interface must implement these functions
// Sizes are in bytes

type Parameter interface {
Name() string
TypeName() string
ClassName() string
Direction() string
Location() string
SizeBytes() int
ToJson()
type FunctionParameter struct {
Name string `json:"name,omitempty"`
TypeName string `json:"type,omitempty"`
ClassName string `json:"class,omitempty"`
Direction string `json:"direction,omitempty"`
Location string `json:"location,omitempty"`
Size int64 `json:"sizes,omitempty"`
}

type FunctionDescription struct {
Parameters []Parameter
ReturnValue Parameter
Name string `json:"name"`
Parameters []FunctionParameter `json:"parameters,omitempty"`
Name string `json:"name"`
}

type VariableDescription struct {
Name string `json:"name"`
Type string `json:"type"`
Name string `json:"name"`
Type string `json:"type"`
Size int64 `json:"sizes,omitempty"`
Direction string `json:"direction,omitempty"`
}

0 comments on commit 7e94e60

Please sign in to comment.