diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -367,6 +367,28 @@ void resetRowAndSequence(); void appendRowToMatrix(); + /// Advance the address by the \p OperationAdvance value. \returns the + /// amount advanced by. + uint64_t advanceAddr(uint64_t OperationAdvance); + + struct AddrAndAdjustedOpcode { + uint64_t AddrDelta; + uint8_t AdjustedOpcode; + }; + + /// Advance the address as required by the specified \p Opcode. + /// \returns the amount advanced by and the calculated adjusted opcode. + AddrAndAdjustedOpcode advanceAddrForOpcode(uint8_t Opcode); + + struct AddrAndLineDelta { + uint64_t Address; + int32_t Line; + }; + + /// Advance the line and address as required by the specified special \p + /// Opcode. \returns the address and line delta. + AddrAndLineDelta handleSpecialOpcode(uint8_t Opcode); + /// Line table we're currently parsing. struct LineTable *LineTable; struct Row Row; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -566,6 +566,67 @@ return LT; } +uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance) { + uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength; + Row.Address.Address += AddrOffset; + return AddrOffset; +} + +DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode +DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode) { + assert(Opcode == DW_LNS_const_add_pc || + Opcode >= LineTable->Prologue.OpcodeBase); + uint8_t OpcodeValue = Opcode; + if (Opcode == DW_LNS_const_add_pc) + OpcodeValue = 255; + uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase; + uint64_t OperationAdvance = AdjustedOpcode / LineTable->Prologue.LineRange; + uint64_t AddrOffset = advanceAddr(OperationAdvance); + return {AddrOffset, AdjustedOpcode}; +} + +DWARFDebugLine::ParsingState::AddrAndLineDelta +DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode) { + // A special opcode value is chosen based on the amount that needs + // to be added to the line and address registers. The maximum line + // increment for a special opcode is the value of the line_base + // field in the header, plus the value of the line_range field, + // minus 1 (line base + line range - 1). If the desired line + // increment is greater than the maximum line increment, a standard + // opcode must be used instead of a special opcode. The "address + // advance" is calculated by dividing the desired address increment + // by the minimum_instruction_length field from the header. The + // special opcode is then calculated using the following formula: + // + // opcode = (desired line increment - line_base) + + // (line_range * address advance) + opcode_base + // + // If the resulting opcode is greater than 255, a standard opcode + // must be used instead. + // + // To decode a special opcode, subtract the opcode_base from the + // opcode itself to give the adjusted opcode. The amount to + // increment the address register is the result of the adjusted + // opcode divided by the line_range multiplied by the + // minimum_instruction_length field from the header. That is: + // + // address increment = (adjusted opcode / line_range) * + // minimum_instruction_length + // + // The amount to increment the line register is the line_base plus + // the result of the adjusted opcode modulo the line_range. That is: + // + // line increment = line_base + (adjusted opcode % line_range) + + DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult = + advanceAddrForOpcode(Opcode); + int32_t LineOffset = + LineTable->Prologue.LineBase + + (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange); + Row.Line += LineOffset; + return {AddrAdvanceResult.AddrDelta, LineOffset}; +} + Error DWARFDebugLine::LineTable::parse( DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, const DWARFContext &Ctx, const DWARFUnit *U, @@ -793,8 +854,7 @@ // result to the address register of the state machine. { uint64_t AddrOffset = - DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; - State.Row.Address.Address += AddrOffset; + State.advanceAddr(DebugLineData.getULEB128(OffsetPtr)); if (OS) *OS << " (" << AddrOffset << ")"; } @@ -849,13 +909,9 @@ // than twice that range will it need to use both DW_LNS_advance_pc // and a special opcode, requiring three or more bytes. { - uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase; - uint64_t AddrOffset = - (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; - State.Row.Address.Address += AddrOffset; + uint64_t AddrOffset = State.advanceAddrForOpcode(Opcode).AddrDelta; if (OS) - *OS - << format(" (0x%16.16" PRIx64 ")", AddrOffset); + *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset); } break; @@ -915,49 +971,11 @@ break; } } else { - // Special Opcodes - - // A special opcode value is chosen based on the amount that needs - // to be added to the line and address registers. The maximum line - // increment for a special opcode is the value of the line_base - // field in the header, plus the value of the line_range field, - // minus 1 (line base + line range - 1). If the desired line - // increment is greater than the maximum line increment, a standard - // opcode must be used instead of a special opcode. The "address - // advance" is calculated by dividing the desired address increment - // by the minimum_instruction_length field from the header. The - // special opcode is then calculated using the following formula: - // - // opcode = (desired line increment - line_base) + - // (line_range * address advance) + opcode_base - // - // If the resulting opcode is greater than 255, a standard opcode - // must be used instead. - // - // To decode a special opcode, subtract the opcode_base from the - // opcode itself to give the adjusted opcode. The amount to - // increment the address register is the result of the adjusted - // opcode divided by the line_range multiplied by the - // minimum_instruction_length field from the header. That is: - // - // address increment = (adjusted opcode / line_range) * - // minimum_instruction_length - // - // The amount to increment the line register is the line_base plus - // the result of the adjusted opcode modulo the line_range. That is: - // - // line increment = line_base + (adjusted opcode % line_range) - - uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase; - uint64_t AddrOffset = - (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; - int32_t LineOffset = - Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); - State.Row.Line += LineOffset; - State.Row.Address.Address += AddrOffset; + // Special Opcodes. + ParsingState::AddrAndLineDelta Delta = State.handleSpecialOpcode(Opcode); if (OS) { - *OS << "address += " << AddrOffset << ", line += " << LineOffset + *OS << "address += " << Delta.Address << ", line += " << Delta.Line << "\n"; OS->indent(12); State.Row.dump(*OS);