1// Copyright 2014 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 profile
6
7import (
8	"errors"
9	"fmt"
10	"sort"
11)
12
13func (p *Profile) decoder() []decoder {
14	return profileDecoder
15}
16
17// preEncode populates the unexported fields to be used by encode
18// (with suffix X) from the corresponding exported fields. The
19// exported fields are cleared up to facilitate testing.
20func (p *Profile) preEncode() {
21	strings := make(map[string]int)
22	addString(strings, "")
23
24	for _, st := range p.SampleType {
25		st.typeX = addString(strings, st.Type)
26		st.unitX = addString(strings, st.Unit)
27	}
28
29	for _, s := range p.Sample {
30		s.labelX = nil
31		var keys []string
32		for k := range s.Label {
33			keys = append(keys, k)
34		}
35		sort.Strings(keys)
36		for _, k := range keys {
37			vs := s.Label[k]
38			for _, v := range vs {
39				s.labelX = append(s.labelX,
40					Label{
41						keyX: addString(strings, k),
42						strX: addString(strings, v),
43					},
44				)
45			}
46		}
47		var numKeys []string
48		for k := range s.NumLabel {
49			numKeys = append(numKeys, k)
50		}
51		sort.Strings(numKeys)
52		for _, k := range numKeys {
53			vs := s.NumLabel[k]
54			for _, v := range vs {
55				s.labelX = append(s.labelX,
56					Label{
57						keyX: addString(strings, k),
58						numX: v,
59					},
60				)
61			}
62		}
63		s.locationIDX = nil
64		for _, l := range s.Location {
65			s.locationIDX = append(s.locationIDX, l.ID)
66		}
67	}
68
69	for _, m := range p.Mapping {
70		m.fileX = addString(strings, m.File)
71		m.buildIDX = addString(strings, m.BuildID)
72	}
73
74	for _, l := range p.Location {
75		for i, ln := range l.Line {
76			if ln.Function != nil {
77				l.Line[i].functionIDX = ln.Function.ID
78			} else {
79				l.Line[i].functionIDX = 0
80			}
81		}
82		if l.Mapping != nil {
83			l.mappingIDX = l.Mapping.ID
84		} else {
85			l.mappingIDX = 0
86		}
87	}
88	for _, f := range p.Function {
89		f.nameX = addString(strings, f.Name)
90		f.systemNameX = addString(strings, f.SystemName)
91		f.filenameX = addString(strings, f.Filename)
92	}
93
94	p.dropFramesX = addString(strings, p.DropFrames)
95	p.keepFramesX = addString(strings, p.KeepFrames)
96
97	if pt := p.PeriodType; pt != nil {
98		pt.typeX = addString(strings, pt.Type)
99		pt.unitX = addString(strings, pt.Unit)
100	}
101
102	p.stringTable = make([]string, len(strings))
103	for s, i := range strings {
104		p.stringTable[i] = s
105	}
106}
107
108func (p *Profile) encode(b *buffer) {
109	for _, x := range p.SampleType {
110		encodeMessage(b, 1, x)
111	}
112	for _, x := range p.Sample {
113		encodeMessage(b, 2, x)
114	}
115	for _, x := range p.Mapping {
116		encodeMessage(b, 3, x)
117	}
118	for _, x := range p.Location {
119		encodeMessage(b, 4, x)
120	}
121	for _, x := range p.Function {
122		encodeMessage(b, 5, x)
123	}
124	encodeStrings(b, 6, p.stringTable)
125	encodeInt64Opt(b, 7, p.dropFramesX)
126	encodeInt64Opt(b, 8, p.keepFramesX)
127	encodeInt64Opt(b, 9, p.TimeNanos)
128	encodeInt64Opt(b, 10, p.DurationNanos)
129	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
130		encodeMessage(b, 11, p.PeriodType)
131	}
132	encodeInt64Opt(b, 12, p.Period)
133}
134
135var profileDecoder = []decoder{
136	nil, // 0
137	// repeated ValueType sample_type = 1
138	func(b *buffer, m message) error {
139		x := new(ValueType)
140		pp := m.(*Profile)
141		pp.SampleType = append(pp.SampleType, x)
142		return decodeMessage(b, x)
143	},
144	// repeated Sample sample = 2
145	func(b *buffer, m message) error {
146		x := new(Sample)
147		pp := m.(*Profile)
148		pp.Sample = append(pp.Sample, x)
149		return decodeMessage(b, x)
150	},
151	// repeated Mapping mapping = 3
152	func(b *buffer, m message) error {
153		x := new(Mapping)
154		pp := m.(*Profile)
155		pp.Mapping = append(pp.Mapping, x)
156		return decodeMessage(b, x)
157	},
158	// repeated Location location = 4
159	func(b *buffer, m message) error {
160		x := new(Location)
161		pp := m.(*Profile)
162		pp.Location = append(pp.Location, x)
163		return decodeMessage(b, x)
164	},
165	// repeated Function function = 5
166	func(b *buffer, m message) error {
167		x := new(Function)
168		pp := m.(*Profile)
169		pp.Function = append(pp.Function, x)
170		return decodeMessage(b, x)
171	},
172	// repeated string string_table = 6
173	func(b *buffer, m message) error {
174		err := decodeStrings(b, &m.(*Profile).stringTable)
175		if err != nil {
176			return err
177		}
178		if *&m.(*Profile).stringTable[0] != "" {
179			return errors.New("string_table[0] must be ''")
180		}
181		return nil
182	},
183	// repeated int64 drop_frames = 7
184	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
185	// repeated int64 keep_frames = 8
186	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
187	// repeated int64 time_nanos = 9
188	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
189	// repeated int64 duration_nanos = 10
190	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
191	// optional string period_type = 11
192	func(b *buffer, m message) error {
193		x := new(ValueType)
194		pp := m.(*Profile)
195		pp.PeriodType = x
196		return decodeMessage(b, x)
197	},
198	// repeated int64 period = 12
199	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
200	// repeated int64 comment = 13
201	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
202	// int64 defaultSampleType = 14
203	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
204}
205
206// postDecode takes the unexported fields populated by decode (with
207// suffix X) and populates the corresponding exported fields.
208// The unexported fields are cleared up to facilitate testing.
209func (p *Profile) postDecode() error {
210	var err error
211
212	mappings := make(map[uint64]*Mapping)
213	for _, m := range p.Mapping {
214		m.File, err = getString(p.stringTable, &m.fileX, err)
215		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
216		mappings[m.ID] = m
217	}
218
219	functions := make(map[uint64]*Function)
220	for _, f := range p.Function {
221		f.Name, err = getString(p.stringTable, &f.nameX, err)
222		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
223		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
224		functions[f.ID] = f
225	}
226
227	locations := make(map[uint64]*Location)
228	for _, l := range p.Location {
229		l.Mapping = mappings[l.mappingIDX]
230		l.mappingIDX = 0
231		for i, ln := range l.Line {
232			if id := ln.functionIDX; id != 0 {
233				l.Line[i].Function = functions[id]
234				if l.Line[i].Function == nil {
235					return fmt.Errorf("Function ID %d not found", id)
236				}
237				l.Line[i].functionIDX = 0
238			}
239		}
240		locations[l.ID] = l
241	}
242
243	for _, st := range p.SampleType {
244		st.Type, err = getString(p.stringTable, &st.typeX, err)
245		st.Unit, err = getString(p.stringTable, &st.unitX, err)
246	}
247
248	for _, s := range p.Sample {
249		labels := make(map[string][]string)
250		numLabels := make(map[string][]int64)
251		for _, l := range s.labelX {
252			var key, value string
253			key, err = getString(p.stringTable, &l.keyX, err)
254			if l.strX != 0 {
255				value, err = getString(p.stringTable, &l.strX, err)
256				labels[key] = append(labels[key], value)
257			} else {
258				numLabels[key] = append(numLabels[key], l.numX)
259			}
260		}
261		if len(labels) > 0 {
262			s.Label = labels
263		}
264		if len(numLabels) > 0 {
265			s.NumLabel = numLabels
266		}
267		s.Location = nil
268		for _, lid := range s.locationIDX {
269			s.Location = append(s.Location, locations[lid])
270		}
271		s.locationIDX = nil
272	}
273
274	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
275	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
276
277	if pt := p.PeriodType; pt == nil {
278		p.PeriodType = &ValueType{}
279	}
280
281	if pt := p.PeriodType; pt != nil {
282		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
283		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
284	}
285	for _, i := range p.commentX {
286		var c string
287		c, err = getString(p.stringTable, &i, err)
288		p.Comments = append(p.Comments, c)
289	}
290
291	p.commentX = nil
292	p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
293	p.stringTable = nil
294	return nil
295}
296
297func (p *ValueType) decoder() []decoder {
298	return valueTypeDecoder
299}
300
301func (p *ValueType) encode(b *buffer) {
302	encodeInt64Opt(b, 1, p.typeX)
303	encodeInt64Opt(b, 2, p.unitX)
304}
305
306var valueTypeDecoder = []decoder{
307	nil, // 0
308	// optional int64 type = 1
309	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
310	// optional int64 unit = 2
311	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
312}
313
314func (p *Sample) decoder() []decoder {
315	return sampleDecoder
316}
317
318func (p *Sample) encode(b *buffer) {
319	encodeUint64s(b, 1, p.locationIDX)
320	for _, x := range p.Value {
321		encodeInt64(b, 2, x)
322	}
323	for _, x := range p.labelX {
324		encodeMessage(b, 3, x)
325	}
326}
327
328var sampleDecoder = []decoder{
329	nil, // 0
330	// repeated uint64 location = 1
331	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
332	// repeated int64 value = 2
333	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
334	// repeated Label label = 3
335	func(b *buffer, m message) error {
336		s := m.(*Sample)
337		n := len(s.labelX)
338		s.labelX = append(s.labelX, Label{})
339		return decodeMessage(b, &s.labelX[n])
340	},
341}
342
343func (p Label) decoder() []decoder {
344	return labelDecoder
345}
346
347func (p Label) encode(b *buffer) {
348	encodeInt64Opt(b, 1, p.keyX)
349	encodeInt64Opt(b, 2, p.strX)
350	encodeInt64Opt(b, 3, p.numX)
351}
352
353var labelDecoder = []decoder{
354	nil, // 0
355	// optional int64 key = 1
356	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
357	// optional int64 str = 2
358	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
359	// optional int64 num = 3
360	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
361}
362
363func (p *Mapping) decoder() []decoder {
364	return mappingDecoder
365}
366
367func (p *Mapping) encode(b *buffer) {
368	encodeUint64Opt(b, 1, p.ID)
369	encodeUint64Opt(b, 2, p.Start)
370	encodeUint64Opt(b, 3, p.Limit)
371	encodeUint64Opt(b, 4, p.Offset)
372	encodeInt64Opt(b, 5, p.fileX)
373	encodeInt64Opt(b, 6, p.buildIDX)
374	encodeBoolOpt(b, 7, p.HasFunctions)
375	encodeBoolOpt(b, 8, p.HasFilenames)
376	encodeBoolOpt(b, 9, p.HasLineNumbers)
377	encodeBoolOpt(b, 10, p.HasInlineFrames)
378}
379
380var mappingDecoder = []decoder{
381	nil, // 0
382	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
383	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
384	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
385	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
386	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
387	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
388	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
389	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
390	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
391	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
392}
393
394func (p *Location) decoder() []decoder {
395	return locationDecoder
396}
397
398func (p *Location) encode(b *buffer) {
399	encodeUint64Opt(b, 1, p.ID)
400	encodeUint64Opt(b, 2, p.mappingIDX)
401	encodeUint64Opt(b, 3, p.Address)
402	for i := range p.Line {
403		encodeMessage(b, 4, &p.Line[i])
404	}
405}
406
407var locationDecoder = []decoder{
408	nil, // 0
409	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
410	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
411	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
412	func(b *buffer, m message) error { // repeated Line line = 4
413		pp := m.(*Location)
414		n := len(pp.Line)
415		pp.Line = append(pp.Line, Line{})
416		return decodeMessage(b, &pp.Line[n])
417	},
418}
419
420func (p *Line) decoder() []decoder {
421	return lineDecoder
422}
423
424func (p *Line) encode(b *buffer) {
425	encodeUint64Opt(b, 1, p.functionIDX)
426	encodeInt64Opt(b, 2, p.Line)
427}
428
429var lineDecoder = []decoder{
430	nil, // 0
431	// optional uint64 function_id = 1
432	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
433	// optional int64 line = 2
434	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
435}
436
437func (p *Function) decoder() []decoder {
438	return functionDecoder
439}
440
441func (p *Function) encode(b *buffer) {
442	encodeUint64Opt(b, 1, p.ID)
443	encodeInt64Opt(b, 2, p.nameX)
444	encodeInt64Opt(b, 3, p.systemNameX)
445	encodeInt64Opt(b, 4, p.filenameX)
446	encodeInt64Opt(b, 5, p.StartLine)
447}
448
449var functionDecoder = []decoder{
450	nil, // 0
451	// optional uint64 id = 1
452	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
453	// optional int64 function_name = 2
454	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
455	// optional int64 function_system_name = 3
456	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
457	// repeated int64 filename = 4
458	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
459	// optional int64 start_line = 5
460	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
461}
462
463func addString(strings map[string]int, s string) int64 {
464	i, ok := strings[s]
465	if !ok {
466		i = len(strings)
467		strings[s] = i
468	}
469	return int64(i)
470}
471
472func getString(strings []string, strng *int64, err error) (string, error) {
473	if err != nil {
474		return "", err
475	}
476	s := int(*strng)
477	if s < 0 || s >= len(strings) {
478		return "", errMalformed
479	}
480	*strng = 0
481	return strings[s], nil
482}
483