You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

464 line
15 KiB

  1. // Copyright 2018 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package dwarf
  15. // This file implements the mapping from PC to lines.
  16. // TODO: Find a way to test this properly.
  17. // http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.2 page 108
  18. import (
  19. "fmt"
  20. "sort"
  21. "strings"
  22. )
  23. // PCToLine returns the file and line number corresponding to the PC value.
  24. // It returns an error if a correspondence cannot be found.
  25. func (d *Data) PCToLine(pc uint64) (file string, line uint64, err error) {
  26. c := d.pcToLineEntries
  27. if len(c) == 0 {
  28. return "", 0, fmt.Errorf("PCToLine: no line table")
  29. }
  30. i := sort.Search(len(c), func(i int) bool { return c[i].pc > pc }) - 1
  31. // c[i] is now the entry in pcToLineEntries with the largest pc that is not
  32. // larger than the query pc.
  33. // The search has failed if:
  34. // - All pcs in c were larger than the query pc (i == -1).
  35. // - c[i] marked the end of a sequence of instructions (c[i].file == 0).
  36. // - c[i] is the last element of c, and isn't the end of a sequence of
  37. // instructions, and the search pc is much larger than c[i].pc. In this
  38. // case, we don't know the range of the last instruction, but the search
  39. // pc is probably past it.
  40. if i == -1 || c[i].file == 0 || (i+1 == len(c) && pc-c[i].pc > 1024) {
  41. return "", 0, fmt.Errorf("no source line defined for PC %#x", pc)
  42. }
  43. if c[i].file >= uint64(len(d.sourceFiles)) {
  44. return "", 0, fmt.Errorf("invalid file number in DWARF data")
  45. }
  46. return d.sourceFiles[c[i].file], c[i].line, nil
  47. }
  48. // LineToBreakpointPCs returns the PCs that should be used as breakpoints
  49. // corresponding to the given file and line number.
  50. // It returns an empty slice if no PCs were found.
  51. func (d *Data) LineToBreakpointPCs(file string, line uint64) ([]uint64, error) {
  52. compDir := d.compilationDirectory()
  53. // Find the closest match in the executable for the specified file.
  54. // We choose the file with the largest number of path components matching
  55. // at the end of the name. If there is a tie, we prefer files that are
  56. // under the compilation directory. If there is still a tie, we choose
  57. // the file with the shortest name.
  58. // TODO: handle duplicate file names in the DWARF?
  59. var bestFile struct {
  60. fileNum uint64 // Index of the file in the DWARF data.
  61. components int // Number of matching path components.
  62. length int // Length of the filename.
  63. underComp bool // File is under the compilation directory.
  64. }
  65. for filenum, filename := range d.sourceFiles {
  66. c := matchingPathComponentSuffixSize(filename, file)
  67. underComp := strings.HasPrefix(filename, compDir)
  68. better := false
  69. if c != bestFile.components {
  70. better = c > bestFile.components
  71. } else if underComp != bestFile.underComp {
  72. better = underComp
  73. } else {
  74. better = len(filename) < bestFile.length
  75. }
  76. if better {
  77. bestFile.fileNum = uint64(filenum)
  78. bestFile.components = c
  79. bestFile.length = len(filename)
  80. bestFile.underComp = underComp
  81. }
  82. }
  83. if bestFile.components == 0 {
  84. return nil, fmt.Errorf("couldn't find file %q", file)
  85. }
  86. c := d.lineToPCEntries[bestFile.fileNum]
  87. // c contains all (pc, line) pairs for the appropriate file.
  88. start := sort.Search(len(c), func(i int) bool { return c[i].line >= line })
  89. end := sort.Search(len(c), func(i int) bool { return c[i].line > line })
  90. // c[i].line == line for all i in the range [start, end).
  91. pcs := make([]uint64, 0, end-start)
  92. for i := start; i < end; i++ {
  93. pcs = append(pcs, c[i].pc)
  94. }
  95. return pcs, nil
  96. }
  97. // compilationDirectory finds the first compilation unit entry in d and returns
  98. // the compilation directory contained in it.
  99. // If it fails, it returns the empty string.
  100. func (d *Data) compilationDirectory() string {
  101. r := d.Reader()
  102. for {
  103. entry, err := r.Next()
  104. if entry == nil || err != nil {
  105. return ""
  106. }
  107. if entry.Tag == TagCompileUnit {
  108. name, _ := entry.Val(AttrCompDir).(string)
  109. return name
  110. }
  111. }
  112. }
  113. // matchingPathComponentSuffixSize returns the largest n such that the last n
  114. // components of the paths p1 and p2 are equal.
  115. // e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2.
  116. func matchingPathComponentSuffixSize(p1, p2 string) int {
  117. // TODO: deal with other path separators.
  118. c1 := strings.Split(p1, "/")
  119. c2 := strings.Split(p2, "/")
  120. min := len(c1)
  121. if len(c2) < min {
  122. min = len(c2)
  123. }
  124. var n int
  125. for n = 0; n < min; n++ {
  126. if c1[len(c1)-1-n] != c2[len(c2)-1-n] {
  127. break
  128. }
  129. }
  130. return n
  131. }
  132. // Standard opcodes. Figure 37, page 178.
  133. // If an opcode >= lineMachine.prologue.opcodeBase, it is a special
  134. // opcode rather than the opcode defined in this table.
  135. const (
  136. lineStdCopy = 0x01
  137. lineStdAdvancePC = 0x02
  138. lineStdAdvanceLine = 0x03
  139. lineStdSetFile = 0x04
  140. lineStdSetColumn = 0x05
  141. lineStdNegateStmt = 0x06
  142. lineStdSetBasicBlock = 0x07
  143. lineStdConstAddPC = 0x08
  144. lineStdFixedAdvancePC = 0x09
  145. lineStdSetPrologueEnd = 0x0a
  146. lineStdSetEpilogueBegin = 0x0b
  147. lineStdSetISA = 0x0c
  148. )
  149. // Extended opcodes. Figure 38, page 179.
  150. const (
  151. lineStartExtendedOpcode = 0x00 // Not defined as a named constant in the spec.
  152. lineExtEndSequence = 0x01
  153. lineExtSetAddress = 0x02
  154. lineExtDefineFile = 0x03
  155. lineExtSetDiscriminator = 0x04 // New in version 4.
  156. lineExtLoUser = 0x80
  157. lineExtHiUser = 0xff
  158. )
  159. // lineHeader holds the information stored in the header of the line table for a
  160. // single compilation unit.
  161. // Section 6.2.4, page 112.
  162. type lineHeader struct {
  163. unitLength int
  164. version int
  165. headerLength int
  166. minInstructionLength int
  167. maxOpsPerInstruction int
  168. defaultIsStmt bool
  169. lineBase int
  170. lineRange int
  171. opcodeBase byte
  172. stdOpcodeLengths []byte
  173. include []string // entry 0 is empty; means current directory
  174. file []lineFile // entry 0 is empty.
  175. }
  176. // lineFile represents a file name stored in the PC/line table, usually in the header.
  177. type lineFile struct {
  178. name string
  179. index int // index into include directories
  180. time int // implementation-defined time of last modification
  181. length int // length in bytes, 0 if not available.
  182. }
  183. // lineMachine holds the registers evaluated during executing of the PC/line mapping engine.
  184. // Section 6.2.2, page 109.
  185. // A .debug_line section consists of multiple line number programs, one for each compilation unit.
  186. type lineMachine struct {
  187. // The program-counter value corresponding to a machine instruction generated by the compiler.
  188. address uint64
  189. // An unsigned integer representing the index of an operation within a VLIW
  190. // instruction. The index of the first operation is 0. For non-VLIW
  191. // architectures, this register will always be 0.
  192. // The address and op_index registers, taken together, form an operation
  193. // pointer that can reference any individual operation with the instruction
  194. // stream.
  195. opIndex uint64
  196. // An unsigned integer indicating the identity of the source file corresponding to a machine instruction.
  197. file uint64
  198. // An unsigned integer indicating a source line number. Lines are numbered
  199. // beginning at 1. The compiler may emit the value 0 in cases where an
  200. // instruction cannot be attributed to any source line.
  201. line uint64
  202. // An unsigned integer indicating a column number within a source line.
  203. // Columns are numbered beginning at 1. The value 0 is reserved to indicate
  204. // that a statement begins at the “left edge” of the line.
  205. column uint64
  206. // A boolean indicating that the current instruction is a recommended
  207. // breakpoint location. A recommended breakpoint location is intended to
  208. // “represent” a line, a statement and/or a semantically distinct subpart of a
  209. // statement.
  210. isStmt bool
  211. // A boolean indicating that the current instruction is the beginning of a basic
  212. // block.
  213. basicBlock bool
  214. // A boolean indicating that the current address is that of the first byte after
  215. // the end of a sequence of target machine instructions. end_sequence
  216. // terminates a sequence of lines; therefore other information in the same
  217. // row is not meaningful.
  218. endSequence bool
  219. // A boolean indicating that the current address is one (of possibly many)
  220. // where execution should be suspended for an entry breakpoint of a
  221. // function.
  222. prologueEnd bool
  223. // A boolean indicating that the current address is one (of possibly many)
  224. // where execution should be suspended for an exit breakpoint of a function.
  225. epilogueBegin bool
  226. // An unsigned integer whose value encodes the applicable instruction set
  227. // architecture for the current instruction.
  228. // The encoding of instruction sets should be shared by all users of a given
  229. // architecture. It is recommended that this encoding be defined by the ABI
  230. // authoring committee for each architecture.
  231. isa uint64
  232. // An unsigned integer identifying the block to which the current instruction
  233. // belongs. Discriminator values are assigned arbitrarily by the DWARF
  234. // producer and serve to distinguish among multiple blocks that may all be
  235. // associated with the same source file, line, and column. Where only one
  236. // block exists for a given source position, the discriminator value should be
  237. // zero.
  238. discriminator uint64
  239. // The header for the current compilation unit.
  240. // Not an actual register, but stored here for cleanliness.
  241. header lineHeader
  242. // Offset in buf of the end of the line number program for the current unit.
  243. unitEndOff Offset
  244. }
  245. // parseHeader parses the header describing the compilation unit in the line
  246. // table starting at the specified offset.
  247. func (m *lineMachine) parseHeader(b *buf) error {
  248. m.header = lineHeader{}
  249. m.header.unitLength = int(b.uint32()) // Note: We are assuming 32-bit DWARF format.
  250. m.unitEndOff = b.off + Offset(m.header.unitLength)
  251. if m.header.unitLength > len(b.data) {
  252. return fmt.Errorf("DWARF: bad PC/line header length")
  253. }
  254. m.header.version = int(b.uint16())
  255. m.header.headerLength = int(b.uint32())
  256. m.header.minInstructionLength = int(b.uint8())
  257. if m.header.version >= 4 {
  258. m.header.maxOpsPerInstruction = int(b.uint8())
  259. } else {
  260. m.header.maxOpsPerInstruction = 1
  261. }
  262. m.header.defaultIsStmt = b.uint8() != 0
  263. m.header.lineBase = int(int8(b.uint8()))
  264. m.header.lineRange = int(b.uint8())
  265. m.header.opcodeBase = b.uint8()
  266. m.header.stdOpcodeLengths = make([]byte, m.header.opcodeBase-1)
  267. copy(m.header.stdOpcodeLengths, b.bytes(int(m.header.opcodeBase-1)))
  268. m.header.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed.
  269. // Includes
  270. for {
  271. name := b.string()
  272. if name == "" {
  273. break
  274. }
  275. m.header.include = append(m.header.include, name)
  276. }
  277. // Files
  278. // Files are 1-indexed in line number program, but we'll deal with that in Data.buildLineCaches.
  279. // Here, just collect the filenames.
  280. for {
  281. name := b.string()
  282. if name == "" {
  283. break
  284. }
  285. index := b.uint()
  286. time := b.uint()
  287. length := b.uint()
  288. f := lineFile{
  289. name: name,
  290. index: int(index),
  291. time: int(time),
  292. length: int(length),
  293. }
  294. m.header.file = append(m.header.file, f)
  295. }
  296. return nil
  297. }
  298. // Special opcodes, page 117.
  299. // There are seven steps to processing special opcodes. We break them up here
  300. // because the caller needs to output a row between steps 2 and 4, and because
  301. // we need to perform just step 2 for the opcode DW_LNS_const_add_pc.
  302. func (m *lineMachine) specialOpcodeStep1(opcode byte) {
  303. adjustedOpcode := int(opcode - m.header.opcodeBase)
  304. lineAdvance := m.header.lineBase + (adjustedOpcode % m.header.lineRange)
  305. m.line += uint64(lineAdvance)
  306. }
  307. func (m *lineMachine) specialOpcodeStep2(opcode byte) {
  308. adjustedOpcode := int(opcode - m.header.opcodeBase)
  309. advance := adjustedOpcode / m.header.lineRange
  310. delta := (int(m.opIndex) + advance) / m.header.maxOpsPerInstruction
  311. m.address += uint64(m.header.minInstructionLength * delta)
  312. m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction)
  313. }
  314. func (m *lineMachine) specialOpcodeSteps4To7() {
  315. m.basicBlock = false
  316. m.prologueEnd = false
  317. m.epilogueBegin = false
  318. m.discriminator = 0
  319. }
  320. // evalCompilationUnit reads the next compilation unit and calls f at each output row.
  321. // Line machine execution continues while f returns true.
  322. func (m *lineMachine) evalCompilationUnit(b *buf, f func(m *lineMachine) (cont bool)) error {
  323. m.reset()
  324. for b.off < m.unitEndOff {
  325. op := b.uint8()
  326. if op >= m.header.opcodeBase {
  327. m.specialOpcodeStep1(op)
  328. m.specialOpcodeStep2(op)
  329. // Step 3 is to output a row, so we call f here.
  330. if !f(m) {
  331. return nil
  332. }
  333. m.specialOpcodeSteps4To7()
  334. continue
  335. }
  336. switch op {
  337. case lineStartExtendedOpcode:
  338. if len(b.data) == 0 {
  339. return fmt.Errorf("DWARF: short extended opcode (1)")
  340. }
  341. size := b.uint()
  342. if uint64(len(b.data)) < size {
  343. return fmt.Errorf("DWARF: short extended opcode (2)")
  344. }
  345. op = b.uint8()
  346. switch op {
  347. case lineExtEndSequence:
  348. m.endSequence = true
  349. if !f(m) {
  350. return nil
  351. }
  352. if len(b.data) == 0 {
  353. return nil
  354. }
  355. m.reset()
  356. case lineExtSetAddress:
  357. m.address = b.addr()
  358. m.opIndex = 0
  359. case lineExtDefineFile:
  360. return fmt.Errorf("DWARF: unimplemented define_file op")
  361. case lineExtSetDiscriminator:
  362. discriminator := b.uint()
  363. m.discriminator = discriminator
  364. default:
  365. return fmt.Errorf("DWARF: unknown extended opcode %#x", op)
  366. }
  367. case lineStdCopy:
  368. if !f(m) {
  369. return nil
  370. }
  371. m.discriminator = 0
  372. m.basicBlock = false
  373. m.prologueEnd = false
  374. m.epilogueBegin = false
  375. case lineStdAdvancePC:
  376. advance := b.uint()
  377. delta := (int(m.opIndex) + int(advance)) / m.header.maxOpsPerInstruction
  378. m.address += uint64(m.header.minInstructionLength * delta)
  379. m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction)
  380. m.basicBlock = false
  381. m.prologueEnd = false
  382. m.epilogueBegin = false
  383. m.discriminator = 0
  384. case lineStdAdvanceLine:
  385. advance := b.int()
  386. m.line = uint64(int64(m.line) + advance)
  387. case lineStdSetFile:
  388. index := b.uint()
  389. m.file = index
  390. case lineStdSetColumn:
  391. column := b.uint()
  392. m.column = column
  393. case lineStdNegateStmt:
  394. m.isStmt = !m.isStmt
  395. case lineStdSetBasicBlock:
  396. m.basicBlock = true
  397. case lineStdFixedAdvancePC:
  398. m.address += uint64(b.uint16())
  399. m.opIndex = 0
  400. case lineStdSetPrologueEnd:
  401. m.prologueEnd = true
  402. case lineStdSetEpilogueBegin:
  403. m.epilogueBegin = true
  404. case lineStdSetISA:
  405. m.isa = b.uint()
  406. case lineStdConstAddPC:
  407. // Update the address and op_index registers.
  408. m.specialOpcodeStep2(255)
  409. default:
  410. panic("not reached")
  411. }
  412. }
  413. return nil
  414. }
  415. // reset sets the machine's registers to the initial state. Page 111.
  416. func (m *lineMachine) reset() {
  417. m.address = 0
  418. m.opIndex = 0
  419. m.file = 1
  420. m.line = 1
  421. m.column = 0
  422. m.isStmt = m.header.defaultIsStmt
  423. m.basicBlock = false
  424. m.endSequence = false
  425. m.prologueEnd = false
  426. m.epilogueBegin = false
  427. m.isa = 0
  428. m.discriminator = 0
  429. }