Coverage Report

Created: 2024-08-27 12:11

/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
968M
  T operator()(T val) {
39
968M
    return ByteSwap(val);
40
968M
  }
elf.cc:unsigned short bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned short>(unsigned short)
Line
Count
Source
38
691k
  T operator()(T val) {
39
691k
    return ByteSwap(val);
40
691k
  }
elf.cc:unsigned int bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned int>(unsigned int)
Line
Count
Source
38
879M
  T operator()(T val) {
39
879M
    return ByteSwap(val);
40
879M
  }
elf.cc:unsigned long bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned long>(unsigned long)
Line
Count
Source
38
88.4M
  T operator()(T val) {
39
88.4M
    return ByteSwap(val);
40
88.4M
  }
elf.cc:unsigned char bloaty::(anonymous namespace)::ByteSwapFunc::operator()<unsigned char>(unsigned char)
Line
Count
Source
38
4.60k
  T operator()(T val) {
39
4.60k
    return ByteSwap(val);
40
4.60k
  }
Unexecuted instantiation: elf.cc:long bloaty::(anonymous namespace)::ByteSwapFunc::operator()<long>(long)
elf.cc:int bloaty::(anonymous namespace)::ByteSwapFunc::operator()<int>(int)
Line
Count
Source
38
5.00k
  T operator()(T val) {
39
5.00k
    return ByteSwap(val);
40
5.00k
  }
41
};
42
43
struct NullFunc {
44
  template <class T>
45
228M
  T operator()(T val) { return val; }
elf.cc:unsigned short bloaty::(anonymous namespace)::NullFunc::operator()<unsigned short>(unsigned short)
Line
Count
Source
45
20.5M
  T operator()(T val) { return val; }
elf.cc:unsigned int bloaty::(anonymous namespace)::NullFunc::operator()<unsigned int>(unsigned int)
Line
Count
Source
45
200M
  T operator()(T val) { return val; }
elf.cc:unsigned char bloaty::(anonymous namespace)::NullFunc::operator()<unsigned char>(unsigned char)
Line
Count
Source
45
6.86M
  T operator()(T val) { return val; }
elf.cc:int bloaty::(anonymous namespace)::NullFunc::operator()<int>(int)
Line
Count
Source
45
19.8k
  T operator()(T val) { return val; }
46
};
47
48
357k
size_t StringViewToSize(string_view str) {
49
357k
  size_t ret;
50
357k
  if (!absl::SimpleAtoi(str, &ret)) {
51
2.69k
    THROWF("couldn't convert string '$0' to integer.", str);
52
2.69k
  }
53
354k
  return ret;
54
357k
}
55
56
template <class T>
57
518k
void AdvancePastStruct(string_view* data) {
58
518k
  *data = data->substr(sizeof(T));
59
518k
}
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
6.48M
  ElfFile(string_view data) : data_(data) {
68
6.48M
    ok_ = Initialize();
69
6.48M
  }
70
71
6.39M
  bool IsOpen() { return ok_; }
72
73
  // Regions of the file where different headers live.
74
203M
  string_view entire_file() const { return data_; }
75
439k
  string_view header_region() const { return header_region_; }
76
439k
  string_view section_headers() const { return section_headers_; }
77
439k
  string_view segment_headers() const { return segment_headers_; }
78
79
102M
  const Elf64_Ehdr& header() const { return header_; }
80
87.8M
  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
159M
    const Elf64_Phdr& header() const { return header_; }
87
6.60M
    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
175M
    const Elf64_Shdr& header() const { return header_; }
101
66.3M
    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
495k
    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
495k
        : elf_(&section.elf()), remaining_(section.contents()) {
141
495k
      Next();
142
495k
    }
143
144
828k
    bool IsDone() const { return done_; }
145
454k
    uint32_t type() const { return type_; }
146
516k
    string_view name() const { return name_; }
147
181k
    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
374M
  bool is_64bit() const { return is_64bit_; }
166
256M
  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
242M
                  absl::string_view* range, T64* out) const {
171
242M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
242M
  }
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
5.76M
                  absl::string_view* range, T64* out) const {
171
5.76M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
5.76M
  }
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
98.5M
                  absl::string_view* range, T64* out) const {
171
98.5M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
98.5M
  }
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
518k
                  absl::string_view* range, T64* out) const {
171
518k
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
518k
  }
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
99.2M
                  absl::string_view* range, T64* out) const {
171
99.2M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
99.2M
  }
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
18.1M
                  absl::string_view* range, T64* out) const {
171
18.1M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
18.1M
  }
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
2.32M
                  absl::string_view* range, T64* out) const {
171
2.32M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
2.32M
  }
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
17.7M
                  absl::string_view* range, T64* out) const {
171
17.7M
    StructReader(*this, contents).Read<T32>(offset, munger, range, out);
172
17.7M
  }
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
214M
  string_view GetRegion(uint64_t start, uint64_t n) const {
180
214M
    return StrictSubstr(data_, start, n);
181
214M
  }
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
242M
        : 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
242M
              T64* out) const {
193
242M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
109M
        return Memcpy(offset, range, out);
195
132M
      } else {
196
132M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
132M
      }
198
242M
    }
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
5.76M
              T64* out) const {
193
5.76M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
3.53M
        return Memcpy(offset, range, out);
195
3.53M
      } else {
196
2.22M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
2.22M
      }
198
5.76M
    }
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
98.5M
              T64* out) const {
193
98.5M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
26.4M
        return Memcpy(offset, range, out);
195
72.0M
      } else {
196
72.0M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
72.0M
      }
198
98.5M
    }
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
518k
              T64* out) const {
193
518k
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
321k
        return Memcpy(offset, range, out);
195
321k
      } else {
196
197k
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
197k
      }
198
518k
    }
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
99.2M
              T64* out) const {
193
99.2M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
46.8M
        return Memcpy(offset, range, out);
195
52.3M
      } else {
196
52.3M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
52.3M
      }
198
99.2M
    }
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
18.1M
              T64* out) const {
193
18.1M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
14.7M
        return Memcpy(offset, range, out);
195
14.7M
      } else {
196
3.43M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
3.43M
      }
198
18.1M
    }
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
2.32M
              T64* out) const {
193
2.32M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
79.6k
        return Memcpy(offset, range, out);
195
2.24M
      } else {
196
2.24M
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
2.24M
      }
198
2.32M
    }
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
17.7M
              T64* out) const {
193
17.7M
      if (elf_.is_64bit() && elf_.is_native_endian()) {
194
17.7M
        return Memcpy(offset, range, out);
195
17.7M
      } else {
196
25.0k
        return ReadFallback<T32, T64, Munger>(offset, range, out);
197
25.0k
      }
198
17.7M
    }
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
242M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
242M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
242M
      if (out_range) {
212
226M
        *out_range = range;
213
226M
      }
214
242M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
242M
    }
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
3.55M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
3.55M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
3.55M
      if (out_range) {
212
3.55M
        *out_range = range;
213
3.55M
      }
214
3.55M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
3.55M
    }
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
2.21M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
2.21M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
2.21M
      if (out_range) {
212
2.21M
        *out_range = range;
213
2.21M
      }
214
2.21M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
2.21M
    }
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
26.4M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
26.4M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
26.4M
      if (out_range) {
212
26.4M
        *out_range = range;
213
26.4M
      }
214
26.4M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
26.4M
    }
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
72.0M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
72.0M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
72.0M
      if (out_range) {
212
72.0M
        *out_range = range;
213
72.0M
      }
214
72.0M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
72.0M
    }
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
518k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
518k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
518k
      if (out_range) {
212
0
        *out_range = range;
213
0
      }
214
518k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
518k
    }
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
61.6M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
61.6M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
61.6M
      if (out_range) {
212
61.6M
        *out_range = range;
213
61.6M
      }
214
61.6M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
61.6M
    }
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
37.5M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
37.5M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
37.5M
      if (out_range) {
212
37.5M
        *out_range = range;
213
37.5M
      }
214
37.5M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
37.5M
    }
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
14.7M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
14.7M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
14.7M
      if (out_range) {
212
2.34M
        *out_range = range;
213
2.34M
      }
214
14.7M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
14.7M
    }
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
3.43M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
3.43M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
3.43M
      if (out_range) {
212
434k
        *out_range = range;
213
434k
      }
214
3.43M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
3.43M
    }
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
79.6k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
79.6k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
79.6k
      if (out_range) {
212
78.3k
        *out_range = range;
213
78.3k
      }
214
79.6k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
79.6k
    }
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
2.24M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
2.24M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
2.24M
      if (out_range) {
212
2.24M
        *out_range = range;
213
2.24M
      }
214
2.24M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
2.24M
    }
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
17.7M
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
17.7M
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
17.7M
      if (out_range) {
212
17.7M
        *out_range = range;
213
17.7M
      }
214
17.7M
      memcpy(out, data_.data() + offset, sizeof(*out));
215
17.7M
    }
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
25.0k
    void Memcpy(uint64_t offset, absl::string_view* out_range, T* out) const {
210
25.0k
      absl::string_view range = StrictSubstr(data_, offset, sizeof(*out));
211
25.0k
      if (out_range) {
212
24.8k
        *out_range = range;
213
24.8k
      }
214
25.0k
      memcpy(out, data_.data() + offset, sizeof(*out));
215
25.0k
    }
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
2.22M
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
2.22M
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
2.22M
    to->e_type       = func(from.e_type);
247
2.22M
    to->e_machine    = func(from.e_machine);
248
2.22M
    to->e_version    = func(from.e_version);
249
2.22M
    to->e_entry      = func(from.e_entry);
250
2.22M
    to->e_phoff      = func(from.e_phoff);
251
2.22M
    to->e_shoff      = func(from.e_shoff);
252
2.22M
    to->e_flags      = func(from.e_flags);
253
2.22M
    to->e_ehsize     = func(from.e_ehsize);
254
2.22M
    to->e_phentsize  = func(from.e_phentsize);
255
2.22M
    to->e_phnum      = func(from.e_phnum);
256
2.22M
    to->e_shentsize  = func(from.e_shentsize);
257
2.22M
    to->e_shnum      = func(from.e_shnum);
258
2.22M
    to->e_shstrndx   = func(from.e_shstrndx);
259
2.22M
  }
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
10.7k
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
10.7k
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
10.7k
    to->e_type       = func(from.e_type);
247
10.7k
    to->e_machine    = func(from.e_machine);
248
10.7k
    to->e_version    = func(from.e_version);
249
10.7k
    to->e_entry      = func(from.e_entry);
250
10.7k
    to->e_phoff      = func(from.e_phoff);
251
10.7k
    to->e_shoff      = func(from.e_shoff);
252
10.7k
    to->e_flags      = func(from.e_flags);
253
10.7k
    to->e_ehsize     = func(from.e_ehsize);
254
10.7k
    to->e_phentsize  = func(from.e_phentsize);
255
10.7k
    to->e_phnum      = func(from.e_phnum);
256
10.7k
    to->e_shentsize  = func(from.e_shentsize);
257
10.7k
    to->e_shnum      = func(from.e_shnum);
258
10.7k
    to->e_shstrndx   = func(from.e_shstrndx);
259
10.7k
  }
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
2.14M
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
2.14M
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
2.14M
    to->e_type       = func(from.e_type);
247
2.14M
    to->e_machine    = func(from.e_machine);
248
2.14M
    to->e_version    = func(from.e_version);
249
2.14M
    to->e_entry      = func(from.e_entry);
250
2.14M
    to->e_phoff      = func(from.e_phoff);
251
2.14M
    to->e_shoff      = func(from.e_shoff);
252
2.14M
    to->e_flags      = func(from.e_flags);
253
2.14M
    to->e_ehsize     = func(from.e_ehsize);
254
2.14M
    to->e_phentsize  = func(from.e_phentsize);
255
2.14M
    to->e_phnum      = func(from.e_phnum);
256
2.14M
    to->e_shentsize  = func(from.e_shentsize);
257
2.14M
    to->e_shnum      = func(from.e_shnum);
258
2.14M
    to->e_shstrndx   = func(from.e_shstrndx);
259
2.14M
  }
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
75.3k
  void operator()(const From& from, Elf64_Ehdr* to, Func func) {
245
75.3k
    memmove(&to->e_ident[0], &from.e_ident[0], EI_NIDENT);
246
75.3k
    to->e_type       = func(from.e_type);
247
75.3k
    to->e_machine    = func(from.e_machine);
248
75.3k
    to->e_version    = func(from.e_version);
249
75.3k
    to->e_entry      = func(from.e_entry);
250
75.3k
    to->e_phoff      = func(from.e_phoff);
251
75.3k
    to->e_shoff      = func(from.e_shoff);
252
75.3k
    to->e_flags      = func(from.e_flags);
253
75.3k
    to->e_ehsize     = func(from.e_ehsize);
254
75.3k
    to->e_phentsize  = func(from.e_phentsize);
255
75.3k
    to->e_phnum      = func(from.e_phnum);
256
75.3k
    to->e_shentsize  = func(from.e_shentsize);
257
75.3k
    to->e_shnum      = func(from.e_shnum);
258
75.3k
    to->e_shstrndx   = func(from.e_shstrndx);
259
75.3k
  }
260
};
261
262
struct ShdrMunger {
263
  template <class From, class Func>
264
72.0M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
72.0M
    to->sh_name       = func(from.sh_name);
266
72.0M
    to->sh_type       = func(from.sh_type);
267
72.0M
    to->sh_flags      = func(from.sh_flags);
268
72.0M
    to->sh_addr       = func(from.sh_addr);
269
72.0M
    to->sh_offset     = func(from.sh_offset);
270
72.0M
    to->sh_size       = func(from.sh_size);
271
72.0M
    to->sh_link       = func(from.sh_link);
272
72.0M
    to->sh_info       = func(from.sh_info);
273
72.0M
    to->sh_addralign  = func(from.sh_addralign);
274
72.0M
    to->sh_entsize    = func(from.sh_entsize);
275
72.0M
  }
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
12.3k
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
12.3k
    to->sh_name       = func(from.sh_name);
266
12.3k
    to->sh_type       = func(from.sh_type);
267
12.3k
    to->sh_flags      = func(from.sh_flags);
268
12.3k
    to->sh_addr       = func(from.sh_addr);
269
12.3k
    to->sh_offset     = func(from.sh_offset);
270
12.3k
    to->sh_size       = func(from.sh_size);
271
12.3k
    to->sh_link       = func(from.sh_link);
272
12.3k
    to->sh_info       = func(from.sh_info);
273
12.3k
    to->sh_addralign  = func(from.sh_addralign);
274
12.3k
    to->sh_entsize    = func(from.sh_entsize);
275
12.3k
  }
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
11.6M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
11.6M
    to->sh_name       = func(from.sh_name);
266
11.6M
    to->sh_type       = func(from.sh_type);
267
11.6M
    to->sh_flags      = func(from.sh_flags);
268
11.6M
    to->sh_addr       = func(from.sh_addr);
269
11.6M
    to->sh_offset     = func(from.sh_offset);
270
11.6M
    to->sh_size       = func(from.sh_size);
271
11.6M
    to->sh_link       = func(from.sh_link);
272
11.6M
    to->sh_info       = func(from.sh_info);
273
11.6M
    to->sh_addralign  = func(from.sh_addralign);
274
11.6M
    to->sh_entsize    = func(from.sh_entsize);
275
11.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
60.4M
  void operator()(const From& from, Elf64_Shdr* to, Func func) {
265
60.4M
    to->sh_name       = func(from.sh_name);
266
60.4M
    to->sh_type       = func(from.sh_type);
267
60.4M
    to->sh_flags      = func(from.sh_flags);
268
60.4M
    to->sh_addr       = func(from.sh_addr);
269
60.4M
    to->sh_offset     = func(from.sh_offset);
270
60.4M
    to->sh_size       = func(from.sh_size);
271
60.4M
    to->sh_link       = func(from.sh_link);
272
60.4M
    to->sh_info       = func(from.sh_info);
273
60.4M
    to->sh_addralign  = func(from.sh_addralign);
274
60.4M
    to->sh_entsize    = func(from.sh_entsize);
275
60.4M
  }
276
};
277
278
struct PhdrMunger {
279
  template <class From, class Func>
280
52.3M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
52.3M
    to->p_type   = func(from.p_type);
282
52.3M
    to->p_flags  = func(from.p_flags);
283
52.3M
    to->p_offset = func(from.p_offset);
284
52.3M
    to->p_vaddr  = func(from.p_vaddr);
285
52.3M
    to->p_paddr  = func(from.p_paddr);
286
52.3M
    to->p_filesz = func(from.p_filesz);
287
52.3M
    to->p_memsz  = func(from.p_memsz);
288
52.3M
    to->p_align  = func(from.p_align);
289
52.3M
  }
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
14.7M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
14.7M
    to->p_type   = func(from.p_type);
282
14.7M
    to->p_flags  = func(from.p_flags);
283
14.7M
    to->p_offset = func(from.p_offset);
284
14.7M
    to->p_vaddr  = func(from.p_vaddr);
285
14.7M
    to->p_paddr  = func(from.p_paddr);
286
14.7M
    to->p_filesz = func(from.p_filesz);
287
14.7M
    to->p_memsz  = func(from.p_memsz);
288
14.7M
    to->p_align  = func(from.p_align);
289
14.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
7.84M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
7.84M
    to->p_type   = func(from.p_type);
282
7.84M
    to->p_flags  = func(from.p_flags);
283
7.84M
    to->p_offset = func(from.p_offset);
284
7.84M
    to->p_vaddr  = func(from.p_vaddr);
285
7.84M
    to->p_paddr  = func(from.p_paddr);
286
7.84M
    to->p_filesz = func(from.p_filesz);
287
7.84M
    to->p_memsz  = func(from.p_memsz);
288
7.84M
    to->p_align  = func(from.p_align);
289
7.84M
  }
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
29.7M
  void operator()(const From& from, Elf64_Phdr* to, Func func) {
281
29.7M
    to->p_type   = func(from.p_type);
282
29.7M
    to->p_flags  = func(from.p_flags);
283
29.7M
    to->p_offset = func(from.p_offset);
284
29.7M
    to->p_vaddr  = func(from.p_vaddr);
285
29.7M
    to->p_paddr  = func(from.p_paddr);
286
29.7M
    to->p_filesz = func(from.p_filesz);
287
29.7M
    to->p_memsz  = func(from.p_memsz);
288
29.7M
    to->p_align  = func(from.p_align);
289
29.7M
  }
290
};
291
292
struct SymMunger {
293
  template <class From, class Func>
294
3.43M
  void operator()(const From& from, Elf64_Sym* to, Func func) {
295
3.43M
    to->st_name   = func(from.st_name);
296
3.43M
    to->st_info   = func(from.st_info);
297
3.43M
    to->st_other  = func(from.st_other);
298
3.43M
    to->st_shndx  = func(from.st_shndx);
299
3.43M
    to->st_value  = func(from.st_value);
300
3.43M
    to->st_size   = func(from.st_size);
301
3.43M
  }
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
3.43M
  void operator()(const From& from, Elf64_Sym* to, Func func) {
295
3.43M
    to->st_name   = func(from.st_name);
296
3.43M
    to->st_info   = func(from.st_info);
297
3.43M
    to->st_other  = func(from.st_other);
298
3.43M
    to->st_shndx  = func(from.st_shndx);
299
3.43M
    to->st_value  = func(from.st_value);
300
3.43M
    to->st_size   = func(from.st_size);
301
3.43M
  }
elf.cc:void bloaty::(anonymous namespace)::SymMunger::operator()<Elf32_Sym, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Sym const&, Elf64_Sym*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
294
2.30k
  void operator()(const From& from, Elf64_Sym* to, Func func) {
295
2.30k
    to->st_name   = func(from.st_name);
296
2.30k
    to->st_info   = func(from.st_info);
297
2.30k
    to->st_other  = func(from.st_other);
298
2.30k
    to->st_shndx  = func(from.st_shndx);
299
2.30k
    to->st_value  = func(from.st_value);
300
2.30k
    to->st_size   = func(from.st_size);
301
2.30k
  }
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
24.8k
  void operator()(const From& from, Elf64_Rela* to, Func func) {
315
24.8k
    to->r_offset = func(from.r_offset);
316
24.8k
    to->r_info   = func(from.r_info);
317
24.8k
    to->r_addend = func(from.r_addend);
318
24.8k
  }
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
19.8k
  void operator()(const From& from, Elf64_Rela* to, Func func) {
315
19.8k
    to->r_offset = func(from.r_offset);
316
19.8k
    to->r_info   = func(from.r_info);
317
19.8k
    to->r_addend = func(from.r_addend);
318
19.8k
  }
elf.cc:void bloaty::(anonymous namespace)::RelaMunger::operator()<Elf32_Rela, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf32_Rela const&, Elf64_Rela*, bloaty::(anonymous namespace)::ByteSwapFunc)
Line
Count
Source
314
5.00k
  void operator()(const From& from, Elf64_Rela* to, Func func) {
315
5.00k
    to->r_offset = func(from.r_offset);
316
5.00k
    to->r_info   = func(from.r_info);
317
5.00k
    to->r_addend = func(from.r_addend);
318
5.00k
  }
319
};
320
321
struct NoteMunger {
322
  template <class From, class Func>
323
197k
  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324
197k
    to->n_namesz = func(from.n_namesz);
325
197k
    to->n_descsz = func(from.n_descsz);
326
197k
    to->n_type   = func(from.n_type);
327
197k
  }
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
5.13k
  void operator()(const From& from, Elf64_Nhdr* to, Func func) {
324
5.13k
    to->n_namesz = func(from.n_namesz);
325
5.13k
    to->n_descsz = func(from.n_descsz);
326
5.13k
    to->n_type   = func(from.n_type);
327
5.13k
  }
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
2.24M
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
2.24M
    to->ch_type = func(from.ch_type);
334
2.24M
    to->ch_size = func(from.ch_size);
335
2.24M
    to->ch_addralign   = func(from.ch_addralign);
336
2.24M
  }
Unexecuted instantiation: elf.cc:void bloaty::(anonymous namespace)::ChdrMunger::operator()<Elf64_Chdr, bloaty::(anonymous namespace)::ByteSwapFunc>(Elf64_Chdr const&, Elf64_Chdr*, bloaty::(anonymous namespace)::ByteSwapFunc)
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
2.02k
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
2.02k
    to->ch_type = func(from.ch_type);
334
2.02k
    to->ch_size = func(from.ch_size);
335
2.02k
    to->ch_addralign   = func(from.ch_addralign);
336
2.02k
  }
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
2.24M
  void operator()(const From& from, Elf64_Chdr* to, Func func) {
333
2.24M
    to->ch_type = func(from.ch_type);
334
2.24M
    to->ch_size = func(from.ch_size);
335
2.24M
    to->ch_addralign   = func(from.ch_addralign);
336
2.24M
  }
337
};
338
339
template <class T32, class T64, class Munger>
340
void ElfFile::StructReader::ReadFallback(uint64_t offset,
341
                                         absl::string_view* range,
342
132M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
132M
  if (elf_.is_64bit()) {
345
14.7M
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
14.7M
    Munger()(*out, out, ByteSwapFunc());
348
117M
  } else {
349
117M
    T32 data32;
350
117M
    Memcpy(offset, range, &data32);
351
117M
    if (elf_.is_native_endian()) {
352
25.2M
      Munger()(data32, out, NullFunc());
353
92.5M
    } else {
354
92.5M
      Munger()(data32, out, ByteSwapFunc());
355
92.5M
    }
356
117M
  }
357
132M
}
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
2.22M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
2.22M
  if (elf_.is_64bit()) {
345
10.8k
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
10.8k
    Munger()(*out, out, ByteSwapFunc());
348
2.21M
  } else {
349
2.21M
    T32 data32;
350
2.21M
    Memcpy(offset, range, &data32);
351
2.21M
    if (elf_.is_native_endian()) {
352
2.14M
      Munger()(data32, out, NullFunc());
353
2.14M
    } else {
354
75.4k
      Munger()(data32, out, ByteSwapFunc());
355
75.4k
    }
356
2.21M
  }
357
2.22M
}
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
72.0M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
72.0M
  if (elf_.is_64bit()) {
345
12.6k
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
12.6k
    Munger()(*out, out, ByteSwapFunc());
348
72.0M
  } else {
349
72.0M
    T32 data32;
350
72.0M
    Memcpy(offset, range, &data32);
351
72.0M
    if (elf_.is_native_endian()) {
352
11.6M
      Munger()(data32, out, NullFunc());
353
60.4M
    } else {
354
60.4M
      Munger()(data32, out, ByteSwapFunc());
355
60.4M
    }
356
72.0M
  }
357
72.0M
}
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
197k
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
197k
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
197k
  } else {
349
197k
    T32 data32;
350
197k
    Memcpy(offset, range, &data32);
351
197k
    if (elf_.is_native_endian()) {
352
192k
      Munger()(data32, out, NullFunc());
353
192k
    } else {
354
5.44k
      Munger()(data32, out, ByteSwapFunc());
355
5.44k
    }
356
197k
  }
357
197k
}
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
52.3M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
52.3M
  if (elf_.is_64bit()) {
345
14.7M
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
14.7M
    Munger()(*out, out, ByteSwapFunc());
348
37.5M
  } else {
349
37.5M
    T32 data32;
350
37.5M
    Memcpy(offset, range, &data32);
351
37.5M
    if (elf_.is_native_endian()) {
352
7.84M
      Munger()(data32, out, NullFunc());
353
29.7M
    } else {
354
29.7M
      Munger()(data32, out, ByteSwapFunc());
355
29.7M
    }
356
37.5M
  }
357
52.3M
}
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
3.43M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
3.43M
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
3.43M
  } else {
349
3.43M
    T32 data32;
350
3.43M
    Memcpy(offset, range, &data32);
351
3.43M
    if (elf_.is_native_endian()) {
352
3.43M
      Munger()(data32, out, NullFunc());
353
3.43M
    } else {
354
2.45k
      Munger()(data32, out, ByteSwapFunc());
355
2.45k
    }
356
3.43M
  }
357
3.43M
}
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
2.24M
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
2.24M
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
2.24M
  } else {
349
2.24M
    T32 data32;
350
2.24M
    Memcpy(offset, range, &data32);
351
2.24M
    if (elf_.is_native_endian()) {
352
2.02k
      Munger()(data32, out, NullFunc());
353
2.24M
    } else {
354
2.24M
      Munger()(data32, out, ByteSwapFunc());
355
2.24M
    }
356
2.24M
  }
357
2.24M
}
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
25.0k
                                         T64* out) const {
343
  // Fallback for either 32-bit ELF file or non-native endian.
344
25.0k
  if (elf_.is_64bit()) {
345
0
    assert(!elf_.is_native_endian());
346
0
    Memcpy(offset, range, out);
347
0
    Munger()(*out, out, ByteSwapFunc());
348
25.0k
  } else {
349
25.0k
    T32 data32;
350
25.0k
    Memcpy(offset, range, &data32);
351
25.0k
    if (elf_.is_native_endian()) {
352
19.8k
      Munger()(data32, out, NullFunc());
353
19.8k
    } else {
354
5.26k
      Munger()(data32, out, ByteSwapFunc());
355
5.26k
    }
356
25.0k
  }
357
25.0k
}
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
38.2M
string_view ElfFile::Section::GetName() const {
360
38.2M
  if (header_.sh_name == SHN_UNDEF) {
361
347k
    return string_view(nullptr, 0);
362
347k
  }
363
37.9M
  return elf_->section_name_table_.ReadString(header_.sh_name);
364
38.2M
}
365
366
46.4M
string_view ElfFile::Section::ReadString(Elf64_Word index) const {
367
46.4M
  assert(header().sh_type == SHT_STRTAB);
368
369
46.4M
  if (index == SHN_UNDEF || index >= contents_.size()) {
370
32.9k
    THROWF("can't read index $0 from strtab, total size is $1", index,
371
32.9k
           contents_.size());
372
32.9k
  }
373
374
46.4M
  string_view ret = StrictSubstr(contents_, index);
375
376
46.4M
  const char* null_pos =
377
46.4M
      static_cast<const char*>(memchr(ret.data(), '\0', ret.size()));
378
379
46.4M
  if (null_pos == NULL) {
380
14.1k
    THROW("no NULL terminator found");
381
14.1k
  }
382
383
46.3M
  size_t len = null_pos - ret.data();
384
46.3M
  ret = ret.substr(0, len);
385
46.3M
  return ret;
386
46.4M
}
387
388
321k
Elf64_Word ElfFile::Section::GetEntryCount() const {
389
321k
  if (header_.sh_entsize == 0) {
390
1.88k
    THROW("sh_entsize is zero");
391
1.88k
  }
392
319k
  return contents_.size() / header_.sh_entsize;
393
321k
}
394
395
void ElfFile::Section::ReadSymbol(Elf64_Word index, Elf64_Sym* sym,
396
18.1M
                                  string_view* file_range) const {
397
18.1M
  assert(header().sh_type == SHT_SYMTAB || header().sh_type == SHT_DYNSYM);
398
0
  size_t offset = header_.sh_entsize * index;
399
18.1M
  elf_->ReadStruct<Elf32_Sym>(contents(), offset, SymMunger(), file_range, sym);
400
18.1M
}
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
17.7M
                                                string_view* file_range) const {
412
17.7M
  assert(header().sh_type == SHT_RELA);
413
0
  size_t offset = header_.sh_entsize * index;
414
17.7M
  elf_->ReadStruct<Elf32_Rela>(contents(), offset, RelaMunger(), file_range,
415
17.7M
                               rela);
416
17.7M
}
417
418
830k
void ElfFile::NoteIter::Next() {
419
830k
  if (remaining_.empty()) {
420
311k
    done_ = true;
421
311k
    return;
422
311k
  }
423
424
518k
  Elf_Note note;
425
518k
  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
518k
  AdvancePastStruct<Elf_Note>(&remaining_);
430
431
518k
  type_ = note.n_type;
432
518k
  name_ = StrictSubstr(remaining_, 0, note.n_namesz);
433
434
  // Size might include NULL terminator.
435
518k
  if (name_[name_.size() - 1] == 0) {
436
495k
    name_ = name_.substr(0, name_.size() - 1);
437
495k
  }
438
439
518k
  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_namesz, 4));
440
518k
  descriptor_ = StrictSubstr(remaining_, 0, note.n_descsz);
441
518k
  remaining_ = StrictSubstr(remaining_, AlignUp(note.n_descsz, 4));
442
518k
}
443
444
6.48M
bool ElfFile::Initialize() {
445
6.48M
  if (data_.size() < EI_NIDENT) {
446
3.99k
    return false;
447
3.99k
  }
448
449
6.47M
  unsigned char ident[EI_NIDENT];
450
6.47M
  memcpy(ident, data_.data(), EI_NIDENT);
451
452
6.47M
  if (memcmp(ident, "\177ELF", 4) != 0) {
453
    // Not an ELF file.
454
707k
    return false;
455
707k
  }
456
457
5.76M
  switch (ident[EI_CLASS]) {
458
2.21M
    case ELFCLASS32:
459
2.21M
      is_64bit_ = false;
460
2.21M
      break;
461
3.55M
    case ELFCLASS64:
462
3.55M
      is_64bit_ = true;
463
3.55M
      break;
464
108
    default:
465
108
      THROWF("unexpected ELF class: $0", ident[EI_CLASS]);
466
5.76M
  }
467
468
5.76M
  switch (ident[EI_DATA]) {
469
5.68M
    case ELFDATA2LSB:
470
5.68M
      is_native_endian_ = GetMachineEndian() == Endian::kLittle;
471
5.68M
      break;
472
86.2k
    case ELFDATA2MSB:
473
86.2k
      is_native_endian_ = GetMachineEndian() == Endian::kBig;
474
86.2k
      break;
475
216
    default:
476
216
      THROWF("unexpected ELF data: $0", ident[EI_DATA]);
477
5.76M
  }
478
479
5.76M
  absl::string_view range;
480
5.76M
  ReadStruct<Elf32_Ehdr>(entire_file(), 0, EhdrMunger(), &range, &header_);
481
482
5.76M
  Section section0;
483
5.76M
  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
5.76M
  if (header_.e_shoff > 0 &&
489
5.76M
      data_.size() > (header_.e_shoff + header_.e_shentsize)) {
490
5.69M
    section_count_ = 1;
491
5.69M
    ReadSection(0, &section0);
492
5.69M
    has_section0 = true;
493
5.69M
  }
494
495
5.76M
  section_count_ = header_.e_shnum;
496
5.76M
  section_string_index_ = header_.e_shstrndx;
497
498
5.76M
  if (section_count_ == 0 && has_section0) {
499
64.1k
    section_count_ = section0.header().sh_size;
500
64.1k
  }
501
502
5.76M
  if (section_string_index_ == SHN_XINDEX && has_section0) {
503
5.78k
    section_string_index_ = section0.header().sh_link;
504
5.78k
  }
505
506
5.76M
  header_region_ = GetRegion(0, header_.e_ehsize);
507
5.76M
  section_headers_ = GetRegion(header_.e_shoff,
508
5.76M
                               CheckedMul(header_.e_shentsize, section_count_));
509
5.76M
  segment_headers_ = GetRegion(
510
5.76M
      header_.e_phoff, CheckedMul(header_.e_phentsize, header_.e_phnum));
511
512
5.76M
  if (section_count_ > 0) {
513
5.67M
    ReadSection(section_string_index_, &section_name_table_);
514
5.67M
    if (section_name_table_.header().sh_type != SHT_STRTAB) {
515
858
      THROW("section string index pointed to non-strtab");
516
858
    }
517
5.67M
  }
518
519
5.76M
  return true;
520
5.76M
}
521
522
99.2M
void ElfFile::ReadSegment(Elf64_Word index, Segment* segment) const {
523
99.2M
  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
99.2M
  Elf64_Phdr* header = &segment->header_;
529
99.2M
  ReadStruct<Elf32_Phdr>(
530
99.2M
      entire_file(),
531
99.2M
      CheckedAdd(header_.e_phoff, CheckedMul(header_.e_phentsize, index)),
532
99.2M
      PhdrMunger(), &segment->range_, header);
533
99.2M
  segment->contents_ = GetRegion(header->p_offset, header->p_filesz);
534
99.2M
}
535
536
98.5M
void ElfFile::ReadSection(Elf64_Word index, Section* section) const {
537
98.5M
  if (index >= section_count_) {
538
1.13k
    THROWF("tried to read section $0, but there are only $1", index,
539
1.13k
           section_count_);
540
1.13k
  }
541
542
98.5M
  Elf64_Shdr* header = &section->header_;
543
98.5M
  ReadStruct<Elf32_Shdr>(
544
98.5M
      entire_file(),
545
98.5M
      CheckedAdd(header_.e_shoff, CheckedMul(header_.e_shentsize, index)),
546
98.5M
      ShdrMunger(), &section->range_, header);
547
548
98.5M
  if (header->sh_type == SHT_NOBITS) {
549
818k
    section->contents_ = string_view();
550
97.6M
  } else {
551
97.6M
    section->contents_ = GetRegion(header->sh_offset, header->sh_size);
552
97.6M
  }
553
554
98.5M
  section->elf_ = this;
555
98.5M
}
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
5.72M
        contents_(data.substr(std::min<size_t>(data.size(), kMagicSize))) {}
582
583
5.08M
  bool IsOpen() const { return magic() == string_view(kMagic); }
584
585
5.15M
  string_view magic() const { return magic_; }
586
66.3k
  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
66.3k
    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
610k
    string_view Consume(size_t n) {
608
610k
      n = (n % 2 == 0 ? n : n + 1);
609
610k
      if (remaining_.size() < n) {
610
414
        THROW("premature end of file");
611
414
      }
612
610k
      string_view ret = remaining_.substr(0, n);
613
610k
      remaining_.remove_prefix(n);
614
610k
      return ret;
615
610k
    }
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
364k
bool ArFile::MemberReader::ReadMember(MemberFile* file) {
630
364k
  struct Header {
631
364k
    char file_id[16];
632
364k
    char modified_timestamp[12];
633
364k
    char owner_id[6];
634
364k
    char group_id[6];
635
364k
    char mode[8];
636
364k
    char size[10];
637
364k
    char end[2];
638
364k
  };
639
640
364k
  if (remaining_.size() == 0) {
641
57.5k
    return false;
642
307k
  } else if (remaining_.size() < sizeof(Header)) {
643
750
    THROW("Premature EOF in AR data");
644
750
  }
645
646
306k
  const Header* header = reinterpret_cast<const Header*>(remaining_.data());
647
306k
  file->header = Consume(sizeof(Header));
648
649
306k
  string_view file_id(&header->file_id[0], sizeof(header->file_id));
650
306k
  string_view size_str(&header->size[0], sizeof(header->size));
651
306k
  file->size = StringViewToSize(size_str);
652
306k
  file->contents = Consume(file->size);
653
306k
  file->file_type = MemberFile::kNormal;
654
655
306k
  if (file_id[0] == '/') {
656
    // Special filename, internal to the format.
657
178k
    if (file_id[1] == ' ') {
658
65.1k
      file->file_type = MemberFile::kSymbolTable;
659
113k
    } else if (file_id[1] == '/') {
660
62.7k
      file->file_type = MemberFile::kLongFilenameTable;
661
62.7k
      long_filenames_ = file->contents;
662
62.7k
    } else if (isdigit(file_id[1])) {
663
50.4k
      size_t offset = StringViewToSize(file_id.substr(1));
664
50.4k
      size_t end = long_filenames_.find('/', offset);
665
666
50.4k
      if (end == std::string::npos) {
667
210
        THROW("Unterminated long filename");
668
210
      }
669
670
50.2k
      file->filename = long_filenames_.substr(offset, end - offset);
671
50.2k
    } else {
672
108
      THROW("Unexpected special filename in AR archive");
673
108
    }
674
178k
  } else {
675
    // Normal filename, slash-terminated.
676
128k
    size_t slash = file_id.find('/');
677
678
128k
    if (slash == std::string::npos) {
679
186
      THROW("BSD-style AR not yet implemented");
680
186
    }
681
682
128k
    file->filename = file_id.substr(0, slash);
683
128k
  }
684
685
306k
  return true;
686
306k
}
687
688
void MaybeAddFileRange(const char* analyzer, RangeSink* sink, string_view label,
689
519k
                       string_view range) {
690
519k
  if (sink) {
691
499k
    sink->AddFileRange(analyzer, label, range);
692
499k
  }
693
519k
}
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
2.74M
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
2.74M
  ArFile ar_file(file.data());
700
2.74M
  uint64_t index_base = 0;
701
702
2.74M
  if (ar_file.IsOpen()) {
703
66.3k
    ArFile::MemberFile member;
704
66.3k
    ArFile::MemberReader reader(ar_file);
705
706
66.3k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
364k
    while (reader.ReadMember(&member)) {
709
303k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
303k
      switch (member.file_type) {
711
175k
        case ArFile::MemberFile::kNormal: {
712
175k
          ElfFile elf(member.contents);
713
175k
          if (elf.IsOpen()) {
714
150k
            func(elf, member.filename, index_base);
715
150k
            index_base += elf.section_count();
716
150k
          } else {
717
24.9k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
24.9k
                              member.contents);
719
24.9k
          }
720
175k
          break;
721
0
        }
722
65.1k
        case ArFile::MemberFile::kSymbolTable:
723
65.1k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
65.1k
                            member.contents);
725
65.1k
          break;
726
62.7k
        case ArFile::MemberFile::kLongFilenameTable:
727
62.7k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
62.7k
                            member.contents);
729
62.7k
          break;
730
303k
      }
731
303k
    }
732
2.67M
  } else {
733
2.67M
    ElfFile elf(file.data());
734
2.67M
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
2.67M
    func(elf, file.filename(), index_base);
739
2.67M
  }
740
2.74M
}
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
798k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
798k
  ArFile ar_file(file.data());
700
798k
  uint64_t index_base = 0;
701
702
798k
  if (ar_file.IsOpen()) {
703
12.6k
    ArFile::MemberFile member;
704
12.6k
    ArFile::MemberReader reader(ar_file);
705
706
12.6k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
72.7k
    while (reader.ReadMember(&member)) {
709
60.1k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
60.1k
      switch (member.file_type) {
711
35.5k
        case ArFile::MemberFile::kNormal: {
712
35.5k
          ElfFile elf(member.contents);
713
35.5k
          if (elf.IsOpen()) {
714
31.0k
            func(elf, member.filename, index_base);
715
31.0k
            index_base += elf.section_count();
716
31.0k
          } else {
717
4.54k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
4.54k
                              member.contents);
719
4.54k
          }
720
35.5k
          break;
721
0
        }
722
12.4k
        case ArFile::MemberFile::kSymbolTable:
723
12.4k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
12.4k
                            member.contents);
725
12.4k
          break;
726
12.0k
        case ArFile::MemberFile::kLongFilenameTable:
727
12.0k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
12.0k
                            member.contents);
729
12.0k
          break;
730
60.1k
      }
731
60.1k
    }
732
785k
  } else {
733
785k
    ElfFile elf(file.data());
734
785k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
785k
    func(elf, file.filename(), index_base);
739
785k
  }
740
798k
}
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
796k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
796k
  ArFile ar_file(file.data());
700
796k
  uint64_t index_base = 0;
701
702
796k
  if (ar_file.IsOpen()) {
703
12.6k
    ArFile::MemberFile member;
704
12.6k
    ArFile::MemberReader reader(ar_file);
705
706
12.6k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
72.7k
    while (reader.ReadMember(&member)) {
709
60.1k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
60.1k
      switch (member.file_type) {
711
35.5k
        case ArFile::MemberFile::kNormal: {
712
35.5k
          ElfFile elf(member.contents);
713
35.5k
          if (elf.IsOpen()) {
714
31.0k
            func(elf, member.filename, index_base);
715
31.0k
            index_base += elf.section_count();
716
31.0k
          } else {
717
4.54k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
4.54k
                              member.contents);
719
4.54k
          }
720
35.5k
          break;
721
0
        }
722
12.4k
        case ArFile::MemberFile::kSymbolTable:
723
12.4k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
12.4k
                            member.contents);
725
12.4k
          break;
726
12.0k
        case ArFile::MemberFile::kLongFilenameTable:
727
12.0k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
12.0k
                            member.contents);
729
12.0k
          break;
730
60.1k
      }
731
60.1k
    }
732
783k
  } else {
733
783k
    ElfFile elf(file.data());
734
783k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
783k
    func(elf, file.filename(), index_base);
739
783k
  }
740
796k
}
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
298k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
298k
  ArFile ar_file(file.data());
700
298k
  uint64_t index_base = 0;
701
702
298k
  if (ar_file.IsOpen()) {
703
23.4k
    ArFile::MemberFile member;
704
23.4k
    ArFile::MemberReader reader(ar_file);
705
706
23.4k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
120k
    while (reader.ReadMember(&member)) {
709
100k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
100k
      switch (member.file_type) {
711
55.6k
        case ArFile::MemberFile::kNormal: {
712
55.6k
          ElfFile elf(member.contents);
713
55.6k
          if (elf.IsOpen()) {
714
45.9k
            func(elf, member.filename, index_base);
715
45.9k
            index_base += elf.section_count();
716
45.9k
          } else {
717
9.64k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
9.64k
                              member.contents);
719
9.64k
          }
720
55.6k
          break;
721
0
        }
722
23.0k
        case ArFile::MemberFile::kSymbolTable:
723
23.0k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
23.0k
                            member.contents);
725
23.0k
          break;
726
21.8k
        case ArFile::MemberFile::kLongFilenameTable:
727
21.8k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
21.8k
                            member.contents);
729
21.8k
          break;
730
100k
      }
731
100k
    }
732
275k
  } else {
733
275k
    ElfFile elf(file.data());
734
275k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
275k
    func(elf, file.filename(), index_base);
739
275k
  }
740
298k
}
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
176k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
176k
  ArFile ar_file(file.data());
700
176k
  uint64_t index_base = 0;
701
702
176k
  if (ar_file.IsOpen()) {
703
2.51k
    ArFile::MemberFile member;
704
2.51k
    ArFile::MemberReader reader(ar_file);
705
706
2.51k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
14.4k
    while (reader.ReadMember(&member)) {
709
11.9k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
11.9k
      switch (member.file_type) {
711
7.07k
        case ArFile::MemberFile::kNormal: {
712
7.07k
          ElfFile elf(member.contents);
713
7.07k
          if (elf.IsOpen()) {
714
6.16k
            func(elf, member.filename, index_base);
715
6.16k
            index_base += elf.section_count();
716
6.16k
          } else {
717
908
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
908
                              member.contents);
719
908
          }
720
7.07k
          break;
721
0
        }
722
2.47k
        case ArFile::MemberFile::kSymbolTable:
723
2.47k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
2.47k
                            member.contents);
725
2.47k
          break;
726
2.40k
        case ArFile::MemberFile::kLongFilenameTable:
727
2.40k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
2.40k
                            member.contents);
729
2.40k
          break;
730
11.9k
      }
731
11.9k
    }
732
174k
  } else {
733
174k
    ElfFile elf(file.data());
734
174k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
174k
    func(elf, file.filename(), index_base);
739
174k
  }
740
176k
}
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
176k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
176k
  ArFile ar_file(file.data());
700
176k
  uint64_t index_base = 0;
701
702
176k
  if (ar_file.IsOpen()) {
703
2.51k
    ArFile::MemberFile member;
704
2.51k
    ArFile::MemberReader reader(ar_file);
705
706
2.51k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
14.1k
    while (reader.ReadMember(&member)) {
709
11.8k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
11.8k
      switch (member.file_type) {
711
6.95k
        case ArFile::MemberFile::kNormal: {
712
6.95k
          ElfFile elf(member.contents);
713
6.95k
          if (elf.IsOpen()) {
714
6.07k
            func(elf, member.filename, index_base);
715
6.07k
            index_base += elf.section_count();
716
6.07k
          } else {
717
884
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
884
                              member.contents);
719
884
          }
720
6.95k
          break;
721
0
        }
722
2.46k
        case ArFile::MemberFile::kSymbolTable:
723
2.46k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
2.46k
                            member.contents);
725
2.46k
          break;
726
2.39k
        case ArFile::MemberFile::kLongFilenameTable:
727
2.39k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
2.39k
                            member.contents);
729
2.39k
          break;
730
11.8k
      }
731
11.8k
    }
732
174k
  } else {
733
174k
    ElfFile elf(file.data());
734
174k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
174k
    func(elf, file.filename(), index_base);
739
174k
  }
740
176k
}
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
75.6k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
75.6k
  ArFile ar_file(file.data());
700
75.6k
  uint64_t index_base = 0;
701
702
75.6k
  if (ar_file.IsOpen()) {
703
1.18k
    ArFile::MemberFile member;
704
1.18k
    ArFile::MemberReader reader(ar_file);
705
706
1.18k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
5.48k
    while (reader.ReadMember(&member)) {
709
4.81k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
4.81k
      switch (member.file_type) {
711
2.54k
        case ArFile::MemberFile::kNormal: {
712
2.54k
          ElfFile elf(member.contents);
713
2.54k
          if (elf.IsOpen()) {
714
2.22k
            func(elf, member.filename, index_base);
715
2.22k
            index_base += elf.section_count();
716
2.22k
          } else {
717
316
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
316
                              member.contents);
719
316
          }
720
2.54k
          break;
721
0
        }
722
1.15k
        case ArFile::MemberFile::kSymbolTable:
723
1.15k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
1.15k
                            member.contents);
725
1.15k
          break;
726
1.11k
        case ArFile::MemberFile::kLongFilenameTable:
727
1.11k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
1.11k
                            member.contents);
729
1.11k
          break;
730
4.81k
      }
731
4.81k
    }
732
74.4k
  } else {
733
74.4k
    ElfFile elf(file.data());
734
74.4k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
74.4k
    func(elf, file.filename(), index_base);
739
74.4k
  }
740
75.6k
}
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
422k
void ForEachElf(const InputFile& file, RangeSink* sink, Func func) {
699
422k
  ArFile ar_file(file.data());
700
422k
  uint64_t index_base = 0;
701
702
422k
  if (ar_file.IsOpen()) {
703
11.3k
    ArFile::MemberFile member;
704
11.3k
    ArFile::MemberReader reader(ar_file);
705
706
11.3k
    MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
707
708
65.0k
    while (reader.ReadMember(&member)) {
709
53.7k
      MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
710
53.7k
      switch (member.file_type) {
711
31.8k
        case ArFile::MemberFile::kNormal: {
712
31.8k
          ElfFile elf(member.contents);
713
31.8k
          if (elf.IsOpen()) {
714
27.7k
            func(elf, member.filename, index_base);
715
27.7k
            index_base += elf.section_count();
716
27.7k
          } else {
717
4.07k
            MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
718
4.07k
                              member.contents);
719
4.07k
          }
720
31.8k
          break;
721
0
        }
722
11.1k
        case ArFile::MemberFile::kSymbolTable:
723
11.1k
          MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
724
11.1k
                            member.contents);
725
11.1k
          break;
726
10.8k
        case ArFile::MemberFile::kLongFilenameTable:
727
10.8k
          MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
728
10.8k
                            member.contents);
729
10.8k
          break;
730
53.7k
      }
731
53.7k
    }
732
411k
  } else {
733
411k
    ElfFile elf(file.data());
734
411k
    if (!elf.IsOpen()) {
735
0
      THROWF("Not an ELF or Archive file: $0", file.filename());
736
0
    }
737
738
411k
    func(elf, file.filename(), index_base);
739
411k
  }
740
422k
}
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
48.8M
static uint64_t ToVMAddr(uint64_t addr, uint64_t ndx, bool is_object) {
748
48.8M
  if (is_object) {
749
11.3M
    if (ndx >= 1 << 24) {
750
35
      THROW("ndx overflow: too many sections");
751
35
    }
752
11.3M
    if (addr >= ((uint64_t)1) << 40) {
753
272
      THROW("address overflow: section too big");
754
272
    }
755
11.3M
    return (ndx << 40) | addr;
756
37.5M
  } else {
757
37.5M
    return addr;
758
37.5M
  }
759
48.8M
}
760
761
1.72M
static bool IsArchiveFile(string_view data) {
762
1.72M
  ArFile ar(data);
763
1.72M
  return ar.IsOpen();
764
1.72M
}
765
766
1.72M
static bool IsObjectFile(string_view data) {
767
1.72M
  ElfFile elf(data);
768
1.72M
  return IsArchiveFile(data) || (elf.IsOpen() && elf.header().e_type == ET_REL);
769
1.72M
}
770
771
108k
static void CheckNotObject(const char* source, RangeSink* sink) {
772
108k
  if (IsObjectFile(sink->input_file().data())) {
773
17.9k
    THROWF(
774
17.9k
        "can't use data source '$0' on object files (only binaries and shared "
775
17.9k
        "libraries)",
776
17.9k
        source);
777
17.9k
  }
778
108k
}
779
780
static bool ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
781
180k
                                 cs_mode* mode) {
782
180k
  switch (e_machine) {
783
58.5k
    case EM_386:
784
58.5k
      *arch = CS_ARCH_X86;
785
58.5k
      *mode = CS_MODE_32;
786
58.5k
      return true;
787
87.7k
    case EM_X86_64:
788
87.7k
      *arch = CS_ARCH_X86;
789
87.7k
      *mode = CS_MODE_64;
790
87.7k
      return true;
791
792
    // These aren't tested, but we include them on the off-chance
793
    // that it will work.
794
299
    case EM_ARM:
795
299
      *arch = CS_ARCH_ARM;
796
299
      *mode = CS_MODE_LITTLE_ENDIAN;
797
299
      return true;
798
259
    case EM_AARCH64:
799
259
      *arch = CS_ARCH_ARM64;
800
259
      *mode = CS_MODE_ARM;
801
259
      return true;
802
411
    case EM_MIPS:
803
411
      *arch = CS_ARCH_MIPS;
804
411
      return true;
805
315
    case EM_PPC:
806
315
      *arch = CS_ARCH_PPC;
807
315
      *mode = CS_MODE_32;
808
315
      return true;
809
245
    case EM_PPC64:
810
245
      *arch = CS_ARCH_PPC;
811
245
      *mode = CS_MODE_64;
812
245
      return true;
813
349
    case EM_SPARC:
814
349
      *arch = CS_ARCH_SPARC;
815
349
      *mode = CS_MODE_BIG_ENDIAN;
816
349
      return true;
817
390
    case EM_SPARCV9:
818
390
      *arch = CS_ARCH_SPARC;
819
390
      *mode = CS_MODE_V9;
820
390
      return true;
821
822
32.1k
    default:
823
32.1k
      if (verbose_level > 1) {
824
0
        printf(
825
0
            "Unable to map to capstone target, disassembly will be "
826
0
            "unavailable");
827
0
      }
828
32.1k
      return false;
829
180k
  }
830
180k
}
831
832
176k
static bool ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
833
176k
  bool capstone_available = true;
834
176k
  ForEachElf(file, nullptr,
835
176k
             [&capstone_available, arch, mode](const ElfFile& elf,
836
176k
                                               string_view /*filename*/,
837
180k
                                               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
180k
               capstone_available &=
841
180k
                   ElfMachineToCapstone(elf.header().e_machine, arch, mode);
842
180k
             });
843
176k
  return capstone_available;
844
176k
}
845
846
static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
847
176k
                           SymbolTable* table, bool disassemble) {
848
176k
  bool is_object = IsObjectFile(file.data());
849
176k
  DisassemblyInfo info;
850
176k
  DisassemblyInfo* infop = &info;
851
176k
  bool capstone_available = ReadElfArchMode(file, &info.arch, &info.mode);
852
853
176k
  ForEachElf(
854
176k
      file, sink,
855
180k
      [=](const ElfFile& elf, string_view /*filename*/, uint64_t index_base) {
856
13.9M
        for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
857
13.7M
          ElfFile::Section section;
858
13.7M
          elf.ReadSection(i, &section);
859
860
13.7M
          if (section.header().sh_type != SHT_SYMTAB) {
861
13.5M
            continue;
862
13.5M
          }
863
864
194k
          Elf64_Word symbol_count = section.GetEntryCount();
865
866
          // Find the corresponding section where the strings for the symbol
867
          // table can be found.
868
194k
          ElfFile::Section strtab_section;
869
194k
          elf.ReadSection(section.header().sh_link, &strtab_section);
870
194k
          if (strtab_section.header().sh_type != SHT_STRTAB) {
871
199
            THROW("symtab section pointed to non-strtab section");
872
199
          }
873
874
15.5M
          for (Elf64_Word i = 1; i < symbol_count; i++) {
875
15.3M
            Elf64_Sym sym;
876
877
15.3M
            section.ReadSymbol(i, &sym, nullptr);
878
879
15.3M
            if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION) {
880
3.33M
              continue;
881
3.33M
            }
882
883
12.0M
            if (sym.st_shndx == STN_UNDEF) {
884
2.09M
              continue;
885
2.09M
            }
886
887
9.92M
            if (sym.st_size == 0) {
888
              // Maybe try to refine?  See ReadELFSectionsRefineSymbols below.
889
3.03M
              continue;
890
3.03M
            }
891
892
6.88M
            string_view name = strtab_section.ReadString(sym.st_name);
893
6.88M
            uint64_t full_addr =
894
6.88M
                ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
895
6.88M
            if (sink && !(capstone_available && disassemble)) {
896
4.77M
              sink->AddVMRangeAllowAlias(
897
4.77M
                  "elf_symbols", full_addr, sym.st_size,
898
4.77M
                  ItaniumDemangle(name, sink->data_source()));
899
4.77M
            }
900
6.88M
            if (table) {
901
2.20M
              table->insert(
902
2.20M
                  std::make_pair(name, std::make_pair(full_addr, sym.st_size)));
903
2.20M
            }
904
6.88M
            if (capstone_available && disassemble &&
905
6.88M
                ELF64_ST_TYPE(sym.st_info) == STT_FUNC) {
906
387k
              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
387k
              uint64_t unused;
911
387k
              if (!sink->Translator()->vm_map.Translate(full_addr, &unused)) {
912
17.6k
                WARN("Can't translate VM pointer ($0) to file", full_addr);
913
17.6k
                continue;
914
17.6k
              }
915
369k
              infop->text = sink->TranslateVMToFile(full_addr).substr(0, sym.st_size);
916
369k
              infop->start_address = full_addr;
917
369k
              DisassembleFindReferences(*infop, sink);
918
369k
            }
919
6.88M
          }
920
194k
        }
921
180k
      });
922
176k
}
923
924
static void ReadELFSymbolTableEntries(const ElfFile& elf,
925
                                      const ElfFile::Section& section,
926
                                      uint64_t index_base, bool is_object,
927
82.2k
                                      RangeSink* sink) {
928
82.2k
  Elf64_Word symbol_count = section.GetEntryCount();
929
930
  // Find the corresponding section where the strings for the symbol
931
  // table can be found.
932
82.2k
  ElfFile::Section strtab_section;
933
82.2k
  elf.ReadSection(section.header().sh_link, &strtab_section);
934
82.2k
  if (strtab_section.header().sh_type != SHT_STRTAB) {
935
3.51k
    THROW("symtab section pointed to non-strtab section");
936
3.51k
  }
937
938
2.85M
  for (Elf64_Word i = 1; i < symbol_count; i++) {
939
2.78M
    Elf64_Sym sym;
940
2.78M
    string_view sym_range;
941
2.78M
    section.ReadSymbol(i, &sym, &sym_range);
942
943
2.78M
    if (ELF64_ST_TYPE(sym.st_info) == STT_SECTION ||
944
2.78M
        sym.st_shndx == STN_UNDEF ||
945
2.78M
        sym.st_name == SHN_UNDEF) {
946
1.13M
      continue;
947
1.13M
    }
948
949
1.64M
    string_view name = strtab_section.ReadString(sym.st_name);
950
1.64M
    uint64_t full_addr =
951
1.64M
        ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
952
    // Capture the trailing NULL.
953
1.64M
    name = string_view(name.data(), name.size() + 1);
954
1.64M
    sink->AddFileRangeForVMAddr("elf_symtab_name", full_addr, name);
955
1.64M
    sink->AddFileRangeForVMAddr("elf_symtab_sym", full_addr, sym_range);
956
1.64M
  }
957
78.7k
}
958
959
static void ReadELFRelaEntries(const ElfFile::Section& section,
960
                               uint64_t index_base, bool is_object,
961
45.5k
                               RangeSink* sink) {
962
45.5k
  Elf64_Word rela_count = section.GetEntryCount();
963
45.5k
  Elf64_Word sh_info = section.header().sh_info;
964
17.7M
  for (Elf64_Word i = 1; i < rela_count; i++) {
965
17.7M
    Elf64_Rela rela;
966
17.7M
    string_view rela_range;
967
17.7M
    section.ReadRelocationWithAddend(i, &rela, &rela_range);
968
17.7M
    uint64_t full_addr =
969
17.7M
        ToVMAddr(rela.r_offset, index_base + sh_info, is_object);
970
17.7M
    sink->AddFileRangeForVMAddr("elf_rela", full_addr, rela_range);
971
17.7M
  }
972
45.5k
}
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
76.0k
static void ReadELFTables(const InputFile& file, RangeSink* sink) {
981
76.0k
  bool is_object = IsObjectFile(file.data());
982
983
  // Disassemble first, because sometimes other tables will refer to things we
984
  // discovered through disassembling.
985
76.0k
  ReadELFSymbols(file, sink, nullptr, true);
986
987
  // Now scan other tables.
988
76.0k
  ForEachElf(file, sink,
989
76.0k
             [sink, is_object](const ElfFile& elf, string_view /*filename*/,
990
76.6k
                               uint32_t index_base) {
991
4.37M
               for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
992
4.31M
                 ElfFile::Section section;
993
4.31M
                 elf.ReadSection(i, &section);
994
995
4.31M
                 switch (section.header().sh_type) {
996
30.3k
                   case SHT_SYMTAB:
997
82.2k
                   case SHT_DYNSYM:
998
82.2k
                     ReadELFSymbolTableEntries(elf, section, index_base,
999
82.2k
                                               is_object, sink);
1000
82.2k
                     break;
1001
45.5k
                   case SHT_RELA:
1002
45.5k
                     ReadELFRelaEntries(section, index_base, is_object, sink);
1003
45.5k
                     break;
1004
4.31M
                 }
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
4.29M
                 if (section.GetName() == ".eh_frame") {
1012
29.7k
                   ReadEhFrame(section.contents(), sink);
1013
4.26M
                 } else if (section.GetName() == ".eh_frame_hdr") {
1014
43.0k
                   ReadEhFrameHdr(section.contents(), sink);
1015
43.0k
                 }
1016
4.29M
               }
1017
76.6k
             });
1018
76.0k
}
1019
1020
enum ReportSectionsBy {
1021
  kReportBySectionName,
1022
  kReportByEscapedSectionName,
1023
  kReportByFlags,
1024
  kReportByArchiveMember,
1025
};
1026
1027
298k
static void DoReadELFSections(RangeSink* sink, enum ReportSectionsBy report_by) {
1028
298k
  bool is_object = IsObjectFile(sink->input_file().data());
1029
298k
  ForEachElf(
1030
298k
      sink->input_file(), sink,
1031
321k
      [=](const ElfFile& elf, string_view filename, uint32_t index_base) {
1032
321k
        std::string name_from_flags;
1033
22.8M
        for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1034
22.6M
          ElfFile::Section section;
1035
22.6M
          elf.ReadSection(i, &section);
1036
22.6M
          string_view name = section.GetName();
1037
1038
22.6M
          if (name.size() == 0) {
1039
84.8k
            return;
1040
84.8k
          }
1041
1042
22.5M
          const auto& header = section.header();
1043
22.5M
          auto addr = header.sh_addr;
1044
22.5M
          auto size = header.sh_size;
1045
22.5M
          auto filesize = (header.sh_type == SHT_NOBITS) ? 0 : size;
1046
22.5M
          auto vmsize = (header.sh_flags & SHF_ALLOC) ? size : 0;
1047
1048
22.5M
          string_view contents = StrictSubstr(section.contents(), 0, filesize);
1049
1050
22.5M
          uint64_t full_addr = ToVMAddr(addr, index_base + i, is_object);
1051
1052
22.5M
          if (report_by == kReportByFlags) {
1053
6.59M
            name_from_flags = std::string(name);
1054
1055
6.59M
            name_from_flags = "Section [";
1056
1057
6.59M
            if (header.sh_flags & SHF_ALLOC) {
1058
5.76M
              name_from_flags += 'A';
1059
5.76M
            }
1060
1061
6.59M
            if (header.sh_flags & SHF_WRITE) {
1062
5.18M
              name_from_flags += 'W';
1063
5.18M
            }
1064
1065
6.59M
            if (header.sh_flags & SHF_EXECINSTR) {
1066
5.17M
              name_from_flags += 'X';
1067
5.17M
            }
1068
1069
6.59M
            name_from_flags += ']';
1070
6.59M
            sink->AddRange("elf_section", name_from_flags, full_addr, vmsize,
1071
6.59M
                           contents);
1072
15.9M
          } else if (report_by == kReportBySectionName) {
1073
3.26M
            sink->AddRange("elf_section", name, full_addr, vmsize, contents);
1074
12.7M
          } else if (report_by == kReportByEscapedSectionName) {
1075
9.45M
            sink->AddRange("elf_section",
1076
9.45M
                           std::string("[section ") + std::string(name) + "]",
1077
9.45M
                           full_addr, vmsize, contents);
1078
9.45M
          } else if (report_by == kReportByArchiveMember) {
1079
3.24M
            sink->AddRange("elf_section", filename, full_addr, vmsize,
1080
3.24M
                           contents);
1081
3.24M
          }
1082
22.5M
        }
1083
1084
236k
        if (report_by == kReportByArchiveMember) {
1085
          // Cover unmapped parts of the file.
1086
25.4k
          sink->AddFileRange("unmapped_armember", filename, elf.entire_file());
1087
25.4k
        }
1088
236k
      });
1089
298k
}
1090
1091
enum ReportSegmentsBy {
1092
  kReportBySegmentName,
1093
  kReportByEscapedSegmentName,
1094
};
1095
1096
std::string GetSegmentName(const ElfFile::Segment& segment, Elf64_Xword i,
1097
49.6M
                           ReportSegmentsBy report_by) {
1098
49.6M
  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
49.6M
  std::string name(absl::StrCat("LOAD #", i, " ["));
1114
1115
49.6M
  if (header.p_flags & PF_R) {
1116
8.25M
    name += 'R';
1117
8.25M
  }
1118
1119
49.6M
  if (header.p_flags & PF_W) {
1120
17.1M
    name += 'W';
1121
17.1M
  }
1122
1123
49.6M
  if (header.p_flags & PF_X) {
1124
4.36M
    name += 'X';
1125
4.36M
  }
1126
1127
49.6M
  name += ']';
1128
1129
49.6M
  if (report_by == kReportByEscapedSegmentName) {
1130
31.1M
    return absl::StrCat("[", name, "]");
1131
31.1M
  } else {
1132
18.4M
    return name;
1133
18.4M
  }
1134
49.6M
}
1135
1136
798k
static void DoReadELFSegments(RangeSink* sink, ReportSegmentsBy report_by) {
1137
798k
  ForEachElf(sink->input_file(), sink,
1138
798k
             [=](const ElfFile& elf, string_view /*filename*/,
1139
816k
                 uint32_t /*index_base*/) {
1140
50.4M
               for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1141
49.6M
                 ElfFile::Segment segment;
1142
49.6M
                 elf.ReadSegment(i, &segment);
1143
49.6M
                 std::string name = GetSegmentName(segment, i, report_by);
1144
1145
49.6M
                 if (segment.header().p_type != PT_LOAD) {
1146
44.0M
                   continue;
1147
44.0M
                 }
1148
1149
5.54M
                 sink->AddRange("elf_segment", name, segment.header().p_vaddr,
1150
5.54M
                                segment.header().p_memsz, segment.contents());
1151
5.54M
               }
1152
816k
             });
1153
1154
798k
  ForEachElf(sink->input_file(), sink,
1155
798k
             [=](const ElfFile& elf, string_view /*filename*/,
1156
814k
                 uint32_t /*index_base*/) {
1157
50.4M
               for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1158
49.6M
                 ElfFile::Segment segment;
1159
49.6M
                 elf.ReadSegment(i, &segment);
1160
49.6M
                 const auto& header = segment.header();
1161
49.6M
                 if (header.p_type != PT_TLS) continue;
1162
1.05M
                 std::string name = "TLS";
1163
1.05M
                 sink->AddRange("elf_segment", "TLS", header.p_vaddr,
1164
1.05M
                                header.p_memsz, segment.contents());
1165
1.05M
               }
1166
814k
             });
1167
798k
}
1168
1169
392k
static void ReadELFSegments(RangeSink* sink) {
1170
392k
  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
71.5k
    DoReadELFSections(sink, kReportByFlags);
1178
320k
  } else {
1179
320k
    DoReadELFSegments(sink, kReportBySegmentName);
1180
320k
  }
1181
392k
}
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
88.7k
                       RangeSink *sink) {
1189
88.7k
  ElfFile elf(file.data());
1190
88.7k
  assert(elf.IsOpen());
1191
0
  dwarf->file = &file;
1192
88.7k
  dwarf->open = &ReadDWARFSections;
1193
7.12M
  for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1194
7.04M
    ElfFile::Section section;
1195
7.04M
    elf.ReadSection(i, &section);
1196
7.04M
    string_view name = section.GetName();
1197
7.04M
    string_view contents = section.contents();
1198
7.04M
    uint64_t uncompressed_size = 0;
1199
1200
7.04M
    if (section.header().sh_flags & SHF_COMPRESSED) {
1201
      // Standard ELF section compression, produced when you link with
1202
      //   --compress-debug-sections=zlib-gabi
1203
2.32M
      Elf64_Chdr chdr;
1204
2.32M
      absl::string_view range;
1205
2.32M
      elf.ReadStruct<Elf32_Chdr>(contents, 0, ChdrMunger(), &range, &chdr);
1206
2.32M
      if (chdr.ch_type != ELFCOMPRESS_ZLIB) {
1207
        // Unknown compression format.
1208
2.28M
        continue;
1209
2.28M
      }
1210
39.6k
      uncompressed_size = chdr.ch_size;
1211
39.6k
      contents.remove_prefix(range.size());
1212
39.6k
    }
1213
1214
4.75M
    if (name.find(".debug_") == 0) {
1215
376k
      name.remove_prefix(string_view(".debug_").size());
1216
4.37M
    } 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
4.75M
    static constexpr string_view dwo_str(".dwo");
1227
4.75M
    if (name.size() >= dwo_str.size() &&
1228
4.75M
        name.rfind(".dwo") == name.size() - dwo_str.size()) {
1229
1.27k
      name.remove_suffix(dwo_str.size());
1230
1.27k
    }
1231
1232
4.75M
    if (string_view* member = dwarf->GetFieldByName(name)) {
1233
384k
      if (uncompressed_size) {
1234
20.6k
        *member = sink->ZlibDecompress(contents, uncompressed_size);
1235
363k
      } else {
1236
363k
        *member = section.contents();
1237
363k
      }
1238
384k
    }
1239
4.75M
  }
1240
88.7k
}
1241
1242
480k
void AddCatchAll(RangeSink* sink) {
1243
  // The last-line fallback to make sure we cover the entire VM space.
1244
480k
  if (sink->IsBaseMap() || sink->data_source() != DataSource::kSegments) {
1245
425k
    if (!sink->IsBaseMap()) {
1246
98.3k
      DoReadELFSections(sink, kReportByEscapedSectionName);
1247
98.3k
    }
1248
425k
    ForEachElf(sink->input_file(), sink,
1249
425k
               [sink](const ElfFile& elf, string_view /*filename*/,
1250
439k
                      uint32_t /*index_base*/) {
1251
439k
                 sink->AddFileRange("elf_catchall", "[ELF Header]",
1252
439k
                                    elf.header_region());
1253
439k
                 sink->AddFileRange("elf_catchall", "[ELF Section Headers]",
1254
439k
                                    elf.section_headers());
1255
439k
                 sink->AddFileRange("elf_catchall", "[ELF Program Headers]",
1256
439k
                                    elf.segment_headers());
1257
439k
               });
1258
425k
  }
1259
480k
  DoReadELFSegments(sink, kReportByEscapedSegmentName);
1260
1261
1262
  // The last-line fallback to make sure we cover the entire file.
1263
480k
  sink->AddFileRange("elf_catchall", "[Unmapped]", sink->input_file().data());
1264
480k
}
1265
1266
class ElfObjectFile : public ObjectFile {
1267
 public:
1268
  ElfObjectFile(std::unique_ptr<InputFile> file)
1269
676k
      : ObjectFile(std::move(file)) {}
1270
1271
676k
  std::string GetBuildId() const override {
1272
676k
    if (IsObjectFile(file_data().data())) {
1273
      // Object files don't have a build ID.
1274
125k
      return std::string();
1275
125k
    }
1276
1277
551k
    ElfFile elf(file_data().data());
1278
551k
    assert(elf.IsOpen());
1279
39.4M
    for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1280
39.0M
      ElfFile::Section section;
1281
39.0M
      elf.ReadSection(i, &section);
1282
39.0M
      if (section.header().sh_type != SHT_NOTE) {
1283
38.5M
        continue;
1284
38.5M
      }
1285
1286
830k
      for (ElfFile::NoteIter notes(section); !notes.IsDone(); notes.Next()) {
1287
516k
        if (notes.name() == "GNU" && notes.type() == NT_GNU_BUILD_ID) {
1288
181k
          return std::string(notes.descriptor());
1289
181k
        }
1290
516k
      }
1291
495k
    }
1292
1293
    // No build id section found.
1294
370k
    return std::string();
1295
551k
  }
1296
1297
337k
  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
1298
663k
    for (auto sink : sinks) {
1299
663k
      if (verbose_level > 1) {
1300
0
        printf("Scanning source %d\n", (int)sink->data_source());
1301
0
      }
1302
663k
      switch (sink->data_source()) {
1303
392k
        case DataSource::kSegments:
1304
392k
          ReadELFSegments(sink);
1305
392k
          break;
1306
54.9k
        case DataSource::kSections:
1307
54.9k
          DoReadELFSections(sink, kReportBySectionName);
1308
54.9k
          break;
1309
0
        case DataSource::kRawSymbols:
1310
54.9k
        case DataSource::kShortSymbols:
1311
54.9k
        case DataSource::kFullSymbols:
1312
54.9k
          ReadELFSymbols(debug_file().file_data(), sink, nullptr, false);
1313
54.9k
          break;
1314
53.3k
        case DataSource::kArchiveMembers:
1315
53.3k
          DoReadELFSections(sink, kReportByArchiveMember);
1316
53.3k
          break;
1317
54.9k
        case DataSource::kCompileUnits: {
1318
54.9k
          CheckNotObject("compileunits", sink);
1319
54.9k
          SymbolTable symtab;
1320
54.9k
          DualMap symbol_map;
1321
54.9k
          NameMunger empty_munger;
1322
54.9k
          RangeSink symbol_sink(&debug_file().file_data(),
1323
54.9k
                                sink->options(),
1324
54.9k
                                DataSource::kRawSymbols,
1325
54.9k
                                &sinks[0]->MapAtIndex(0), nullptr);
1326
54.9k
          symbol_sink.AddOutput(&symbol_map, &empty_munger);
1327
54.9k
          ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab,
1328
54.9k
                         false);
1329
54.9k
          dwarf::File dwarf;
1330
54.9k
          ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1331
54.9k
          ReadDWARFCompileUnits(dwarf, symbol_map, sink);
1332
54.9k
          break;
1333
54.9k
        }
1334
53.6k
        case DataSource::kInlines: {
1335
53.6k
          CheckNotObject("lineinfo", sink);
1336
53.6k
          dwarf::File dwarf;
1337
53.6k
          ReadDWARFSections(debug_file().file_data(), &dwarf, sink);
1338
53.6k
          ReadDWARFInlines(dwarf, sink, true);
1339
53.6k
          DoReadELFSections(sink, kReportByEscapedSectionName);
1340
53.6k
          break;
1341
54.9k
        }
1342
0
        default:
1343
0
          THROW("unknown data source");
1344
663k
      }
1345
1346
533k
      switch (sink->data_source()) {
1347
381k
        case DataSource::kSegments:
1348
420k
        case DataSource::kSections:
1349
457k
        case DataSource::kArchiveMembers:
1350
457k
          break;
1351
76.0k
        default:
1352
          // Add these *after* processing all other data sources.
1353
76.0k
          ReadELFTables(sink->input_file(), sink);
1354
76.0k
          break;
1355
533k
      }
1356
1357
480k
      AddCatchAll(sink);
1358
480k
    }
1359
337k
  }
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.25M
std::unique_ptr<ObjectFile> TryOpenELFFile(std::unique_ptr<InputFile>& file) {
1418
1.25M
  ElfFile elf(file->data());
1419
1.25M
  ArFile ar(file->data());
1420
1.25M
  if (elf.IsOpen() || ar.IsOpen()) {
1421
676k
    return std::unique_ptr<ObjectFile>(new ElfObjectFile(std::move(file)));
1422
676k
  } else {
1423
580k
    return nullptr;
1424
580k
  }
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