/*
* Copyright ( C ) 2018 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_ELF_ELF_DEBUG_READER_H_
#define ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_
#include "base/array_ref.h"
#include "dwarf/headers.h"
#include "elf/elf_utils.h"
#include "xz_utils.h"
#include <map>
#include <string_view>
namespace art {
// Trivial ELF file reader.
//
// It is the bare minimum needed to read mini-debug-info symbols for unwinding.
// We use it to merge JIT mini-debug-infos together or to prune them after GC.
template <typename ElfTypes>
class ElfDebugReader {
public :
// Note that the input buffer might be misaligned.
using Elf_Ehdr ALIGNED(1 ) = typename ElfTypes::Ehdr;
using Elf_Phdr ALIGNED(1 ) = typename ElfTypes::Phdr;
using Elf_Shdr ALIGNED(1 ) = typename ElfTypes::Shdr;
using Elf_Sym ALIGNED(1 ) = typename ElfTypes::Sym;
using Elf_Addr ALIGNED(1 ) = typename ElfTypes::Addr;
// Call Frame Information.
struct CFI {
uint32_t length; // Length excluding the size of this field.
int32_t cie_pointer; // Offset in the section or -1 for CIE.
const uint8_t* data() const { return reinterpret_cast <const uint8_t*>(this ); }
size_t size() const { return sizeof (uint32_t) + length; }
} PACKED(1 );
// Common Information Entry.
struct CIE : public CFI {
} PACKED(1 );
// Frame Description Entry.
struct FDE : public CFI {
Elf_Addr sym_addr;
Elf_Addr sym_size;
} PACKED(1 );
explicit ElfDebugReader(ArrayRef<const uint8_t> file) : file_(file) {
header_ = Read<Elf_Ehdr>(/*offset=*/ 0);
CHECK_EQ(header_->e_ident[0 ], ELFMAG0);
CHECK_EQ(header_->e_ident[1 ], ELFMAG1);
CHECK_EQ(header_->e_ident[2 ], ELFMAG2);
CHECK_EQ(header_->e_ident[3 ], ELFMAG3);
CHECK_EQ(header_->e_ident[4 ], sizeof (Elf_Addr) / sizeof (uint32_t));
CHECK_EQ(header_->e_ehsize, sizeof (Elf_Ehdr));
// Find all ELF sections.
CHECK_EQ(header_->e_shentsize, sizeof (Elf_Shdr));
sections_ = Read<Elf_Shdr>(header_->e_shoff, header_->e_shnum);
for (const Elf_Shdr& section : sections_) {
const char * name = Read<char >(sections_[header_->e_shstrndx].sh_offset + section.sh_name);
section_map_[std::string_view(name)] = §ion;
}
// Decompressed embedded debug symbols, if any.
const Elf_Shdr* gnu_debugdata = section_map_[".gnu_debugdata" ];
if (gnu_debugdata != nullptr) {
auto compressed = Read<uint8_t>(gnu_debugdata->sh_offset, gnu_debugdata->sh_size);
XzDecompress(compressed, &decompressed_gnu_debugdata_);
gnu_debugdata_reader_.reset(new ElfDebugReader(decompressed_gnu_debugdata_));
}
}
explicit ElfDebugReader(const std::vector<uint8_t>& file)
: ElfDebugReader(ArrayRef<const uint8_t>(file)) {
}
// Check that ELF signature is present at the start of the files,
// and that the ELF bitness matches the ElfTypes template arguments.
static bool IsValidElfHeader(const std::vector<uint8_t>& data) {
static constexpr bool kIs64Bit = sizeof (Elf_Addr) == sizeof (uint64_t);
static constexpr char kMagic[] = { 0 x7f, 'E' , 'L' , 'F' , kIs64Bit ? 2 : 1 };
return data.size() >= sizeof (kMagic) && memcmp(data.data(), kMagic, sizeof (kMagic)) == 0 ;
}
const Elf_Ehdr* GetHeader() { return header_; }
ArrayRef<Elf_Shdr> GetSections() { return sections_; }
const Elf_Shdr* GetSection(const char * name) { return section_map_[name]; }
// Find the base address where the ELF file wants to be loaded.
// This is generally zero (therefore always requiring relocation).
Elf_Addr GetLoadAddress() {
std::optional<Elf_Addr> addr;
CHECK_EQ(header_->e_phentsize, sizeof (Elf_Phdr));
for (const Elf_Phdr& phdr : Read<Elf_Phdr>(header_->e_phoff, header_->e_phnum)) {
if (phdr.p_type == PT_LOAD) {
addr = addr.has_value() ? std::min(addr.value(), phdr.p_vaddr) : phdr.p_vaddr;
}
}
CHECK(addr.has_value());
return addr.value();
}
template <typename VisitSym>
void VisitFunctionSymbols(VisitSym&& visit_sym) {
const Elf_Shdr* symtab = GetSection(".symtab" );
const Elf_Shdr* strtab = GetSection(".strtab" );
const Elf_Shdr* text = GetSection(".text" );
if (symtab != nullptr && strtab != nullptr) {
CHECK_EQ(symtab->sh_entsize, sizeof (Elf_Sym));
size_t count = symtab->sh_size / sizeof (Elf_Sym);
for (const Elf_Sym& symbol : Read<Elf_Sym>(symtab->sh_offset, count)) {
if (ELF_ST_TYPE(symbol.st_info) == STT_FUNC &&
symbol.st_shndx < sections_.size() && // Ignore ABS section.
§ions_[symbol.st_shndx] == text) {
visit_sym(symbol, Read<char >(strtab->sh_offset + symbol.st_name));
}
}
}
if (gnu_debugdata_reader_ != nullptr) {
gnu_debugdata_reader_->VisitFunctionSymbols(std::forward<VisitSym>(visit_sym));
}
}
template <typename VisitSym>
void VisitDynamicSymbols(VisitSym&& visit_sym) {
const Elf_Shdr* dynsym = GetSection(".dynsym" );
const Elf_Shdr* dynstr = GetSection(".dynstr" );
if (dynsym != nullptr && dynstr != nullptr) {
CHECK_EQ(dynsym->sh_entsize, sizeof (Elf_Sym));
size_t count = dynsym->sh_size / sizeof (Elf_Sym);
for (const Elf_Sym& symbol : Read<Elf_Sym>(dynsym->sh_offset, count)) {
visit_sym(symbol, Read<char >(dynstr->sh_offset + symbol.st_name));
}
}
}
template <typename VisitCIE, typename VisitFDE>
void VisitDebugFrame(VisitCIE&& visit_cie, VisitFDE&& visit_fde) {
const Elf_Shdr* debug_frame = GetSection(".debug_frame" );
if (debug_frame != nullptr) {
for (size_t offset = 0 ; offset < debug_frame->sh_size;) {
const CFI* entry = Read<CFI>(debug_frame->sh_offset + offset);
DCHECK_LE(entry->size(), debug_frame->sh_size - offset);
if (entry->cie_pointer == -1 ) {
visit_cie(Read<CIE>(debug_frame->sh_offset + offset));
} else {
const FDE* fde = Read<FDE>(debug_frame->sh_offset + offset);
visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer));
}
offset += entry->size();
}
}
if (gnu_debugdata_reader_ != nullptr) {
gnu_debugdata_reader_->VisitDebugFrame(std::forward<VisitCIE>(visit_cie),
std::forward<VisitFDE>(visit_fde));
}
}
private :
template <typename T>
const T* Read(size_t offset) {
DCHECK_LE(offset + sizeof (T), file_.size());
return reinterpret_cast <const T*>(file_.data() + offset);
}
template <typename T>
ArrayRef<const T> Read(size_t offset, size_t count) {
DCHECK_LE(offset + count * sizeof (T), file_.size());
return ArrayRef<const T>(Read<T>(offset), count);
}
ArrayRef<const uint8_t> const file_;
const Elf_Ehdr* header_;
ArrayRef<const Elf_Shdr> sections_;
std::unordered_map<std::string_view, const Elf_Shdr*> section_map_;
std::vector<uint8_t> decompressed_gnu_debugdata_;
std::unique_ptr<ElfDebugReader> gnu_debugdata_reader_;
DISALLOW_COPY_AND_ASSIGN(ElfDebugReader);
};
} // namespace art
#endif // ART_LIBELFFILE_ELF_ELF_DEBUG_READER_H_
Messung V0.5 in Prozent C=90 H=96 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland