blob: 00b0a850e0d4635239d1112f717243238bd6d2a9 [file] [log] [blame]
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -07001// 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 runtime
6
Michael Matloob432cb662015-11-11 12:39:30 -05007import (
8 "runtime/internal/sys"
9 "unsafe"
10)
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -070011
Russ Cox97f83862014-09-03 13:02:48 -040012// NOTE: Func does not expose the actual unexported fields, because we return *Func
13// values to users, and we want to keep them from being able to overwrite the data
14// with (say) *f = Func{}.
15// All code operating on a *Func must call raw to get the *_func instead.
16
17// A Func represents a Go function in the running binary.
18type Func struct {
19 opaque struct{} // unexported field to disallow conversions
20}
21
22func (f *Func) raw() *_func {
23 return (*_func)(unsafe.Pointer(f))
24}
25
26// funcdata.h
27const (
Russ Coxd98553a2014-11-11 17:04:34 -050028 _PCDATA_StackMapIndex = 0
Russ Cox97f83862014-09-03 13:02:48 -040029 _FUNCDATA_ArgsPointerMaps = 0
30 _FUNCDATA_LocalsPointerMaps = 1
Russ Cox97f83862014-09-03 13:02:48 -040031 _ArgsSizeUnknown = -0x80000000
32)
33
Michael Hudson-Doyle67426a82015-03-12 12:22:18 +130034// moduledata records information about the layout of the executable
35// image. It is written by the linker. Any changes here must be
36// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
Russ Cox512f75e2015-05-08 01:43:18 -040037// moduledata is stored in read-only memory; none of the pointers here
38// are visible to the garbage collector.
Michael Hudson-Doyle67426a82015-03-12 12:22:18 +130039type moduledata struct {
Michael Hudson-Doyle3a84e332015-03-16 11:53:08 +130040 pclntable []byte
41 ftab []functab
42 filetab []uint32
43 findfunctab uintptr
44 minpc, maxpc uintptr
Russ Cox97f83862014-09-03 13:02:48 -040045
Michael Hudson-Doyle67426a82015-03-12 12:22:18 +130046 text, etext uintptr
47 noptrdata, enoptrdata uintptr
48 data, edata uintptr
49 bss, ebss uintptr
50 noptrbss, enoptrbss uintptr
51 end, gcdata, gcbss uintptr
Keith Randall63116de2014-12-27 19:26:40 -080052
Michael Hudson-Doyle3a84e332015-03-16 11:53:08 +130053 typelinks []*_type
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +000054
Michael Hudson-Doyle77fc03f2015-04-11 12:05:21 +080055 modulename string
56 modulehashes []modulehash
57
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +000058 gcdatamask, gcbssmask bitvector
59
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +000060 next *moduledata
Michael Hudson-Doyle67426a82015-03-12 12:22:18 +130061}
62
Michael Hudson-Doyle77fc03f2015-04-11 12:05:21 +080063// For each shared library a module links against, the linker creates an entry in the
64// moduledata.modulehashes slice containing the name of the module, the abi hash seen
65// at link time and a pointer to the runtime abi hash. These are checked in
66// moduledataverify1 below.
67type modulehash struct {
68 modulename string
69 linktimehash string
70 runtimehash *string
71}
72
Michael Hudson-Doylef616af22015-04-01 14:17:43 +130073var firstmoduledata moduledata // linker symbol
74var lastmoduledatap *moduledata // linker symbol
Russ Cox97f83862014-09-03 13:02:48 -040075
76type functab struct {
77 entry uintptr
78 funcoff uintptr
79}
80
Keith Randall6dd31662015-02-09 16:36:25 -080081const minfunc = 16 // minimum function size
82const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
Keith Randall63116de2014-12-27 19:26:40 -080083
84// findfunctab is an array of these structures.
85// Each bucket represents 4096 bytes of the text segment.
86// Each subbucket represents 256 bytes of the text segment.
87// To find a function given a pc, locate the bucket and subbucket for
88// that pc. Add together the idx and subbucket value to obtain a
89// function index. Then scan the functab array starting at that
90// index to find the target function.
91// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
92type findfuncbucket struct {
Keith Randall6dd31662015-02-09 16:36:25 -080093 idx uint32
Keith Randall63116de2014-12-27 19:26:40 -080094 subbuckets [16]byte
95}
96
Michael Hudson-Doylefa896732015-05-06 14:30:28 +120097func moduledataverify() {
98 for datap := &firstmoduledata; datap != nil; datap = datap.next {
99 moduledataverify1(datap)
100 }
101}
102
Russ Cox434e0bc2015-06-28 22:26:35 -0400103const debugPcln = false
104
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200105func moduledataverify1(datap *moduledata) {
Russ Cox97f83862014-09-03 13:02:48 -0400106 // See golang.org/s/go12symtab for header: 0xfffffffb,
107 // two zero bytes, a byte giving the PC quantum,
108 // and a byte giving the pointer width in bytes.
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200109 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
110 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
Michael Matloob432cb662015-11-11 12:39:30 -0500111 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize {
Russ Cox97f83862014-09-03 13:02:48 -0400112 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
Keith Randallb2a950b2014-12-27 20:58:00 -0800113 throw("invalid function symbol table\n")
Russ Cox97f83862014-09-03 13:02:48 -0400114 }
115
Russ Cox97f83862014-09-03 13:02:48 -0400116 // ftab is lookup table for function by program counter.
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200117 nftab := len(datap.ftab) - 1
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400118 var pcCache pcvalueCache
Russ Cox97f83862014-09-03 13:02:48 -0400119 for i := 0; i < nftab; i++ {
120 // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200121 if datap.ftab[i].entry > datap.ftab[i+1].entry {
122 f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
123 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
Russ Cox97f83862014-09-03 13:02:48 -0400124 f2name := "end"
125 if i+1 < nftab {
Keith Randall0bb8fc62014-12-28 23:16:32 -0800126 f2name = funcname(f2)
Russ Cox97f83862014-09-03 13:02:48 -0400127 }
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200128 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
Russ Cox97f83862014-09-03 13:02:48 -0400129 for j := 0; j <= i; j++ {
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200130 print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
Russ Cox97f83862014-09-03 13:02:48 -0400131 }
Keith Randallb2a950b2014-12-27 20:58:00 -0800132 throw("invalid runtime symbol table")
Russ Cox97f83862014-09-03 13:02:48 -0400133 }
Russ Cox434e0bc2015-06-28 22:26:35 -0400134
135 if debugPcln || nftab-i < 5 {
Russ Cox8b99bb72015-06-29 13:32:09 -0400136 // Check a PC near but not at the very end.
137 // The very end might be just padding that is not covered by the tables.
138 // No architecture rounds function entries to more than 16 bytes,
139 // but if one came along we'd need to subtract more here.
Russ Cox74ec5bf2015-07-23 02:23:14 -0400140 // But don't use the next PC if it corresponds to a foreign object chunk
141 // (no pcln table, f2.pcln == 0). That chunk might have an alignment
142 // more than 16 bytes.
Russ Cox434e0bc2015-06-28 22:26:35 -0400143 f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
Russ Cox74ec5bf2015-07-23 02:23:14 -0400144 end := f.entry
145 if i+1 < nftab {
146 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
147 if f2.pcln != 0 {
148 end = f2.entry - 16
149 if end < f.entry {
150 end = f.entry
151 }
152 }
153 }
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400154 pcvalue(f, f.pcfile, end, &pcCache, true)
155 pcvalue(f, f.pcln, end, &pcCache, true)
156 pcvalue(f, f.pcsp, end, &pcCache, true)
Russ Cox434e0bc2015-06-28 22:26:35 -0400157 }
Russ Cox97f83862014-09-03 13:02:48 -0400158 }
159
Michael Hudson-Doylefa896732015-05-06 14:30:28 +1200160 if datap.minpc != datap.ftab[0].entry ||
161 datap.maxpc != datap.ftab[nftab].entry {
Michael Hudson-Doyle3a84e332015-03-16 11:53:08 +1300162 throw("minpc or maxpc invalid")
163 }
Michael Hudson-Doyle77fc03f2015-04-11 12:05:21 +0800164
165 for _, modulehash := range datap.modulehashes {
166 if modulehash.linktimehash != *modulehash.runtimehash {
167 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
168 throw("abi mismatch")
169 }
170 }
Russ Cox97f83862014-09-03 13:02:48 -0400171}
172
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700173// FuncForPC returns a *Func describing the function that contains the
174// given program counter address, or else nil.
175func FuncForPC(pc uintptr) *Func {
Russ Cox97f83862014-09-03 13:02:48 -0400176 return (*Func)(unsafe.Pointer(findfunc(pc)))
177}
178
179// Name returns the name of the function.
180func (f *Func) Name() string {
Keith Randall0bb8fc62014-12-28 23:16:32 -0800181 return funcname(f.raw())
Russ Cox97f83862014-09-03 13:02:48 -0400182}
183
184// Entry returns the entry address of the function.
185func (f *Func) Entry() uintptr {
186 return f.raw().entry
187}
188
189// FileLine returns the file name and line number of the
190// source code corresponding to the program counter pc.
191// The result will not be accurate if pc is not a program
192// counter within f.
193func (f *Func) FileLine(pc uintptr) (file string, line int) {
194 // Pass strict=false here, because anyone can call this function,
195 // and they might just be wrong about targetpc belonging to f.
Russ Cox656be312014-11-12 14:54:31 -0500196 file, line32 := funcline1(f.raw(), pc, false)
197 return file, int(line32)
Russ Cox97f83862014-09-03 13:02:48 -0400198}
199
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000200func findmoduledatap(pc uintptr) *moduledata {
Michael Hudson-Doylea1f57592015-04-07 12:55:02 +1200201 for datap := &firstmoduledata; datap != nil; datap = datap.next {
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000202 if datap.minpc <= pc && pc <= datap.maxpc {
203 return datap
204 }
205 }
206 return nil
207}
208
Russ Cox97f83862014-09-03 13:02:48 -0400209func findfunc(pc uintptr) *_func {
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000210 datap := findmoduledatap(pc)
211 if datap == nil {
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700212 return nil
213 }
Keith Randall63116de2014-12-27 19:26:40 -0800214 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700215
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000216 x := pc - datap.minpc
Keith Randall63116de2014-12-27 19:26:40 -0800217 b := x / pcbucketsize
Keith Randall6dd31662015-02-09 16:36:25 -0800218 i := x % pcbucketsize / (pcbucketsize / nsub)
Keith Randall63116de2014-12-27 19:26:40 -0800219
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000220 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
Keith Randall63116de2014-12-27 19:26:40 -0800221 idx := ffb.idx + uint32(ffb.subbuckets[i])
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000222 if pc < datap.ftab[idx].entry {
Keith Randall63116de2014-12-27 19:26:40 -0800223 throw("findfunc: bad findfunctab entry")
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700224 }
225
Keith Randall63116de2014-12-27 19:26:40 -0800226 // linear search to find func with pc >= entry.
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000227 for datap.ftab[idx+1].entry <= pc {
Keith Randall63116de2014-12-27 19:26:40 -0800228 idx++
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700229 }
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000230 return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700231}
232
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400233type pcvalueCache struct {
234 entries [16]pcvalueCacheEnt
235}
236
237type pcvalueCacheEnt struct {
238 // targetpc and off together are the key of this cache entry.
239 targetpc uintptr
240 off int32
241 // val is the value of this cached pcvalue entry.
242 val int32
243}
244
245func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700246 if off == 0 {
247 return -1
248 }
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400249
250 // Check the cache. This speeds up walks of deep stacks, which
251 // tend to have the same recursive functions over and over.
252 //
253 // This cache is small enough that full associativity is
254 // cheaper than doing the hashing for a less associative
255 // cache.
256 if cache != nil {
257 for _, ent := range cache.entries {
258 // We check off first because we're more
259 // likely to have multiple entries with
260 // different offsets for the same targetpc
261 // than the other way around, so we'll usually
262 // fail in the first clause.
263 if ent.off == off && ent.targetpc == targetpc {
264 return ent.val
265 }
266 }
267 }
268
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000269 datap := findmoduledatap(f.entry) // inefficient
Ian Lance Taylor692054e2015-07-18 13:35:12 -0700270 if datap == nil {
271 if strict && panicking == 0 {
272 print("runtime: no module data for ", hex(f.entry), "\n")
273 throw("no module data")
274 }
275 return -1
276 }
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000277 p := datap.pclntable[off:]
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700278 pc := f.entry
279 val := int32(-1)
Russ Cox6c67dd92014-08-24 20:28:29 -0400280 for {
281 var ok bool
282 p, ok = step(p, &pc, &val, pc == f.entry)
283 if !ok {
284 break
285 }
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700286 if targetpc < pc {
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400287 // Replace a random entry in the cache. Random
288 // replacement prevents a performance cliff if
289 // a recursive stack's cycle is slightly
290 // larger than the cache.
291 if cache != nil {
292 ci := fastrand1() % uint32(len(cache.entries))
293 cache.entries[ci] = pcvalueCacheEnt{
294 targetpc: targetpc,
295 off: off,
296 val: val,
297 }
298 }
299
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700300 return val
301 }
302 }
Russ Cox97f83862014-09-03 13:02:48 -0400303
304 // If there was a table, it should have covered all program counters.
305 // If not, something is wrong.
306 if panicking != 0 || !strict {
307 return -1
308 }
309
Keith Randall0bb8fc62014-12-28 23:16:32 -0800310 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
Russ Cox97f83862014-09-03 13:02:48 -0400311
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000312 p = datap.pclntable[off:]
Russ Cox97f83862014-09-03 13:02:48 -0400313 pc = f.entry
314 val = -1
315 for {
316 var ok bool
317 p, ok = step(p, &pc, &val, pc == f.entry)
318 if !ok {
319 break
320 }
321 print("\tvalue=", val, " until pc=", hex(pc), "\n")
322 }
323
Keith Randallb2a950b2014-12-27 20:58:00 -0800324 throw("invalid runtime symbol table")
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700325 return -1
326}
327
Keith Randall0bb8fc62014-12-28 23:16:32 -0800328func cfuncname(f *_func) *byte {
Russ Cox97f83862014-09-03 13:02:48 -0400329 if f == nil || f.nameoff == 0 {
330 return nil
331 }
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000332 datap := findmoduledatap(f.entry) // inefficient
Ian Lance Taylor692054e2015-07-18 13:35:12 -0700333 if datap == nil {
334 return nil
335 }
Nodir Turakulov3be4d592015-10-09 11:15:53 -0700336 return &datap.pclntable[f.nameoff]
Russ Cox97f83862014-09-03 13:02:48 -0400337}
338
Keith Randall0bb8fc62014-12-28 23:16:32 -0800339func funcname(f *_func) string {
340 return gostringnocopy(cfuncname(f))
Russ Cox97f83862014-09-03 13:02:48 -0400341}
342
Russ Cox656be312014-11-12 14:54:31 -0500343func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000344 datap := findmoduledatap(f.entry) // inefficient
Ian Lance Taylor692054e2015-07-18 13:35:12 -0700345 if datap == nil {
346 return "?", 0
347 }
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400348 fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
349 line = pcvalue(f, f.pcln, targetpc, nil, strict)
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000350 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
Keith Randall0bb8fc62014-12-28 23:16:32 -0800351 // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
Russ Cox656be312014-11-12 14:54:31 -0500352 return "?", 0
Russ Cox97f83862014-09-03 13:02:48 -0400353 }
Michael Hudson-Doylefae4a122015-03-29 21:59:00 +0000354 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
Russ Cox656be312014-11-12 14:54:31 -0500355 return
Russ Cox97f83862014-09-03 13:02:48 -0400356}
357
Russ Cox656be312014-11-12 14:54:31 -0500358func funcline(f *_func, targetpc uintptr) (file string, line int32) {
359 return funcline1(f, targetpc, true)
Russ Cox97f83862014-09-03 13:02:48 -0400360}
361
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400362func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
363 x := pcvalue(f, f.pcsp, targetpc, cache, true)
Michael Matloob432cb662015-11-11 12:39:30 -0500364 if x&(sys.PtrSize-1) != 0 {
Russ Cox434e0bc2015-06-28 22:26:35 -0400365 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
Russ Cox97f83862014-09-03 13:02:48 -0400366 }
367 return x
368}
369
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400370func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
Russ Cox97f83862014-09-03 13:02:48 -0400371 if table < 0 || table >= f.npcdata {
372 return -1
373 }
374 off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
Austin Clementsbeedb1e2015-08-12 23:43:43 -0400375 return pcvalue(f, off, targetpc, cache, true)
Russ Cox97f83862014-09-03 13:02:48 -0400376}
377
Russ Cox97f83862014-09-03 13:02:48 -0400378func funcdata(f *_func, i int32) unsafe.Pointer {
379 if i < 0 || i >= f.nfuncdata {
380 return nil
381 }
382 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
Michael Matloob432cb662015-11-11 12:39:30 -0500383 if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
Russ Cox97f83862014-09-03 13:02:48 -0400384 if uintptr(unsafe.Pointer(f))&4 != 0 {
385 println("runtime: misaligned func", f)
386 }
387 p = add(p, 4)
388 }
Michael Matloob432cb662015-11-11 12:39:30 -0500389 return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize))
Russ Cox97f83862014-09-03 13:02:48 -0400390}
391
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700392// step advances to the next pc, value pair in the encoded table.
Russ Cox6c67dd92014-08-24 20:28:29 -0400393func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
394 p, uvdelta := readvarint(p)
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700395 if uvdelta == 0 && !first {
Russ Cox6c67dd92014-08-24 20:28:29 -0400396 return nil, false
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700397 }
398 if uvdelta&1 != 0 {
399 uvdelta = ^(uvdelta >> 1)
400 } else {
401 uvdelta >>= 1
402 }
403 vdelta := int32(uvdelta)
Russ Cox6c67dd92014-08-24 20:28:29 -0400404 p, pcdelta := readvarint(p)
Michael Matloob432cb662015-11-11 12:39:30 -0500405 *pc += uintptr(pcdelta * sys.PCQuantum)
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700406 *val += vdelta
Russ Cox6c67dd92014-08-24 20:28:29 -0400407 return p, true
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700408}
409
Russ Cox6c67dd92014-08-24 20:28:29 -0400410// readvarint reads a varint from p.
411func readvarint(p []byte) (newp []byte, val uint32) {
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700412 var v, shift uint32
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700413 for {
Russ Cox6c67dd92014-08-24 20:28:29 -0400414 b := p[0]
415 p = p[1:]
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700416 v |= (uint32(b) & 0x7F) << shift
417 if b&0x80 == 0 {
418 break
419 }
420 shift += 7
421 }
Russ Cox6c67dd92014-08-24 20:28:29 -0400422 return p, v
Josh Bleecher Snyder0be59732014-08-22 08:41:32 -0700423}
Russ Cox484f8012015-02-19 13:38:46 -0500424
425type stackmap struct {
426 n int32 // number of bitmaps
427 nbit int32 // number of bits in each bitmap
428 bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
429}
430
431//go:nowritebarrier
432func stackmapdata(stkmap *stackmap, n int32) bitvector {
433 if n < 0 || n >= stkmap.n {
434 throw("stackmapdata: index out of range")
435 }
436 return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
437}