ogle/debug/dwarf: use existing I/O implementation to parse line table LGTM=nigeltao R=nigeltao https://golang.org/cl/89300044
diff --git a/debug/dwarf/line.go b/debug/dwarf/line.go index 5a23922..de095bd 100644 --- a/debug/dwarf/line.go +++ b/debug/dwarf/line.go
@@ -11,7 +11,6 @@ // TODO: Find a way to test this properly. import ( - "encoding/binary" "fmt" ) @@ -23,9 +22,14 @@ return } var m lineMachine - for offset := 0; offset < len(d.line); { + // Assume the first info unit is the same as us. Extremely likely. TODO? + if len(d.unit) == 0 { + return "", 0, fmt.Errorf("no info section") + } + buf := makeBuf(d, &d.unit[0], "line", 0, d.line) + for len(buf.data) > 0 { var found bool - offset, found, err = m.evalCompilationUnit(d.line, offset, pc) + found, err = m.evalCompilationUnit(&buf, pc) if err != nil { return "", 0, err } @@ -165,79 +169,66 @@ // parseLinePrologue parses the prologue/header describing the compilation // unit in the line table starting at the specified offset. -func (m *lineMachine) parseLinePrologue(data []byte, offset int) (int, error) { - // TODO: Assumes little endian +func (m *lineMachine) parseLinePrologue(b *buf) error { m.prologue = linePrologue{} - m.prologue.unitLength = int(binary.LittleEndian.Uint32(data[offset:])) - if m.prologue.unitLength > len(data)-4 { - return 0, fmt.Errorf("DWARF: bad PC/line header length") + m.prologue.unitLength = int(b.uint32()) + if m.prologue.unitLength > len(b.data) { + return fmt.Errorf("DWARF: bad PC/line header length") } - offset += 4 - m.prologue.version = int(binary.LittleEndian.Uint16(data[offset:])) - offset += 2 - m.prologue.headerLength = int(binary.LittleEndian.Uint32(data[offset:])) - offset += 4 - m.prologue.minInstructionLength = int(data[offset]) - offset += 1 + m.prologue.version = int(b.uint16()) + m.prologue.headerLength = int(b.uint32()) + m.prologue.minInstructionLength = int(b.uint8()) if m.prologue.version >= 4 { - m.prologue.maxOpsPerInstruction = int(data[offset]) - offset += 1 + m.prologue.maxOpsPerInstruction = int(b.uint8()) } else { m.prologue.maxOpsPerInstruction = 1 } - m.prologue.defaultIsStmt = data[offset] != 0 - offset += 1 - m.prologue.lineBase = int(int8(data[offset])) - offset += 1 - m.prologue.lineRange = int(data[offset]) - offset += 1 - m.prologue.opcodeBase = data[offset] - offset += 1 + m.prologue.defaultIsStmt = b.uint8() != 0 + m.prologue.lineBase = int(int8(b.uint8())) + m.prologue.lineRange = int(b.uint8()) + m.prologue.opcodeBase = b.uint8() m.prologue.stdOpcodeLengths = make([]byte, m.prologue.opcodeBase-1) - copy(m.prologue.stdOpcodeLengths, data[offset:]) - offset += int(m.prologue.opcodeBase - 1) + copy(m.prologue.stdOpcodeLengths, b.bytes(int(m.prologue.opcodeBase-1))) m.prologue.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed. // Includes + name := make([]byte, 0, 64) + zeroTerminatedString := func() string { + name = name[:0] + for { + c := b.uint8() + if c == 0 { + break + } + name = append(name, c) + } + return string(name) + } for { - if data[offset] == 0 { - offset++ + name := zeroTerminatedString() + if name == "" { break } - startOfName := offset - for data[offset] != 0 { - offset++ - } - m.prologue.include = append(m.prologue.include, string(data[startOfName:offset])) - offset++ // terminal NUL + m.prologue.include = append(m.prologue.include, name) } // Files m.prologue.file = make([]lineFile, 1, 10) // entries are 1-indexed in line number program. for { - if data[offset] == 0 { - offset++ + name := zeroTerminatedString() + if name == "" { break } - startOfName := offset - for data[offset] != 0 { - offset++ - } - name := data[startOfName:offset] - offset++ // terminal NUL - index, w := uleb128(data[offset:]) - offset += w - time, w := uleb128(data[offset:]) - offset += w - length, w := uleb128(data[offset:]) - offset += w + index := b.uint() + time := b.uint() + length := b.uint() f := lineFile{ - name: string(name), + name: name, index: int(index), time: int(time), length: int(length), } m.prologue.file = append(m.prologue.file, f) } - return offset, nil + return nil } // Special opcodes, page 117. @@ -255,61 +246,46 @@ m.discriminator = 0 } -// evalCompilationUnit scans the compilation unit starting at the specified offset to see if it contains the PC. -// It returns when it finds the PC or at the end of the compilation unit. -// The return values are the offset where it stops and whether the PC was found; if so, -// the machine's registers contain the relevant information. -func (m *lineMachine) evalCompilationUnit(data []byte, startOffset int, pc uint64) (int, bool, error) { - offset, err := m.parseLinePrologue(data, startOffset) +// evalCompilationUnit reads the next compilation unit to see if it contains the PC. +// The return value reports whether the PC was found; if so, the machine's registers +// contain the relevant information. +func (m *lineMachine) evalCompilationUnit(b *buf, pc uint64) (bool, error) { + err := m.parseLinePrologue(b) if err != nil { - return offset, false, err + return false, err } m.reset() - for offset < len(data) { - op := data[offset] - offset++ + for len(b.data) > 0 { + op := b.uint8() if op >= m.prologue.opcodeBase { m.specialOpcode(op) continue } switch op { case lineStartExtendedOpcode: - if len(data) == 0 { - return offset, false, fmt.Errorf("DWARF: short extended opcode (1)") + if len(b.data) == 0 { + return false, fmt.Errorf("DWARF: short extended opcode (1)") } - size, wid := uleb128(data[offset:]) - if uint64(len(data)) < size { - return offset, false, fmt.Errorf("DWARF: short extended opcode (2)") + size := b.uint() + if uint64(len(b.data)) < size { + return false, fmt.Errorf("DWARF: short extended opcode (2)") } - offset += int(wid) - op = data[offset] - offset++ + op = b.uint8() switch op { case lineExtEndSequence: m.endSequence = true m.reset() - return offset, false, nil + return false, nil case lineExtSetAddress: - var addr uint64 - // TODO: Assumes little-endian. - switch size { - case 1 + 4: // TODO: How should we do this? - addr = uint64(binary.LittleEndian.Uint32(data[offset:])) - offset += 4 - case 1 + 8: - addr = binary.LittleEndian.Uint64(data[offset:]) - offset += 8 - } - m.address = addr + m.address = b.addr() m.opIndex = 0 case lineExtDefineFile: - return offset, false, fmt.Errorf("DWARF: unimplemented define_file op") + return false, fmt.Errorf("DWARF: unimplemented define_file op") case lineExtSetDiscriminator: - discriminator, wid := uleb128(data[offset:]) + discriminator := b.uint() m.line = discriminator - offset += wid default: - return offset, false, fmt.Errorf("DWARF: unknown extended opcode %#x", op) + return false, fmt.Errorf("DWARF: unknown extended opcode %#x", op) } case lineStdCopy: m.discriminator = 0 @@ -318,47 +294,39 @@ m.epilogueBegin = false if m.address >= pc { // TODO: if m.address > pc, is this one step too far? - return offset, true, nil + return true, nil } case lineStdAdvancePC: - advance, wid := uleb128(data[offset:]) + advance := b.uint() delta := (int(m.opIndex) + int(advance)) / m.prologue.maxOpsPerInstruction m.address += uint64(m.prologue.minInstructionLength * delta) m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.prologue.maxOpsPerInstruction) - offset += wid m.basicBlock = false m.prologueEnd = false m.epilogueBegin = false m.discriminator = 0 case lineStdAdvanceLine: - advance, wid := sleb128(data[offset:]) + advance := b.int() m.line = uint64(int64(m.line) + advance) - offset += wid case lineStdSetFile: - index, wid := uleb128(data[offset:]) + index := b.uint() m.file = index - offset += wid case lineStdSetColumn: - column, wid := uleb128(data[offset:]) + column := b.uint() m.column = column - offset += wid case lineStdNegateStmt: m.isStmt = !m.isStmt case lineStdSetBasicBlock: m.basicBlock = true case lineStdFixedAdvancePC: - delta := binary.LittleEndian.Uint16(data[offset:]) - m.address += uint64(delta) + m.address += uint64(b.uint16()) m.opIndex = 0 - offset += 2 case lineStdSetPrologueEnd: m.prologueEnd = true case lineStdSetEpilogueBegin: m.epilogueBegin = true case lineStdSetISA: - isa, wid := uleb128(data[offset:]) - m.isa = isa - offset += wid + m.isa = b.uint() case lineStdConstAddPC: // TODO: Is this right? Seems crazy - why not just use 255 as a special opcode? m.specialOpcode(255) @@ -384,38 +352,3 @@ m.isa = 0 m.discriminator = 0 } - -// uleb128 decodes a varint-encoded unsigned integer. -// TODO: use the buffer interface. -func uleb128(v []uint8) (u uint64, length int) { - var shift uint - var x byte - for length, x = range v { - u |= (uint64(x) & 0x7F) << shift - shift += 7 - if x&0x80 == 0 { - break - } - } - return u, length + 1 -} - -// sleb128 decodes a varint-encoded signed integer. -// TODO: use the buffer interface. -func sleb128(v []uint8) (s int64, length int) { - var shift uint - var sign int64 = -1 - var x byte - for length, x = range v { - s |= (int64(x) & 0x7F) << shift - shift += 7 - sign <<= 7 - if x&0x80 == 0 { - if x&0x40 != 0 { - s |= sign - } - break - } - } - return s, length + 1 -}