github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/cmd/sigs2h/main.go (about) 1 // The sigs2h tool converts function signatures to C headers (*.json -> *.h). 2 package main 3 4 import ( 5 "bufio" 6 "encoding/json" 7 "flag" 8 "fmt" 9 "io" 10 "log" 11 "os" 12 "sort" 13 "text/template" 14 15 "github.com/decomp/exp/bin" 16 "github.com/mewkiz/pkg/errutil" 17 "github.com/pkg/errors" 18 ) 19 20 func usage() { 21 const use = ` 22 Convert function signatures to empty C headers (*.json -> *.h). 23 24 Usage: 25 26 sigs2h [OPTION]... FILE.json 27 28 Flags: 29 ` 30 fmt.Fprint(os.Stderr, use[1:]) 31 flag.PrintDefaults() 32 } 33 34 func main() { 35 // Parse command line flags. 36 var ( 37 // output specifies the output path. 38 output string 39 ) 40 flag.StringVar(&output, "o", "", "output path") 41 flag.Parse() 42 flag.Usage = usage 43 flag.Parse() 44 if flag.NArg() != 1 { 45 flag.Usage() 46 os.Exit(1) 47 } 48 jsonPath := flag.Arg(0) 49 50 // Store C header output. 51 w := os.Stdout 52 if len(output) > 0 { 53 f, err := os.Create(output) 54 if err != nil { 55 log.Fatal(err) 56 } 57 defer f.Close() 58 w = f 59 } 60 if err := convert(w, jsonPath); err != nil { 61 log.Fatalf("%+v", err) 62 } 63 } 64 65 // convert converts the the given function signatures to C headers. 66 func convert(w io.Writer, jsonPath string) error { 67 // Parse file. 68 sigs := make(map[bin.Address]FuncSig) 69 if err := parseJSON(jsonPath, &sigs); err != nil { 70 return errors.WithStack(err) 71 } 72 var funcAddrs []bin.Address 73 for funcAddr := range sigs { 74 funcAddrs = append(funcAddrs, funcAddr) 75 } 76 sort.Sort(bin.Addresses(funcAddrs)) 77 78 // Convert function signatures to C. 79 const source = ` 80 #include <stdint.h> // int8_t, ... 81 #include <stdarg.h> // va_list 82 #if __WORDSIZE == 64 83 typedef uint64_t size_t; 84 #else 85 typedef uint32_t size_t; 86 #endif 87 88 #include "types.h" 89 90 {{ range . }} 91 // {{ .Addr }} 92 {{ .Sig }} {} 93 {{ end }} 94 ` 95 var funcSigs []Signature 96 for _, funcAddr := range funcAddrs { 97 sig := sigs[funcAddr] 98 s := sig.Sig 99 if len(s) == 0 { 100 s = fmt.Sprintf("void %s() /* signature missing */", sig.Name) 101 } 102 funcSig := Signature{ 103 Addr: funcAddr, 104 Sig: s, 105 } 106 funcSigs = append(funcSigs, funcSig) 107 } 108 t := template.New("signatures") 109 if _, err := t.Parse(source[1:]); err != nil { 110 return errors.WithStack(err) 111 } 112 if err := t.Execute(w, funcSigs); err != nil { 113 return errutil.Err(err) 114 } 115 return nil 116 } 117 118 // Signature represents a function signature. 119 type Signature struct { 120 // Function address. 121 Addr bin.Address 122 // Function signature. 123 Sig string 124 } 125 126 // FuncSig represents a function signature. 127 type FuncSig struct { 128 // Function name. 129 Name string `json:"name"` 130 // Function signature. 131 Sig string `json:"sig"` 132 } 133 134 // ### [ Helper functions ] #################################################### 135 136 // parseJSON parses the given JSON file and stores the result into v. 137 func parseJSON(jsonPath string, v interface{}) error { 138 f, err := os.Open(jsonPath) 139 if err != nil { 140 return errors.WithStack(err) 141 } 142 defer f.Close() 143 br := bufio.NewReader(f) 144 dec := json.NewDecoder(br) 145 return dec.Decode(v) 146 }