1// Copyright 2023 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
5package raw
6
7import (
8	"bufio"
9	"encoding/binary"
10	"fmt"
11	"io"
12
13	"internal/trace/event"
14	"internal/trace/version"
15)
16
17// Reader parses trace bytes with only very basic validation
18// into an event stream.
19type Reader struct {
20	r     *bufio.Reader
21	v     version.Version
22	specs []event.Spec
23}
24
25// NewReader creates a new reader for the trace wire format.
26func NewReader(r io.Reader) (*Reader, error) {
27	br := bufio.NewReader(r)
28	v, err := version.ReadHeader(br)
29	if err != nil {
30		return nil, err
31	}
32	return &Reader{r: br, v: v, specs: v.Specs()}, nil
33}
34
35// Version returns the version of the trace that we're reading.
36func (r *Reader) Version() version.Version {
37	return r.v
38}
39
40// ReadEvent reads and returns the next trace event in the byte stream.
41func (r *Reader) ReadEvent() (Event, error) {
42	evb, err := r.r.ReadByte()
43	if err == io.EOF {
44		return Event{}, io.EOF
45	}
46	if err != nil {
47		return Event{}, err
48	}
49	if int(evb) >= len(r.specs) || evb == 0 {
50		return Event{}, fmt.Errorf("invalid event type: %d", evb)
51	}
52	ev := event.Type(evb)
53	spec := r.specs[ev]
54	args, err := r.readArgs(len(spec.Args))
55	if err != nil {
56		return Event{}, err
57	}
58	if spec.IsStack {
59		len := int(args[1])
60		for i := 0; i < len; i++ {
61			// Each stack frame has four args: pc, func ID, file ID, line number.
62			frame, err := r.readArgs(4)
63			if err != nil {
64				return Event{}, err
65			}
66			args = append(args, frame...)
67		}
68	}
69	var data []byte
70	if spec.HasData {
71		data, err = r.readData()
72		if err != nil {
73			return Event{}, err
74		}
75	}
76	return Event{
77		Version: r.v,
78		Ev:      ev,
79		Args:    args,
80		Data:    data,
81	}, nil
82}
83
84func (r *Reader) readArgs(n int) ([]uint64, error) {
85	var args []uint64
86	for i := 0; i < n; i++ {
87		val, err := binary.ReadUvarint(r.r)
88		if err != nil {
89			return nil, err
90		}
91		args = append(args, val)
92	}
93	return args, nil
94}
95
96func (r *Reader) readData() ([]byte, error) {
97	len, err := binary.ReadUvarint(r.r)
98	if err != nil {
99		return nil, err
100	}
101	var data []byte
102	for i := 0; i < int(len); i++ {
103		b, err := r.r.ReadByte()
104		if err != nil {
105			return nil, err
106		}
107		data = append(data, b)
108	}
109	return data, nil
110}
111