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.
262 lines
7.8 KiB
262 lines
7.8 KiB
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ART_LIBELFFILE_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
|
|
#define ART_LIBELFFILE_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
|
|
|
|
#include <cstdint>
|
|
|
|
#include "dwarf/dwarf_constants.h"
|
|
#include "dwarf/writer.h"
|
|
|
|
namespace art {
|
|
namespace dwarf {
|
|
|
|
// Writer for the .debug_line opcodes (DWARF-3).
|
|
// The writer is very light-weight, however it will do the following for you:
|
|
// * Choose the most compact encoding of a given opcode.
|
|
// * Keep track of current state and convert absolute values to deltas.
|
|
// * Divide by header-defined factors as appropriate.
|
|
template<typename Vector = std::vector<uint8_t>>
|
|
class DebugLineOpCodeWriter final : private Writer<Vector> {
|
|
static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
|
|
|
|
public:
|
|
static constexpr int kOpcodeBase = 13;
|
|
static constexpr bool kDefaultIsStmt = false;
|
|
static constexpr int kLineBase = -5;
|
|
static constexpr int kLineRange = 14;
|
|
|
|
void AddRow() {
|
|
this->PushUint8(DW_LNS_copy);
|
|
}
|
|
|
|
void AdvancePC(uint64_t absolute_address) {
|
|
DCHECK_NE(current_address_, 0u); // Use SetAddress for the first advance.
|
|
DCHECK_GE(absolute_address, current_address_);
|
|
if (absolute_address != current_address_) {
|
|
uint64_t delta = FactorCodeOffset(absolute_address - current_address_);
|
|
if (delta <= INT32_MAX) {
|
|
this->PushUint8(DW_LNS_advance_pc);
|
|
this->PushUleb128(static_cast<int>(delta));
|
|
current_address_ = absolute_address;
|
|
} else {
|
|
SetAddress(absolute_address);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AdvanceLine(int absolute_line) {
|
|
int delta = absolute_line - current_line_;
|
|
if (delta != 0) {
|
|
this->PushUint8(DW_LNS_advance_line);
|
|
this->PushSleb128(delta);
|
|
current_line_ = absolute_line;
|
|
}
|
|
}
|
|
|
|
void SetFile(int file) {
|
|
if (current_file_ != file) {
|
|
this->PushUint8(DW_LNS_set_file);
|
|
this->PushUleb128(file);
|
|
current_file_ = file;
|
|
}
|
|
}
|
|
|
|
void SetColumn(int column) {
|
|
this->PushUint8(DW_LNS_set_column);
|
|
this->PushUleb128(column);
|
|
}
|
|
|
|
void SetIsStmt(bool is_stmt) {
|
|
if (is_stmt_ != is_stmt) {
|
|
this->PushUint8(DW_LNS_negate_stmt);
|
|
is_stmt_ = is_stmt;
|
|
}
|
|
}
|
|
|
|
void SetBasicBlock() {
|
|
this->PushUint8(DW_LNS_set_basic_block);
|
|
}
|
|
|
|
void SetPrologueEnd() {
|
|
uses_dwarf3_features_ = true;
|
|
this->PushUint8(DW_LNS_set_prologue_end);
|
|
}
|
|
|
|
void SetEpilogueBegin() {
|
|
uses_dwarf3_features_ = true;
|
|
this->PushUint8(DW_LNS_set_epilogue_begin);
|
|
}
|
|
|
|
void SetISA(int isa) {
|
|
uses_dwarf3_features_ = true;
|
|
this->PushUint8(DW_LNS_set_isa);
|
|
this->PushUleb128(isa);
|
|
}
|
|
|
|
void EndSequence() {
|
|
this->PushUint8(0);
|
|
this->PushUleb128(1);
|
|
this->PushUint8(DW_LNE_end_sequence);
|
|
current_address_ = 0;
|
|
current_file_ = 1;
|
|
current_line_ = 1;
|
|
is_stmt_ = kDefaultIsStmt;
|
|
}
|
|
|
|
// Uncoditionally set address using the long encoding.
|
|
// This gives the linker opportunity to relocate the address.
|
|
void SetAddress(uint64_t absolute_address) {
|
|
DCHECK_GE(absolute_address, current_address_);
|
|
FactorCodeOffset(absolute_address); // Check if it is factorable.
|
|
this->PushUint8(0);
|
|
if (use_64bit_address_) {
|
|
this->PushUleb128(1 + 8);
|
|
this->PushUint8(DW_LNE_set_address);
|
|
patch_locations_.push_back(this->data()->size());
|
|
this->PushUint64(absolute_address);
|
|
} else {
|
|
this->PushUleb128(1 + 4);
|
|
this->PushUint8(DW_LNE_set_address);
|
|
patch_locations_.push_back(this->data()->size());
|
|
this->PushUint32(absolute_address);
|
|
}
|
|
current_address_ = absolute_address;
|
|
}
|
|
|
|
void DefineFile(const char* filename,
|
|
int directory_index,
|
|
int modification_time,
|
|
int file_size) {
|
|
int size = 1 +
|
|
strlen(filename) + 1 +
|
|
UnsignedLeb128Size(directory_index) +
|
|
UnsignedLeb128Size(modification_time) +
|
|
UnsignedLeb128Size(file_size);
|
|
this->PushUint8(0);
|
|
this->PushUleb128(size);
|
|
size_t start = data()->size();
|
|
this->PushUint8(DW_LNE_define_file);
|
|
this->PushString(filename);
|
|
this->PushUleb128(directory_index);
|
|
this->PushUleb128(modification_time);
|
|
this->PushUleb128(file_size);
|
|
DCHECK_EQ(start + size, data()->size());
|
|
}
|
|
|
|
// Compact address and line opcode.
|
|
void AddRow(uint64_t absolute_address, int absolute_line) {
|
|
DCHECK_GE(absolute_address, current_address_);
|
|
|
|
// If the address is definitely too far, use the long encoding.
|
|
uint64_t delta_address = FactorCodeOffset(absolute_address - current_address_);
|
|
if (delta_address > UINT8_MAX) {
|
|
AdvancePC(absolute_address);
|
|
delta_address = 0;
|
|
}
|
|
|
|
// If the line is definitely too far, use the long encoding.
|
|
int delta_line = absolute_line - current_line_;
|
|
if (!(kLineBase <= delta_line && delta_line < kLineBase + kLineRange)) {
|
|
AdvanceLine(absolute_line);
|
|
delta_line = 0;
|
|
}
|
|
|
|
// Both address and line should be reasonable now. Use the short encoding.
|
|
int opcode = kOpcodeBase + (delta_line - kLineBase) +
|
|
(static_cast<int>(delta_address) * kLineRange);
|
|
if (opcode > UINT8_MAX) {
|
|
// If the address is still too far, try to increment it by const amount.
|
|
int const_advance = (0xFF - kOpcodeBase) / kLineRange;
|
|
opcode -= (kLineRange * const_advance);
|
|
if (opcode <= UINT8_MAX) {
|
|
this->PushUint8(DW_LNS_const_add_pc);
|
|
} else {
|
|
// Give up and use long encoding for address.
|
|
AdvancePC(absolute_address);
|
|
// Still use the opcode to do line advance and copy.
|
|
opcode = kOpcodeBase + (delta_line - kLineBase);
|
|
}
|
|
}
|
|
DCHECK(kOpcodeBase <= opcode && opcode <= 0xFF);
|
|
this->PushUint8(opcode); // Special opcode.
|
|
current_line_ = absolute_line;
|
|
current_address_ = absolute_address;
|
|
}
|
|
|
|
int GetCodeFactorBits() const {
|
|
return code_factor_bits_;
|
|
}
|
|
|
|
uint64_t CurrentAddress() const {
|
|
return current_address_;
|
|
}
|
|
|
|
int CurrentFile() const {
|
|
return current_file_;
|
|
}
|
|
|
|
int CurrentLine() const {
|
|
return current_line_;
|
|
}
|
|
|
|
const std::vector<uintptr_t>& GetPatchLocations() const {
|
|
return patch_locations_;
|
|
}
|
|
|
|
using Writer<Vector>::data;
|
|
|
|
DebugLineOpCodeWriter(bool use64bitAddress,
|
|
int codeFactorBits,
|
|
const typename Vector::allocator_type& alloc =
|
|
typename Vector::allocator_type())
|
|
: Writer<Vector>(&opcodes_),
|
|
opcodes_(alloc),
|
|
uses_dwarf3_features_(false),
|
|
use_64bit_address_(use64bitAddress),
|
|
code_factor_bits_(codeFactorBits),
|
|
current_address_(0),
|
|
current_file_(1),
|
|
current_line_(1),
|
|
is_stmt_(kDefaultIsStmt) {
|
|
}
|
|
|
|
private:
|
|
uint64_t FactorCodeOffset(uint64_t offset) const {
|
|
DCHECK_GE(code_factor_bits_, 0);
|
|
DCHECK_EQ((offset >> code_factor_bits_) << code_factor_bits_, offset);
|
|
return offset >> code_factor_bits_;
|
|
}
|
|
|
|
Vector opcodes_;
|
|
bool uses_dwarf3_features_;
|
|
bool use_64bit_address_;
|
|
int code_factor_bits_;
|
|
uint64_t current_address_;
|
|
int current_file_;
|
|
int current_line_;
|
|
bool is_stmt_;
|
|
std::vector<uintptr_t> patch_locations_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
|
|
};
|
|
|
|
} // namespace dwarf
|
|
} // namespace art
|
|
|
|
#endif // ART_LIBELFFILE_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
|