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