blob: 6ebc1c70d0cdf6381bbbafa5e4bf1dfa1bfbaf1d [file] [log] [blame]
Joe Tsaib4e370e2018-08-15 14:59:51 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// pbdump is a tool for decoding the wire format for protocol buffer messages.
6package main
7
8import (
9 "bytes"
10 "flag"
11 "fmt"
12 "io/ioutil"
13 "log"
14 "os"
15 "path/filepath"
16 "sort"
17 "strconv"
18 "strings"
19
20 "google.golang.org/proto/internal/encoding/pack"
21 "google.golang.org/proto/internal/encoding/wire"
22 "google.golang.org/proto/reflect/protoreflect"
23 "google.golang.org/proto/reflect/prototype"
24)
25
26func main() {
27 log.SetFlags(0)
28 log.SetOutput(os.Stderr)
29
30 var fs fields
31 flag.Var((*boolFields)(&fs), "bools", "List of bool fields")
32 flag.Var((*intFields)(&fs), "ints", "List of int32 or int64 fields")
33 flag.Var((*sintFields)(&fs), "sints", "List of sint32 or sint64 fields")
34 flag.Var((*uintFields)(&fs), "uints", "List of enum, uint32, or uint64 fields")
35 flag.Var((*uint32Fields)(&fs), "uint32s", "List of fixed32 fields")
36 flag.Var((*int32Fields)(&fs), "int32s", "List of sfixed32 fields")
37 flag.Var((*float32Fields)(&fs), "float32s", "List of float fields")
38 flag.Var((*uint64Fields)(&fs), "uint64s", "List of fixed64 fields")
39 flag.Var((*int64Fields)(&fs), "int64s", "List of sfixed64 fields")
40 flag.Var((*float64Fields)(&fs), "float64s", "List of double fields")
41 flag.Var((*stringFields)(&fs), "strings", "List of string fields")
42 flag.Var((*bytesFields)(&fs), "bytes", "List of bytes fields")
43 flag.Var((*messageFields)(&fs), "messages", "List of message fields")
44 flag.Var((*groupFields)(&fs), "groups", "List of group fields")
45 printDesc := flag.Bool("print_descriptor", false, "Print the message descriptor")
46 printSource := flag.Bool("print_source", false, "Print the output in valid Go syntax")
47 flag.Usage = func() {
48 log.Printf("Usage: %s [OPTIONS]... [INPUTS]...\n\n%s\n", filepath.Base(os.Args[0]), strings.Join([]string{
49 "Print structured representations of encoded protocol buffer messages.",
50 "Since the protobuf wire format is not fully self-describing, type information",
51 "about the proto message can be provided using flags (e.g., -messages).",
52 "Each field list is a comma-separated list of field identifiers,",
53 "where each field identifier is a dot-separated list of field numbers,",
54 "identifying each field relative to the root message.",
55 "",
56 "For example, \"-messages 1,3,3.1 -float32s 1.2 -bools 3.1.2\" represents:",
57 "",
58 " message M {",
59 " optional M1 f1 = 1; // -messages 1",
60 " message M1 {",
61 " repeated float f2 = 2; // -float32s 1.2",
62 " }",
63 " optional M3 f3 = 3; // -messages 3",
64 " message M3 {",
65 " optional M1 f1 = 1; // -messages 3.1",
66 " message M1 {",
67 " repeated bool f2 = 2; // -bools 3.1.2",
68 " }",
69 " }",
70 " }",
71 "",
72 "Arbitrarily complex message schemas can be represented using these flags.",
73 "Scalar field types are marked as repeated so that pbdump can decode",
74 "the packed representations of such field types.",
75 "",
76 "If no inputs are specified, the wire data is read in from stdin, otherwise",
77 "the contents of each specified input file is concatenated and",
78 "treated as one large message.",
79 "",
80 "Options:",
81 " -bools fields " + flag.Lookup("bools").Usage,
82 " -ints fields " + flag.Lookup("ints").Usage,
83 " -sints fields " + flag.Lookup("sints").Usage,
84 " -uints fields " + flag.Lookup("uints").Usage,
85 " -int32s fields " + flag.Lookup("int32s").Usage,
86 " -int64s fields " + flag.Lookup("int64s").Usage,
87 " -uint32s fields " + flag.Lookup("uint32s").Usage,
88 " -uint64s fields " + flag.Lookup("uint64s").Usage,
89 " -float32s fields " + flag.Lookup("float32s").Usage,
90 " -float64s fields " + flag.Lookup("float64s").Usage,
91 " -strings fields " + flag.Lookup("strings").Usage,
92 " -bytes fields " + flag.Lookup("bytes").Usage,
93 " -messages fields " + flag.Lookup("messages").Usage,
94 " -groups fields " + flag.Lookup("groups").Usage,
95 " -print_descriptor " + flag.Lookup("print_descriptor").Usage,
96 " -print_source " + flag.Lookup("print_source").Usage,
97 }, "\n"))
98 }
99 flag.Parse()
100
101 // Create message types.
102 var desc protoreflect.MessageDescriptor
103 if len(fs) > 0 {
104 var err error
105 desc, err = fs.Descriptor()
106 if err != nil {
107 log.Fatalf("Descriptor error: %v", err)
108 }
109 if *printDesc {
110 log.Printf("%#v\n", desc)
111 }
112 }
113
114 // Read message input.
115 var buf []byte
116 if flag.NArg() == 0 {
117 b, err := ioutil.ReadAll(os.Stdin)
118 if err != nil {
119 log.Fatalf("ReadAll error: %v", err)
120 }
121 buf = b
122 }
123 for _, f := range flag.Args() {
124 b, err := ioutil.ReadFile(f)
125 if err != nil {
126 log.Fatalf("ReadFile error: %v", err)
127 }
128 buf = append(buf, b...)
129 }
130
131 // Parse and print message structure.
132 defer log.Printf("fatal input: %q", buf) // debug printout if panic occurs
133 var m pack.Message
134 m.UnmarshalDescriptor(buf, desc)
135 if *printSource {
136 fmt.Fprintf(os.Stdout, "%#v\n", m)
137 } else {
138 fmt.Fprintf(os.Stdout, "%+v\n", m)
139 }
140 if !bytes.Equal(buf, m.Marshal()) || len(buf) != m.Size() {
141 log.Fatalf("roundtrip mismatch:\n\tgot: %d %x\n\twant: %d %x", m.Size(), m, len(buf), buf)
142 }
143 os.Exit(0) // exit cleanly, avoid debug printout
144}
145
146// fields is a tree of fields, keyed by a field number.
147// Fields representing messages or groups have sub-fields.
148type fields map[wire.Number]*field
149type field struct {
150 kind protoreflect.Kind
151 sub fields // only for MessageKind or GroupKind
152}
153
154// Set parses s as a comma-separated list (see the help above for the format)
155// and treats each field identifier as the specified kind.
156func (fs *fields) Set(s string, k protoreflect.Kind) error {
157 if *fs == nil {
158 *fs = make(fields)
159 }
160 for _, s := range strings.Split(s, ",") {
161 if err := fs.set("", strings.TrimSpace(s), k); err != nil {
162 return err
163 }
164 }
165 return nil
166}
167func (fs fields) set(prefix, s string, k protoreflect.Kind) error {
168 if s == "" {
169 return nil
170 }
171
172 // Parse next field number.
173 i := strings.IndexByte(s, '.')
174 if i < 0 {
175 i = len(s)
176 }
177 prefix = strings.TrimPrefix(prefix+"."+s[:i], ".")
178 n, _ := strconv.ParseInt(s[:i], 10, 32)
179 num := wire.Number(n)
180 if num < wire.MinValidNumber || wire.MaxValidNumber < num {
181 return fmt.Errorf("invalid field: %v", prefix)
182 }
183 s = strings.TrimPrefix(s[i:], ".")
184
185 // Handle the current field.
186 if fs[num] == nil {
187 fs[num] = &field{0, make(fields)}
188 }
189 if len(s) == 0 {
190 if fs[num].kind.IsValid() {
191 return fmt.Errorf("field %v already set as %v type", prefix, fs[num].kind)
192 }
193 fs[num].kind = k
194 }
195 if err := fs[num].sub.set(prefix, s, k); err != nil {
196 return err
197 }
198
199 // Verify that only messages or groups can have sub-fields.
200 k2 := fs[num].kind
201 if k2 > 0 && k2 != protoreflect.MessageKind && k2 != protoreflect.GroupKind && len(fs[num].sub) > 0 {
202 return fmt.Errorf("field %v of %v type cannot have sub-fields", prefix, k2)
203 }
204 return nil
205}
206
207// Descriptor returns the field tree as a message descriptor.
208func (fs fields) Descriptor() (protoreflect.MessageDescriptor, error) {
209 ftyp, err := prototype.NewFile(&prototype.File{
210 Syntax: protoreflect.Proto2,
211 Messages: []prototype.Message{fs.messageDescriptor("M")},
212 })
213 if err != nil {
214 return nil, err
215 }
216 return ftyp.Messages().Get(0), nil
217}
218func (fs fields) messageDescriptor(name protoreflect.FullName) prototype.Message {
219 m := prototype.Message{Name: name.Name()}
220 for _, n := range fs.sortedNums() {
221 f := prototype.Field{
222 Name: protoreflect.Name(fmt.Sprintf("f%d", n)),
223 Number: n,
224 Cardinality: protoreflect.Optional,
225 Kind: fs[n].kind,
226 }
227 if !f.Kind.IsValid() {
228 f.Kind = protoreflect.MessageKind
229 }
230 switch f.Kind {
231 case protoreflect.BoolKind, protoreflect.EnumKind,
232 protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
233 protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
234 protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind,
235 protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
236 f.Cardinality = protoreflect.Repeated
237 f.IsPacked = true
238 case protoreflect.MessageKind, protoreflect.GroupKind:
239 s := name.Append(protoreflect.Name(fmt.Sprintf("M%d", n)))
240 f.MessageType = prototype.PlaceholderMessage(s)
241 m.Messages = append(m.Messages, fs[n].sub.messageDescriptor(s))
242 }
243 m.Fields = append(m.Fields, f)
244 }
245 return m
246}
247
248func (fs fields) sortedNums() (ns []wire.Number) {
249 for n := range fs {
250 ns = append(ns, n)
251 }
252 sort.Slice(ns, func(i, j int) bool { return ns[i] < ns[j] })
253 return ns
254}
255
256type (
257 boolFields fields
258 intFields fields
259 sintFields fields
260 uintFields fields
261 uint32Fields fields
262 int32Fields fields
263 float32Fields fields
264 uint64Fields fields
265 int64Fields fields
266 float64Fields fields
267 stringFields fields
268 bytesFields fields
269 messageFields fields
270 groupFields fields
271)
272
273// String and Set implement flag.Value.
274// The String method is not implemented since the flag helper never prints it.
275func (p *boolFields) String() string { return "not implemented" }
276func (p *intFields) String() string { return "not implemented" }
277func (p *sintFields) String() string { return "not implemented" }
278func (p *uintFields) String() string { return "not implemented" }
279func (p *uint32Fields) String() string { return "not implemented" }
280func (p *int32Fields) String() string { return "not implemented" }
281func (p *float32Fields) String() string { return "not implemented" }
282func (p *uint64Fields) String() string { return "not implemented" }
283func (p *int64Fields) String() string { return "not implemented" }
284func (p *float64Fields) String() string { return "not implemented" }
285func (p *stringFields) String() string { return "not implemented" }
286func (p *bytesFields) String() string { return "not implemented" }
287func (p *messageFields) String() string { return "not implemented" }
288func (p *groupFields) String() string { return "not implemented" }
289func (p *boolFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.BoolKind) }
290func (p *intFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Int64Kind) }
291func (p *sintFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Sint64Kind) }
292func (p *uintFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Uint64Kind) }
293func (p *uint32Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Fixed32Kind) }
294func (p *int32Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Sfixed32Kind) }
295func (p *float32Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.FloatKind) }
296func (p *uint64Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Fixed64Kind) }
297func (p *int64Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.Sfixed64Kind) }
298func (p *float64Fields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.DoubleKind) }
299func (p *stringFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.StringKind) }
300func (p *bytesFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.BytesKind) }
301func (p *messageFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.MessageKind) }
302func (p *groupFields) Set(s string) error { return (*fields)(p).Set(s, protoreflect.GroupKind) }