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}
201
202// postDecode takes the unexported fields populated by decode (with
203// suffix X) and populates the corresponding exported fields.
204// The unexported fields are cleared up to facilitate testing.
205func (p *Profile) postDecode() error {
206	var err error
207
208	mappings := make(map[uint64]*Mapping)
209	for _, m := range p.Mapping {
210		m.File, err = getString(p.stringTable, &m.fileX, err)
211		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
212		mappings[m.ID] = m
213	}
214
215	functions := make(map[uint64]*Function)
216	for _, f := range p.Function {
217		f.Name, err = getString(p.stringTable, &f.nameX, err)
218		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
219		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
220		functions[f.ID] = f
221	}
222
223	locations := make(map[uint64]*Location)
224	for _, l := range p.Location {
225		l.Mapping = mappings[l.mappingIDX]
226		l.mappingIDX = 0
227		for i, ln := range l.Line {
228			if id := ln.functionIDX; id != 0 {
229				l.Line[i].Function = functions[id]
230				if l.Line[i].Function == nil {
231					return fmt.Errorf("Function ID %d not found", id)
232				}
233				l.Line[i].functionIDX = 0
234			}
235		}
236		locations[l.ID] = l
237	}
238
239	for _, st := range p.SampleType {
240		st.Type, err = getString(p.stringTable, &st.typeX, err)
241		st.Unit, err = getString(p.stringTable, &st.unitX, err)
242	}
243
244	for _, s := range p.Sample {
245		labels := make(map[string][]string)
246		numLabels := make(map[string][]int64)
247		for _, l := range s.labelX {
248			var key, value string
249			key, err = getString(p.stringTable, &l.keyX, err)
250			if l.strX != 0 {
251				value, err = getString(p.stringTable, &l.strX, err)
252				labels[key] = append(labels[key], value)
253			} else {
254				numLabels[key] = append(numLabels[key], l.numX)
255			}
256		}
257		if len(labels) > 0 {
258			s.Label = labels
259		}
260		if len(numLabels) > 0 {
261			s.NumLabel = numLabels
262		}
263		s.Location = nil
264		for _, lid := range s.locationIDX {
265			s.Location = append(s.Location, locations[lid])
266		}
267		s.locationIDX = nil
268	}
269
270	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
271	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
272
273	if pt := p.PeriodType; pt == nil {
274		p.PeriodType = &ValueType{}
275	}
276
277	if pt := p.PeriodType; pt != nil {
278		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
279		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
280	}
281	p.stringTable = nil
282	return nil
283}
284
285func (p *ValueType) decoder() []decoder {
286	return valueTypeDecoder
287}
288
289func (p *ValueType) encode(b *buffer) {
290	encodeInt64Opt(b, 1, p.typeX)
291	encodeInt64Opt(b, 2, p.unitX)
292}
293
294var valueTypeDecoder = []decoder{
295	nil, // 0
296	// optional int64 type = 1
297	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
298	// optional int64 unit = 2
299	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
300}
301
302func (p *Sample) decoder() []decoder {
303	return sampleDecoder
304}
305
306func (p *Sample) encode(b *buffer) {
307	encodeUint64s(b, 1, p.locationIDX)
308	for _, x := range p.Value {
309		encodeInt64(b, 2, x)
310	}
311	for _, x := range p.labelX {
312		encodeMessage(b, 3, x)
313	}
314}
315
316var sampleDecoder = []decoder{
317	nil, // 0
318	// repeated uint64 location = 1
319	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
320	// repeated int64 value = 2
321	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
322	// repeated Label label = 3
323	func(b *buffer, m message) error {
324		s := m.(*Sample)
325		n := len(s.labelX)
326		s.labelX = append(s.labelX, Label{})
327		return decodeMessage(b, &s.labelX[n])
328	},
329}
330
331func (p Label) decoder() []decoder {
332	return labelDecoder
333}
334
335func (p Label) encode(b *buffer) {
336	encodeInt64Opt(b, 1, p.keyX)
337	encodeInt64Opt(b, 2, p.strX)
338	encodeInt64Opt(b, 3, p.numX)
339}
340
341var labelDecoder = []decoder{
342	nil, // 0
343	// optional int64 key = 1
344	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
345	// optional int64 str = 2
346	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
347	// optional int64 num = 3
348	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
349}
350
351func (p *Mapping) decoder() []decoder {
352	return mappingDecoder
353}
354
355func (p *Mapping) encode(b *buffer) {
356	encodeUint64Opt(b, 1, p.ID)
357	encodeUint64Opt(b, 2, p.Start)
358	encodeUint64Opt(b, 3, p.Limit)
359	encodeUint64Opt(b, 4, p.Offset)
360	encodeInt64Opt(b, 5, p.fileX)
361	encodeInt64Opt(b, 6, p.buildIDX)
362	encodeBoolOpt(b, 7, p.HasFunctions)
363	encodeBoolOpt(b, 8, p.HasFilenames)
364	encodeBoolOpt(b, 9, p.HasLineNumbers)
365	encodeBoolOpt(b, 10, p.HasInlineFrames)
366}
367
368var mappingDecoder = []decoder{
369	nil, // 0
370	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
371	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
372	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
373	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
374	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
375	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
376	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
377	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
378	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
379	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
380}
381
382func (p *Location) decoder() []decoder {
383	return locationDecoder
384}
385
386func (p *Location) encode(b *buffer) {
387	encodeUint64Opt(b, 1, p.ID)
388	encodeUint64Opt(b, 2, p.mappingIDX)
389	encodeUint64Opt(b, 3, p.Address)
390	for i := range p.Line {
391		encodeMessage(b, 4, &p.Line[i])
392	}
393}
394
395var locationDecoder = []decoder{
396	nil, // 0
397	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
398	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
399	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
400	func(b *buffer, m message) error { // repeated Line line = 4
401		pp := m.(*Location)
402		n := len(pp.Line)
403		pp.Line = append(pp.Line, Line{})
404		return decodeMessage(b, &pp.Line[n])
405	},
406}
407
408func (p *Line) decoder() []decoder {
409	return lineDecoder
410}
411
412func (p *Line) encode(b *buffer) {
413	encodeUint64Opt(b, 1, p.functionIDX)
414	encodeInt64Opt(b, 2, p.Line)
415}
416
417var lineDecoder = []decoder{
418	nil, // 0
419	// optional uint64 function_id = 1
420	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
421	// optional int64 line = 2
422	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
423}
424
425func (p *Function) decoder() []decoder {
426	return functionDecoder
427}
428
429func (p *Function) encode(b *buffer) {
430	encodeUint64Opt(b, 1, p.ID)
431	encodeInt64Opt(b, 2, p.nameX)
432	encodeInt64Opt(b, 3, p.systemNameX)
433	encodeInt64Opt(b, 4, p.filenameX)
434	encodeInt64Opt(b, 5, p.StartLine)
435}
436
437var functionDecoder = []decoder{
438	nil, // 0
439	// optional uint64 id = 1
440	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
441	// optional int64 function_name = 2
442	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
443	// optional int64 function_system_name = 3
444	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
445	// repeated int64 filename = 4
446	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
447	// optional int64 start_line = 5
448	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
449}
450
451func addString(strings map[string]int, s string) int64 {
452	i, ok := strings[s]
453	if !ok {
454		i = len(strings)
455		strings[s] = i
456	}
457	return int64(i)
458}
459
460func getString(strings []string, strng *int64, err error) (string, error) {
461	if err != nil {
462		return "", err
463	}
464	s := int(*strng)
465	if s < 0 || s >= len(strings) {
466		return "", errMalformed
467	}
468	*strng = 0
469	return strings[s], nil
470}
471