return ret, symbolizeResult
}
-// locForPC returns the location ID for addr.
-// addr must a return PC or 1 + the PC of an inline marker. This returns the location of the corresponding call.
-// It may emit to b.pb, so there must be no message encoding in progress.
-func (b *profileBuilder) locForPC(addr uintptr) uint64 {
- if loc, ok := b.locs[addr]; ok {
- return loc.id
- }
-
- // Expand this one address using CallersFrames so we can cache
- // each expansion. In general, CallersFrames takes a whole
- // stack, but in this case we know there will be no skips in
- // the stack and we have return PCs anyway.
- frames := runtime.CallersFrames([]uintptr{addr})
- frame, more := frames.Next()
- if frame.Function == "runtime.goexit" {
- // Short-circuit if we see runtime.goexit so the loop
- // below doesn't allocate a useless empty location.
- return 0
- }
-
- symbolizeResult := lookupTried
- if frame.PC == 0 || frame.Function == "" || frame.File == "" || frame.Line == 0 {
- symbolizeResult |= lookupFailed
- }
-
- if frame.PC == 0 {
- // If we failed to resolve the frame, at least make up
- // a reasonable call PC. This mostly happens in tests.
- frame.PC = addr - 1
- }
-
- // We can't write out functions while in the middle of the
- // Location message, so record new functions we encounter and
- // write them out after the Location.
- type newFunc struct {
- id uint64
- name, file string
- }
- newFuncs := make([]newFunc, 0, 8)
-
- id := uint64(len(b.locs)) + 1
- b.locs[addr] = locInfo{id: id, pcs: []uintptr{addr}}
- start := b.pb.startMessage()
- b.pb.uint64Opt(tagLocation_ID, id)
- b.pb.uint64Opt(tagLocation_Address, uint64(frame.PC))
- for frame.Function != "runtime.goexit" {
- // Write out each line in frame expansion.
- funcID := uint64(b.funcs[frame.Function])
- if funcID == 0 {
- funcID = uint64(len(b.funcs)) + 1
- b.funcs[frame.Function] = int(funcID)
- newFuncs = append(newFuncs, newFunc{funcID, frame.Function, frame.File})
- }
- b.pbLine(tagLocation_Line, funcID, int64(frame.Line))
- if !more {
- break
- }
- frame, more = frames.Next()
- }
- for i := range b.mem {
- if b.mem[i].start <= addr && addr < b.mem[i].end || b.mem[i].fake {
- b.pb.uint64Opt(tagLocation_MappingID, uint64(i+1))
-
- m := b.mem[i]
- m.funcs |= symbolizeResult
- b.mem[i] = m
- break
- }
- }
- b.pb.endMessage(tagProfile_Location, start)
-
- // Write out functions we found during frame expansion.
- for _, fn := range newFuncs {
- start := b.pb.startMessage()
- b.pb.uint64Opt(tagFunction_ID, fn.id)
- b.pb.int64Opt(tagFunction_Name, b.stringIndex(fn.name))
- b.pb.int64Opt(tagFunction_SystemName, b.stringIndex(fn.name))
- b.pb.int64Opt(tagFunction_Filename, b.stringIndex(fn.file))
- b.pb.endMessage(tagProfile_Function, start)
- }
-
- b.flush()
- return id
-}
-
type locInfo struct {
// location id assigned by the profileBuilder
id uint64