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.
229 lines
7.1 KiB
229 lines
7.1 KiB
/*
|
|
* Copyright (C) 2014 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_INFO_ENTRY_WRITER_H_
|
|
#define ART_LIBELFFILE_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
|
|
|
|
#include <cstdint>
|
|
#include <unordered_map>
|
|
|
|
#include "base/casts.h"
|
|
#include "base/leb128.h"
|
|
#include "dwarf/debug_abbrev_writer.h"
|
|
#include "dwarf/dwarf_constants.h"
|
|
#include "dwarf/expression.h"
|
|
#include "dwarf/writer.h"
|
|
|
|
namespace art {
|
|
namespace dwarf {
|
|
|
|
/*
|
|
* Writer for debug information entries (DIE).
|
|
*
|
|
* Usage:
|
|
* StartTag(DW_TAG_compile_unit);
|
|
* WriteStrp(DW_AT_producer, "Compiler name", debug_str);
|
|
* StartTag(DW_TAG_subprogram);
|
|
* WriteStrp(DW_AT_name, "Foo", debug_str);
|
|
* EndTag();
|
|
* EndTag();
|
|
*/
|
|
template <typename Vector = std::vector<uint8_t>>
|
|
class DebugInfoEntryWriter final : private Writer<Vector> {
|
|
static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
|
|
|
|
public:
|
|
static constexpr size_t kCompilationUnitHeaderSize = 11;
|
|
|
|
// Start debugging information entry.
|
|
// Returns offset of the entry in compilation unit.
|
|
size_t StartTag(Tag tag) {
|
|
if (inside_entry_) {
|
|
// Write abbrev code for the previous entry.
|
|
// Parent entry is finalized before any children are written.
|
|
this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_yes));
|
|
inside_entry_ = false;
|
|
}
|
|
debug_abbrev_->StartAbbrev(tag);
|
|
// Abbrev code placeholder of sufficient size.
|
|
abbrev_code_offset_ = this->data()->size();
|
|
this->PushUleb128(debug_abbrev_->NextAbbrevCode());
|
|
depth_++;
|
|
inside_entry_ = true;
|
|
return abbrev_code_offset_ + kCompilationUnitHeaderSize;
|
|
}
|
|
|
|
// End debugging information entry.
|
|
void EndTag() {
|
|
DCHECK_GT(depth_, 0);
|
|
if (inside_entry_) {
|
|
// Write abbrev code for this entry.
|
|
this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_no));
|
|
inside_entry_ = false;
|
|
// This entry has no children and so there is no terminator.
|
|
} else {
|
|
// The entry has been already finalized so it must be parent entry
|
|
// and we need to write the terminator required by DW_CHILDREN_yes.
|
|
this->PushUint8(0);
|
|
}
|
|
depth_--;
|
|
}
|
|
|
|
void WriteAddr(Attribute attrib, uint64_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_addr);
|
|
patch_locations_.push_back(this->data()->size());
|
|
if (is64bit_) {
|
|
this->PushUint64(value);
|
|
} else {
|
|
this->PushUint32(value);
|
|
}
|
|
}
|
|
|
|
void WriteBlock(Attribute attrib, const uint8_t* ptr, size_t num_bytes) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_block);
|
|
this->PushUleb128(num_bytes);
|
|
this->PushData(ptr, num_bytes);
|
|
}
|
|
|
|
void WriteExprLoc(Attribute attrib, const Expression& expr) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_exprloc);
|
|
this->PushUleb128(dchecked_integral_cast<uint32_t>(expr.size()));
|
|
this->PushData(expr.data());
|
|
}
|
|
|
|
void WriteData1(Attribute attrib, uint8_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data1);
|
|
this->PushUint8(value);
|
|
}
|
|
|
|
void WriteData2(Attribute attrib, uint16_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data2);
|
|
this->PushUint16(value);
|
|
}
|
|
|
|
void WriteData4(Attribute attrib, uint32_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data4);
|
|
this->PushUint32(value);
|
|
}
|
|
|
|
void WriteData8(Attribute attrib, uint64_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data8);
|
|
this->PushUint64(value);
|
|
}
|
|
|
|
void WriteSecOffset(Attribute attrib, uint32_t offset) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
|
|
this->PushUint32(offset);
|
|
}
|
|
|
|
void WriteSdata(Attribute attrib, int value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sdata);
|
|
this->PushSleb128(value);
|
|
}
|
|
|
|
void WriteUdata(Attribute attrib, int value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
|
|
this->PushUleb128(value);
|
|
}
|
|
|
|
void WriteUdata(Attribute attrib, uint32_t value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
|
|
this->PushUleb128(value);
|
|
}
|
|
|
|
void WriteFlag(Attribute attrib, bool value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag);
|
|
this->PushUint8(value ? 1 : 0);
|
|
}
|
|
|
|
void WriteFlagPresent(Attribute attrib) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag_present);
|
|
}
|
|
|
|
void WriteRef4(Attribute attrib, uint32_t cu_offset) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref4);
|
|
this->PushUint32(cu_offset);
|
|
}
|
|
|
|
void WriteRef(Attribute attrib, uint32_t cu_offset) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
|
|
this->PushUleb128(cu_offset);
|
|
}
|
|
|
|
void WriteString(Attribute attrib, const char* value) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_string);
|
|
this->PushString(value);
|
|
}
|
|
|
|
void WriteStrp(Attribute attrib, size_t debug_str_offset) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
|
|
this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
|
|
}
|
|
|
|
void WriteStrp(Attribute attrib, const char* str, size_t len,
|
|
std::vector<uint8_t>* debug_str) {
|
|
debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
|
|
this->PushUint32(debug_str->size());
|
|
debug_str->insert(debug_str->end(), str, str + len);
|
|
debug_str->push_back(0);
|
|
}
|
|
|
|
void WriteStrp(Attribute attrib, const char* str, std::vector<uint8_t>* debug_str) {
|
|
WriteStrp(attrib, str, strlen(str), debug_str);
|
|
}
|
|
|
|
bool Is64bit() const { return is64bit_; }
|
|
|
|
const std::vector<uintptr_t>& GetPatchLocations() const {
|
|
return patch_locations_;
|
|
}
|
|
|
|
int Depth() const { return depth_; }
|
|
|
|
using Writer<Vector>::data;
|
|
using Writer<Vector>::size;
|
|
using Writer<Vector>::UpdateUint32;
|
|
|
|
DebugInfoEntryWriter(bool is64bitArch,
|
|
DebugAbbrevWriter<Vector>* debug_abbrev,
|
|
const typename Vector::allocator_type& alloc =
|
|
typename Vector::allocator_type())
|
|
: Writer<Vector>(&entries_),
|
|
debug_abbrev_(debug_abbrev),
|
|
entries_(alloc),
|
|
is64bit_(is64bitArch) {
|
|
}
|
|
|
|
~DebugInfoEntryWriter() {
|
|
DCHECK(!inside_entry_);
|
|
DCHECK_EQ(depth_, 0);
|
|
}
|
|
|
|
private:
|
|
DebugAbbrevWriter<Vector>* debug_abbrev_;
|
|
Vector entries_;
|
|
bool is64bit_;
|
|
int depth_ = 0;
|
|
size_t abbrev_code_offset_ = 0; // Location to patch once we know the code.
|
|
bool inside_entry_ = false; // Entry ends at first child (if any).
|
|
std::vector<uintptr_t> patch_locations_;
|
|
};
|
|
|
|
} // namespace dwarf
|
|
} // namespace art
|
|
|
|
#endif // ART_LIBELFFILE_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
|