mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
133 lines
4.1 KiB
C++
133 lines
4.1 KiB
C++
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/debug/elf_reader_linux.h"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <elf.h>
|
|
|
|
#include <vector>
|
|
|
|
#include "base/bits.h"
|
|
#include "base/containers/span.h"
|
|
#include "base/sha1.h"
|
|
#include "base/strings/stringprintf.h"
|
|
|
|
namespace base {
|
|
namespace debug {
|
|
|
|
namespace {
|
|
|
|
#if __SIZEOF_POINTER__ == 4
|
|
using Ehdr = Elf32_Ehdr;
|
|
using Dyn = Elf32_Dyn;
|
|
using Half = Elf32_Half;
|
|
using Nhdr = Elf32_Nhdr;
|
|
using Phdr = Elf32_Phdr;
|
|
using Word = Elf32_Word;
|
|
#else
|
|
using Ehdr = Elf64_Ehdr;
|
|
using Dyn = Elf64_Dyn;
|
|
using Half = Elf64_Half;
|
|
using Nhdr = Elf64_Nhdr;
|
|
using Phdr = Elf64_Phdr;
|
|
using Word = Elf64_Word;
|
|
#endif
|
|
|
|
using ElfSegment = span<const char>;
|
|
|
|
Optional<std::string> ElfSegmentBuildIDNoteAsString(const ElfSegment& segment) {
|
|
const void* section_end = segment.data() + segment.size_bytes();
|
|
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(segment.data());
|
|
while (note_header < section_end) {
|
|
if (note_header->n_type == NT_GNU_BUILD_ID)
|
|
break;
|
|
note_header = reinterpret_cast<const Nhdr*>(
|
|
reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) +
|
|
bits::Align(note_header->n_namesz, 4) +
|
|
bits::Align(note_header->n_descsz, 4));
|
|
}
|
|
|
|
if (note_header >= section_end || note_header->n_descsz != kSHA1Length)
|
|
return nullopt;
|
|
|
|
const uint8_t* guid = reinterpret_cast<const uint8_t*>(note_header) +
|
|
sizeof(Nhdr) + bits::Align(note_header->n_namesz, 4);
|
|
|
|
uint32_t dword = htonl(*reinterpret_cast<const int32_t*>(guid));
|
|
uint16_t word1 = htons(*reinterpret_cast<const int16_t*>(guid + 4));
|
|
uint16_t word2 = htons(*reinterpret_cast<const int16_t*>(guid + 6));
|
|
std::string identifier;
|
|
identifier.reserve(kSHA1Length * 2); // as hex string
|
|
SStringPrintf(&identifier, "%08X%04X%04X", dword, word1, word2);
|
|
for (size_t i = 8; i < note_header->n_descsz; ++i)
|
|
StringAppendF(&identifier, "%02X", guid[i]);
|
|
|
|
return identifier;
|
|
}
|
|
|
|
std::vector<ElfSegment> FindElfSegments(const void* elf_mapped_base,
|
|
uint32_t segment_type) {
|
|
const char* elf_base = reinterpret_cast<const char*>(elf_mapped_base);
|
|
if (strncmp(elf_base, ELFMAG, SELFMAG) != 0)
|
|
return std::vector<ElfSegment>();
|
|
|
|
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
|
|
const Phdr* phdrs =
|
|
reinterpret_cast<const Phdr*>(elf_base + elf_header->e_phoff);
|
|
std::vector<ElfSegment> segments;
|
|
for (Half i = 0; i < elf_header->e_phnum; ++i) {
|
|
if (phdrs[i].p_type == segment_type)
|
|
segments.push_back({elf_base + phdrs[i].p_offset, phdrs[i].p_filesz});
|
|
}
|
|
return segments;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Optional<std::string> ReadElfBuildId(const void* elf_base) {
|
|
// Elf program headers can have multiple PT_NOTE arrays.
|
|
std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_NOTE);
|
|
if (segs.empty())
|
|
return nullopt;
|
|
Optional<std::string> id;
|
|
for (const ElfSegment& seg : segs) {
|
|
id = ElfSegmentBuildIDNoteAsString(seg);
|
|
if (id)
|
|
return id;
|
|
}
|
|
|
|
return nullopt;
|
|
}
|
|
|
|
Optional<std::string> ReadElfLibraryName(const void* elf_base) {
|
|
std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_DYNAMIC);
|
|
if (segs.empty())
|
|
return nullopt;
|
|
DCHECK_EQ(1u, segs.size());
|
|
|
|
const ElfSegment& dynamic_seg = segs.front();
|
|
const Dyn* dynamic_start = reinterpret_cast<const Dyn*>(dynamic_seg.data());
|
|
const Dyn* dynamic_end = reinterpret_cast<const Dyn*>(
|
|
dynamic_seg.data() + dynamic_seg.size_bytes());
|
|
Optional<std::string> soname;
|
|
Word soname_strtab_offset = 0;
|
|
const char* strtab_addr = 0;
|
|
for (const Dyn* dynamic_iter = dynamic_start; dynamic_iter < dynamic_end;
|
|
++dynamic_iter) {
|
|
if (dynamic_iter->d_tag == DT_STRTAB) {
|
|
strtab_addr =
|
|
dynamic_iter->d_un.d_ptr + reinterpret_cast<const char*>(elf_base);
|
|
} else if (dynamic_iter->d_tag == DT_SONAME) {
|
|
soname_strtab_offset = dynamic_iter->d_un.d_val;
|
|
}
|
|
}
|
|
if (soname_strtab_offset && strtab_addr)
|
|
return std::string(strtab_addr + soname_strtab_offset);
|
|
return nullopt;
|
|
}
|
|
|
|
} // namespace debug
|
|
} // namespace base
|