Coverage Report

Created: 2024-05-15 07:01

/src/bloaty/src/elf.cc
Line
Count
Source (jump to first uncovered line)
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"
22
#include "third_party/freebsd_elf/elf.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
754M
  T operator()(T val) {
39
754M
    return ByteSwap(val);
40
754M
  }
elf.cc:unsigned short bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned short>(unsigned short)
Line
Count
Source
38
348k
  T operator()(T val) {
39
348k
    return ByteSwap(val);
40
348k
  }
elf.cc:unsigned int bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned int>(unsigned int)
Line
Count
Source
38
524M
  T operator()(T val) {
39
524M
    return ByteSwap(val);
40
524M
  }
elf.cc:unsigned long bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned long>(unsigned long)
Line
Count
Source
38
229M
  T operator()(T val) {
39
229M
    return ByteSwap(val);
40
229M
  }
Unexecuted instantiation: elf.cc:unsigned char bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned char>(unsigned char)
Unexecuted instantiation: elf.cc:long bloaty::(anonymous namespace)::ByteSwapFunc::operator()<long>(long)
Unexecuted instantiation: elf.cc:int bloaty::(anonymous namespace)::ByteSwapFunc::operator()<int>(int)
41
};
42
43
struct NullFunc {
44
  template <class T>
45
1.83G
  T operator()(T val) { return val; }
elf.cc:unsigned short bloaty::(anonymous namespace)::NullFunc::operator()<unsigned short>(unsigned short)
Line
Count
Source
45
32.3M
  T operator()(T val) { return val; }
elf.cc:unsigned int bloaty::(anonymous namespace)::NullFunc::operator()<unsigned int>(unsigned int)
Line
Count
Source
45
1.79G
  T operator()(T val) { return val; }
elf.cc:unsigned char bloaty::(anonymous namespace)::NullFunc::operator()<unsigned char>(unsigned char)
Line
Count
Source
45
9.19M
  T operator()(T val) { return val; }
elf.cc:int bloaty::(anonymous namespace)::NullFunc::operator()<int>(int)
Line
Count
Source
45
73.4k
  T operator()(T val) { return val; }
46
};
47
48
793k
size_t StringViewToSize(string_view str) {
49
793k
  size_t ret;
50
793k
  if (!absl::SimpleAtoi(str, &ret)) {
51
5.17k
    THROWF("couldn't convert string '$0' to integer.", str);
52
5.17k
  }
53
787k
  return ret;
54
793k
}
55
56
template <class T>
57
975k
void AdvancePastStruct(string_view* data) {
58
975k
  *data = data->substr(sizeof(T));
59
975k
}
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
11.6M
  ElfFile(string_view data) : data_(data) {
68
11.6M
    ok_ = Initialize();
69
11.6M
  }
70
71
11.4M
  bool IsOpen() { return ok_; }
72
73
  // Regions of the file where different headers live.
74
721M
  string_view entire_file() const { return data_; }
75
874k
  string_view header_region() const { return header_region_; }
76
874k
  string_view section_headers() const { return section_headers_; }
77
874k
  string_view segment_headers() const { return segment_headers_; }
78
79
560M
  const Elf64_Ehdr& header() const { return header_; }
80
135M
  Elf64_Xword section_count() const { return section_count_; }
81
0
  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
918M
    const Elf64_Phdr& header() const { return header_; }
87
48.2M
    string_view contents() const { return contents_; }
88
0
    string_view range() const { return range_; }
89
90
   private:
91
    friend class ElfFile;
92
    Elf64_Phdr header_;
93
    string_view contents_;
94
    string_view range_;
95
  };
96
97
  // Represents an ELF section (.text, .data, .bss, etc.)
98
  class Section {
99
   public:
100
323M
    const Elf64_Shdr& header() const { return header_; }
101
145M
    string_view contents() const { return contents_; }
102
0
    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
933k
    const ElfFile& elf() const { return *elf_; }
128
129
   private:
130
    friend class ElfFile;
131
    const ElfFile* elf_;
132
    Elf64_Shdr header_;
133
    string_view contents_;
134
    string_view range_;
135
  };
136
137
  class NoteIter {
138
   public:
139
    NoteIter(const Section& section)
140
933k
        : elf_(&section.elf()), remaining_(section.contents()) {
141
933k
      Next();
142
933k
    }
143
144
1.60M
    bool IsDone() const { return done_; }
145
887k
    uint32_t type() const { return type_; }
146
973k
    string_view name() const { return name_; }
147
304k
    string_view descriptor() const { return descriptor_; }
148
149
    void Next();
150
151
   public:
152
    const ElfFile* elf_;
153
    string_view name_;
154
    string_view descriptor_;
155
    string_view remaining_;
156
    uint32_t type_;
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
1.11G
  bool is_64bit() const { return is_64bit_; }
166
847M
  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
809M
                  absl::string_view* range, T64* out) const {
171
809M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
809M
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Ehdr, Elf64_Ehdr, bloaty::(anonymous namespace)::EhdrMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::EhdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Ehdr*) const
Line
Count
Source
170
11.1M
                  absl::string_view* range, T64* out) const {
171
11.1M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
11.1M
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Shdr, Elf64_Shdr, bloaty::(anonymous namespace)::ShdrMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::ShdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Shdr*) const
Line
Count
Source
170
155M
                  absl::string_view* range, T64* out) const {
171
155M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
155M
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf_Note, Elf_Note, bloaty::(anonymous namespace)::NoteMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::NoteMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf_Note*) const
Line
Count
Source
170
975k
                  absl::string_view* range, T64* out) const {
171
975k
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
975k
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Phdr, Elf64_Phdr, bloaty::(anonymous namespace)::PhdrMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::PhdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Phdr*) const
Line
Count
Source
170
554M
                  absl::string_view* range, T64* out) const {
171
554M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
554M
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Sym, Elf64_Sym, bloaty::(anonymous namespace)::SymMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::SymMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Sym*) const
Line
Count
Source
170
40.5M
                  absl::string_view* range, T64* out) const {
171
40.5M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
40.5M
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Chdr, Elf64_Chdr, bloaty::(anonymous namespace)::ChdrMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::ChdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Chdr*) const
Line
Count
Source
170
786k
                  absl::string_view* range, T64* out) const {
171
786k
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
786k
  }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Rela, Elf64_Rela, bloaty::(anonymous namespace)::RelaMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::RelaMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rela*) const
Line
Count
Source
170
46.2M
                  absl::string_view* range, T64* out) const {
171
46.2M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
46.2M
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ElfFile::ReadStruct<Elf32_Rel, Elf64_Rel, bloaty::(anonymous namespace)::RelMunger>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long, bloaty::(anonymous namespace)::RelMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rel*) const
173
174
 private:
175
  friend class Section;
176
177
  bool Initialize();
178
179
741M
  string_view GetRegion(uint64_t start, uint64_t n) const {
180
741M
    return StrictSubstr(data_, start, n);
181
741M
  }
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
809M
        : 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
809M
              T64* out) const {
193
809M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
500M
        return Memcpy(offset, range, out);
195
500M
      } else {
196
308M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
308M
      }
198
809M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Ehdr, Elf64_Ehdr, bloaty::(anonymous namespace)::EhdrMunger>(unsigned long, bloaty::(anonymous namespace)::EhdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Ehdr*) const
Line
Count
Source
192
11.1M
              T64* out) const {
193
11.1M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
7.60M
        return Memcpy(offset, range, out);
195
7.60M
      } else {
196
3.50M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
3.50M
      }
198
11.1M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Shdr, Elf64_Shdr, bloaty::(anonymous namespace)::ShdrMunger>(unsigned long, bloaty::(anonymous namespace)::ShdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Shdr*) const
Line
Count
Source
192
155M
              T64* out) const {
193
155M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
99.7M
        return Memcpy(offset, range, out);
195
99.7M
      } else {
196
56.1M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
56.1M
      }
198
155M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf_Note, Elf_Note, bloaty::(anonymous namespace)::NoteMunger>(unsigned long, bloaty::(anonymous namespace)::NoteMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf_Note*) const
Line
Count
Source
192
975k
              T64* out) const {
193
975k
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
782k
        return Memcpy(offset, range, out);
195
782k
      } else {
196
192k
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
192k
      }
198
975k
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Phdr, Elf64_Phdr, bloaty::(anonymous namespace)::PhdrMunger>(unsigned long, bloaty::(anonymous namespace)::PhdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Phdr*) const
Line
Count
Source
192
554M
              T64* out) const {
193
554M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
310M
        return Memcpy(offset, range, out);
195
310M
      } else {
196
243M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
243M
      }
198
554M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Sym, Elf64_Sym, bloaty::(anonymous namespace)::SymMunger>(unsigned long, bloaty::(anonymous namespace)::SymMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Sym*) const
Line
Count
Source
192
40.5M
              T64* out) const {
193
40.5M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
35.9M
        return Memcpy(offset, range, out);
195
35.9M
      } else {
196
4.59M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
4.59M
      }
198
40.5M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Chdr, Elf64_Chdr, bloaty::(anonymous namespace)::ChdrMunger>(unsigned long, bloaty::(anonymous namespace)::ChdrMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Chdr*) const
Line
Count
Source
192
786k
              T64* out) const {
193
786k
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
166k
        return Memcpy(offset, range, out);
195
619k
      } else {
196
619k
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
619k
      }
198
786k
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Rela, Elf64_Rela, bloaty::(anonymous namespace)::RelaMunger>(unsigned long, bloaty::(anonymous namespace)::RelaMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rela*) const
Line
Count
Source
192
46.2M
              T64* out) const {
193
46.2M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
46.1M
        return Memcpy(offset, range, out);
195
46.1M
      } else {
196
73.7k
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
73.7k
      }
198
46.2M
    }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Read<Elf32_Rel, Elf64_Rel, bloaty::(anonymous namespace)::RelMunger>(unsigned long, bloaty::(anonymous namespace)::RelMunger, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rel*) const
199
200
   private:
201
    const ElfFile& elf_;
202
    string_view data_;
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
809M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
809M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
809M
      if (out_range) {
212
776M
        *out_range = range;
213
776M
      }
214
809M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
809M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Ehdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Ehdr*) const
Line
Count
Source
209
7.62M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
7.62M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
7.62M
      if (out_range) {
212
7.62M
        *out_range = range;
213
7.62M
      }
214
7.62M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
7.62M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Ehdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Ehdr*) const
Line
Count
Source
209
3.48M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
3.48M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
3.48M
      if (out_range) {
212
3.48M
        *out_range = range;
213
3.48M
      }
214
3.48M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
3.48M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Shdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Shdr*) const
Line
Count
Source
209
103M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
103M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
103M
      if (out_range) {
212
103M
        *out_range = range;
213
103M
      }
214
103M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
103M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Shdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Shdr*) const
Line
Count
Source
209
52.6M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
52.6M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
52.6M
      if (out_range) {
212
52.6M
        *out_range = range;
213
52.6M
      }
214
52.6M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
52.6M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf_Note>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf_Note*) const
Line
Count
Source
209
975k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
975k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
975k
      if (out_range) {
212
0
        *out_range = range;
213
0
      }
214
975k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
975k
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Phdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Phdr*) const
Line
Count
Source
209
345M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
345M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
345M
      if (out_range) {
212
345M
        *out_range = range;
213
345M
      }
214
345M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
345M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Phdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Phdr*) const
Line
Count
Source
209
208M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
208M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
208M
      if (out_range) {
212
208M
        *out_range = range;
213
208M
      }
214
208M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
208M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Sym>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Sym*) const
Line
Count
Source
209
35.9M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
35.9M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
35.9M
      if (out_range) {
212
7.27M
        *out_range = range;
213
7.27M
      }
214
35.9M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
35.9M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Sym>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Sym*) const
Line
Count
Source
209
4.59M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
4.59M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
4.59M
      if (out_range) {
212
896k
        *out_range = range;
213
896k
      }
214
4.59M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
4.59M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Chdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Chdr*) const
Line
Count
Source
209
220k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
220k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
220k
      if (out_range) {
212
219k
        *out_range = range;
213
219k
      }
214
220k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
220k
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Chdr>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Chdr*) const
Line
Count
Source
209
566k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
566k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
566k
      if (out_range) {
212
565k
        *out_range = range;
213
565k
      }
214
566k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
566k
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Rela>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rela*) const
Line
Count
Source
209
46.1M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
46.1M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
46.1M
      if (out_range) {
212
46.1M
        *out_range = range;
213
46.1M
      }
214
46.1M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
46.1M
    }
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Rela>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Rela*) const
Line
Count
Source
209
73.7k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
73.7k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
73.7k
      if (out_range) {
212
73.4k
        *out_range = range;
213
73.4k
      }
214
73.7k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
73.7k
    }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf64_Rel>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rel*) const
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::Memcpy<Elf32_Rel>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf32_Rel*) const
216
  };
217
218
  bool ok_;
219
  bool is_64bit_;
220
  bool is_native_endian_;
221
  string_view data_;
222
  Elf64_Ehdr header_;
223
  Elf64_Xword section_count_;
224
  Elf64_Xword section_string_index_;
225
  string_view header_region_;
226
  string_view section_headers_;
227
  string_view segment_headers_;
228
  Section section_name_table_;
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
3.50M
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
3.50M
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
3.50M
    to->e_type       = func(from.e_type);
247
3.50M
    to->e_machine    = func(from.e_machine);
248
3.50M
    to->e_version    = func(from.e_version);
249
3.50M
    to->e_entry      = func(from.e_entry);
250
3.50M
    to->e_phoff      = func(from.e_phoff);
251
3.50M
    to->e_shoff      = func(from.e_shoff);
252
3.50M
    to->e_flags      = func(from.e_flags);
253
3.50M
    to->e_ehsize     = func(from.e_ehsize);
254
3.50M
    to->e_phentsize  = func(from.e_phentsize);
255
3.50M
    to->e_phnum      = func(from.e_phnum);
256
3.50M
    to->e_shentsize  = func(from.e_shentsize);
257
3.50M
    to->e_shnum      = func(from.e_shnum);
258
3.50M
    to->e_shstrndx   = func(from.e_shstrndx);
259
3.50M
  }
elf.cc:void bloaty::(anonymous namespace)::EhdrMunger::operator()<Elf64_Ehdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Ehdr const&, Elf64_Ehdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
244
18.2k
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
18.2k
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
18.2k
    to->e_type       = func(from.e_type);
247
18.2k
    to->e_machine    = func(from.e_machine);
248
18.2k
    to->e_version    = func(from.e_version);
249
18.2k
    to->e_entry      = func(from.e_entry);
250
18.2k
    to->e_phoff      = func(from.e_phoff);
251
18.2k
    to->e_shoff      = func(from.e_shoff);
252
18.2k
    to->e_flags      = func(from.e_flags);
253
18.2k
    to->e_ehsize     = func(from.e_ehsize);
254
18.2k
    to->e_phentsize  = func(from.e_phentsize);
255
18.2k
    to->e_phnum      = func(from.e_phnum);
256
18.2k
    to->e_shentsize  = func(from.e_shentsize);
257
18.2k
    to->e_shnum      = func(from.e_shnum);
258
18.2k
    to->e_shstrndx   = func(from.e_shstrndx);
259
18.2k
  }
elf.cc:void bloaty::(anonymous namespace)::EhdrMunger::operator()<Elf32_Ehdr, bloaty::(anonymous namespace)::NullFunc>(Elf32_Ehdr const&, Elf64_Ehdr*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
244
3.46M
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
3.46M
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
3.46M
    to->e_type       = func(from.e_type);
247
3.46M
    to->e_machine    = func(from.e_machine);
248
3.46M
    to->e_version    = func(from.e_version);
249
3.46M
    to->e_entry      = func(from.e_entry);
250
3.46M
    to->e_phoff      = func(from.e_phoff);
251
3.46M
    to->e_shoff      = func(from.e_shoff);
252
3.46M
    to->e_flags      = func(from.e_flags);
253
3.46M
    to->e_ehsize     = func(from.e_ehsize);
254
3.46M
    to->e_phentsize  = func(from.e_phentsize);
255
3.46M
    to->e_phnum      = func(from.e_phnum);
256
3.46M
    to->e_shentsize  = func(from.e_shentsize);
257
3.46M
    to->e_shnum      = func(from.e_shnum);
258
3.46M
    to->e_shstrndx   = func(from.e_shstrndx);
259
3.46M
  }
elf.cc:void bloaty::(anonymous namespace)::EhdrMunger::operator()<Elf32_Ehdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Ehdr const&, Elf64_Ehdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
244
25.3k
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
25.3k
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
25.3k
    to->e_type       = func(from.e_type);
247
25.3k
    to->e_machine    = func(from.e_machine);
248
25.3k
    to->e_version    = func(from.e_version);
249
25.3k
    to->e_entry      = func(from.e_entry);
250
25.3k
    to->e_phoff      = func(from.e_phoff);
251
25.3k
    to->e_shoff      = func(from.e_shoff);
252
25.3k
    to->e_flags      = func(from.e_flags);
253
25.3k
    to->e_ehsize     = func(from.e_ehsize);
254
25.3k
    to->e_phentsize  = func(from.e_phentsize);
255
25.3k
    to->e_phnum      = func(from.e_phnum);
256
25.3k
    to->e_shentsize  = func(from.e_shentsize);
257
25.3k
    to->e_shnum      = func(from.e_shnum);
258
25.3k
    to->e_shstrndx   = func(from.e_shstrndx);
259
25.3k
  }
260
};
261
262
struct ShdrMunger {
263
  template <class From, class Func>
264
56.1M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
56.1M
    to->sh_name       = func(from.sh_name);
266
56.1M
    to->sh_type       = func(from.sh_type);
267
56.1M
    to->sh_flags      = func(from.sh_flags);
268
56.1M
    to->sh_addr       = func(from.sh_addr);
269
56.1M
    to->sh_offset     = func(from.sh_offset);
270
56.1M
    to->sh_size       = func(from.sh_size);
271
56.1M
    to->sh_link       = func(from.sh_link);
272
56.1M
    to->sh_info       = func(from.sh_info);
273
56.1M
    to->sh_addralign  = func(from.sh_addralign);
274
56.1M
    to->sh_entsize    = func(from.sh_entsize);
275
56.1M
  }
elf.cc:void bloaty::(anonymous namespace)::ShdrMunger::operator()<Elf64_Shdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Shdr const&, Elf64_Shdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
264
3.48M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
3.48M
    to->sh_name       = func(from.sh_name);
266
3.48M
    to->sh_type       = func(from.sh_type);
267
3.48M
    to->sh_flags      = func(from.sh_flags);
268
3.48M
    to->sh_addr       = func(from.sh_addr);
269
3.48M
    to->sh_offset     = func(from.sh_offset);
270
3.48M
    to->sh_size       = func(from.sh_size);
271
3.48M
    to->sh_link       = func(from.sh_link);
272
3.48M
    to->sh_info       = func(from.sh_info);
273
3.48M
    to->sh_addralign  = func(from.sh_addralign);
274
3.48M
    to->sh_entsize    = func(from.sh_entsize);
275
3.48M
  }
elf.cc:void bloaty::(anonymous namespace)::ShdrMunger::operator()<Elf32_Shdr, bloaty::(anonymous namespace)::NullFunc>(Elf32_Shdr const&, Elf64_Shdr*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
264
48.6M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
48.6M
    to->sh_name       = func(from.sh_name);
266
48.6M
    to->sh_type       = func(from.sh_type);
267
48.6M
    to->sh_flags      = func(from.sh_flags);
268
48.6M
    to->sh_addr       = func(from.sh_addr);
269
48.6M
    to->sh_offset     = func(from.sh_offset);
270
48.6M
    to->sh_size       = func(from.sh_size);
271
48.6M
    to->sh_link       = func(from.sh_link);
272
48.6M
    to->sh_info       = func(from.sh_info);
273
48.6M
    to->sh_addralign  = func(from.sh_addralign);
274
48.6M
    to->sh_entsize    = func(from.sh_entsize);
275
48.6M
  }
elf.cc:void bloaty::(anonymous namespace)::ShdrMunger::operator()<Elf32_Shdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Shdr const&, Elf64_Shdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
264
3.94M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
3.94M
    to->sh_name       = func(from.sh_name);
266
3.94M
    to->sh_type       = func(from.sh_type);
267
3.94M
    to->sh_flags      = func(from.sh_flags);
268
3.94M
    to->sh_addr       = func(from.sh_addr);
269
3.94M
    to->sh_offset     = func(from.sh_offset);
270
3.94M
    to->sh_size       = func(from.sh_size);
271
3.94M
    to->sh_link       = func(from.sh_link);
272
3.94M
    to->sh_info       = func(from.sh_info);
273
3.94M
    to->sh_addralign  = func(from.sh_addralign);
274
3.94M
    to->sh_entsize    = func(from.sh_entsize);
275
3.94M
  }
276
};
277
278
struct PhdrMunger {
279
  template <class From, class Func>
280
243M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
243M
    to->p_type   = func(from.p_type);
282
243M
    to->p_flags  = func(from.p_flags);
283
243M
    to->p_offset = func(from.p_offset);
284
243M
    to->p_vaddr  = func(from.p_vaddr);
285
243M
    to->p_paddr  = func(from.p_paddr);
286
243M
    to->p_filesz = func(from.p_filesz);
287
243M
    to->p_memsz  = func(from.p_memsz);
288
243M
    to->p_align  = func(from.p_align);
289
243M
  }
elf.cc:void bloaty::(anonymous namespace)::PhdrMunger::operator()<Elf64_Phdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Phdr const&, Elf64_Phdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
280
34.7M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
34.7M
    to->p_type   = func(from.p_type);
282
34.7M
    to->p_flags  = func(from.p_flags);
283
34.7M
    to->p_offset = func(from.p_offset);
284
34.7M
    to->p_vaddr  = func(from.p_vaddr);
285
34.7M
    to->p_paddr  = func(from.p_paddr);
286
34.7M
    to->p_filesz = func(from.p_filesz);
287
34.7M
    to->p_memsz  = func(from.p_memsz);
288
34.7M
    to->p_align  = func(from.p_align);
289
34.7M
  }
elf.cc:void bloaty::(anonymous namespace)::PhdrMunger::operator()<Elf32_Phdr, bloaty::(anonymous namespace)::NullFunc>(Elf32_Phdr const&, Elf64_Phdr*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
280
158M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
158M
    to->p_type   = func(from.p_type);
282
158M
    to->p_flags  = func(from.p_flags);
283
158M
    to->p_offset = func(from.p_offset);
284
158M
    to->p_vaddr  = func(from.p_vaddr);
285
158M
    to->p_paddr  = func(from.p_paddr);
286
158M
    to->p_filesz = func(from.p_filesz);
287
158M
    to->p_memsz  = func(from.p_memsz);
288
158M
    to->p_align  = func(from.p_align);
289
158M
  }
elf.cc:void bloaty::(anonymous namespace)::PhdrMunger::operator()<Elf32_Phdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Phdr const&, Elf64_Phdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
280
50.0M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
50.0M
    to->p_type   = func(from.p_type);
282
50.0M
    to->p_flags  = func(from.p_flags);
283
50.0M
    to->p_offset = func(from.p_offset);
284
50.0M
    to->p_vaddr  = func(from.p_vaddr);
285
50.0M
    to->p_paddr  = func(from.p_paddr);
286
50.0M
    to->p_filesz = func(from.p_filesz);
287
50.0M
    to->p_memsz  = func(from.p_memsz);
288
50.0M
    to->p_align  = func(from.p_align);
289
50.0M
  }
290
};
291
292
struct SymMunger {
293
  template <class From, class Func>
294
4.59M
  void operator()(const From& from, Elf64_Sym* to, Func func) {
295
4.59M
    to->st_name   = func(from.st_name);
296
4.59M
    to->st_info   = func(from.st_info);
297
4.59M
    to->st_other  = func(from.st_other);
298
4.59M
    to->st_shndx  = func(from.st_shndx);
299
4.59M
    to->st_value  = func(from.st_value);
300
4.59M
    to->st_size   = func(from.st_size);
301
4.59M
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::SymMunger::operator()<Elf64_Sym, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Sym const&, Elf64_Sym*, bloaty::(anonymous namespace)::ByteSwapFunc)
elf.cc:void bloaty::(anonymous namespace)::SymMunger::operator()<Elf32_Sym, bloaty::(anonymous namespace)::NullFunc>(Elf32_Sym const&, Elf64_Sym*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
294
4.59M
  void operator()(const From& from, Elf64_Sym* to, Func func) {
295
4.59M
    to->st_name   = func(from.st_name);
296
4.59M
    to->st_info   = func(from.st_info);
297
4.59M
    to->st_other  = func(from.st_other);
298
4.59M
    to->st_shndx  = func(from.st_shndx);
299
4.59M
    to->st_value  = func(from.st_value);
300
4.59M
    to->st_size   = func(from.st_size);
301
4.59M
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::SymMunger::operator()<Elf32_Sym, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Sym const&, Elf64_Sym*, bloaty::(anonymous namespace)::ByteSwapFunc)
302
};
303
304
struct RelMunger {
305
  template <class From, class Func>
306
0
  void operator()(const From& from, Elf64_Rel* to, Func func) {
307
0
    to->r_offset = func(from.r_offset);
308
0
    to->r_info   = func(from.r_info);
309
0
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::RelMunger::operator()<Elf64_Rel, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Rel const&, Elf64_Rel*, bloaty::(anonymous namespace)::ByteSwapFunc)
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::RelMunger::operator()<Elf32_Rel, bloaty::(anonymous namespace)::NullFunc>(Elf32_Rel const&, Elf64_Rel*, bloaty::(anonymous namespace)::NullFunc)
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::RelMunger::operator()<Elf32_Rel, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Rel const&, Elf64_Rel*, bloaty::(anonymous namespace)::ByteSwapFunc)
310
};
311
312
struct RelaMunger {
313
  template <class From, class Func>
314
73.4k
  void operator()(const From& from, Elf64_Rela* to, Func func) {
315
73.4k
    to->r_offset = func(from.r_offset);
316
73.4k
    to->r_info   = func(from.r_info);
317
73.4k
    to->r_addend = func(from.r_addend);
318
73.4k
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::RelaMunger::operator()<Elf64_Rela, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Rela const&, Elf64_Rela*, bloaty::(anonymous namespace)::ByteSwapFunc)
elf.cc:void bloaty::(anonymous namespace)::RelaMunger::operator()<Elf32_Rela, bloaty::(anonymous namespace)::NullFunc>(Elf32_Rela const&, Elf64_Rela*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
314
73.4k
  void operator()(const From& from, Elf64_Rela* to, Func func) {
315
73.4k
    to->r_offset = func(from.r_offset);
316
73.4k
    to->r_info   = func(from.r_info);
317
73.4k
    to->r_addend = func(from.r_addend);
318
73.4k
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::RelaMunger::operator()<Elf32_Rela, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Rela const&, Elf64_Rela*, bloaty::(anonymous namespace)::ByteSwapFunc)
319
};
320
321
struct NoteMunger {
322
  template <class From, class Func>
323
192k
  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324
192k
    to->n_namesz = func(from.n_namesz);
325
192k
    to->n_descsz = func(from.n_descsz);
326
192k
    to->n_type   = func(from.n_type);
327
192k
  }
elf.cc:void bloaty::(anonymous namespace)::NoteMunger::operator()<Elf_Note, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf_Note const&, Elf_Note*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
323
54
  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324
54
    to->n_namesz = func(from.n_namesz);
325
54
    to->n_descsz = func(from.n_descsz);
326
54
    to->n_type   = func(from.n_type);
327
54
  }
elf.cc:void bloaty::(anonymous namespace)::NoteMunger::operator()<Elf_Note, bloaty::(anonymous namespace)::NullFunc>(Elf_Note const&, Elf_Note*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
323
192k
  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324
192k
    to->n_namesz = func(from.n_namesz);
325
192k
    to->n_descsz = func(from.n_descsz);
326
192k
    to->n_type   = func(from.n_type);
327
192k
  }
328
};
329
330
struct ChdrMunger {
331
  template <class From, class Func>
332
619k
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
619k
    to->ch_type = func(from.ch_type);
334
619k
    to->ch_size = func(from.ch_size);
335
619k
    to->ch_addralign   = func(from.ch_addralign);
336
619k
  }
elf.cc:void bloaty::(anonymous namespace)::ChdrMunger::operator()<Elf64_Chdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Chdr const&, Elf64_Chdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
332
53.7k
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
53.7k
    to->ch_type = func(from.ch_type);
334
53.7k
    to->ch_size = func(from.ch_size);
335
53.7k
    to->ch_addralign   = func(from.ch_addralign);
336
53.7k
  }
elf.cc:void bloaty::(anonymous namespace)::ChdrMunger::operator()<Elf32_Chdr, bloaty::(anonymous namespace)::NullFunc>(Elf32_Chdr const&, Elf64_Chdr*, bloaty::(anonymous namespace)::NullFunc)
Line
Count
Source
332
347k
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
347k
    to->ch_type = func(from.ch_type);
334
347k
    to->ch_size = func(from.ch_size);
335
347k
    to->ch_addralign   = func(from.ch_addralign);
336
347k
  }
elf.cc:void bloaty::(anonymous namespace)::ChdrMunger::operator()<Elf32_Chdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Chdr const&, Elf64_Chdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
332
218k
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
218k
    to->ch_type = func(from.ch_type);
334
218k
    to->ch_size = func(from.ch_size);
335
218k
    to->ch_addralign   = func(from.ch_addralign);
336
218k
  }
337
};
338
339
template <class T32, class T64, class Munger>
340
void ElfFile::StructReader::ReadFallback(uint64_t offset,
341
                                         absl::string_view* range,
342
308M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
308M
  if (elf_.is_64bit()) {
345
38.3M
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
38.3M
    Munger()(*out, out, ByteSwapFunc());
348
270M
  } else {
349
270M
    T32 data32;
350
270M
    Memcpy(offset, range, &data32);
351
270M
    if (elf_.is_native_endian()) {
352
216M
      Munger()(data32, out, NullFunc());
353
216M
    } else {
354
54.2M
      Munger()(data32, out, ByteSwapFunc());
355
54.2M
    }
356
270M
  }
357
308M
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Ehdr, Elf64_Ehdr, bloaty::(anonymous namespace)::EhdrMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Ehdr*) const
Line
Count
Source
342
3.50M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
3.50M
  if (elf_.is_64bit()) {
345
18.4k
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
18.4k
    Munger()(*out, out, ByteSwapFunc());
348
3.48M
  } else {
349
3.48M
    T32 data32;
350
3.48M
    Memcpy(offset, range, &data32);
351
3.48M
    if (elf_.is_native_endian()) {
352
3.46M
      Munger()(data32, out, NullFunc());
353
3.46M
    } else {
354
25.4k
      Munger()(data32, out, ByteSwapFunc());
355
25.4k
    }
356
3.48M
  }
357
3.50M
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Shdr, Elf64_Shdr, bloaty::(anonymous namespace)::ShdrMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Shdr*) const
Line
Count
Source
342
56.1M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
56.1M
  if (elf_.is_64bit()) {
345
3.48M
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
3.48M
    Munger()(*out, out, ByteSwapFunc());
348
52.6M
  } else {
349
52.6M
    T32 data32;
350
52.6M
    Memcpy(offset, range, &data32);
351
52.6M
    if (elf_.is_native_endian()) {
352
48.6M
      Munger()(data32, out, NullFunc());
353
48.6M
    } else {
354
3.94M
      Munger()(data32, out, ByteSwapFunc());
355
3.94M
    }
356
52.6M
  }
357
56.1M
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf_Note, Elf_Note, bloaty::(anonymous namespace)::NoteMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf_Note*) const
Line
Count
Source
342
192k
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
192k
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
192k
  } else {
349
192k
    T32 data32;
350
192k
    Memcpy(offset, range, &data32);
351
192k
    if (elf_.is_native_endian()) {
352
192k
      Munger()(data32, out, NullFunc());
353
192k
    } else {
354
168
      Munger()(data32, out, ByteSwapFunc());
355
168
    }
356
192k
  }
357
192k
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Phdr, Elf64_Phdr, bloaty::(anonymous namespace)::PhdrMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Phdr*) const
Line
Count
Source
342
243M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
243M
  if (elf_.is_64bit()) {
345
34.7M
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
34.7M
    Munger()(*out, out, ByteSwapFunc());
348
208M
  } else {
349
208M
    T32 data32;
350
208M
    Memcpy(offset, range, &data32);
351
208M
    if (elf_.is_native_endian()) {
352
158M
      Munger()(data32, out, NullFunc());
353
158M
    } else {
354
50.0M
      Munger()(data32, out, ByteSwapFunc());
355
50.0M
    }
356
208M
  }
357
243M
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Sym, Elf64_Sym, bloaty::(anonymous namespace)::SymMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Sym*) const
Line
Count
Source
342
4.59M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
4.59M
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
4.59M
  } else {
349
4.59M
    T32 data32;
350
4.59M
    Memcpy(offset, range, &data32);
351
4.59M
    if (elf_.is_native_endian()) {
352
4.59M
      Munger()(data32, out, NullFunc());
353
4.59M
    } else {
354
149
      Munger()(data32, out, ByteSwapFunc());
355
149
    }
356
4.59M
  }
357
4.59M
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Chdr, Elf64_Chdr, bloaty::(anonymous namespace)::ChdrMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Chdr*) const
Line
Count
Source
342
619k
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
619k
  if (elf_.is_64bit()) {
345
53.7k
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
53.7k
    Munger()(*out, out, ByteSwapFunc());
348
566k
  } else {
349
566k
    T32 data32;
350
566k
    Memcpy(offset, range, &data32);
351
566k
    if (elf_.is_native_endian()) {
352
347k
      Munger()(data32, out, NullFunc());
353
347k
    } else {
354
218k
      Munger()(data32, out, ByteSwapFunc());
355
218k
    }
356
566k
  }
357
619k
}
elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Rela, Elf64_Rela, bloaty::(anonymous namespace)::RelaMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rela*) const
Line
Count
Source
342
73.7k
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
73.7k
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
73.7k
  } else {
349
73.7k
    T32 data32;
350
73.7k
    Memcpy(offset, range, &data32);
351
73.7k
    if (elf_.is_native_endian()) {
352
73.4k
      Munger()(data32, out, NullFunc());
353
73.4k
    } else {
354
325
      Munger()(data32, out, ByteSwapFunc());
355
325
    }
356
73.7k
  }
357
73.7k
}
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ElfFile::StructReader::ReadFallback<Elf32_Rel, Elf64_Rel, bloaty::(anonymous namespace)::RelMunger>(unsigned long, std::__1::basic_string_view<char, std::__1::char_traits<char> >*, Elf64_Rel*) const
358
359
71.4M
string_view ElfFile::Section::GetName() const {
360
71.4M
  if (header_.sh_name == SHN_UNDEF) {
361
2.50M
    return string_view(nullptr, 0);
362
2.50M
  }
363
68.9M
  return elf_->section_name_table_.ReadString(header_.sh_name);
364
71.4M
}
365
366
89.7M
string_view ElfFile::Section::ReadString(Elf64_Word index) const {
367
89.7M
  assert(header().sh_type == SHT_STRTAB);
368
369
89.7M
  if (index == SHN_UNDEF || index >= contents_.size()) {
370
85.4k
    THROWF("can't read index $0 from strtab, total size is $1", index,
371
85.4k
           contents_.size());
372
85.4k
  }
373
374
89.7M
  string_view ret = StrictSubstr(contents_, index);
375
376
89.7M
  const char* null_pos =
377
89.7M
      static_cast<const char*>(memchr(ret.data(), '\0', ret.size()));
378
379
89.7M
  if (null_pos == NULL) {
380
1.99k
    THROW("no NULL terminator found");
381
1.99k
  }
382
383
89.7M
  size_t len = null_pos - ret.data();
384
89.7M
  ret = ret.substr(0, len);
385
89.7M
  return ret;
386
89.7M
}
387
388
617k
Elf64_Word ElfFile::Section::GetEntryCount() const {
389
617k
  if (header_.sh_entsize == 0) {
390
1.40k
    THROW("sh_entsize is zero");
391
1.40k
  }
392
616k
  return contents_.size() / header_.sh_entsize;
393
617k
}
394
395
void ElfFile::Section::ReadSymbol(Elf64_Word index, Elf64_Sym* sym,
396
40.5M
                                  string_view* file_range) const {
397
40.5M
  assert(header().sh_type == SHT_SYMTAB || header().sh_type == SHT_DYNSYM);
398
0
  size_t offset = header_.sh_entsize * index;
399
40.5M
  elf_->ReadStruct<Elf32_Sym>(contents(), offset, SymMunger(), file_range, sym);
400
40.5M
}
401
402
void ElfFile::Section::ReadRelocation(Elf64_Word index, Elf64_Rel* rel,
403
0
                                      string_view* file_range) const {
404
0
  assert(header().sh_type == SHT_REL);
405
0
  size_t offset = header_.sh_entsize * index;
406
0
  elf_->ReadStruct<Elf32_Rel>(contents(), offset, RelMunger(), file_range, rel);
407
0
}
408
409
void ElfFile::Section::ReadRelocationWithAddend(Elf64_Word index,
410
                                                Elf64_Rela* rela,
411
46.2M
                                                string_view* file_range) const {
412
46.2M
  assert(header().sh_type == SHT_RELA);
413
0
  size_t offset = header_.sh_entsize * index;
414
46.2M
  elf_->ReadStruct<Elf32_Rela>(contents(), offset, RelaMunger(), file_range,
415
46.2M
                               rela);
416
46.2M
}
417
418
1.60M
void ElfFile::NoteIter::Next() {
419
1.60M
  if (remaining_.empty()) {
420
626k
    done_ = true;
421
626k
    return;
422
626k
  }
423
424
975k
  Elf_Note note;
425
975k
  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
975k
  AdvancePastStruct<Elf_Note>(&remaining_);
430
431
975k
  type_ = note.n_type;
432
975k
  name_ = StrictSubstr(remaining_, 0, note.n_namesz);
433
434
  // Size might include NULL terminator.
435
975k
  if (name_[name_.size() - 1] == 0) {
436
944k
    name_ = name_.substr(0, name_.size() - 1);
437
944k
  }
438
439
975k
  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_namesz, 4));
440
975k
  descriptor_ = StrictSubstr(remaining_, 0, note.n_descsz);
441
975k
  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_descsz, 4));
442
975k
}
443
444
11.6M
bool ElfFile::Initialize() {
445
11.6M
  if (data_.size() < EI_NIDENT) {
446
4.87k
    return false;
447
4.87k
  }
448
449
11.6M
  unsigned char ident[EI_NIDENT];
450
11.6M
  memcpy(ident, data_.data(), EI_NIDENT);
451
452
11.6M
  if (memcmp(ident, "\177ELF", 4) != 0) {
453
    // Not an ELF file.
454
493k
    return false;
455
493k
  }
456
457
11.1M
  switch (ident[EI_CLASS]) {
458
3.48M
    case ELFCLASS32:
459
3.48M
      is_64bit_ = false;
460
3.48M
      break;
461
7.62M
    case ELFCLASS64:
462
7.62M
      is_64bit_ = true;
463
7.62M
      break;
464
138
    default:
465
138
      THROWF("unexpected ELF class: $0", ident[EI_CLASS]);
466
11.1M
  }
467
468
11.1M
  switch (ident[EI_DATA]) {
469
11.0M
    case ELFDATA2LSB:
470
11.0M
      is_native_endian_ = GetMachineEndian() == Endian::kLittle;
471
11.0M
      break;
472
43.7k
    case ELFDATA2MSB:
473
43.7k
      is_native_endian_ = GetMachineEndian() == Endian::kBig;
474
43.7k
      break;
475
234
    default:
476
234
      THROWF("unexpected ELF data: $0", ident[EI_DATA]);
477
11.1M
  }
478
479
11.1M
  absl::string_view range;
480
11.1M
  ReadStruct<Elf32_Ehdr>(entire_file(), 0, EhdrMunger(), &range, &header_);
481
482
11.1M
  Section section0;
483
11.1M
  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
11.1M
  if (header_.e_shoff > 0 &&
489
11.1M
      data_.size() > (header_.e_shoff + header_.e_shentsize)) {
490
10.9M
    section_count_ = 1;
491
10.9M
    ReadSection(0, &section0);
492
10.9M
    has_section0 = true;
493
10.9M
  }
494
495
11.1M
  section_count_ = header_.e_shnum;
496
11.1M
  section_string_index_ = header_.e_shstrndx;
497
498
11.1M
  if (section_count_ == 0 && has_section0) {
499
109k
    section_count_ = section0.header().sh_size;
500
109k
  }
501
502
11.1M
  if (section_string_index_ == SHN_XINDEX && has_section0) {
503
4.69k
    section_string_index_ = section0.header().sh_link;
504
4.69k
  }
505
506
11.1M
  header_region_ = GetRegion(0, header_.e_ehsize);
507
11.1M
  section_headers_ = GetRegion(header_.e_shoff,
508
11.1M
                               CheckedMul(header_.e_shentsize, section_count_));
509
11.1M
  segment_headers_ = GetRegion(
510
11.1M
      header_.e_phoff, CheckedMul(header_.e_phentsize, header_.e_phnum));
511
512
11.1M
  if (section_count_ > 0) {
513
10.8M
    ReadSection(section_string_index_, &section_name_table_);
514
10.8M
    if (section_name_table_.header().sh_type != SHT_STRTAB) {
515
1.59k
      THROW("section string index pointed to non-strtab");
516
1.59k
    }
517
10.8M
  }
518
519
11.1M
  return true;
520
11.1M
}
521
522
554M
void ElfFile::ReadSegment(Elf64_Word index, Segment* segment) const {
523
554M
  if (index >= header_.e_phnum) {
524
0
    THROWF("segment $0 doesn't exist, only $1 segments", index,
525
0
           header_.e_phnum);
526
0
  }
527
528
554M
  Elf64_Phdr* header = &segment->header_;
529
554M
  ReadStruct<Elf32_Phdr>(
530
554M
      entire_file(),
531
554M
      CheckedAdd(header_.e_phoff, CheckedMul(header_.e_phentsize, index)),
532
554M
      PhdrMunger(), &segment->range_, header);
533
554M
  segment->contents_ = GetRegion(header->p_offset, header->p_filesz);
534
554M
}
535
536
155M
void ElfFile::ReadSection(Elf64_Word index, Section* section) const {
537
155M
  if (index >= section_count_) {
538
2.88k
    THROWF("tried to read section $0, but there are only $1", index,
539
2.88k
           section_count_);
540
2.88k
  }
541
542
155M
  Elf64_Shdr* header = &section->header_;
543
155M
  ReadStruct<Elf32_Shdr>(
544
155M
      entire_file(),
545
155M
      CheckedAdd(header_.e_shoff, CheckedMul(header_.e_shentsize, index)),
546
155M
      ShdrMunger(), &section->range_, header);
547
548
155M
  if (header->sh_type == SHT_NOBITS) {
549
1.68M
    section->contents_ = string_view();
550
154M
  } else {
551
154M
    section->contents_ = GetRegion(header->sh_offset, header->sh_size);
552
154M
  }
553
554
155M
  section->elf_ = this;
555
155M
}
556
557
0
bool ElfFile::FindSectionByName(absl::string_view name, Section* section) const {
558
0
  for (Elf64_Word i = 0; i < section_count_; i++) {
559
0
    ReadSection(i, section);
560
0
    if (section->GetName() == name) {
561
0
      return true;
562
0
    }
563
0
  }
564
0
  return false;
565
0
}
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)
580
      : magic_(StrictSubstr(data, 0, kMagicSize)),
581
10.2M
        contents_(data.substr(std::min<size_t>(data.size(), kMagicSize))) {}
582
583
8.98M
  bool IsOpen() const { return magic() == string_view(kMagic); }
584
585
9.13M
  string_view magic() const { return magic_; }
586
147k
  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;
596
    string_view header;
597
    string_view contents;
598
  };
599
600
  class MemberReader {
601
   public:
602
147k
    MemberReader(const ArFile& ar) : remaining_(ar.contents()) {}
603
    bool ReadMember(MemberFile* file);
604
0
    bool IsEof() const { return remaining_.size() == 0; }
605
606
   private:
607
1.34M
    string_view Consume(size_t n) {
608
1.34M
      n = (n % 2 == 0 ? n : n + 1);
609
1.34M
      if (remaining_.size() < n) {
610
666
        THROW("premature end of file");
611
666
      }
612
1.34M
      string_view ret = remaining_.substr(0, n);
613
1.34M
      remaining_.remove_prefix(n);
614
1.34M
      return ret;
615
1.34M
    }
616
617
    string_view long_filenames_;
618
    string_view remaining_;
619
  };
620
621
 private:
622
  const string_view magic_;
623
  const string_view contents_;
624
625
  static constexpr const char* kMagic = "!<arch>\n";
626
  static constexpr int kMagicSize = 8;
627
};
628
629
808k
bool ArFile::MemberReader::ReadMember(MemberFile* file) {
630
808k
  struct Header {
631
808k
    char file_id[16];
632
808k
    char modified_timestamp[12];
633
808k
    char owner_id[6];
634
808k
    char group_id[6];
635
808k
    char mode[8];
636
808k
    char size[10];
637
808k
    char end[2];
638
808k
  };
639
640
808k
  if (remaining_.size() == 0) {
641
130k
    return false;
642
678k
  } else if (remaining_.size() < sizeof(Header)) {
643
750
    THROW("Premature EOF in AR data");
644
750
  }
645
646
677k
  const Header* header = reinterpret_cast<const Header*>(remaining_.data());
647
677k
  file->header = Consume(sizeof(Header));
648
649
677k
  string_view file_id(&header->file_id[0], sizeof(header->file_id));
650
677k
  string_view size_str(&header->size[0], sizeof(header->size));
651
677k
  file->size = StringViewToSize(size_str);
652
677k
  file->contents = Consume(file->size);
653
677k
  file->file_type = MemberFile::kNormal;
654
655
677k
  if (file_id[0] == '/') {
656
    // Special filename, internal to the format.
657
395k
    if (file_id[1] == ' ') {
658
142k
      file->file_type = MemberFile::kSymbolTable;
659
252k
    } else if (file_id[1] == '/') {
660
137k
      file->file_type = MemberFile::kLongFilenameTable;
661
137k
      long_filenames_ = file->contents;
662
137k
    } else if (isdigit(file_id[1])) {
663
115k
      size_t offset = StringViewToSize(file_id.substr(1));
664
115k
      size_t end = long_filenames_.find('/', offset);
665
666
115k
      if (end == std::string::npos) {
667
264
        THROW("Unterminated long filename");
668
264
      }
669
670
115k
      file->filename = long_filenames_.substr(offset, end - offset);
671
115k
    } else {
672
138
      THROW("Unexpected special filename in AR archive");
673
138
    }
674
395k
  } else {
675
    // Normal filename, slash-terminated.
676
282k
    size_t slash = file_id.find('/');
677
678
282k
    if (slash == std::string::npos) {
679
234
      THROW("BSD-style AR not yet implemented");
680
234
    }
681
682
282k
    file->filename = file_id.substr(0, slash);
683
282k
  }
684
685
676k
  return true;
686
677k
}
687
688
void MaybeAddFileRange(const char* analyzer, RangeSink* sink, string_view label,
689
1.13M
                       string_view range) {
690
1.13M
  if (sink) {
691
1.09M
    sink->AddFileRange(analyzer, label, range);
692
1.09M
  }
693
1.13M
}
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
5.29M
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
5.29M
  ArFile ar_file(file.data());
700
5.29M
  uint64_t index_base = 0;
701
702
5.29M
  if (ar_file.IsOpen()) {
703
147k
    ArFile::MemberFile member;
704
147k
    ArFile::MemberReader reader(ar_file);
705
706
147k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
808k
    while (reader.ReadMember(&member)) {
709
670k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
670k
      switch (member.file_type) {
711
391k
        case ArFile::MemberFile::kNormal: {
712
391k
          ElfFile elf(member.contents);
713
391k
          if (elf.IsOpen()) {
714
352k
            func(elf, member.filename, index_base);
715
352k
            index_base += elf.section_count();
716
352k
          } else {
717
38.6k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
38.6k
                              member.contents);
719
38.6k
          }
720
391k
          break;
721
0
        }
722
142k
        case ArFile::MemberFile::kSymbolTable:
723
142k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
142k
                            member.contents);
725
142k
          break;
726
137k
        case ArFile::MemberFile::kLongFilenameTable:
727
137k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
137k
                            member.contents);
729
137k
          break;
730
670k
      }
731
670k
    }
732
5.14M
  } else {
733
5.14M
    ElfFile elf(file.data());
734
5.14M
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
5.14M
    func(elf, file.filename(), index_base);
739
5.14M
  }
740
5.29M
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::DoReadELFSegments(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSegmentsBy)::$_4>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::DoReadELFSegments(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSegmentsBy)::$_4)
Line
Count
Source
698
1.50M
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
1.50M
  ArFile ar_file(file.data());
700
1.50M
  uint64_t index_base = 0;
701
702
1.50M
  if (ar_file.IsOpen()) {
703
29.4k
    ArFile::MemberFile member;
704
29.4k
    ArFile::MemberReader reader(ar_file);
705
706
29.4k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
167k
    while (reader.ReadMember(&member)) {
709
138k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
138k
      switch (member.file_type) {
711
82.1k
        case ArFile::MemberFile::kNormal: {
712
82.1k
          ElfFile elf(member.contents);
713
82.1k
          if (elf.IsOpen()) {
714
74.8k
            func(elf, member.filename, index_base);
715
74.8k
            index_base += elf.section_count();
716
74.8k
          } else {
717
7.27k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
7.27k
                              member.contents);
719
7.27k
          }
720
82.1k
          break;
721
0
        }
722
28.7k
        case ArFile::MemberFile::kSymbolTable:
723
28.7k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
28.7k
                            member.contents);
725
28.7k
          break;
726
27.8k
        case ArFile::MemberFile::kLongFilenameTable:
727
27.8k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
27.8k
                            member.contents);
729
27.8k
          break;
730
138k
      }
731
138k
    }
732
1.47M
  } else {
733
1.47M
    ElfFile elf(file.data());
734
1.47M
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
1.47M
    func(elf, file.filename(), index_base);
739
1.47M
  }
740
1.50M
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::DoReadELFSegments(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSegmentsBy)::$_5>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::DoReadELFSegments(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSegmentsBy)::$_5)
Line
Count
Source
698
1.50M
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
1.50M
  ArFile ar_file(file.data());
700
1.50M
  uint64_t index_base = 0;
701
702
1.50M
  if (ar_file.IsOpen()) {
703
28.5k
    ArFile::MemberFile member;
704
28.5k
    ArFile::MemberReader reader(ar_file);
705
706
28.5k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
163k
    while (reader.ReadMember(&member)) {
709
135k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
135k
      switch (member.file_type) {
711
80.4k
        case ArFile::MemberFile::kNormal: {
712
80.4k
          ElfFile elf(member.contents);
713
80.4k
          if (elf.IsOpen()) {
714
73.3k
            func(elf, member.filename, index_base);
715
73.3k
            index_base += elf.section_count();
716
73.3k
          } else {
717
7.06k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
7.06k
                              member.contents);
719
7.06k
          }
720
80.4k
          break;
721
0
        }
722
27.7k
        case ArFile::MemberFile::kSymbolTable:
723
27.7k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
27.7k
                            member.contents);
725
27.7k
          break;
726
26.9k
        case ArFile::MemberFile::kLongFilenameTable:
727
26.9k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
26.9k
                            member.contents);
729
26.9k
          break;
730
135k
      }
731
135k
    }
732
1.47M
  } else {
733
1.47M
    ElfFile elf(file.data());
734
1.47M
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
1.47M
    func(elf, file.filename(), index_base);
739
1.47M
  }
740
1.50M
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::DoReadELFSections(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSectionsBy)::$_3>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::DoReadELFSections(bloaty::RangeSink*, bloaty::(anonymous namespace)::ReportSectionsBy)::$_3)
Line
Count
Source
698
647k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
647k
  ArFile ar_file(file.data());
700
647k
  uint64_t index_base = 0;
701
702
647k
  if (ar_file.IsOpen()) {
703
49.7k
    ArFile::MemberFile member;
704
49.7k
    ArFile::MemberReader reader(ar_file);
705
706
49.7k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
254k
    while (reader.ReadMember(&member)) {
709
212k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
212k
      switch (member.file_type) {
711
119k
        case ArFile::MemberFile::kNormal: {
712
119k
          ElfFile elf(member.contents);
713
119k
          if (elf.IsOpen()) {
714
105k
            func(elf, member.filename, index_base);
715
105k
            index_base += elf.section_count();
716
105k
          } else {
717
14.5k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
14.5k
                              member.contents);
719
14.5k
          }
720
119k
          break;
721
0
        }
722
47.3k
        case ArFile::MemberFile::kSymbolTable:
723
47.3k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
47.3k
                            member.contents);
725
47.3k
          break;
726
45.2k
        case ArFile::MemberFile::kLongFilenameTable:
727
45.2k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
45.2k
                            member.contents);
729
45.2k
          break;
730
212k
      }
731
212k
    }
732
597k
  } else {
733
597k
    ElfFile elf(file.data());
734
597k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
597k
    func(elf, file.filename(), index_base);
739
597k
  }
740
647k
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::ReadElfArchMode(bloaty::InputFile const&, cs_arch*, cs_mode*)::$_0>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::ReadElfArchMode(bloaty::InputFile const&, cs_arch*, cs_mode*)::$_0)
Line
Count
Source
698
331k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
331k
  ArFile ar_file(file.data());
700
331k
  uint64_t index_base = 0;
701
702
331k
  if (ar_file.IsOpen()) {
703
5.29k
    ArFile::MemberFile member;
704
5.29k
    ArFile::MemberReader reader(ar_file);
705
706
5.29k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
30.3k
    while (reader.ReadMember(&member)) {
709
25.0k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
25.0k
      switch (member.file_type) {
711
14.9k
        case ArFile::MemberFile::kNormal: {
712
14.9k
          ElfFile elf(member.contents);
713
14.9k
          if (elf.IsOpen()) {
714
13.6k
            func(elf, member.filename, index_base);
715
13.6k
            index_base += elf.section_count();
716
13.6k
          } else {
717
1.30k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
1.30k
                              member.contents);
719
1.30k
          }
720
14.9k
          break;
721
0
        }
722
5.14k
        case ArFile::MemberFile::kSymbolTable:
723
5.14k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
5.14k
                            member.contents);
725
5.14k
          break;
726
5.00k
        case ArFile::MemberFile::kLongFilenameTable:
727
5.00k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
5.00k
                            member.contents);
729
5.00k
          break;
730
25.0k
      }
731
25.0k
    }
732
325k
  } else {
733
325k
    ElfFile elf(file.data());
734
325k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
325k
    func(elf, file.filename(), index_base);
739
325k
  }
740
331k
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::ReadELFSymbols(bloaty::InputFile const&, bloaty::RangeSink*, std::__1::map<std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::pair<unsigned long, unsigned long>, std::__1::less<std::__1::basic_string_view<char, std::__1::char_traits<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string_view<char, std::__1::char_traits<char> > const, std::__1::pair<unsigned long, unsigned long> > > >*, bool)::$_1>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::ReadELFSymbols(bloaty::InputFile const&, bloaty::RangeSink*, std::__1::map<std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::pair<unsigned long, unsigned long>, std::__1::less<std::__1::basic_string_view<char, std::__1::char_traits<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string_view<char, std::__1::char_traits<char> > const, std::__1::pair<unsigned long, unsigned long> > > >*, bool)::$_1)
Line
Count
Source
698
331k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
331k
  ArFile ar_file(file.data());
700
331k
  uint64_t index_base = 0;
701
702
331k
  if (ar_file.IsOpen()) {
703
5.29k
    ArFile::MemberFile member;
704
5.29k
    ArFile::MemberReader reader(ar_file);
705
706
5.29k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
29.1k
    while (reader.ReadMember(&member)) {
709
24.5k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
24.5k
      switch (member.file_type) {
711
14.4k
        case ArFile::MemberFile::kNormal: {
712
14.4k
          ElfFile elf(member.contents);
713
14.4k
          if (elf.IsOpen()) {
714
13.2k
            func(elf, member.filename, index_base);
715
13.2k
            index_base += elf.section_count();
716
13.2k
          } else {
717
1.22k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
1.22k
                              member.contents);
719
1.22k
          }
720
14.4k
          break;
721
0
        }
722
5.14k
        case ArFile::MemberFile::kSymbolTable:
723
5.14k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
5.14k
                            member.contents);
725
5.14k
          break;
726
4.99k
        case ArFile::MemberFile::kLongFilenameTable:
727
4.99k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
4.99k
                            member.contents);
729
4.99k
          break;
730
24.5k
      }
731
24.5k
    }
732
325k
  } else {
733
325k
    ElfFile elf(file.data());
734
325k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
325k
    func(elf, file.filename(), index_base);
739
325k
  }
740
331k
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::ReadELFTables(bloaty::InputFile const&, bloaty::RangeSink*)::$_2>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::ReadELFTables(bloaty::InputFile const&, bloaty::RangeSink*)::$_2)
Line
Count
Source
698
143k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
143k
  ArFile ar_file(file.data());
700
143k
  uint64_t index_base = 0;
701
702
143k
  if (ar_file.IsOpen()) {
703
2.30k
    ArFile::MemberFile member;
704
2.30k
    ArFile::MemberReader reader(ar_file);
705
706
2.30k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
11.3k
    while (reader.ReadMember(&member)) {
709
9.79k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
9.79k
      switch (member.file_type) {
711
5.39k
        case ArFile::MemberFile::kNormal: {
712
5.39k
          ElfFile elf(member.contents);
713
5.39k
          if (elf.IsOpen()) {
714
4.90k
            func(elf, member.filename, index_base);
715
4.90k
            index_base += elf.section_count();
716
4.90k
          } else {
717
490
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
490
                              member.contents);
719
490
          }
720
5.39k
          break;
721
0
        }
722
2.22k
        case ArFile::MemberFile::kSymbolTable:
723
2.22k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
2.22k
                            member.contents);
725
2.22k
          break;
726
2.16k
        case ArFile::MemberFile::kLongFilenameTable:
727
2.16k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
2.16k
                            member.contents);
729
2.16k
          break;
730
9.79k
      }
731
9.79k
    }
732
140k
  } else {
733
140k
    ElfFile elf(file.data());
734
140k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
140k
    func(elf, file.filename(), index_base);
739
140k
  }
740
143k
}
elf.cc:void bloaty::(anonymous namespace)::ForEachElf<bloaty::(anonymous namespace)::AddCatchAll(bloaty::RangeSink*)::$_6>(bloaty::InputFile const&, bloaty::RangeSink*, bloaty::(anonymous namespace)::AddCatchAll(bloaty::RangeSink*)::$_6)
Line
Count
Source
698
832k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
832k
  ArFile ar_file(file.data());
700
832k
  uint64_t index_base = 0;
701
702
832k
  if (ar_file.IsOpen()) {
703
26.4k
    ArFile::MemberFile member;
704
26.4k
    ArFile::MemberReader reader(ar_file);
705
706
26.4k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
151k
    while (reader.ReadMember(&member)) {
709
125k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
125k
      switch (member.file_type) {
711
74.5k
        case ArFile::MemberFile::kNormal: {
712
74.5k
          ElfFile elf(member.contents);
713
74.5k
          if (elf.IsOpen()) {
714
67.8k
            func(elf, member.filename, index_base);
715
67.8k
            index_base += elf.section_count();
716
67.8k
          } else {
717
6.73k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
6.73k
                              member.contents);
719
6.73k
          }
720
74.5k
          break;
721
0
        }
722
25.7k
        case ArFile::MemberFile::kSymbolTable:
723
25.7k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
25.7k
                            member.contents);
725
25.7k
          break;
726
25.0k
        case ArFile::MemberFile::kLongFilenameTable:
727
25.0k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
25.0k
                            member.contents);
729
25.0k
          break;
730
125k
      }
731
125k
    }
732
806k
  } else {
733
806k
    ElfFile elf(file.data());
734
806k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
806k
    func(elf, file.filename(), index_base);
739
806k
  }
740
832k
}
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
114M
static uint64_t ToVMAddr(uint64_t addr, uint64_t ndx, bool is_object) {
748
114M
  if (is_object) {
749
35.5M
    if (ndx >= 1 << 24) {
750
49
      THROW("ndx overflow: too many sections");
751
49
    }
752
35.5M
    if (addr >= ((uint64_t)1) << 40) {
753
872
      THROW("address overflow: section too big");
754
872
    }
755
35.5M
    return (ndx << 40) | addr;
756
79.1M
  } else {
757
79.1M
    return addr;
758
79.1M
  }
759
114M
}
760
761
3.39M
static bool IsArchiveFile(string_view data) {
762
3.39M
  ArFile ar(data);
763
3.39M
  return ar.IsOpen();
764
3.39M
}
765
766
3.39M
static bool IsObjectFile(string_view data) {
767
3.39M
  ElfFile elf(data);
768
3.39M
  return IsArchiveFile(data) || (elf.IsOpen() && elf.header().e_type == ET_REL);
769
3.39M
}
770
771
210k
static void CheckNotObject(const char* source, RangeSink* sink) {
772
210k
  if (IsObjectFile(sink->input_file().data())) {
773
48.9k
    THROWF(
774
48.9k
        "can't use data source '$0' on object files (only binaries and shared "
775
48.9k
        "libraries)",
776
48.9k
        source);
777
48.9k
  }
778
210k
}
779
780
static bool ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
781
339k
                                 cs_mode* mode) {
782
339k
  switch (e_machine) {
783
89.0k
    case EM_386:
784
89.0k
      *arch = CS_ARCH_X86;
785
89.0k
      *mode = CS_MODE_32;
786
89.0k
      return true;
787
202k
    case EM_X86_64:
788
202k
      *arch = CS_ARCH_X86;
789
202k
      *mode = CS_MODE_64;
790
202k
      return true;
791
792
    // These aren't tested, but we include them on the off-chance
793
    // that it will work.
794
431
    case EM_ARM:
795
431
      *arch = CS_ARCH_ARM;
796
431
      *mode = CS_MODE_LITTLE_ENDIAN;
797
431
      return true;
798
210
    case EM_AARCH64:
799
210
      *arch = CS_ARCH_ARM64;
800
210
      *mode = CS_MODE_ARM;
801
210
      return true;
802
799
    case EM_MIPS:
803
799
      *arch = CS_ARCH_MIPS;
804
799
      return true;
805
290
    case EM_PPC:
806
290
      *arch = CS_ARCH_PPC;
807
290
      *mode = CS_MODE_32;
808
290
      return true;
809
365
    case EM_PPC64:
810
365
      *arch = CS_ARCH_PPC;
811
365
      *mode = CS_MODE_64;
812
365
      return true;
813
1.72k
    case EM_SPARC:
814
1.72k
      *arch = CS_ARCH_SPARC;
815
1.72k
      *mode = CS_MODE_BIG_ENDIAN;
816
1.72k
      return true;
817
578
    case EM_SPARCV9:
818
578
      *arch = CS_ARCH_SPARC;
819
578
      *mode = CS_MODE_V9;
820
578
      return true;
821
822
43.5k
    default:
823
43.5k
      if (verbose_level > 1) {
824
0
        printf(
825
0
            "Unable to map to capstone target, disassembly will be "
826
0
            "unavailable");
827
0
      }
828
43.5k
      return false;
829
339k
  }
830
339k
}
831
832
331k
static bool ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
833
331k
  bool capstone_available = true;
834
331k
  ForEachElf(file, nullptr,
835
331k
             [&capstone_available, arch, mode](const ElfFile& elf,
836
331k
                                               string_view /*filename*/,
837
339k
                                               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
339k
               capstone_available &=
841
339k
                   ElfMachineToCapstone(elf.header().e_machine, arch, mode);
842
339k
             });
843
331k
  return capstone_available;
844
331k
}
845
846
static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
847
331k
                           SymbolTable* table, bool disassemble) {
848
331k
  bool is_object = IsObjectFile(file.data());
849
331k
  DisassemblyInfo info;
850
331k
  DisassemblyInfo* infop = &info;
851
331k
  bool capstone_available = ReadElfArchMode(file, &info.arch, &info.mode);
852
853
331k
  ForEachElf(
854
331k
      file, sink,
855
339k
      [=](const ElfFile& elf, string_view /*filename*/, uint64_t index_base) {
856
22.0M
        for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
857
21.7M
          ElfFile::Section section;
858
21.7M
          elf.ReadSection(i, &section);
859
860
21.7M
          if (section.header().sh_type != SHT_SYMTAB) {
861
21.3M
            continue;
862
21.3M
          }
863
864
335k
          Elf64_Word symbol_count = section.GetEntryCount();
865
866
          // Find the corresponding section where the strings for the symbol
867
          // table can be found.
868
335k
          ElfFile::Section strtab_section;
869
335k
          elf.ReadSection(section.header().sh_link, &strtab_section);
870
335k
          if (strtab_section.header().sh_type != SHT_STRTAB) {
871
353
            THROW("symtab section pointed to non-strtab section");
872
353
          }
873
874
32.6M
          for (Elf64_Word i = 1; i < symbol_count; i++) {
875
32.3M
            Elf64_Sym sym;
876
877
32.3M
            section.ReadSymbol(i, &sym, nullptr);
878
879
32.3M
            if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION) {
880
6.84M
              continue;
881
6.84M
            }
882
883
25.4M
            if (sym.st_shndx == STN_UNDEF) {
884
4.01M
              continue;
885
4.01M
            }
886
887
21.4M
            if (sym.st_size == 0) {
888
              // Maybe try to refine?  See ReadELFSectionsRefineSymbols below.
889
5.51M
              continue;
890
5.51M
            }
891
892
15.9M
            string_view name = strtab_section.ReadString(sym.st_name);
893
15.9M
            uint64_t full_addr =
894
15.9M
                ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
895
15.9M
            if (sink && !(capstone_available && disassemble)) {
896
10.6M
              sink->AddVMRangeAllowAlias(
897
10.6M
                  "elf_symbols", full_addr, sym.st_size,
898
10.6M
                  ItaniumDemangle(name, sink->data_source()));
899
10.6M
            }
900
15.9M
            if (table) {
901
5.04M
              table->insert(
902
5.04M
                  std::make_pair(name, std::make_pair(full_addr, sym.st_size)));
903
5.04M
            }
904
15.9M
            if (capstone_available && disassemble &&
905
15.9M
                ELF64_ST_TYPE(sym.st_info) == STT_FUNC) {
906
989k
              if (verbose_level > 1) {
907
0
                printf("Disassembling function: %s\n", name.data());
908
0
              }
909
              // TODO(brandonvu) Continue if VM pointer cannot be translated. Issue #315
910
989k
              uint64_t unused;
911
989k
              if (!sink->Translator()->vm_map.Translate(full_addr, &unused)) {
912
24.6k
                WARN("Can't translate VM pointer ($0) to file", full_addr);
913
24.6k
                continue;
914
24.6k
              }
915
964k
              infop->text = sink->TranslateVMToFile(full_addr).substr(0, sym.st_size);
916
964k
              infop->start_address = full_addr;
917
964k
              DisassembleFindReferences(*infop, sink);
918
964k
            }
919
15.9M
          }
920
335k
        }
921
339k
      });
922
331k
}
923
924
static void ReadELFSymbolTableEntries(const ElfFile& elf,
925
                                      const ElfFile::Section& section,
926
                                      uint64_t index_base, bool is_object,
927
172k
                                      RangeSink* sink) {
928
172k
  Elf64_Word symbol_count = section.GetEntryCount();
929
930
  // Find the corresponding section where the strings for the symbol
931
  // table can be found.
932
172k
  ElfFile::Section strtab_section;
933
172k
  elf.ReadSection(section.header().sh_link, &strtab_section);
934
172k
  if (strtab_section.header().sh_type != SHT_STRTAB) {
935
2.66k
    THROW("symtab section pointed to non-strtab section");
936
2.66k
  }
937
938
8.34M
  for (Elf64_Word i = 1; i < symbol_count; i++) {
939
8.17M
    Elf64_Sym sym;
940
8.17M
    string_view sym_range;
941
8.17M
    section.ReadSymbol(i, &sym, &sym_range);
942
943
8.17M
    if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION ||
944
8.17M
        sym.st_shndx == STN_UNDEF ||
945
8.17M
        sym.st_name == SHN_UNDEF) {
946
3.32M
      continue;
947
3.32M
    }
948
949
4.84M
    string_view name = strtab_section.ReadString(sym.st_name);
950
4.84M
    uint64_t full_addr =
951
4.84M
        ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
952
    // Capture the trailing NULL.
953
4.84M
    name = string_view(name.data(), name.size() + 1);
954
4.84M
    sink->AddFileRangeForVMAddr("elf_symtab_name", full_addr, name);
955
4.84M
    sink->AddFileRangeForVMAddr("elf_symtab_sym", full_addr, sym_range);
956
4.84M
  }
957
170k
}
958
959
static void ReadELFRelaEntries(const ElfFile::Section& section,
960
                               uint64_t index_base, bool is_object,
961
111k
                               RangeSink* sink) {
962
111k
  Elf64_Word rela_count = section.GetEntryCount();
963
111k
  Elf64_Word sh_info = section.header().sh_info;
964
46.3M
  for (Elf64_Word i = 1; i < rela_count; i++) {
965
46.2M
    Elf64_Rela rela;
966
46.2M
    string_view rela_range;
967
46.2M
    section.ReadRelocationWithAddend(i, &rela, &rela_range);
968
46.2M
    uint64_t full_addr =
969
46.2M
        ToVMAddr(rela.r_offset, index_base + sh_info, is_object);
970
46.2M
    sink->AddFileRangeForVMAddr("elf_rela", full_addr, rela_range);
971
46.2M
  }
972
111k
}
973
974
// Adds file ranges for the symbol tables and string tables *themselves* (ie.
975
// the space that the symtab/strtab take up in the file).  This will cover
976
//   .symtab
977
//   .strtab
978
//   .dynsym
979
//   .dynstr
980
145k
static void ReadELFTables(const InputFile& file, RangeSink* sink) {
981
145k
  bool is_object = IsObjectFile(file.data());
982
983
  // Disassemble first, because sometimes other tables will refer to things we
984
  // discovered through disassembling.
985
145k
  ReadELFSymbols(file, sink, nullptr, true);
986
987
  // Now scan other tables.
988
145k
  ForEachElf(file, sink,
989
145k
             [sink, is_object](const ElfFile& elf, string_view /*filename*/,
990
145k
                               uint32_t index_base) {
991
7.62M
               for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
992
7.51M
                 ElfFile::Section section;
993
7.51M
                 elf.ReadSection(i, &section);
994
995
7.51M
                 switch (section.header().sh_type) {
996
62.2k
                   case SHT_SYMTAB:
997
172k
                   case SHT_DYNSYM:
998
172k
                     ReadELFSymbolTableEntries(elf, section, index_base,
999
172k
                                               is_object, sink);
1000
172k
                     break;
1001
111k
                   case SHT_RELA:
1002
111k
                     ReadELFRelaEntries(section, index_base, is_object, sink);
1003
111k
                     break;
1004
7.51M
                 }
1005
1006
                 // We are looking by section name, which is a little different
1007
                 // than what the loader actually does (which is find
1008
                 // eh_frame_hdr from the program headers and then find eh_frame
1009
                 // fde entries from there). But these section names should be
1010
                 // standard enough that this approach works also.
1011
7.48M
                 if (section.GetName() == ".eh_frame") {
1012
79.9k
                   ReadEhFrame(section.contents(), sink);
1013
7.40M
                 } else if (section.GetName() == ".eh_frame_hdr") {
1014
91.2k
                   ReadEhFrameHdr(section.contents(), sink);
1015
91.2k
                 }
1016
7.48M
               }
1017
145k
             });
1018
145k
}
1019
1020
enum ReportSectionsBy {
1021
  kReportBySectionName,
1022
  kReportByEscapedSectionName,
1023
  kReportByFlags,
1024
  kReportByArchiveMember,
1025
};
1026
1027
647k
static void DoReadELFSections(RangeSink* sink, enum ReportSectionsBy report_by) {
1028
647k
  bool is_object = IsObjectFile(sink->input_file().data());
1029
647k
  ForEachElf(
1030
647k
      sink->input_file(), sink,
1031
702k
      [=](const ElfFile& elf, string_view filename, uint32_t index_base) {
1032
702k
        std::string name_from_flags;
1033
48.4M
        for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1034
47.8M
          ElfFile::Section section;
1035
47.8M
          elf.ReadSection(i, &section);
1036
47.8M
          string_view name = section.GetName();
1037
1038
47.8M
          if (name.size() == 0) {
1039
152k
            return;
1040
152k
          }
1041
1042
47.7M
          const auto& header = section.header();
1043
47.7M
          auto addr = header.sh_addr;
1044
47.7M
          auto size = header.sh_size;
1045
47.7M
          auto filesize = (header.sh_type == SHT_NOBITS) ? 0 : size;
1046
47.7M
          auto vmsize = (header.sh_flags & SHF_ALLOC) ? size : 0;
1047
1048
47.7M
          string_view contents = StrictSubstr(section.contents(), 0, filesize);
1049
1050
47.7M
          uint64_t full_addr = ToVMAddr(addr, index_base + i, is_object);
1051
1052
47.7M
          if (report_by == kReportByFlags) {
1053
20.8M
            name_from_flags = std::string(name);
1054
1055
20.8M
            name_from_flags = "Section [";
1056
1057
20.8M
            if (header.sh_flags & SHF_ALLOC) {
1058
16.6M
              name_from_flags += 'A';
1059
16.6M
            }
1060
1061
20.8M
            if (header.sh_flags & SHF_WRITE) {
1062
1.35M
              name_from_flags += 'W';
1063
1.35M
            }
1064
1065
20.8M
            if (header.sh_flags & SHF_EXECINSTR) {
1066
4.33M
              name_from_flags += 'X';
1067
4.33M
            }
1068
1069
20.8M
            name_from_flags += ']';
1070
20.8M
            sink->AddRange("elf_section", name_from_flags, full_addr, vmsize,
1071
20.8M
                           contents);
1072
26.8M
          } else if (report_by == kReportBySectionName) {
1073
5.48M
            sink->AddRange("elf_section", name, full_addr, vmsize, contents);
1074
21.3M
          } else if (report_by == kReportByEscapedSectionName) {
1075
15.8M
            sink->AddRange("elf_section",
1076
15.8M
                           std::string("[section ") + std::string(name) + "]",
1077
15.8M
                           full_addr, vmsize, contents);
1078
15.8M
          } else if (report_by == kReportByArchiveMember) {
1079
5.48M
            sink->AddRange("elf_section", filename, full_addr, vmsize,
1080
5.48M
                           contents);
1081
5.48M
          }
1082
47.7M
        }
1083
1084
550k
        if (report_by == kReportByArchiveMember) {
1085
          // Cover unmapped parts of the file.
1086
66.8k
          sink->AddFileRange("unmapped_armember", filename, elf.entire_file());
1087
66.8k
        }
1088
550k
      });
1089
647k
}
1090
1091
enum ReportSegmentsBy {
1092
  kReportBySegmentName,
1093
  kReportByEscapedSegmentName,
1094
};
1095
1096
std::string GetSegmentName(const ElfFile::Segment& segment, Elf64_Xword i,
1097
277M
                           ReportSegmentsBy report_by) {
1098
277M
  const auto& header = segment.header();
1099
1100
  // Include the segment index in the label, to support embedded.
1101
  //
1102
  // Including the index in the segment label differentiates
1103
  // segments with the same access control (e.g. RWX vs RW). In
1104
  // ELF files built for embedded microcontroller projects, a
1105
  // segment is used for each distinct type of memory. In simple
1106
  // cases, there is a segment for the flash (which will store
1107
  // code and read-only data) and a segment for RAM (which
1108
  // usually stores globals, stacks, and maybe a heap). In more
1109
  // involved projects, there may be special segments for faster
1110
  // RAM (e.g. core coupled RAM or CCRAM), or there may even be
1111
  // memory overlays to support manual paging of code from flash
1112
  // (which may be slow) into RAM.
1113
277M
  std::string name(absl::StrCat("LOAD #", i, " ["));
1114
1115
277M
  if (header.p_flags & PF_R) {
1116
71.8M
    name += 'R';
1117
71.8M
  }
1118
1119
277M
  if (header.p_flags & PF_W) {
1120
101M
    name += 'W';
1121
101M
  }
1122
1123
277M
  if (header.p_flags & PF_X) {
1124
71.8M
    name += 'X';
1125
71.8M
  }
1126
1127
277M
  name += ']';
1128
1129
277M
  if (report_by == kReportByEscapedSegmentName) {
1130
181M
    return absl::StrCat("[", name, "]");
1131
181M
  } else {
1132
96.0M
    return name;
1133
96.0M
  }
1134
277M
}
1135
1136
1.50M
static void DoReadELFSegments(RangeSink* sink, ReportSegmentsBy report_by) {
1137
1.50M
  ForEachElf(sink->input_file(), sink,
1138
1.50M
             [=](const ElfFile& elf, string_view /*filename*/,
1139
1.55M
                 uint32_t /*index_base*/) {
1140
278M
               for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1141
277M
                 ElfFile::Segment segment;
1142
277M
                 elf.ReadSegment(i, &segment);
1143
277M
                 std::string name = GetSegmentName(segment, i, report_by);
1144
1145
277M
                 if (segment.header().p_type != PT_LOAD) {
1146
233M
                   continue;
1147
233M
                 }
1148
1149
43.4M
                 sink->AddRange("elf_segment", name, segment.header().p_vaddr,
1150
43.4M
                                segment.header().p_memsz, segment.contents());
1151
43.4M
               }
1152
1.55M
             });
1153
1154
1.50M
  ForEachElf(sink->input_file(), sink,
1155
1.50M
             [=](const ElfFile& elf, string_view /*filename*/,
1156
1.54M
                 uint32_t /*index_base*/) {
1157
278M
               for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1158
276M
                 ElfFile::Segment segment;
1159
276M
                 elf.ReadSegment(i, &segment);
1160
276M
                 const auto& header = segment.header();
1161
276M
                 if (header.p_type != PT_TLS) continue;
1162
4.79M
                 std::string name = "TLS";
1163
4.79M
                 sink->AddRange("elf_segment", "TLS", header.p_vaddr,
1164
4.79M
                                header.p_memsz, segment.contents());
1165
4.79M
               }
1166
1.54M
             });
1167
1.50M
}
1168
1169
757k
static void ReadELFSegments(RangeSink* sink) {
1170
757k
  if (IsObjectFile(sink->input_file().data())) {
1171
    // Object files don't actually have segments.  But we can cheat a little bit
1172
    // and make up "segments" based on section flags.  This can be really useful
1173
    // when you are compiling with -ffunction-sections and -fdata-sections,
1174
    // because in those cases the actual "sections" report becomes pretty
1175
    // useless (since every function/data has its own section, it's like the
1176
    // "symbols" report except less readable).
1177
188k
    DoReadELFSections(sink, kReportByFlags);
1178
568k
  } else {
1179
568k
    DoReadELFSegments(sink, kReportBySegmentName);
1180
568k
  }
1181
757k
}
1182
1183
// ELF files put debug info directly into the binary, so we call the DWARF
1184
// reader directly on them.  At the moment we don't attempt to make these
1185
// work with object files.
1186
1187
void ReadDWARFSections(const InputFile &file, dwarf::File *dwarf,
1188
151k
                       RangeSink *sink) {
1189
151k
  ElfFile elf(file.data());
1190
151k
  assert(elf.IsOpen());
1191
0
  dwarf->file = &file;
1192
151k
  dwarf->open = &ReadDWARFSections;
1193
8.88M
  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1194
8.73M
    ElfFile::Section section;
1195
8.73M
    elf.ReadSection(i, &section);
1196
8.73M
    string_view name = section.GetName();
1197
8.73M
    string_view contents = section.contents();
1198
8.73M
    uint64_t uncompressed_size = 0;
1199
1200
8.73M
    if (section.header().sh_flags & SHF_COMPRESSED) {
1201
      // Standard ELF section compression, produced when you link with
1202
      //   --compress-debug-sections=zlib-gabi
1203
786k
      Elf64_Chdr chdr;
1204
786k
      absl::string_view range;
1205
786k
      elf.ReadStruct<Elf32_Chdr>(contents, 0, ChdrMunger(), &range, &chdr);
1206
786k
      if (chdr.ch_type != ELFCOMPRESS_ZLIB) {
1207
        // Unknown compression format.
1208
599k
        continue;
1209
599k
      }
1210
186k
      uncompressed_size = chdr.ch_size;
1211
186k
      contents.remove_prefix(range.size());
1212
186k
    }
1213
1214
8.13M
    if (name.find(".debug_") == 0) {
1215
912k
      name.remove_prefix(string_view(".debug_").size());
1216
7.22M
    } else if (name.find(".zdebug_") == 0) {
1217
      // GNU format compressed debug info, produced when you link with
1218
      //   --compress-debug-sections=zlib-gnu
1219
0
      name.remove_prefix(string_view(".zdebug_").size());
1220
0
      if (ReadBytes(4, &contents) != "ZLIB") {
1221
0
        continue;  // Bad compression header.
1222
0
      }
1223
0
      uncompressed_size = ReadBigEndian<uint64_t>(&contents);
1224
0
    }
1225
1226
8.13M
    static constexpr string_view dwo_str(".dwo");
1227
8.13M
    if (name.size() >= dwo_str.size() &&
1228
8.13M
        name.rfind(".dwo") == name.size() - dwo_str.size()) {
1229
0
      name.remove_suffix(dwo_str.size());
1230
0
    }
1231
1232
8.13M
    if (string_view* member = dwarf->GetFieldByName(name)) {
1233
1.11M
      if (uncompressed_size) {
1234
49.6k
        *member = sink->ZlibDecompress(contents, uncompressed_size);
1235
1.07M
      } else {
1236
1.07M
        *member = section.contents();
1237
1.07M
      }
1238
1.11M
    }
1239
8.13M
  }
1240
151k
}
1241
1242
941k
void AddCatchAll(RangeSink* sink) {
1243
  // The last-line fallback to make sure we cover the entire VM space.
1244
941k
  if (sink->IsBaseMap() || sink->data_source() != DataSource::kSegments) {
1245
836k
    if (!sink->IsBaseMap()) {
1246
204k
      DoReadELFSections(sink, kReportByEscapedSectionName);
1247
204k
    }
1248
836k
    ForEachElf(sink->input_file(), sink,
1249
836k
               [sink](const ElfFile& elf, string_view /*filename*/,
1250
874k
                      uint32_t /*index_base*/) {
1251
874k
                 sink->AddFileRange("elf_catchall", "[ELF Header]",
1252
874k
                                    elf.header_region());
1253
874k
                 sink->AddFileRange("elf_catchall", "[ELF Section Headers]",
1254
874k
                                    elf.section_headers());
1255
874k
                 sink->AddFileRange("elf_catchall", "[ELF Program Headers]",
1256
874k
                                    elf.segment_headers());
1257
874k
               });
1258
836k
  }
1259
941k
  DoReadELFSegments(sink, kReportByEscapedSegmentName);
1260
1261
1262
  // The last-line fallback to make sure we cover the entire file.
1263
941k
  sink->AddFileRange("elf_catchall", "[Unmapped]", sink->input_file().data());
1264
941k
}
1265
1266
class ElfObjectFile : public ObjectFile {
1267
 public:
1268
  ElfObjectFile(std::unique_ptr<InputFile> file)
1269
1.30M
      : ObjectFile(std::move(file)) {}
1270
1271
1.30M
  std::string GetBuildId() const override {
1272
1.30M
    if (IsObjectFile(file_data().data())) {
1273
      // Object files don't have a build ID.
1274
328k
      return std::string();
1275
328k
    }
1276
1277
978k
    ElfFile elf(file_data().data());
1278
978k
    assert(elf.IsOpen());
1279
48.3M
    for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1280
47.6M
      ElfFile::Section section;
1281
47.6M
      elf.ReadSection(i, &section);
1282
47.6M
      if (section.header().sh_type != SHT_NOTE) {
1283
46.7M
        continue;
1284
46.7M
      }
1285
1286
1.60M
      for (ElfFile::NoteIter notes(section); !notes.IsDone(); notes.Next()) {
1287
973k
        if (notes.name() == "GNU" && notes.type() == NT_GNU_BUILD_ID) {
1288
304k
          return std::string(notes.descriptor());
1289
304k
        }
1290
973k
      }
1291
934k
    }
1292
1293
    // No build id section found.
1294
673k
    return std::string();
1295
978k
  }
1296
1297
651k
  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
1298
1.28M
    for (auto sink : sinks) {
1299
1.28M
      if (verbose_level > 1) {
1300
0
        printf("Scanning source %d\n", (int)sink->data_source());
1301
0
      }
1302
1.28M
      switch (sink->data_source()) {
1303
757k
        case DataSource::kSegments:
1304
757k
          ReadELFSegments(sink);
1305
757k
          break;
1306
105k
        case DataSource::kSections:
1307
105k
          DoReadELFSections(sink, kReportBySectionName);
1308
105k
          break;
1309
0
        case DataSource::kRawSymbols:
1310
105k
        case DataSource::kShortSymbols:
1311
105k
        case DataSource::kFullSymbols:
1312
105k
          ReadELFSymbols(debug_file().file_data(), sink, nullptr, false);
1313
105k
          break;
1314
104k
        case DataSource::kArchiveMembers:
1315
104k
          DoReadELFSections(sink, kReportByArchiveMember);
1316
104k
          break;
1317
105k
        case DataSource::kCompileUnits: {
1318
105k
          CheckNotObject("compileunits", sink);
1319
105k
          SymbolTable symtab;
1320
105k
          DualMap symbol_map;
1321
105k
          NameMunger empty_munger;
1322
105k
          RangeSink symbol_sink(&debug_file().file_data(),
1323
105k
                                sink->options(),
1324
105k
                                DataSource::kRawSymbols,
1325
105k
                                &sinks[0]->MapAtIndex(0), nullptr);
1326
105k
          symbol_sink.AddOutput(&symbol_map, &empty_munger);
1327
105k
          ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab,
1328
105k
                         false);
1329
105k
          dwarf::File dwarf;
1330
105k
          ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1331
105k
          ReadDWARFCompileUnits(dwarf, symbol_map, sink);
1332
105k
          break;
1333
105k
        }
1334
104k
        case DataSource::kInlines: {
1335
104k
          CheckNotObject("lineinfo", sink);
1336
104k
          dwarf::File dwarf;
1337
104k
          ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1338
104k
          ReadDWARFInlines(dwarf, sink, true);
1339
104k
          DoReadELFSections(sink, kReportByEscapedSectionName);
1340
104k
          break;
1341
105k
        }
1342
0
        default:
1343
0
          THROW("unknown data source");
1344
1.28M
      }
1345
1346
1.04M
      switch (sink->data_source()) {
1347
737k
        case DataSource::kSegments:
1348
819k
        case DataSource::kSections:
1349
900k
        case DataSource::kArchiveMembers:
1350
900k
          break;
1351
145k
        default:
1352
          // Add these *after* processing all other data sources.
1353
145k
          ReadELFTables(sink->input_file(), sink);
1354
145k
          break;
1355
1.04M
      }
1356
1357
941k
      AddCatchAll(sink);
1358
941k
    }
1359
651k
  }
1360
1361
  bool GetDisassemblyInfo(const absl::string_view symbol,
1362
                          DataSource symbol_source,
1363
0
                          DisassemblyInfo* info) const override {
1364
0
    return DoGetDisassemblyInfo(&symbol, symbol_source, info);
1365
0
  }
1366
1367
  bool DoGetDisassemblyInfo(const absl::string_view* symbol,
1368
                            DataSource symbol_source,
1369
0
                            DisassemblyInfo* info) const {
1370
    // Find the corresponding file range.  This also could be optimized not to
1371
    // build the entire map.
1372
0
    DualMap base_map;
1373
0
    NameMunger empty_munger;
1374
0
    RangeSink base_sink(&file_data(), bloaty::Options(), DataSource::kSegments,
1375
0
                        nullptr, nullptr);
1376
0
    base_sink.AddOutput(&base_map, &empty_munger);
1377
0
    std::vector<RangeSink*> sink_ptrs{&base_sink};
1378
0
    ProcessFile(sink_ptrs);
1379
1380
    // Could optimize this not to build the whole table if necessary.
1381
0
    SymbolTable symbol_table;
1382
0
    RangeSink symbol_sink(&file_data(), bloaty::Options(), symbol_source,
1383
0
                          &base_map, nullptr);
1384
0
    symbol_sink.AddOutput(&info->symbol_map, &empty_munger);
1385
0
    ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table,
1386
0
                   false);
1387
1388
0
    if (symbol) {
1389
0
      auto entry = symbol_table.find(*symbol);
1390
0
      if (entry == symbol_table.end()) {
1391
0
        entry = symbol_table.find(ItaniumDemangle(*symbol, symbol_source));
1392
0
        if (entry == symbol_table.end()) {
1393
0
          return false;
1394
0
        }
1395
0
      }
1396
0
      uint64_t vmaddr = entry->second.first;
1397
0
      uint64_t size = entry->second.second;
1398
1399
      // TODO(haberman); Add PLT entries to symbol map, so call <plt stub> gets
1400
      // symbolized.
1401
1402
0
      uint64_t fileoff;
1403
0
      if (!base_map.vm_map.Translate(vmaddr, &fileoff)) {
1404
0
        THROWF("Couldn't translate VM address for function $0", symbol);
1405
0
      }
1406
1407
0
      info->text = StrictSubstr(file_data().data(), fileoff, size);
1408
0
      info->start_address = vmaddr;
1409
0
    }
1410
1411
0
    return ReadElfArchMode(file_data(), &info->arch, &info->mode);
1412
0
  }
1413
};
1414
1415
}  // namespace
1416
1417
1.54M
std::unique_ptr<ObjectFile> TryOpenELFFile(std::unique_ptr<InputFile>& file) {
1418
1.54M
  ElfFile elf(file->data());
1419
1.54M
  ArFile ar(file->data());
1420
1.54M
  if (elf.IsOpen() || ar.IsOpen()) {
1421
1.30M
    return std::unique_ptr<ObjectFile>(new ElfObjectFile(std::move(file)));
1422
1.30M
  } else {
1423
237k
    return nullptr;
1424
237k
  }
1425
1426
  // A few functions that have been defined but are not yet used.
1427
0
  (void)&ElfFile::FindSectionByName;
1428
0
  (void)&ElfFile::Section::ReadRelocation;
1429
0
}
1430
1431
}  // namespace bloaty