elf.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <string>
17 #include <iostream>
18 #include "absl/numeric/int128.h"
19 #include "absl/strings/escaping.h"
20 #include "absl/strings/string_view.h"
21 #include "absl/strings/substitute.h"
23 #include "bloaty.h"
24 #include "util.h"
25 
26 #include <assert.h>
27 #include <limits.h>
28 #include <stdlib.h>
29 
30 using absl::string_view;
31 
32 namespace bloaty {
33 
34 namespace {
35 
36 struct ByteSwapFunc {
37  template <class T>
38  T operator()(T val) {
39  return ByteSwap(val);
40  }
41 };
42 
43 struct NullFunc {
44  template <class T>
45  T operator()(T val) { return val; }
46 };
47 
48 size_t StringViewToSize(string_view str) {
49  size_t ret;
50  if (!absl::SimpleAtoi(str, &ret)) {
51  THROWF("couldn't convert string '$0' to integer.", str);
52  }
53  return ret;
54 }
55 
56 template <class T>
57 void AdvancePastStruct(string_view* data) {
58  *data = data->substr(sizeof(T));
59 }
60 
61 // ElfFile /////////////////////////////////////////////////////////////////////
62 
63 // For parsing the pieces we need out of an ELF file (.o, .so, and binaries).
64 
65 class ElfFile {
66  public:
67  ElfFile(string_view data) : data_(data) {
68  ok_ = Initialize();
69  }
70 
71  bool IsOpen() { return ok_; }
72 
73  // Regions of the file where different headers live.
74  string_view entire_file() const { return data_; }
75  string_view header_region() const { return header_region_; }
76  string_view section_headers() const { return section_headers_; }
77  string_view segment_headers() const { return segment_headers_; }
78 
79  const Elf64_Ehdr& header() const { return header_; }
80  Elf64_Xword section_count() const { return section_count_; }
81  Elf64_Xword section_string_index() const { return section_string_index_; }
82 
83  // Represents an ELF segment (data used by the loader / dynamic linker).
84  class Segment {
85  public:
86  const Elf64_Phdr& header() const { return header_; }
87  string_view contents() const { return contents_; }
88  string_view range() const { return range_; }
89 
90  private:
91  friend class ElfFile;
95  };
96 
97  // Represents an ELF section (.text, .data, .bss, etc.)
98  class Section {
99  public:
100  const Elf64_Shdr& header() const { return header_; }
101  string_view contents() const { return contents_; }
102  string_view range() const { return range_; }
103 
104  // For SHN_UNDEF (undefined name), returns [nullptr, 0].
105  string_view GetName() const;
106 
107  // Requires: this is a section with fixed-width entries (symbol table,
108  // relocation table, etc).
109  Elf64_Word GetEntryCount() const;
110 
111  // Requires: header().sh_type == SHT_STRTAB.
112  string_view ReadString(Elf64_Word index) const;
113 
114  // Requires: header().sh_type == SHT_SYMTAB || header().sh_type ==
115  // SHT_DYNSYM
116  void ReadSymbol(Elf64_Word index, Elf64_Sym* sym,
117  string_view* file_range) const;
118 
119  // Requires: header().sh_type == SHT_REL
120  void ReadRelocation(Elf64_Word index, Elf64_Rel* rel,
121  string_view* file_range) const;
122 
123  // Requires: header().sh_type == SHT_RELA
124  void ReadRelocationWithAddend(Elf64_Word index, Elf64_Rela* rel,
125  string_view* file_range) const;
126 
127  const ElfFile& elf() const { return *elf_; }
128 
129  private:
130  friend class ElfFile;
131  const ElfFile* elf_;
135  };
136 
137  class NoteIter {
138  public:
139  NoteIter(const Section& section)
140  : elf_(&section.elf()), remaining_(section.contents()) {
141  Next();
142  }
143 
144  bool IsDone() const { return done_; }
145  uint32_t type() const { return type_; }
146  string_view name() const { return name_; }
147  string_view descriptor() const { return descriptor_; }
148 
149  void Next();
150 
151  public:
152  const ElfFile* elf_;
157  bool done_ = false;
158  };
159 
160  void ReadSegment(Elf64_Word index, Segment* segment) const;
161  void ReadSection(Elf64_Word index, Section* section) const;
162 
163  bool FindSectionByName(absl::string_view name, Section* section) const;
164 
165  bool is_64bit() const { return is_64bit_; }
166  bool is_native_endian() const { return is_native_endian_; }
167 
168  template <class T32, class T64, class Munger>
169  void ReadStruct(absl::string_view contents, uint64_t offset, Munger munger,
170  absl::string_view* range, T64* out) const {
171  StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172  }
173 
174  private:
175  friend class Section;
176 
177  bool Initialize();
178 
179  string_view GetRegion(uint64_t start, uint64_t n) const {
180  return StrictSubstr(data_, start, n);
181  }
182 
183  // Shared code for reading various ELF structures. Handles endianness
184  // conversion and 32->64 bit conversion, when necessary.
185  class StructReader {
186  public:
187  StructReader(const ElfFile& elf, string_view data)
188  : elf_(elf), data_(data) {}
189 
190  template <class T32, class T64, class Munger>
191  void Read(uint64_t offset, Munger /*munger*/, absl::string_view* range,
192  T64* out) const {
193  if (elf_.is_64bit() && elf_.is_native_endian()) {
194  return Memcpy(offset, range, out);
195  } else {
196  return ReadFallback<T32, T64, Munger>(offset, range, out);
197  }
198  }
199 
200  private:
201  const ElfFile& elf_;
203 
204  template <class T32, class T64, class Munger>
205  void ReadFallback(uint64_t offset, absl::string_view* range,
206  T64* out) const;
207 
208  template <class T>
209  void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
211  if (out_range) {
212  *out_range = range;
213  }
214  memcpy(out, data_.data() + offset, sizeof(*out));
215  }
216  };
217 
218  bool ok_;
219  bool is_64bit_;
229 };
230 
231 // ELF uses different structure definitions for 32/64 bit files. The sizes of
232 // members are different, and members are even in a different order!
233 //
234 // These mungers can convert 32 bit structures to 64-bit ones. They can also
235 // handle converting endianness. We use templates so a single template function
236 // can handle all three patterns:
237 //
238 // 32 native -> 64 native
239 // 32 swapped -> 64 native
240 // 64 swapped -> 64 native
241 
242 struct EhdrMunger {
243  template <class From, class Func>
244  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245  memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246  to->e_type = func(from.e_type);
247  to->e_machine = func(from.e_machine);
248  to->e_version = func(from.e_version);
249  to->e_entry = func(from.e_entry);
250  to->e_phoff = func(from.e_phoff);
251  to->e_shoff = func(from.e_shoff);
252  to->e_flags = func(from.e_flags);
253  to->e_ehsize = func(from.e_ehsize);
254  to->e_phentsize = func(from.e_phentsize);
255  to->e_phnum = func(from.e_phnum);
256  to->e_shentsize = func(from.e_shentsize);
257  to->e_shnum = func(from.e_shnum);
258  to->e_shstrndx = func(from.e_shstrndx);
259  }
260 };
261 
262 struct ShdrMunger {
263  template <class From, class Func>
264  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265  to->sh_name = func(from.sh_name);
266  to->sh_type = func(from.sh_type);
267  to->sh_flags = func(from.sh_flags);
268  to->sh_addr = func(from.sh_addr);
269  to->sh_offset = func(from.sh_offset);
270  to->sh_size = func(from.sh_size);
271  to->sh_link = func(from.sh_link);
272  to->sh_info = func(from.sh_info);
273  to->sh_addralign = func(from.sh_addralign);
274  to->sh_entsize = func(from.sh_entsize);
275  }
276 };
277 
278 struct PhdrMunger {
279  template <class From, class Func>
280  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281  to->p_type = func(from.p_type);
282  to->p_flags = func(from.p_flags);
283  to->p_offset = func(from.p_offset);
284  to->p_vaddr = func(from.p_vaddr);
285  to->p_paddr = func(from.p_paddr);
286  to->p_filesz = func(from.p_filesz);
287  to->p_memsz = func(from.p_memsz);
288  to->p_align = func(from.p_align);
289  }
290 };
291 
292 struct SymMunger {
293  template <class From, class Func>
294  void operator()(const From& from, Elf64_Sym* to, Func func) {
295  to->st_name = func(from.st_name);
296  to->st_info = func(from.st_info);
297  to->st_other = func(from.st_other);
298  to->st_shndx = func(from.st_shndx);
299  to->st_value = func(from.st_value);
300  to->st_size = func(from.st_size);
301  }
302 };
303 
304 struct RelMunger {
305  template <class From, class Func>
306  void operator()(const From& from, Elf64_Rel* to, Func func) {
307  to->r_offset = func(from.r_offset);
308  to->r_info = func(from.r_info);
309  }
310 };
311 
312 struct RelaMunger {
313  template <class From, class Func>
314  void operator()(const From& from, Elf64_Rela* to, Func func) {
315  to->r_offset = func(from.r_offset);
316  to->r_info = func(from.r_info);
317  to->r_addend = func(from.r_addend);
318  }
319 };
320 
321 struct NoteMunger {
322  template <class From, class Func>
323  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324  to->n_namesz = func(from.n_namesz);
325  to->n_descsz = func(from.n_descsz);
326  to->n_type = func(from.n_type);
327  }
328 };
329 
330 struct ChdrMunger {
331  template <class From, class Func>
332  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333  to->ch_type = func(from.ch_type);
334  to->ch_size = func(from.ch_size);
335  to->ch_addralign = func(from.ch_addralign);
336  }
337 };
338 
339 template <class T32, class T64, class Munger>
340 void ElfFile::StructReader::ReadFallback(uint64_t offset,
342  T64* out) const {
343  // Fallback for either 32-bit ELF file or non-native endian.
344  if (elf_.is_64bit()) {
345  assert(!elf_.is_native_endian());
346  Memcpy(offset, range, out);
347  Munger()(*out, out, ByteSwapFunc());
348  } else {
349  T32 data32;
350  Memcpy(offset, range, &data32);
351  if (elf_.is_native_endian()) {
352  Munger()(data32, out, NullFunc());
353  } else {
354  Munger()(data32, out, ByteSwapFunc());
355  }
356  }
357 }
358 
360  if (header_.sh_name == SHN_UNDEF) {
361  return string_view(nullptr, 0);
362  }
363  return elf_->section_name_table_.ReadString(header_.sh_name);
364 }
365 
366 string_view ElfFile::Section::ReadString(Elf64_Word index) const {
367  assert(header().sh_type == SHT_STRTAB);
368 
369  if (index == SHN_UNDEF || index >= contents_.size()) {
370  THROWF("can't read index $0 from strtab, total size is $1", index,
371  contents_.size());
372  }
373 
375 
376  const char* null_pos =
377  static_cast<const char*>(memchr(ret.data(), '\0', ret.size()));
378 
379  if (null_pos == NULL) {
380  THROW("no NULL terminator found");
381  }
382 
383  size_t len = null_pos - ret.data();
384  ret = ret.substr(0, len);
385  return ret;
386 }
387 
388 Elf64_Word ElfFile::Section::GetEntryCount() const {
389  if (header_.sh_entsize == 0) {
390  THROW("sh_entsize is zero");
391  }
392  return contents_.size() / header_.sh_entsize;
393 }
394 
395 void ElfFile::Section::ReadSymbol(Elf64_Word index, Elf64_Sym* sym,
396  string_view* file_range) const {
397  assert(header().sh_type == SHT_SYMTAB || header().sh_type == SHT_DYNSYM);
398  size_t offset = header_.sh_entsize * index;
399  elf_->ReadStruct<Elf32_Sym>(contents(), offset, SymMunger(), file_range, sym);
400 }
401 
402 void ElfFile::Section::ReadRelocation(Elf64_Word index, Elf64_Rel* rel,
403  string_view* file_range) const {
404  assert(header().sh_type == SHT_REL);
405  size_t offset = header_.sh_entsize * index;
406  elf_->ReadStruct<Elf32_Rel>(contents(), offset, RelMunger(), file_range, rel);
407 }
408 
409 void ElfFile::Section::ReadRelocationWithAddend(Elf64_Word index,
410  Elf64_Rela* rela,
411  string_view* file_range) const {
412  assert(header().sh_type == SHT_RELA);
413  size_t offset = header_.sh_entsize * index;
414  elf_->ReadStruct<Elf32_Rela>(contents(), offset, RelaMunger(), file_range,
415  rela);
416 }
417 
419  if (remaining_.empty()) {
420  done_ = true;
421  return;
422  }
423 
424  Elf_Note note;
425  elf_->ReadStruct<Elf_Note>(remaining_, 0, NoteMunger(), nullptr, &note);
426 
427  // 32-bit and 64-bit note are the same size, so we don't have to treat
428  // them separately when advancing.
429  AdvancePastStruct<Elf_Note>(&remaining_);
430 
431  type_ = note.n_type;
432  name_ = StrictSubstr(remaining_, 0, note.n_namesz);
433 
434  // Size might include NULL terminator.
435  if (name_[name_.size() - 1] == 0) {
436  name_ = name_.substr(0, name_.size() - 1);
437  }
438 
439  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_namesz, 4));
440  descriptor_ = StrictSubstr(remaining_, 0, note.n_descsz);
441  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_descsz, 4));
442 }
443 
444 bool ElfFile::Initialize() {
445  if (data_.size() < EI_NIDENT) {
446  return false;
447  }
448 
449  unsigned char ident[EI_NIDENT];
450  memcpy(ident, data_.data(), EI_NIDENT);
451 
452  if (memcmp(ident, "\177ELF", 4) != 0) {
453  // Not an ELF file.
454  return false;
455  }
456 
457  switch (ident[EI_CLASS]) {
458  case ELFCLASS32:
459  is_64bit_ = false;
460  break;
461  case ELFCLASS64:
462  is_64bit_ = true;
463  break;
464  default:
465  THROWF("unexpected ELF class: $0", ident[EI_CLASS]);
466  }
467 
468  switch (ident[EI_DATA]) {
469  case ELFDATA2LSB:
471  break;
472  case ELFDATA2MSB:
474  break;
475  default:
476  THROWF("unexpected ELF data: $0", ident[EI_DATA]);
477  }
478 
480  ReadStruct<Elf32_Ehdr>(entire_file(), 0, EhdrMunger(), &range, &header_);
481 
482  Section section0;
483  bool has_section0 = 0;
484 
485  // ELF extensions: if certain fields overflow, we have to find their true data
486  // from elsewhere. For more info see:
487  // https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-94076/index.html
488  if (header_.e_shoff > 0 &&
489  data_.size() > (header_.e_shoff + header_.e_shentsize)) {
490  section_count_ = 1;
491  ReadSection(0, &section0);
492  has_section0 = true;
493  }
494 
495  section_count_ = header_.e_shnum;
496  section_string_index_ = header_.e_shstrndx;
497 
498  if (section_count_ == 0 && has_section0) {
499  section_count_ = section0.header().sh_size;
500  }
501 
502  if (section_string_index_ == SHN_XINDEX && has_section0) {
503  section_string_index_ = section0.header().sh_link;
504  }
505 
506  header_region_ = GetRegion(0, header_.e_ehsize);
507  section_headers_ = GetRegion(header_.e_shoff,
508  CheckedMul(header_.e_shentsize, section_count_));
509  segment_headers_ = GetRegion(
510  header_.e_phoff, CheckedMul(header_.e_phentsize, header_.e_phnum));
511 
512  if (section_count_ > 0) {
514  if (section_name_table_.header().sh_type != SHT_STRTAB) {
515  THROW("section string index pointed to non-strtab");
516  }
517  }
518 
519  return true;
520 }
521 
522 void ElfFile::ReadSegment(Elf64_Word index, Segment* segment) const {
523  if (index >= header_.e_phnum) {
524  THROWF("segment $0 doesn't exist, only $1 segments", index,
525  header_.e_phnum);
526  }
527 
528  Elf64_Phdr* header = &segment->header_;
529  ReadStruct<Elf32_Phdr>(
530  entire_file(),
531  CheckedAdd(header_.e_phoff, CheckedMul(header_.e_phentsize, index)),
532  PhdrMunger(), &segment->range_, header);
533  segment->contents_ = GetRegion(header->p_offset, header->p_filesz);
534 }
535 
536 void ElfFile::ReadSection(Elf64_Word index, Section* section) const {
537  if (index >= section_count_) {
538  THROWF("tried to read section $0, but there are only $1", index,
540  }
541 
542  Elf64_Shdr* header = &section->header_;
543  ReadStruct<Elf32_Shdr>(
544  entire_file(),
545  CheckedAdd(header_.e_shoff, CheckedMul(header_.e_shentsize, index)),
546  ShdrMunger(), &section->range_, header);
547 
548  if (header->sh_type == SHT_NOBITS) {
549  section->contents_ = string_view();
550  } else {
551  section->contents_ = GetRegion(header->sh_offset, header->sh_size);
552  }
553 
554  section->elf_ = this;
555 }
556 
557 bool ElfFile::FindSectionByName(absl::string_view name, Section* section) const {
558  for (Elf64_Word i = 0; i < section_count_; i++) {
559  ReadSection(i, section);
560  if (section->GetName() == name) {
561  return true;
562  }
563  }
564  return false;
565 }
566 
567 
568 // ArFile //////////////////////////////////////////////////////////////////////
569 
570 // For parsing .a files (static libraries).
571 //
572 // The best documentation I've been able to find for this file format is
573 // Wikipedia: https://en.wikipedia.org/wiki/Ar_(Unix)
574 //
575 // So far we only parse the System V / GNU variant.
576 
577 class ArFile {
578  public:
579  ArFile(string_view data)
581  contents_(data.substr(std::min<size_t>(data.size(), kMagicSize))) {}
582 
583  bool IsOpen() const { return magic() == string_view(kMagic); }
584 
585  string_view magic() const { return magic_; }
586  string_view contents() const { return contents_; }
587 
588  struct MemberFile {
589  enum {
590  kSymbolTable, // Stores a symbol table.
591  kLongFilenameTable, // Stores long filenames, users should ignore.
592  kNormal, // Regular data file.
593  } file_type;
594  string_view filename; // Only when file_type == kNormal
595  size_t size;
598  };
599 
600  class MemberReader {
601  public:
602  MemberReader(const ArFile& ar) : remaining_(ar.contents()) {}
603  bool ReadMember(MemberFile* file);
604  bool IsEof() const { return remaining_.size() == 0; }
605 
606  private:
607  string_view Consume(size_t n) {
608  n = (n % 2 == 0 ? n : n + 1);
609  if (remaining_.size() < n) {
610  THROW("premature end of file");
611  }
614  return ret;
615  }
616 
619  };
620 
621  private:
623  const string_view contents_;
624 
625  static constexpr const char* kMagic = "!<arch>\n";
626  static constexpr int kMagicSize = 8;
627 };
628 
629 bool ArFile::MemberReader::ReadMember(MemberFile* file) {
630  struct Header {
631  char file_id[16];
632  char modified_timestamp[12];
633  char owner_id[6];
634  char group_id[6];
635  char mode[8];
636  char size[10];
637  char end[2];
638  };
639 
640  if (remaining_.size() == 0) {
641  return false;
642  } else if (remaining_.size() < sizeof(Header)) {
643  THROW("Premature EOF in AR data");
644  }
645 
646  const Header* header = reinterpret_cast<const Header*>(remaining_.data());
647  file->header = Consume(sizeof(Header));
648 
649  string_view file_id(&header->file_id[0], sizeof(header->file_id));
650  string_view size_str(&header->size[0], sizeof(header->size));
651  file->size = StringViewToSize(size_str);
652  file->contents = Consume(file->size);
653  file->file_type = MemberFile::kNormal;
654 
655  if (file_id[0] == '/') {
656  // Special filename, internal to the format.
657  if (file_id[1] == ' ') {
658  file->file_type = MemberFile::kSymbolTable;
659  } else if (file_id[1] == '/') {
660  file->file_type = MemberFile::kLongFilenameTable;
661  long_filenames_ = file->contents;
662  } else if (isdigit(file_id[1])) {
663  size_t offset = StringViewToSize(file_id.substr(1));
664  size_t end = long_filenames_.find('/', offset);
665 
666  if (end == std::string::npos) {
667  THROW("Unterminated long filename");
668  }
669 
670  file->filename = long_filenames_.substr(offset, end - offset);
671  } else {
672  THROW("Unexpected special filename in AR archive");
673  }
674  } else {
675  // Normal filename, slash-terminated.
676  size_t slash = file_id.find('/');
677 
678  if (slash == std::string::npos) {
679  THROW("BSD-style AR not yet implemented");
680  }
681 
682  file->filename = file_id.substr(0, slash);
683  }
684 
685  return true;
686 }
687 
688 void MaybeAddFileRange(const char* analyzer, RangeSink* sink, string_view label,
689  string_view range) {
690  if (sink) {
691  sink->AddFileRange(analyzer, label, range);
692  }
693 }
694 
695 // Iterate over each ELF file, agnostic to whether it is inside a .a (AR) file
696 // or not.
697 template <class Func>
698 void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699  ArFile ar_file(file.data());
700  uint64_t index_base = 0;
701 
702  if (ar_file.IsOpen()) {
703  ArFile::MemberFile member;
704  ArFile::MemberReader reader(ar_file);
705 
706  MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707 
708  while (reader.ReadMember(&member)) {
709  MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710  switch (member.file_type) {
711  case ArFile::MemberFile::kNormal: {
712  ElfFile elf(member.contents);
713  if (elf.IsOpen()) {
714  func(elf, member.filename, index_base);
715  index_base += elf.section_count();
716  } else {
717  MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718  member.contents);
719  }
720  break;
721  }
722  case ArFile::MemberFile::kSymbolTable:
723  MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724  member.contents);
725  break;
726  case ArFile::MemberFile::kLongFilenameTable:
727  MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728  member.contents);
729  break;
730  }
731  }
732  } else {
733  ElfFile elf(file.data());
734  if (!elf.IsOpen()) {
735  THROWF("Not an ELF or Archive file: $0", file.filename());
736  }
737 
738  func(elf, file.filename(), index_base);
739  }
740 }
741 
742 // For object files, addresses are relative to the section they live in, which
743 // is indicated by ndx. We split this into:
744 //
745 // - 24 bits for index (up to 16M symbols with -ffunction-sections)
746 // - 40 bits for address (up to 1TB section)
747 static uint64_t ToVMAddr(uint64_t addr, uint64_t ndx, bool is_object) {
748  if (is_object) {
749  if (ndx >= 1 << 24) {
750  THROW("ndx overflow: too many sections");
751  }
752  if (addr >= ((uint64_t)1) << 40) {
753  THROW("address overflow: section too big");
754  }
755  return (ndx << 40) | addr;
756  } else {
757  return addr;
758  }
759 }
760 
761 static bool IsArchiveFile(string_view data) {
762  ArFile ar(data);
763  return ar.IsOpen();
764 }
765 
766 static bool IsObjectFile(string_view data) {
767  ElfFile elf(data);
768  return IsArchiveFile(data) || (elf.IsOpen() && elf.header().e_type == ET_REL);
769 }
770 
771 static void CheckNotObject(const char* source, RangeSink* sink) {
772  if (IsObjectFile(sink->input_file().data())) {
773  THROWF(
774  "can't use data source '$0' on object files (only binaries and shared "
775  "libraries)",
776  source);
777  }
778 }
779 
780 static bool ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
781  cs_mode* mode) {
782  switch (e_machine) {
783  case EM_386:
784  *arch = CS_ARCH_X86;
785  *mode = CS_MODE_32;
786  return true;
787  case EM_X86_64:
788  *arch = CS_ARCH_X86;
789  *mode = CS_MODE_64;
790  return true;
791 
792  // These aren't tested, but we include them on the off-chance
793  // that it will work.
794  case EM_ARM:
795  *arch = CS_ARCH_ARM;
797  return true;
798  case EM_AARCH64:
799  *arch = CS_ARCH_ARM64;
800  *mode = CS_MODE_ARM;
801  return true;
802  case EM_MIPS:
803  *arch = CS_ARCH_MIPS;
804  return true;
805  case EM_PPC:
806  *arch = CS_ARCH_PPC;
807  *mode = CS_MODE_32;
808  return true;
809  case EM_PPC64:
810  *arch = CS_ARCH_PPC;
811  *mode = CS_MODE_64;
812  return true;
813  case EM_SPARC:
814  *arch = CS_ARCH_SPARC;
816  return true;
817  case EM_SPARCV9:
818  *arch = CS_ARCH_SPARC;
819  *mode = CS_MODE_V9;
820  return true;
821 
822  default:
823  if (verbose_level > 1) {
824  printf(
825  "Unable to map to capstone target, disassembly will be "
826  "unavailable");
827  }
828  return false;
829  }
830 }
831 
832 static bool ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
833  bool capstone_available = true;
834  ForEachElf(file, nullptr,
835  [&capstone_available, arch, mode](const ElfFile& elf,
836  string_view /*filename*/,
837  uint32_t /*index_base*/) {
838  // Last .o file wins? (For .a files)? It's kind of arbitrary,
839  // but a single .a file shouldn't have multiple archs in it.
840  capstone_available &=
841  ElfMachineToCapstone(elf.header().e_machine, arch, mode);
842  });
843  return capstone_available;
844 }
845 
846 static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
847  SymbolTable* table, bool disassemble) {
848  bool is_object = IsObjectFile(file.data());
849  DisassemblyInfo info;
850  DisassemblyInfo* infop = &info;
851  bool capstone_available = ReadElfArchMode(file, &info.arch, &info.mode);
852 
853  ForEachElf(
854  file, sink,
855  [=](const ElfFile& elf, string_view /*filename*/, uint64_t index_base) {
856  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
857  ElfFile::Section section;
858  elf.ReadSection(i, &section);
859 
860  if (section.header().sh_type != SHT_SYMTAB) {
861  continue;
862  }
863 
864  Elf64_Word symbol_count = section.GetEntryCount();
865 
866  // Find the corresponding section where the strings for the symbol
867  // table can be found.
868  ElfFile::Section strtab_section;
869  elf.ReadSection(section.header().sh_link, &strtab_section);
870  if (strtab_section.header().sh_type != SHT_STRTAB) {
871  THROW("symtab section pointed to non-strtab section");
872  }
873 
874  for (Elf64_Word i = 1; i < symbol_count; i++) {
875  Elf64_Sym sym;
876 
877  section.ReadSymbol(i, &sym, nullptr);
878 
879  if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION) {
880  continue;
881  }
882 
883  if (sym.st_shndx == STN_UNDEF) {
884  continue;
885  }
886 
887  if (sym.st_size == 0) {
888  // Maybe try to refine? See ReadELFSectionsRefineSymbols below.
889  continue;
890  }
891 
892  string_view name = strtab_section.ReadString(sym.st_name);
893  uint64_t full_addr =
894  ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
895  if (sink && !(capstone_available && disassemble)) {
896  sink->AddVMRangeAllowAlias(
897  "elf_symbols", full_addr, sym.st_size,
898  ItaniumDemangle(name, sink->data_source()));
899  }
900  if (table) {
901  table->insert(
902  std::make_pair(name, std::make_pair(full_addr, sym.st_size)));
903  }
904  if (capstone_available && disassemble &&
905  ELF64_ST_TYPE(sym.st_info) == STT_FUNC) {
906  if (verbose_level > 1) {
907  printf("Disassembling function: %s\n", name.data());
908  }
909  infop->text = sink->TranslateVMToFile(full_addr).substr(0, sym.st_size);
910  infop->start_address = full_addr;
912  }
913  }
914  }
915  });
916 }
917 
918 static void ReadELFSymbolTableEntries(const ElfFile& elf,
919  const ElfFile::Section& section,
920  uint64_t index_base, bool is_object,
921  RangeSink* sink) {
922  Elf64_Word symbol_count = section.GetEntryCount();
923 
924  // Find the corresponding section where the strings for the symbol
925  // table can be found.
926  ElfFile::Section strtab_section;
927  elf.ReadSection(section.header().sh_link, &strtab_section);
928  if (strtab_section.header().sh_type != SHT_STRTAB) {
929  THROW("symtab section pointed to non-strtab section");
930  }
931 
932  for (Elf64_Word i = 1; i < symbol_count; i++) {
933  Elf64_Sym sym;
934  string_view sym_range;
935  section.ReadSymbol(i, &sym, &sym_range);
936 
937  if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION ||
938  sym.st_shndx == STN_UNDEF ||
939  sym.st_name == SHN_UNDEF) {
940  continue;
941  }
942 
943  string_view name = strtab_section.ReadString(sym.st_name);
944  uint64_t full_addr =
945  ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
946  // Capture the trailing NULL.
947  name = string_view(name.data(), name.size() + 1);
948  sink->AddFileRangeForVMAddr("elf_symtab_name", full_addr, name);
949  sink->AddFileRangeForVMAddr("elf_symtab_sym", full_addr, sym_range);
950  }
951 }
952 
953 static void ReadELFRelaEntries(const ElfFile::Section& section,
954  uint64_t index_base, bool is_object,
955  RangeSink* sink) {
956  Elf64_Word rela_count = section.GetEntryCount();
957  Elf64_Word sh_info = section.header().sh_info;
958  for (Elf64_Word i = 1; i < rela_count; i++) {
959  Elf64_Rela rela;
960  string_view rela_range;
961  section.ReadRelocationWithAddend(i, &rela, &rela_range);
962  uint64_t full_addr =
963  ToVMAddr(rela.r_offset, index_base + sh_info, is_object);
964  sink->AddFileRangeForVMAddr("elf_rela", full_addr, rela_range);
965  }
966 }
967 
968 // Adds file ranges for the symbol tables and string tables *themselves* (ie.
969 // the space that the symtab/strtab take up in the file). This will cover
970 // .symtab
971 // .strtab
972 // .dynsym
973 // .dynstr
974 static void ReadELFTables(const InputFile& file, RangeSink* sink) {
975  bool is_object = IsObjectFile(file.data());
976 
977  // Disassemble first, because sometimes other tables will refer to things we
978  // discovered through disassembling.
979  ReadELFSymbols(file, sink, nullptr, true);
980 
981  // Now scan other tables.
982  ForEachElf(file, sink,
983  [sink, is_object](const ElfFile& elf, string_view /*filename*/,
984  uint32_t index_base) {
985  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
986  ElfFile::Section section;
987  elf.ReadSection(i, &section);
988 
989  switch (section.header().sh_type) {
990  case SHT_SYMTAB:
991  case SHT_DYNSYM:
992  ReadELFSymbolTableEntries(elf, section, index_base,
993  is_object, sink);
994  break;
995  case SHT_RELA:
996  ReadELFRelaEntries(section, index_base, is_object, sink);
997  break;
998  }
999 
1000  // We are looking by section name, which is a little different
1001  // than what the loader actually does (which is find
1002  // eh_frame_hdr from the program headers and then find eh_frame
1003  // fde entries from there). But these section names should be
1004  // standard enough that this approach works also.
1005  if (section.GetName() == ".eh_frame") {
1006  ReadEhFrame(section.contents(), sink);
1007  } else if (section.GetName() == ".eh_frame_hdr") {
1008  ReadEhFrameHdr(section.contents(), sink);
1009  }
1010  }
1011  });
1012 }
1013 
1014 enum ReportSectionsBy {
1015  kReportBySectionName,
1016  kReportByEscapedSectionName,
1017  kReportByFlags,
1018  kReportByArchiveMember,
1019 };
1020 
1021 static void DoReadELFSections(RangeSink* sink, enum ReportSectionsBy report_by) {
1022  bool is_object = IsObjectFile(sink->input_file().data());
1023  ForEachElf(
1024  sink->input_file(), sink,
1025  [=](const ElfFile& elf, string_view filename, uint32_t index_base) {
1026  std::string name_from_flags;
1027  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1028  ElfFile::Section section;
1029  elf.ReadSection(i, &section);
1030  string_view name = section.GetName();
1031 
1032  if (name.size() == 0) {
1033  return;
1034  }
1035 
1036  const auto& header = section.header();
1037  auto addr = header.sh_addr;
1038  auto size = header.sh_size;
1039  auto filesize = (header.sh_type == SHT_NOBITS) ? 0 : size;
1040  auto vmsize = (header.sh_flags & SHF_ALLOC) ? size : 0;
1041 
1042  string_view contents = StrictSubstr(section.contents(), 0, filesize);
1043 
1044  uint64_t full_addr = ToVMAddr(addr, index_base + i, is_object);
1045 
1046  if (report_by == kReportByFlags) {
1047  name_from_flags = std::string(name);
1048 
1049  name_from_flags = "Section [";
1050 
1051  if (header.sh_flags & SHF_ALLOC) {
1052  name_from_flags += 'A';
1053  }
1054 
1055  if (header.sh_flags & SHF_WRITE) {
1056  name_from_flags += 'W';
1057  }
1058 
1059  if (header.sh_flags & SHF_EXECINSTR) {
1060  name_from_flags += 'X';
1061  }
1062 
1063  name_from_flags += ']';
1064  sink->AddRange("elf_section", name_from_flags, full_addr, vmsize,
1065  contents);
1066  } else if (report_by == kReportBySectionName) {
1067  sink->AddRange("elf_section", name, full_addr, vmsize, contents);
1068  } else if (report_by == kReportByEscapedSectionName) {
1069  sink->AddRange("elf_section",
1070  std::string("[section ") + std::string(name) + "]",
1071  full_addr, vmsize, contents);
1072  } else if (report_by == kReportByArchiveMember) {
1073  sink->AddRange("elf_section", filename, full_addr, vmsize,
1074  contents);
1075  }
1076  }
1077 
1078  if (report_by == kReportByArchiveMember) {
1079  // Cover unmapped parts of the file.
1080  sink->AddFileRange("unmapped_armember", filename, elf.entire_file());
1081  }
1082  });
1083 }
1084 
1085 enum ReportSegmentsBy {
1086  kReportBySegmentName,
1087  kReportByEscapedSegmentName,
1088 };
1089 
1090 std::string GetSegmentName(const ElfFile::Segment& segment, Elf64_Xword i,
1091  ReportSegmentsBy report_by) {
1092  const auto& header = segment.header();
1093 
1094  // Include the segment index in the label, to support embedded.
1095  //
1096  // Including the index in the segment label differentiates
1097  // segments with the same access control (e.g. RWX vs RW). In
1098  // ELF files built for embedded microcontroller projects, a
1099  // segment is used for each distinct type of memory. In simple
1100  // cases, there is a segment for the flash (which will store
1101  // code and read-only data) and a segment for RAM (which
1102  // usually stores globals, stacks, and maybe a heap). In more
1103  // involved projects, there may be special segments for faster
1104  // RAM (e.g. core coupled RAM or CCRAM), or there may even be
1105  // memory overlays to support manual paging of code from flash
1106  // (which may be slow) into RAM.
1107  std::string name(absl::StrCat("LOAD #", i, " ["));
1108 
1109  if (header.p_flags & PF_R) {
1110  name += 'R';
1111  }
1112 
1113  if (header.p_flags & PF_W) {
1114  name += 'W';
1115  }
1116 
1117  if (header.p_flags & PF_X) {
1118  name += 'X';
1119  }
1120 
1121  name += ']';
1122 
1123  if (report_by == kReportByEscapedSegmentName) {
1124  return absl::StrCat("[", name, "]");
1125  } else {
1126  return name;
1127  }
1128 }
1129 
1130 static void DoReadELFSegments(RangeSink* sink, ReportSegmentsBy report_by) {
1131  ForEachElf(sink->input_file(), sink,
1132  [=](const ElfFile& elf, string_view /*filename*/,
1133  uint32_t /*index_base*/) {
1134  for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1135  ElfFile::Segment segment;
1136  elf.ReadSegment(i, &segment);
1137  std::string name = GetSegmentName(segment, i, report_by);
1138 
1139  if (segment.header().p_type != PT_LOAD) {
1140  continue;
1141  }
1142 
1143  sink->AddRange("elf_segment", name, segment.header().p_vaddr,
1144  segment.header().p_memsz, segment.contents());
1145  }
1146  });
1147 
1148  ForEachElf(sink->input_file(), sink,
1149  [=](const ElfFile& elf, string_view /*filename*/,
1150  uint32_t /*index_base*/) {
1151  for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1152  ElfFile::Segment segment;
1153  elf.ReadSegment(i, &segment);
1154  const auto& header = segment.header();
1155  if (header.p_type != PT_TLS) continue;
1156  std::string name = "TLS";
1157  sink->AddRange("elf_segment", "TLS", header.p_vaddr,
1158  header.p_memsz, segment.contents());
1159  }
1160  });
1161 }
1162 
1163 static void ReadELFSegments(RangeSink* sink) {
1164  if (IsObjectFile(sink->input_file().data())) {
1165  // Object files don't actually have segments. But we can cheat a little bit
1166  // and make up "segments" based on section flags. This can be really useful
1167  // when you are compiling with -ffunction-sections and -fdata-sections,
1168  // because in those cases the actual "sections" report becomes pretty
1169  // useless (since every function/data has its own section, it's like the
1170  // "symbols" report except less readable).
1171  DoReadELFSections(sink, kReportByFlags);
1172  } else {
1173  DoReadELFSegments(sink, kReportBySegmentName);
1174  }
1175 }
1176 
1177 // ELF files put debug info directly into the binary, so we call the DWARF
1178 // reader directly on them. At the moment we don't attempt to make these
1179 // work with object files.
1180 
1181 static void ReadDWARFSections(const InputFile &file, dwarf::File *dwarf,
1182  RangeSink *sink) {
1183  ElfFile elf(file.data());
1184  assert(elf.IsOpen());
1185  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1186  ElfFile::Section section;
1187  elf.ReadSection(i, &section);
1188  string_view name = section.GetName();
1189  string_view contents = section.contents();
1190  uint64_t uncompressed_size = 0;
1191 
1192  if (section.header().sh_flags & SHF_COMPRESSED) {
1193  // Standard ELF section compression, produced when you link with
1194  // --compress-debug-sections=zlib-gabi
1195  Elf64_Chdr chdr;
1197  elf.ReadStruct<Elf32_Chdr>(contents, 0, ChdrMunger(), &range, &chdr);
1198  if (chdr.ch_type != ELFCOMPRESS_ZLIB) {
1199  // Unknown compression format.
1200  continue;
1201  }
1202  uncompressed_size = chdr.ch_size;
1203  contents.remove_prefix(range.size());
1204  }
1205 
1206  if (name.find(".debug_") == 0) {
1207  name.remove_prefix(string_view(".debug_").size());
1208  } else if (name.find(".zdebug_") == 0) {
1209  // GNU format compressed debug info, produced when you link with
1210  // --compress-debug-sections=zlib-gnu
1211  name.remove_prefix(string_view(".zdebug_").size());
1212  if (ReadBytes(4, &contents) != "ZLIB") {
1213  continue; // Bad compression header.
1214  }
1215  uncompressed_size = ReadBigEndian<uint64_t>(&contents);
1216  }
1217 
1218  if (string_view* member = dwarf->GetFieldByName(name)) {
1219  if (uncompressed_size) {
1220  *member = sink->ZlibDecompress(contents, uncompressed_size);
1221  } else {
1222  *member = section.contents();
1223  }
1224  }
1225  }
1226 }
1227 
1228 void AddCatchAll(RangeSink* sink) {
1229  // The last-line fallback to make sure we cover the entire VM space.
1230  if (sink->IsBaseMap() || sink->data_source() != DataSource::kSegments) {
1231  if (!sink->IsBaseMap()) {
1232  DoReadELFSections(sink, kReportByEscapedSectionName);
1233  }
1234  ForEachElf(sink->input_file(), sink,
1235  [sink](const ElfFile& elf, string_view /*filename*/,
1236  uint32_t /*index_base*/) {
1237  sink->AddFileRange("elf_catchall", "[ELF Header]",
1238  elf.header_region());
1239  sink->AddFileRange("elf_catchall", "[ELF Section Headers]",
1240  elf.section_headers());
1241  sink->AddFileRange("elf_catchall", "[ELF Program Headers]",
1242  elf.segment_headers());
1243  });
1244  }
1245  DoReadELFSegments(sink, kReportByEscapedSegmentName);
1246 
1247 
1248  // The last-line fallback to make sure we cover the entire file.
1249  sink->AddFileRange("elf_catchall", "[Unmapped]", sink->input_file().data());
1250 }
1251 
1252 class ElfObjectFile : public ObjectFile {
1253  public:
1254  ElfObjectFile(std::unique_ptr<InputFile> file)
1255  : ObjectFile(std::move(file)) {}
1256 
1257  std::string GetBuildId() const override {
1258  if (IsObjectFile(file_data().data())) {
1259  // Object files don't have a build ID.
1260  return std::string();
1261  }
1262 
1263  ElfFile elf(file_data().data());
1264  assert(elf.IsOpen());
1265  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1266  ElfFile::Section section;
1267  elf.ReadSection(i, &section);
1268  if (section.header().sh_type != SHT_NOTE) {
1269  continue;
1270  }
1271 
1272  for (ElfFile::NoteIter notes(section); !notes.IsDone(); notes.Next()) {
1273  if (notes.name() == "GNU" && notes.type() == NT_GNU_BUILD_ID) {
1274  return std::string(notes.descriptor());
1275  }
1276  }
1277  }
1278 
1279  // No build id section found.
1280  return std::string();
1281  }
1282 
1283  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
1284  for (auto sink : sinks) {
1285  if (verbose_level > 1) {
1286  printf("Scanning source %d\n", (int)sink->data_source());
1287  }
1288  switch (sink->data_source()) {
1289  case DataSource::kSegments:
1290  ReadELFSegments(sink);
1291  break;
1292  case DataSource::kSections:
1293  DoReadELFSections(sink, kReportBySectionName);
1294  break;
1295  case DataSource::kRawSymbols:
1296  case DataSource::kShortSymbols:
1297  case DataSource::kFullSymbols:
1298  ReadELFSymbols(debug_file().file_data(), sink, nullptr, false);
1299  break;
1300  case DataSource::kArchiveMembers:
1301  DoReadELFSections(sink, kReportByArchiveMember);
1302  break;
1303  case DataSource::kCompileUnits: {
1304  CheckNotObject("compileunits", sink);
1306  DualMap symbol_map;
1307  NameMunger empty_munger;
1308  RangeSink symbol_sink(&debug_file().file_data(),
1309  sink->options(),
1310  DataSource::kRawSymbols,
1311  &sinks[0]->MapAtIndex(0), nullptr);
1312  symbol_sink.AddOutput(&symbol_map, &empty_munger);
1313  ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab,
1314  false);
1315  dwarf::File dwarf;
1316  ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1317  ReadDWARFCompileUnits(dwarf, symbol_map, sink);
1318  break;
1319  }
1320  case DataSource::kInlines: {
1321  CheckNotObject("lineinfo", sink);
1322  dwarf::File dwarf;
1323  ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1324  ReadDWARFInlines(dwarf, sink, true);
1325  DoReadELFSections(sink, kReportByEscapedSectionName);
1326  break;
1327  }
1328  default:
1329  THROW("unknown data source");
1330  }
1331 
1332  switch (sink->data_source()) {
1333  case DataSource::kSegments:
1334  case DataSource::kSections:
1335  case DataSource::kArchiveMembers:
1336  break;
1337  default:
1338  // Add these *after* processing all other data sources.
1339  ReadELFTables(sink->input_file(), sink);
1340  break;
1341  }
1342 
1343  AddCatchAll(sink);
1344  }
1345  }
1346 
1347  bool GetDisassemblyInfo(const absl::string_view symbol,
1348  DataSource symbol_source,
1349  DisassemblyInfo* info) const override {
1350  return DoGetDisassemblyInfo(&symbol, symbol_source, info);
1351  }
1352 
1353  bool DoGetDisassemblyInfo(const absl::string_view* symbol,
1354  DataSource symbol_source,
1355  DisassemblyInfo* info) const {
1356  // Find the corresponding file range. This also could be optimized not to
1357  // build the entire map.
1358  DualMap base_map;
1359  NameMunger empty_munger;
1360  RangeSink base_sink(&file_data(), bloaty::Options(), DataSource::kSegments,
1361  nullptr, nullptr);
1362  base_sink.AddOutput(&base_map, &empty_munger);
1363  std::vector<RangeSink*> sink_ptrs{&base_sink};
1364  ProcessFile(sink_ptrs);
1365 
1366  // Could optimize this not to build the whole table if necessary.
1367  SymbolTable symbol_table;
1368  RangeSink symbol_sink(&file_data(), bloaty::Options(), symbol_source,
1369  &base_map, nullptr);
1370  symbol_sink.AddOutput(&info->symbol_map, &empty_munger);
1371  ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table,
1372  false);
1373 
1374  if (symbol) {
1375  auto entry = symbol_table.find(*symbol);
1376  if (entry == symbol_table.end()) {
1377  entry = symbol_table.find(ItaniumDemangle(*symbol, symbol_source));
1378  if (entry == symbol_table.end()) {
1379  return false;
1380  }
1381  }
1382  uint64_t vmaddr = entry->second.first;
1383  uint64_t size = entry->second.second;
1384 
1385  // TODO(haberman); Add PLT entries to symbol map, so call <plt stub> gets
1386  // symbolized.
1387 
1388  uint64_t fileoff;
1389  if (!base_map.vm_map.Translate(vmaddr, &fileoff)) {
1390  THROWF("Couldn't translate VM address for function $0", symbol);
1391  }
1392 
1393  info->text = StrictSubstr(file_data().data(), fileoff, size);
1394  info->start_address = vmaddr;
1395  }
1396 
1397  return ReadElfArchMode(file_data(), &info->arch, &info->mode);
1398  }
1399 };
1400 
1401 } // namespace
1402 
1403 std::unique_ptr<ObjectFile> TryOpenELFFile(std::unique_ptr<InputFile>& file) {
1404  ElfFile elf(file->data());
1405  ArFile ar(file->data());
1406  if (elf.IsOpen() || ar.IsOpen()) {
1407  return std::unique_ptr<ObjectFile>(new ElfObjectFile(std::move(file)));
1408  } else {
1409  return nullptr;
1410  }
1411 
1412  // A few functions that have been defined but are not yet used.
1413  (void)&ElfFile::FindSectionByName;
1414  (void)&ElfFile::Section::ReadRelocation;
1415 }
1416 
1417 } // namespace bloaty
section_name_table_
Section section_name_table_
Definition: elf.cc:228
xds_interop_client.str
str
Definition: xds_interop_client.py:487
NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID
Definition: elf_common.h:787
EM_X86_64
#define EM_X86_64
Definition: elf_common.h:250
header_
Elf64_Phdr header_
Definition: elf.cc:92
descriptor_
string_view descriptor_
Definition: elf.cc:154
filename
const char * filename
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
bloaty
Definition: bloaty.cc:69
Elf64_Sym::st_value
Elf64_Addr st_value
Definition: elf64.h:211
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
kMagic
static constexpr const char * kMagic
Definition: elf.cc:625
ELFCOMPRESS_ZLIB
#define ELFCOMPRESS_ZLIB
Definition: elf_common.h:893
done_
bool done_
Definition: elf.cc:157
Elf64_Rela::r_offset
Elf64_Addr r_offset
Definition: elf64.h:154
SHT_NOBITS
#define SHT_NOBITS
Definition: elf_common.h:408
EM_PPC64
#define EM_PPC64
Definition: elf_common.h:223
SHT_STRTAB
#define SHT_STRTAB
Definition: elf_common.h:403
CS_MODE_32
@ CS_MODE_32
32-bit mode (X86)
Definition: capstone.h:107
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
section
OPENSSL_EXPORT const char * section
Definition: conf.h:114
CS_MODE_LITTLE_ENDIAN
@ CS_MODE_LITTLE_ENDIAN
little-endian mode (default mode)
Definition: capstone.h:104
section_headers_
string_view section_headers_
Definition: elf.cc:226
magic
uintptr_t magic
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:83
capstone.range
range
Definition: third_party/bloaty/third_party/capstone/bindings/python/capstone/__init__.py:6
absl::string_view::find
size_type find(string_view s, size_type pos=0) const noexcept
Definition: abseil-cpp/absl/strings/string_view.cc:81
Elf32_Rel
Definition: elf32.h:138
CS_MODE_ARM
@ CS_MODE_ARM
32-bit ARM
Definition: capstone.h:105
magic_
const string_view magic_
Definition: elf.cc:622
bloaty::verbose_level
int verbose_level
Definition: bloaty.cc:74
CS_ARCH_PPC
@ CS_ARCH_PPC
PowerPC architecture.
Definition: capstone.h:79
section_string_index_
Elf64_Xword section_string_index_
Definition: elf.cc:224
STT_SECTION
#define STT_SECTION
Definition: elf_common.h:813
absl::cord_internal::Consume
void Consume(CordRep *rep, ConsumeFn consume_fn)
Definition: cord_rep_consume.cc:45
Elf_Note
Definition: elf_common.h:51
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
section_count_
Elf64_Xword section_count_
Definition: elf.cc:223
SHT_DYNSYM
#define SHT_DYNSYM
Definition: elf_common.h:411
bloaty.h
Elf64_Half
uint16_t Elf64_Half
Definition: elf64.h:43
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
Elf64_Chdr::ch_size
Elf64_Xword ch_size
Definition: elf64.h:267
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
cs_arch
cs_arch
Architecture type.
Definition: capstone.h:74
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
setup.name
name
Definition: setup.py:542
ok_
bool ok_
Definition: elf.cc:218
absl::ABSL_NAMESPACE_BEGIN::IsDone
bool IsDone(void *arg)
Definition: abseil-cpp/absl/synchronization/blocking_counter.cc:27
Elf64_Sym::st_shndx
Elf64_Half st_shndx
Definition: elf64.h:210
to
size_t to
Definition: abseil-cpp/absl/container/internal/layout_test.cc:1385
absl::base_internal::Next
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:453
SHF_COMPRESSED
#define SHF_COMPRESSED
Definition: elf_common.h:496
T
#define T(upbtypeconst, upbtype, ctype, default_value)
remaining_
string_view remaining_
Definition: elf.cc:155
SHN_UNDEF
#define SHN_UNDEF
Definition: elf_common.h:387
PF_R
#define PF_R
Definition: elf_common.h:547
versiongenerate.file_data
string file_data
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/xcode/Scripts/versiongenerate.py:84
header_region_
string_view header_region_
Definition: elf.cc:225
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
for
for(map_begin_internal(intern, &it);!map_done(&it);map_next(&it))
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/map.c:207
from
size_t from
Definition: abseil-cpp/absl/container/internal/layout_test.cc:1384
cs_mode
cs_mode
Mode type.
Definition: capstone.h:103
absl::SimpleAtoi
ABSL_NAMESPACE_BEGIN ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type *out)
Definition: abseil-cpp/absl/strings/numbers.h:271
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
SHT_REL
#define SHT_REL
Definition: elf_common.h:409
Elf64_Phdr
Definition: elf64.h:119
start
static uint64_t start
Definition: benchmark-pound.c:74
bloaty::ItaniumDemangle
std::string ItaniumDemangle(string_view symbol, DataSource source)
Definition: bloaty.cc:169
file_type
enum bloaty::@3662::ArFile::MemberFile::@102 file_type
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
testing::internal::posix::Read
int Read(int fd, void *buf, unsigned int count)
Definition: bloaty/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:2044
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
absl::string_view::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:277
bloaty::Endian::kLittle
@ kLittle
THROW
#define THROW(msg)
Definition: bloaty/src/util.h:45
ET_REL
#define ET_REL
Definition: elf_common.h:197
absl::random_internal_nanobenchmark::Func
FuncOutput(*)(const void *, FuncInput) Func
Definition: abseil-cpp/absl/random/internal/nanobenchmark.h:68
Elf64_Sym::st_size
Elf64_Xword st_size
Definition: elf64.h:212
bloaty::CheckedAdd
void CheckedAdd(int64_t *accum, int64_t val)
Definition: bloaty.cc:124
member
int member
Definition: abseil-cpp/absl/base/invoke_test.cc:87
Elf64_Xword
uint64_t Elf64_Xword
Definition: elf64.h:49
data_
string_view data_
Definition: elf.cc:202
elf.h
EM_ARM
#define EM_ARM
Definition: elf_common.h:229
SHN_XINDEX
#define SHN_XINDEX
Definition: elf_common.h:396
CS_ARCH_X86
@ CS_ARCH_X86
X86 architecture (including x86 & x86-64)
Definition: capstone.h:78
range_
string_view range_
Definition: elf.cc:94
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
EM_PPC
#define EM_PPC
Definition: elf_common.h:222
Elf64_Ehdr
Definition: elf64.h:68
Elf64_Shdr
Definition: elf64.h:101
SHT_RELA
#define SHT_RELA
Definition: elf_common.h:404
bloaty::CheckedMul
uint64_t CheckedMul(uint64_t a, uint64_t b)
Definition: bloaty/src/util.h:80
EI_DATA
#define EI_DATA
Definition: elf_common.h:131
benchmark::Initialize
void Initialize(int *argc, char **argv)
Definition: benchmark/src/benchmark.cc:602
Elf64_Chdr
Definition: elf64.h:264
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
name_
string_view name_
Definition: elf.cc:153
bloaty::DataSource
DataSource
Definition: bloaty.h:52
EM_AARCH64
#define EM_AARCH64
Definition: elf_common.h:298
CS_MODE_BIG_ENDIAN
@ CS_MODE_BIG_ENDIAN
big-endian mode
Definition: capstone.h:124
kMagicSize
static constexpr int kMagicSize
Definition: elf.cc:626
min
#define min(a, b)
Definition: qsort.h:83
Elf64_Sym::st_info
unsigned char st_info
Definition: elf64.h:208
arch
cs_arch arch
Definition: cstool.c:13
filename
string_view filename
Definition: elf.cc:594
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
ELFCLASS64
#define ELFCLASS64
Definition: elf_common.h:154
bloaty::TryOpenELFFile
std::unique_ptr< ObjectFile > TryOpenELFFile(std::unique_ptr< InputFile > &file)
Definition: elf.cc:1403
section
Definition: loader.h:337
CS_ARCH_SPARC
@ CS_ARCH_SPARC
Sparc architecture.
Definition: capstone.h:80
Elf64_Chdr::ch_type
Elf64_Word ch_type
Definition: elf64.h:265
CS_ARCH_MIPS
@ CS_ARCH_MIPS
Mips architecture.
Definition: capstone.h:77
EI_NIDENT
#define EI_NIDENT
Definition: elf_common.h:137
symtab
upb_symtab * symtab
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:774
bloaty::AlignUp
size_t AlignUp(size_t offset, size_t granularity)
Definition: bloaty/src/util.h:105
contents
string_view contents
Definition: elf.cc:597
SHT_SYMTAB
#define SHT_SYMTAB
Definition: elf_common.h:402
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
EM_SPARC
#define EM_SPARC
Definition: elf_common.h:209
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
bloaty::DisassembleFindReferences
void DisassembleFindReferences(const DisassemblyInfo &info, RangeSink *sink)
Definition: disassemble.cc:43
CS_MODE_64
@ CS_MODE_64
64-bit mode (X86, PPC)
Definition: capstone.h:108
absl::string_view::remove_prefix
ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n)
Definition: abseil-cpp/absl/strings/string_view.h:344
ProcessFile
static void ProcessFile(int fd)
Definition: ares-fuzz.c:31
bm_diff.note
note
Definition: bm_diff.py:274
EM_MIPS
#define EM_MIPS
Definition: elf_common.h:215
CS_ARCH_ARM
@ CS_ARCH_ARM
ARM architecture (including Thumb, Thumb-2)
Definition: capstone.h:75
STT_FUNC
#define STT_FUNC
Definition: elf_common.h:812
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
Elf32_Chdr
Definition: elf32.h:261
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
ELFCLASS32
#define ELFCLASS32
Definition: elf_common.h:153
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
string_view
absl::string_view string_view
Definition: attr.cc:22
file::size
int size
Definition: bloaty/third_party/zlib/examples/gzappend.c:172
is_native_endian_
bool is_native_endian_
Definition: elf.cc:220
THROWF
#define THROWF(...)
Definition: bloaty/src/util.h:46
Elf64_Rel
Definition: elf64.h:147
type_
uint32_t type_
Definition: elf.cc:156
google::protobuf::python::message_descriptor::GetName
static PyObject * GetName(PyBaseDescriptor *self, void *closure)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/descriptor.cc:471
bloaty::SymbolTable
std::map< absl::string_view, std::pair< uint64_t, uint64_t > > SymbolTable
Definition: bloaty.h:253
Elf64_Rela
Definition: elf64.h:153
bloaty::Endian::kBig
@ kBig
mkowners.rel
rel
Definition: mkowners.py:109
long_filenames_
string_view long_filenames_
Definition: elf.cc:617
SHT_NOTE
#define SHT_NOTE
Definition: elf_common.h:407
ELF64_ST_TYPE
#define ELF64_ST_TYPE(info)
Definition: elf64.h:217
bloaty::GetMachineEndian
Endian GetMachineEndian()
Definition: bloaty/src/util.h:115
bloaty::pe::AddCatchAll
void AddCatchAll(const PeFile &pe, RangeSink *sink)
Definition: pe.cc:203
CS_MODE_V9
@ CS_MODE_V9
SparcV9 mode (Sparc)
Definition: capstone.h:116
table
uint8_t table[256]
Definition: hpack_parser.cc:456
absl::string_view::empty
constexpr bool empty() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:292
Elf64_Word
uint32_t Elf64_Word
Definition: elf64.h:47
Elf32_Rela
Definition: elf32.h:144
util.h
Elf64_Sym
Definition: elf64.h:206
CS_ARCH_ARM64
@ CS_ARCH_ARM64
ARM-64, also called AArch64.
Definition: capstone.h:76
EM_386
#define EM_386
Definition: elf_common.h:210
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
PF_X
#define PF_X
Definition: elf_common.h:545
EI_CLASS
#define EI_CLASS
Definition: elf_common.h:130
header
string_view header
Definition: elf.cc:596
absl::string_view::data
constexpr const_pointer data() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:336
Elf32_Sym
Definition: elf32.h:199
is_64bit_
bool is_64bit_
Definition: elf.cc:219
descriptor
static const char descriptor[1336]
Definition: certs.upbdefs.c:16
Elf64_Sym::st_name
Elf64_Word st_name
Definition: elf64.h:207
bloaty::StrictSubstr
absl::string_view StrictSubstr(absl::string_view data, size_t off, size_t n)
Definition: bloaty/src/util.h:89
bloaty::ReadBytes
absl::string_view ReadBytes(size_t bytes, absl::string_view *data)
Definition: bloaty/src/util.h:165
absl::string_view::substr
constexpr string_view substr(size_type pos=0, size_type n=npos) const
Definition: abseil-cpp/absl/strings/string_view.h:399
ELFDATA2LSB
#define ELFDATA2LSB
Definition: elf_common.h:158
STN_UNDEF
#define STN_UNDEF
Definition: elf_common.h:835
EM_SPARCV9
#define EM_SPARCV9
Definition: elf_common.h:231
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
segment_headers_
string_view segment_headers_
Definition: elf.cc:227
if
if(p->owned &&p->wrapped !=NULL)
Definition: call.c:42
elf_
const ElfFile * elf_
Definition: elf.cc:131
size
size_t size
Definition: elf.cc:595
bloaty::ReadDWARFInlines
void ReadDWARFInlines(const dwarf::File &file, RangeSink *sink, bool include_line)
Definition: dwarf.cc:691
reader
void reader(void *n)
Definition: libuv/docs/code/locks/main.c:8
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
ELFDATA2MSB
#define ELFDATA2MSB
Definition: elf_common.h:159
contents_
string_view contents_
Definition: elf.cc:93
bloaty::ReadDWARFCompileUnits
void ReadDWARFCompileUnits(const dwarf::File &file, const DualMap &map, RangeSink *sink)
Definition: dwarf.cc:630
bloaty::ByteSwap
constexpr T ByteSwap(T val)
Definition: bloaty/src/util.h:133
PF_W
#define PF_W
Definition: elf_common.h:546


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:18