// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice. func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte { b = append(b, dwarf.DW_CFA_def_cfa_offset_sf) b = dwarf.AppendSleb128(b, cfa/dataAlignmentFactor) switch { case deltapc < 0x40: b = append(b, uint8(dwarf.DW_CFA_advance_loc+deltapc)) case deltapc < 0x100: b = append(b, dwarf.DW_CFA_advance_loc1) b = append(b, uint8(deltapc)) case deltapc < 0x10000: b = append(b, dwarf.DW_CFA_advance_loc2) b = Thearch.Append16(b, uint16(deltapc)) default: b = append(b, dwarf.DW_CFA_advance_loc4) b = Thearch.Append32(b, uint32(deltapc)) } return b }
func writeframes(ctxt *Link, syms []*Symbol) []*Symbol { var dwarfctxt dwarf.Context = dwctxt{ctxt} if framesec == nil { framesec = Linklookup(ctxt, ".debug_frame", 0) } framesec.Type = obj.SDWARFSECT framesec.R = framesec.R[:0] fs := framesec syms = append(syms, fs) // Emit the CIE, Section 6.4.1 cieReserve := uint32(16) if haslinkregister(ctxt) { cieReserve = 32 } Adduint32(ctxt, fs, cieReserve) // initial length, must be multiple of thearch.ptrsize Adduint32(ctxt, fs, 0xffffffff) // cid. Adduint8(ctxt, fs, 3) // dwarf version (appendix F) Adduint8(ctxt, fs, 0) // augmentation "" dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor dwarf.Sleb128put(dwarfctxt, fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr)) // return_address_register Adduint8(ctxt, fs, dwarf.DW_CFA_def_cfa) // Set the current frame address.. dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)... if haslinkregister(ctxt) { dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...plus a 0 offset. Adduint8(ctxt, fs, dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue. dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr)) Adduint8(ctxt, fs, dwarf.DW_CFA_val_offset) // The previous value... dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register... dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...is CFA+0. } else { dwarf.Uleb128put(dwarfctxt, fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame). Adduint8(ctxt, fs, dwarf.DW_CFA_offset_extended) // The previous value... dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr)) // ...of the return address... dwarf.Uleb128put(dwarfctxt, fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)]. } // 4 is to exclude the length field. pad := int64(cieReserve) + 4 - fs.Size if pad < 0 { Exitf("dwarf: cieReserve too small by %d bytes.", -pad) } Addbytes(ctxt, fs, zeros[:pad]) var deltaBuf []byte var pcsp Pciter for _, ctxt.Cursym = range ctxt.Textp { s := ctxt.Cursym if s.FuncInfo == nil { continue } // Emit a FDE, Section 6.4.1. // First build the section contents into a byte buffer. deltaBuf = deltaBuf[:0] for pciterinit(ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) { nextpc := pcsp.nextpc // pciterinit goes up to the end of the function, // but DWARF expects us to stop just before the end. if int64(nextpc) == s.Size { nextpc-- if nextpc < pcsp.pc { continue } } if haslinkregister(ctxt) { // TODO(bryanpkc): This is imprecise. In general, the instruction // that stores the return address to the stack frame is not the // same one that allocates the frame. if pcsp.value > 0 { // The return address is preserved at (CFA-frame_size) // after a stack frame has been allocated. deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf) deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr)) deltaBuf = dwarf.AppendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor) } else { // The return address is restored into the link register // when a stack frame has been de-allocated. deltaBuf = append(deltaBuf, dwarf.DW_CFA_same_value) deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr)) } deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value)) } else { deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(SysArch.PtrSize)+int64(pcsp.value)) } } pad := int(Rnd(int64(len(deltaBuf)), int64(SysArch.PtrSize))) - len(deltaBuf) deltaBuf = append(deltaBuf, zeros[:pad]...) // Emit the FDE header, Section 6.4.1. // 4 bytes: length, must be multiple of thearch.ptrsize // 4 bytes: Pointer to the CIE above, at offset 0 // ptrsize: initial location // ptrsize: address range Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself) if Linkmode == LinkExternal { adddwarfref(ctxt, fs, framesec, 4) } else { Adduint32(ctxt, fs, 0) // CIE offset } Addaddr(ctxt, fs, s) adduintxx(ctxt, fs, uint64(s.Size), SysArch.PtrSize) // address range Addbytes(ctxt, fs, deltaBuf) } return syms }