dwarf.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. // Copyright 2019 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. // Writes dwarf information to object files.
  5. package obj
  6. import (
  7. "github.com/twitchyliquid64/golang-asm/dwarf"
  8. "github.com/twitchyliquid64/golang-asm/objabi"
  9. "github.com/twitchyliquid64/golang-asm/src"
  10. "fmt"
  11. "sort"
  12. "sync"
  13. )
  14. // Generate a sequence of opcodes that is as short as possible.
  15. // See section 6.2.5
  16. const (
  17. LINE_BASE = -4
  18. LINE_RANGE = 10
  19. PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
  20. OPCODE_BASE = 11
  21. )
  22. // generateDebugLinesSymbol fills the debug lines symbol of a given function.
  23. //
  24. // It's worth noting that this function doesn't generate the full debug_lines
  25. // DWARF section, saving that for the linker. This function just generates the
  26. // state machine part of debug_lines. The full table is generated by the
  27. // linker. Also, we use the file numbers from the full package (not just the
  28. // function in question) when generating the state machine. We do this so we
  29. // don't have to do a fixup on the indices when writing the full section.
  30. func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
  31. dctxt := dwCtxt{ctxt}
  32. // Emit a LNE_set_address extended opcode, so as to establish the
  33. // starting text address of this function.
  34. dctxt.AddUint8(lines, 0)
  35. dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
  36. dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
  37. dctxt.AddAddress(lines, s, 0)
  38. // Set up the debug_lines state machine to the default values
  39. // we expect at the start of a new sequence.
  40. stmt := true
  41. line := int64(1)
  42. pc := s.Func.Text.Pc
  43. var lastpc int64 // last PC written to line table, not last PC in func
  44. name := ""
  45. prologue, wrotePrologue := false, false
  46. // Walk the progs, generating the DWARF table.
  47. for p := s.Func.Text; p != nil; p = p.Link {
  48. prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
  49. // If we're not at a real instruction, keep looping!
  50. if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
  51. continue
  52. }
  53. newStmt := p.Pos.IsStmt() != src.PosNotStmt
  54. newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
  55. // Output debug info.
  56. wrote := false
  57. if name != newName {
  58. newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
  59. dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
  60. dwarf.Uleb128put(dctxt, lines, int64(newFile))
  61. name = newName
  62. wrote = true
  63. }
  64. if prologue && !wrotePrologue {
  65. dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
  66. wrotePrologue = true
  67. wrote = true
  68. }
  69. if stmt != newStmt {
  70. dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
  71. stmt = newStmt
  72. wrote = true
  73. }
  74. if line != int64(newLine) || wrote {
  75. pcdelta := p.Pc - pc
  76. lastpc = p.Pc
  77. putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
  78. line, pc = int64(newLine), p.Pc
  79. }
  80. }
  81. // Because these symbols will be concatenated together by the
  82. // linker, we need to reset the state machine that controls the
  83. // debug symbols. Do this using an end-of-sequence operator.
  84. //
  85. // Note: at one point in time, Delve did not support multiple end
  86. // sequence ops within a compilation unit (bug for this:
  87. // https://github.com/go-delve/delve/issues/1694), however the bug
  88. // has since been fixed (Oct 2019).
  89. //
  90. // Issue 38192: the DWARF standard specifies that when you issue
  91. // an end-sequence op, the PC value should be one past the last
  92. // text address in the translation unit, so apply a delta to the
  93. // text address before the end sequence op. If this isn't done,
  94. // GDB will assign a line number of zero the last row in the line
  95. // table, which we don't want.
  96. lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
  97. putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
  98. dctxt.AddUint8(lines, 0) // start extended opcode
  99. dwarf.Uleb128put(dctxt, lines, 1)
  100. dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
  101. }
  102. func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
  103. // Choose a special opcode that minimizes the number of bytes needed to
  104. // encode the remaining PC delta and LC delta.
  105. var opcode int64
  106. if deltaLC < LINE_BASE {
  107. if deltaPC >= PC_RANGE {
  108. opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
  109. } else {
  110. opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
  111. }
  112. } else if deltaLC < LINE_BASE+LINE_RANGE {
  113. if deltaPC >= PC_RANGE {
  114. opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
  115. if opcode > 255 {
  116. opcode -= LINE_RANGE
  117. }
  118. } else {
  119. opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
  120. }
  121. } else {
  122. if deltaPC <= PC_RANGE {
  123. opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
  124. if opcode > 255 {
  125. opcode = 255
  126. }
  127. } else {
  128. // Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1).
  129. //
  130. // Let x=deltaPC-PC_RANGE. If we use opcode 255, x will be the remaining
  131. // deltaPC that we need to encode separately before emitting 255. If we
  132. // use opcode 249, we will need to encode x+1. If x+1 takes one more
  133. // byte to encode than x, then we use opcode 255.
  134. //
  135. // In all other cases x and x+1 take the same number of bytes to encode,
  136. // so we use opcode 249, which may save us a byte in encoding deltaLC,
  137. // for similar reasons.
  138. switch deltaPC - PC_RANGE {
  139. // PC_RANGE is the largest deltaPC we can encode in one byte, using
  140. // DW_LNS_const_add_pc.
  141. //
  142. // (1<<16)-1 is the largest deltaPC we can encode in three bytes, using
  143. // DW_LNS_fixed_advance_pc.
  144. //
  145. // (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for
  146. // n=1,3,4,5,..., using DW_LNS_advance_pc.
  147. case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
  148. (1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
  149. opcode = 255
  150. default:
  151. opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
  152. }
  153. }
  154. }
  155. if opcode < OPCODE_BASE || opcode > 255 {
  156. panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
  157. }
  158. // Subtract from deltaPC and deltaLC the amounts that the opcode will add.
  159. deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
  160. deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
  161. // Encode deltaPC.
  162. if deltaPC != 0 {
  163. if deltaPC <= PC_RANGE {
  164. // Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
  165. // instruction.
  166. opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
  167. if opcode < OPCODE_BASE {
  168. panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
  169. }
  170. dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
  171. } else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
  172. dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
  173. dctxt.AddUint16(s, uint16(deltaPC))
  174. } else {
  175. dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
  176. dwarf.Uleb128put(dctxt, s, int64(deltaPC))
  177. }
  178. }
  179. // Encode deltaLC.
  180. if deltaLC != 0 {
  181. dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
  182. dwarf.Sleb128put(dctxt, s, deltaLC)
  183. }
  184. // Output the special opcode.
  185. dctxt.AddUint8(s, uint8(opcode))
  186. }
  187. // implement dwarf.Context
  188. type dwCtxt struct{ *Link }
  189. func (c dwCtxt) PtrSize() int {
  190. return c.Arch.PtrSize
  191. }
  192. func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
  193. ls := s.(*LSym)
  194. ls.WriteInt(c.Link, ls.Size, size, i)
  195. }
  196. func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
  197. c.AddInt(s, 2, int64(i))
  198. }
  199. func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
  200. b := []byte{byte(i)}
  201. c.AddBytes(s, b)
  202. }
  203. func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
  204. ls := s.(*LSym)
  205. ls.WriteBytes(c.Link, ls.Size, b)
  206. }
  207. func (c dwCtxt) AddString(s dwarf.Sym, v string) {
  208. ls := s.(*LSym)
  209. ls.WriteString(c.Link, ls.Size, len(v), v)
  210. ls.WriteInt(c.Link, ls.Size, 1, 0)
  211. }
  212. func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
  213. ls := s.(*LSym)
  214. size := c.PtrSize()
  215. if data != nil {
  216. rsym := data.(*LSym)
  217. ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
  218. } else {
  219. ls.WriteInt(c.Link, ls.Size, size, value)
  220. }
  221. }
  222. func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
  223. ls := s.(*LSym)
  224. rsym := data.(*LSym)
  225. ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
  226. }
  227. func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
  228. panic("should be used only in the linker")
  229. }
  230. func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
  231. size := 4
  232. if isDwarf64(c.Link) {
  233. size = 8
  234. }
  235. ls := s.(*LSym)
  236. rsym := t.(*LSym)
  237. ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
  238. r := &ls.R[len(ls.R)-1]
  239. r.Type = objabi.R_DWARFSECREF
  240. }
  241. func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
  242. ls := s.(*LSym)
  243. rsym := f.(*LSym)
  244. fidx := c.Link.PosTable.FileIndex(rsym.Name)
  245. // Note the +1 here -- the value we're writing is going to be an
  246. // index into the DWARF line table file section, whose entries
  247. // are numbered starting at 1, not 0.
  248. ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
  249. }
  250. func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
  251. ls := s.(*LSym)
  252. return ls.Size
  253. }
  254. // Here "from" is a symbol corresponding to an inlined or concrete
  255. // function, "to" is the symbol for the corresponding abstract
  256. // function, and "dclIdx" is the index of the symbol of interest with
  257. // respect to the Dcl slice of the original pre-optimization version
  258. // of the inlined function.
  259. func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
  260. ls := from.(*LSym)
  261. tls := to.(*LSym)
  262. ridx := len(ls.R) - 1
  263. c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
  264. }
  265. func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
  266. ls := s.(*LSym)
  267. c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
  268. }
  269. func (c dwCtxt) Logf(format string, args ...interface{}) {
  270. c.Link.Logf(format, args...)
  271. }
  272. func isDwarf64(ctxt *Link) bool {
  273. return ctxt.Headtype == objabi.Haix
  274. }
  275. func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
  276. if s.Type != objabi.STEXT {
  277. ctxt.Diag("dwarfSym of non-TEXT %v", s)
  278. }
  279. if s.Func.dwarfInfoSym == nil {
  280. s.Func.dwarfInfoSym = &LSym{
  281. Type: objabi.SDWARFFCN,
  282. }
  283. if ctxt.Flag_locationlists {
  284. s.Func.dwarfLocSym = &LSym{
  285. Type: objabi.SDWARFLOC,
  286. }
  287. }
  288. s.Func.dwarfRangesSym = &LSym{
  289. Type: objabi.SDWARFRANGE,
  290. }
  291. s.Func.dwarfDebugLinesSym = &LSym{
  292. Type: objabi.SDWARFLINES,
  293. }
  294. if s.WasInlined() {
  295. s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
  296. }
  297. }
  298. return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
  299. }
  300. func (s *LSym) Length(dwarfContext interface{}) int64 {
  301. return s.Size
  302. }
  303. // fileSymbol returns a symbol corresponding to the source file of the
  304. // first instruction (prog) of the specified function. This will
  305. // presumably be the file in which the function is defined.
  306. func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
  307. p := fn.Func.Text
  308. if p != nil {
  309. f, _ := linkgetlineFromPos(ctxt, p.Pos)
  310. fsym := ctxt.Lookup(f)
  311. return fsym
  312. }
  313. return nil
  314. }
  315. // populateDWARF fills in the DWARF Debugging Information Entries for
  316. // TEXT symbol 's'. The various DWARF symbols must already have been
  317. // initialized in InitTextSym.
  318. func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
  319. info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
  320. if info.Size != 0 {
  321. ctxt.Diag("makeFuncDebugEntry double process %v", s)
  322. }
  323. var scopes []dwarf.Scope
  324. var inlcalls dwarf.InlCalls
  325. if ctxt.DebugInfo != nil {
  326. scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
  327. }
  328. var err error
  329. dwctxt := dwCtxt{ctxt}
  330. filesym := ctxt.fileSymbol(s)
  331. fnstate := &dwarf.FnState{
  332. Name: s.Name,
  333. Importpath: myimportpath,
  334. Info: info,
  335. Filesym: filesym,
  336. Loc: loc,
  337. Ranges: ranges,
  338. Absfn: absfunc,
  339. StartPC: s,
  340. Size: s.Size,
  341. External: !s.Static(),
  342. Scopes: scopes,
  343. InlCalls: inlcalls,
  344. UseBASEntries: ctxt.UseBASEntries,
  345. }
  346. if absfunc != nil {
  347. err = dwarf.PutAbstractFunc(dwctxt, fnstate)
  348. if err != nil {
  349. ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
  350. }
  351. err = dwarf.PutConcreteFunc(dwctxt, fnstate)
  352. } else {
  353. err = dwarf.PutDefaultFunc(dwctxt, fnstate)
  354. }
  355. if err != nil {
  356. ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
  357. }
  358. // Fill in the debug lines symbol.
  359. ctxt.generateDebugLinesSymbol(s, lines)
  360. }
  361. // DwarfIntConst creates a link symbol for an integer constant with the
  362. // given name, type and value.
  363. func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
  364. if myimportpath == "" {
  365. return
  366. }
  367. s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
  368. s.Type = objabi.SDWARFCONST
  369. ctxt.Data = append(ctxt.Data, s)
  370. })
  371. dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
  372. }
  373. func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
  374. absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
  375. if absfn.Size != 0 {
  376. ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
  377. }
  378. if s.Func == nil {
  379. s.Func = new(FuncInfo)
  380. }
  381. scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
  382. dwctxt := dwCtxt{ctxt}
  383. filesym := ctxt.fileSymbol(s)
  384. fnstate := dwarf.FnState{
  385. Name: s.Name,
  386. Importpath: myimportpath,
  387. Info: absfn,
  388. Filesym: filesym,
  389. Absfn: absfn,
  390. External: !s.Static(),
  391. Scopes: scopes,
  392. UseBASEntries: ctxt.UseBASEntries,
  393. }
  394. if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
  395. ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
  396. }
  397. }
  398. // This table is designed to aid in the creation of references between
  399. // DWARF subprogram DIEs.
  400. //
  401. // In most cases when one DWARF DIE has to refer to another DWARF DIE,
  402. // the target of the reference has an LSym, which makes it easy to use
  403. // the existing relocation mechanism. For DWARF inlined routine DIEs,
  404. // however, the subprogram DIE has to refer to a child
  405. // parameter/variable DIE of the abstract subprogram. This child DIE
  406. // doesn't have an LSym, and also of interest is the fact that when
  407. // DWARF generation is happening for inlined function F within caller
  408. // G, it's possible that DWARF generation hasn't happened yet for F,
  409. // so there is no way to know the offset of a child DIE within F's
  410. // abstract function. Making matters more complex, each inlined
  411. // instance of F may refer to a subset of the original F's variables
  412. // (depending on what happens with optimization, some vars may be
  413. // eliminated).
  414. //
  415. // The fixup table below helps overcome this hurdle. At the point
  416. // where a parameter/variable reference is made (via a call to
  417. // "ReferenceChildDIE"), a fixup record is generate that records
  418. // the relocation that is targeting that child variable. At a later
  419. // point when the abstract function DIE is emitted, there will be
  420. // a call to "RegisterChildDIEOffsets", at which point the offsets
  421. // needed to apply fixups are captured. Finally, once the parallel
  422. // portion of the compilation is done, fixups can actually be applied
  423. // during the "Finalize" method (this can't be done during the
  424. // parallel portion of the compile due to the possibility of data
  425. // races).
  426. //
  427. // This table is also used to record the "precursor" function node for
  428. // each function that is the target of an inline -- child DIE references
  429. // have to be made with respect to the original pre-optimization
  430. // version of the function (to allow for the fact that each inlined
  431. // body may be optimized differently).
  432. type DwarfFixupTable struct {
  433. ctxt *Link
  434. mu sync.Mutex
  435. symtab map[*LSym]int // maps abstract fn LSYM to index in svec
  436. svec []symFixups
  437. precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
  438. }
  439. type symFixups struct {
  440. fixups []relFixup
  441. doffsets []declOffset
  442. inlIndex int32
  443. defseen bool
  444. }
  445. type declOffset struct {
  446. // Index of variable within DCL list of pre-optimization function
  447. dclIdx int32
  448. // Offset of var's child DIE with respect to containing subprogram DIE
  449. offset int32
  450. }
  451. type relFixup struct {
  452. refsym *LSym
  453. relidx int32
  454. dclidx int32
  455. }
  456. type fnState struct {
  457. // precursor function (really *gc.Node)
  458. precursor interface{}
  459. // abstract function symbol
  460. absfn *LSym
  461. }
  462. func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
  463. return &DwarfFixupTable{
  464. ctxt: ctxt,
  465. symtab: make(map[*LSym]int),
  466. precursor: make(map[*LSym]fnState),
  467. }
  468. }
  469. func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
  470. if fnstate, found := ft.precursor[s]; found {
  471. return fnstate.precursor
  472. }
  473. return nil
  474. }
  475. func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
  476. if _, found := ft.precursor[s]; found {
  477. ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
  478. }
  479. // initialize abstract function symbol now. This is done here so
  480. // as to avoid data races later on during the parallel portion of
  481. // the back end.
  482. absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
  483. absfn.Set(AttrDuplicateOK, true)
  484. absfn.Type = objabi.SDWARFABSFCN
  485. ft.ctxt.Data = append(ft.ctxt.Data, absfn)
  486. // In the case of "late" inlining (inlines that happen during
  487. // wrapper generation as opposed to the main inlining phase) it's
  488. // possible that we didn't cache the abstract function sym for the
  489. // text symbol -- do so now if needed. See issue 38068.
  490. if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
  491. s.Func.dwarfAbsFnSym = absfn
  492. }
  493. ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
  494. }
  495. // Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
  496. // is targeting child 'c' of DIE with symbol 'tgt'.
  497. func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
  498. // Protect against concurrent access if multiple backend workers
  499. ft.mu.Lock()
  500. defer ft.mu.Unlock()
  501. // Create entry for symbol if not already present.
  502. idx, found := ft.symtab[tgt]
  503. if !found {
  504. ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
  505. idx = len(ft.svec) - 1
  506. ft.symtab[tgt] = idx
  507. }
  508. // Do we have child DIE offsets available? If so, then apply them,
  509. // otherwise create a fixup record.
  510. sf := &ft.svec[idx]
  511. if len(sf.doffsets) > 0 {
  512. found := false
  513. for _, do := range sf.doffsets {
  514. if do.dclIdx == int32(dclidx) {
  515. off := do.offset
  516. s.R[ridx].Add += int64(off)
  517. found = true
  518. break
  519. }
  520. }
  521. if !found {
  522. ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
  523. }
  524. } else {
  525. sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
  526. }
  527. }
  528. // Called once DWARF generation is complete for a given abstract function,
  529. // whose children might have been referenced via a call above. Stores
  530. // the offsets for any child DIEs (vars, params) so that they can be
  531. // consumed later in on DwarfFixupTable.Finalize, which applies any
  532. // outstanding fixups.
  533. func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
  534. // Length of these two slices should agree
  535. if len(vars) != len(coffsets) {
  536. ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
  537. return
  538. }
  539. // Generate the slice of declOffset's based in vars/coffsets
  540. doffsets := make([]declOffset, len(coffsets))
  541. for i := range coffsets {
  542. doffsets[i].dclIdx = vars[i].ChildIndex
  543. doffsets[i].offset = coffsets[i]
  544. }
  545. ft.mu.Lock()
  546. defer ft.mu.Unlock()
  547. // Store offsets for this symbol.
  548. idx, found := ft.symtab[s]
  549. if !found {
  550. sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
  551. ft.svec = append(ft.svec, sf)
  552. ft.symtab[s] = len(ft.svec) - 1
  553. } else {
  554. sf := &ft.svec[idx]
  555. sf.doffsets = doffsets
  556. sf.defseen = true
  557. }
  558. }
  559. func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
  560. sf := &ft.svec[slot]
  561. for _, f := range sf.fixups {
  562. dfound := false
  563. for _, doffset := range sf.doffsets {
  564. if doffset.dclIdx == f.dclidx {
  565. f.refsym.R[f.relidx].Add += int64(doffset.offset)
  566. dfound = true
  567. break
  568. }
  569. }
  570. if !dfound {
  571. ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
  572. }
  573. }
  574. }
  575. // return the LSym corresponding to the 'abstract subprogram' DWARF
  576. // info entry for a function.
  577. func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
  578. // Protect against concurrent access if multiple backend workers
  579. ft.mu.Lock()
  580. defer ft.mu.Unlock()
  581. if fnstate, found := ft.precursor[fnsym]; found {
  582. return fnstate.absfn
  583. }
  584. ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
  585. return nil
  586. }
  587. // Called after all functions have been compiled; the main job of this
  588. // function is to identify cases where there are outstanding fixups.
  589. // This scenario crops up when we have references to variables of an
  590. // inlined routine, but that routine is defined in some other package.
  591. // This helper walks through and locate these fixups, then invokes a
  592. // helper to create an abstract subprogram DIE for each one.
  593. func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
  594. if trace {
  595. ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
  596. }
  597. // Collect up the keys from the precursor map, then sort the
  598. // resulting list (don't want to rely on map ordering here).
  599. fns := make([]*LSym, len(ft.precursor))
  600. idx := 0
  601. for fn := range ft.precursor {
  602. fns[idx] = fn
  603. idx++
  604. }
  605. sort.Sort(BySymName(fns))
  606. // Should not be called during parallel portion of compilation.
  607. if ft.ctxt.InParallel {
  608. ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
  609. }
  610. // Generate any missing abstract functions.
  611. for _, s := range fns {
  612. absfn := ft.AbsFuncDwarfSym(s)
  613. slot, found := ft.symtab[absfn]
  614. if !found || !ft.svec[slot].defseen {
  615. ft.ctxt.GenAbstractFunc(s)
  616. }
  617. }
  618. // Apply fixups.
  619. for _, s := range fns {
  620. absfn := ft.AbsFuncDwarfSym(s)
  621. slot, found := ft.symtab[absfn]
  622. if !found {
  623. ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
  624. } else {
  625. ft.processFixups(slot, s)
  626. }
  627. }
  628. }
  629. type BySymName []*LSym
  630. func (s BySymName) Len() int { return len(s) }
  631. func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
  632. func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }