Coverage Report

Created: 2025-12-31 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/perfetto/buildtools/android-unwinding/libunwindstack/ElfInterface.cpp
Line
Count
Source
1
/*
2
 * Copyright (C) 2017 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <elf.h>
18
#include <stdint.h>
19
20
#include <memory>
21
#include <string>
22
#include <utility>
23
24
#include <zlib.h>
25
#include <zstd.h>
26
27
#include <unwindstack/DwarfError.h>
28
#include <unwindstack/DwarfSection.h>
29
#include <unwindstack/ElfInterface.h>
30
#include <unwindstack/Log.h>
31
#include <unwindstack/Memory.h>
32
#include <unwindstack/Regs.h>
33
34
#include "DwarfDebugFrame.h"
35
#include "DwarfEhFrame.h"
36
#include "DwarfEhFrameWithHdr.h"
37
#include "MemoryBuffer.h"
38
#include "MemoryXz.h"
39
#include "Symbols.h"
40
41
namespace unwindstack {
42
43
1.71k
ElfInterface::~ElfInterface() {
44
8.76k
  for (auto symbol : symbols_) {
45
8.76k
    delete symbol;
46
8.76k
  }
47
1.71k
}
48
49
0
bool ElfInterface::IsValidPc(uint64_t pc) {
50
0
  if (!pt_loads_.empty()) {
51
0
    for (auto& entry : pt_loads_) {
52
0
      uint64_t start = entry.second.table_offset;
53
0
      uint64_t end = start + entry.second.table_size;
54
0
      if (pc >= start && pc < end) {
55
0
        return true;
56
0
      }
57
0
    }
58
0
    return false;
59
0
  }
60
61
  // No PT_LOAD data, look for a fde for this pc in the section data.
62
0
  if (debug_frame_ != nullptr && debug_frame_->GetFdeFromPc(pc) != nullptr) {
63
0
    return true;
64
0
  }
65
66
0
  if (eh_frame_ != nullptr && eh_frame_->GetFdeFromPc(pc) != nullptr) {
67
0
    return true;
68
0
  }
69
70
0
  return false;
71
0
}
72
73
0
bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
74
0
  if (text_size_ != 0) {
75
0
    *addr = text_addr_;
76
0
    *size = text_size_;
77
0
    return true;
78
0
  }
79
0
  return false;
80
0
}
81
82
81
std::shared_ptr<Memory> ElfInterface::CreateGnuDebugdataMemory() {
83
81
  if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
84
0
    return nullptr;
85
0
  }
86
87
81
  auto decompressed = std::make_shared<MemoryXz>(memory_.get(), gnu_debugdata_offset_,
88
81
                                                 gnu_debugdata_size_, GetSoname());
89
81
  if (!decompressed || !decompressed->Init()) {
90
81
    gnu_debugdata_offset_ = 0;
91
81
    gnu_debugdata_size_ = 0;
92
81
    return nullptr;
93
81
  }
94
0
  return decompressed;
95
81
}
96
97
0
static bool ZlibDecompress(uint8_t* compressed_data, size_t compressed_size, MemoryBuffer* memory) {
98
0
  z_stream stream;
99
0
  stream.zalloc = Z_NULL;
100
0
  stream.zfree = Z_NULL;
101
0
  stream.opaque = Z_NULL;
102
0
  if (inflateInit(&stream) != Z_OK) {
103
0
    return false;
104
0
  }
105
0
  stream.next_in = compressed_data;
106
0
  stream.avail_in = compressed_size;
107
0
  stream.next_out = memory->Data();
108
0
  stream.avail_out = memory->Size();
109
0
  int ret = inflate(&stream, Z_FINISH);
110
0
  if (inflateEnd(&stream) != Z_OK) {
111
0
    return false;
112
0
  }
113
0
  return ret == Z_STREAM_END;
114
0
}
115
116
5
static bool ZstdDecompress(uint8_t* compressed_data, size_t compressed_size, MemoryBuffer* memory) {
117
5
  size_t decompress_size =
118
5
      ZSTD_decompress(memory->Data(), memory->Size(), compressed_data, compressed_size);
119
5
  return memory->Size() == decompress_size;
120
5
}
121
122
template <typename ChdrType>
123
std::shared_ptr<Memory> CreateMemoryFromCompressedSection(SectionInfo& info,
124
8
                                                          std::shared_ptr<Memory>& elf_memory) {
125
8
  if (info.size < sizeof(ChdrType)) {
126
0
    return nullptr;
127
0
  }
128
129
8
  uint8_t* compressed_data = elf_memory->GetPtr(info.offset);
130
8
  std::vector<uint8_t> compressed;
131
8
  if (compressed_data == nullptr || elf_memory->GetPtr(info.offset + info.size - 1) == nullptr) {
132
8
    compressed.resize(info.size);
133
8
    if (!elf_memory->ReadFully(info.offset, compressed.data(), info.size)) {
134
3
      return nullptr;
135
3
    }
136
5
    compressed_data = compressed.data();
137
5
  }
138
139
5
  ChdrType* chdr = reinterpret_cast<ChdrType*>(compressed_data);
140
5
  std::shared_ptr<MemoryBuffer> memory(new MemoryBuffer(chdr->ch_size, info.offset));
141
142
5
  bool ret = false;
143
5
  if (chdr->ch_type == ELFCOMPRESS_ZLIB) {
144
0
    ret = ZlibDecompress(&compressed_data[sizeof(ChdrType)], info.size - sizeof(ChdrType),
145
0
                         memory.get());
146
5
  } else if (chdr->ch_type == ELFCOMPRESS_ZSTD) {
147
5
    ret = ZstdDecompress(&compressed_data[sizeof(ChdrType)], info.size - sizeof(ChdrType),
148
5
                         memory.get());
149
5
  }
150
5
  if (!ret) {
151
5
    return nullptr;
152
5
  }
153
  // Set the section info to match the uncompressed section data.
154
0
  info.size = chdr->ch_size;
155
0
  info.flags &= ~SHF_COMPRESSED;
156
0
  return memory;
157
5
}
std::__1::shared_ptr<unwindstack::Memory> unwindstack::CreateMemoryFromCompressedSection<Elf32_Chdr>(unwindstack::SectionInfo&, std::__1::shared_ptr<unwindstack::Memory>&)
Line
Count
Source
124
8
                                                          std::shared_ptr<Memory>& elf_memory) {
125
8
  if (info.size < sizeof(ChdrType)) {
126
0
    return nullptr;
127
0
  }
128
129
8
  uint8_t* compressed_data = elf_memory->GetPtr(info.offset);
130
8
  std::vector<uint8_t> compressed;
131
8
  if (compressed_data == nullptr || elf_memory->GetPtr(info.offset + info.size - 1) == nullptr) {
132
8
    compressed.resize(info.size);
133
8
    if (!elf_memory->ReadFully(info.offset, compressed.data(), info.size)) {
134
3
      return nullptr;
135
3
    }
136
5
    compressed_data = compressed.data();
137
5
  }
138
139
5
  ChdrType* chdr = reinterpret_cast<ChdrType*>(compressed_data);
140
5
  std::shared_ptr<MemoryBuffer> memory(new MemoryBuffer(chdr->ch_size, info.offset));
141
142
5
  bool ret = false;
143
5
  if (chdr->ch_type == ELFCOMPRESS_ZLIB) {
144
0
    ret = ZlibDecompress(&compressed_data[sizeof(ChdrType)], info.size - sizeof(ChdrType),
145
0
                         memory.get());
146
5
  } else if (chdr->ch_type == ELFCOMPRESS_ZSTD) {
147
5
    ret = ZstdDecompress(&compressed_data[sizeof(ChdrType)], info.size - sizeof(ChdrType),
148
5
                         memory.get());
149
5
  }
150
5
  if (!ret) {
151
5
    return nullptr;
152
5
  }
153
  // Set the section info to match the uncompressed section data.
154
0
  info.size = chdr->ch_size;
155
  info.flags &= ~SHF_COMPRESSED;
156
0
  return memory;
157
5
}
Unexecuted instantiation: std::__1::shared_ptr<unwindstack::Memory> unwindstack::CreateMemoryFromCompressedSection<Elf64_Chdr>(unwindstack::SectionInfo&, std::__1::shared_ptr<unwindstack::Memory>&)
158
159
template <typename ElfTypes>
160
1.71k
void ElfInterfaceImpl<ElfTypes>::InitHeaders() {
161
1.71k
  if (eh_frame_hdr_info_.offset != 0) {
162
159
    DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
163
159
    eh_frame_.reset(eh_frame_hdr);
164
159
    if (!eh_frame_hdr->EhFrameInit(eh_frame_info_) || !eh_frame_->Init(eh_frame_hdr_info_)) {
165
25
      eh_frame_hdr_info_ = {};
166
25
      eh_frame_.reset(nullptr);
167
25
    }
168
159
  }
169
170
1.71k
  if (eh_frame_.get() == nullptr && eh_frame_info_.offset != 0) {
171
    // If there is an eh_frame section without an eh_frame_hdr section,
172
    // or using the frame hdr object failed to init.
173
768
    eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
174
768
    if (!eh_frame_->Init(eh_frame_info_)) {
175
16
      eh_frame_info_ = {};
176
16
      eh_frame_.reset(nullptr);
177
16
    }
178
768
  }
179
180
1.71k
  if (debug_frame_info_.offset != 0) {
181
20
    std::shared_ptr<Memory> debug_memory = memory_;
182
20
    if (debug_frame_info_.flags & SHF_COMPRESSED) {
183
8
      debug_memory = CreateMemoryFromCompressedSection<ChdrType>(debug_frame_info_, memory_);
184
8
    }
185
20
    debug_frame_.reset(new DwarfDebugFrame<AddressType>(debug_memory));
186
20
    if (!debug_frame_->Init(debug_frame_info_)) {
187
8
      debug_frame_.reset(nullptr);
188
8
      debug_frame_info_ = {};
189
8
    }
190
20
  }
191
1.71k
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::InitHeaders()
Line
Count
Source
160
24
void ElfInterfaceImpl<ElfTypes>::InitHeaders() {
161
24
  if (eh_frame_hdr_info_.offset != 0) {
162
0
    DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
163
0
    eh_frame_.reset(eh_frame_hdr);
164
0
    if (!eh_frame_hdr->EhFrameInit(eh_frame_info_) || !eh_frame_->Init(eh_frame_hdr_info_)) {
165
0
      eh_frame_hdr_info_ = {};
166
0
      eh_frame_.reset(nullptr);
167
0
    }
168
0
  }
169
170
24
  if (eh_frame_.get() == nullptr && eh_frame_info_.offset != 0) {
171
    // If there is an eh_frame section without an eh_frame_hdr section,
172
    // or using the frame hdr object failed to init.
173
0
    eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
174
0
    if (!eh_frame_->Init(eh_frame_info_)) {
175
0
      eh_frame_info_ = {};
176
0
      eh_frame_.reset(nullptr);
177
0
    }
178
0
  }
179
180
24
  if (debug_frame_info_.offset != 0) {
181
9
    std::shared_ptr<Memory> debug_memory = memory_;
182
9
    if (debug_frame_info_.flags & SHF_COMPRESSED) {
183
8
      debug_memory = CreateMemoryFromCompressedSection<ChdrType>(debug_frame_info_, memory_);
184
8
    }
185
9
    debug_frame_.reset(new DwarfDebugFrame<AddressType>(debug_memory));
186
9
    if (!debug_frame_->Init(debug_frame_info_)) {
187
8
      debug_frame_.reset(nullptr);
188
8
      debug_frame_info_ = {};
189
8
    }
190
9
  }
191
24
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::InitHeaders()
Line
Count
Source
160
1.68k
void ElfInterfaceImpl<ElfTypes>::InitHeaders() {
161
1.68k
  if (eh_frame_hdr_info_.offset != 0) {
162
159
    DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
163
159
    eh_frame_.reset(eh_frame_hdr);
164
159
    if (!eh_frame_hdr->EhFrameInit(eh_frame_info_) || !eh_frame_->Init(eh_frame_hdr_info_)) {
165
25
      eh_frame_hdr_info_ = {};
166
25
      eh_frame_.reset(nullptr);
167
25
    }
168
159
  }
169
170
1.68k
  if (eh_frame_.get() == nullptr && eh_frame_info_.offset != 0) {
171
    // If there is an eh_frame section without an eh_frame_hdr section,
172
    // or using the frame hdr object failed to init.
173
768
    eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
174
768
    if (!eh_frame_->Init(eh_frame_info_)) {
175
16
      eh_frame_info_ = {};
176
16
      eh_frame_.reset(nullptr);
177
16
    }
178
768
  }
179
180
1.68k
  if (debug_frame_info_.offset != 0) {
181
11
    std::shared_ptr<Memory> debug_memory = memory_;
182
11
    if (debug_frame_info_.flags & SHF_COMPRESSED) {
183
0
      debug_memory = CreateMemoryFromCompressedSection<ChdrType>(debug_frame_info_, memory_);
184
0
    }
185
11
    debug_frame_.reset(new DwarfDebugFrame<AddressType>(debug_memory));
186
11
    if (!debug_frame_->Init(debug_frame_info_)) {
187
0
      debug_frame_.reset(nullptr);
188
0
      debug_frame_info_ = {};
189
0
    }
190
11
  }
191
1.68k
}
192
193
template <typename ElfTypes>
194
1.71k
bool ElfInterfaceImpl<ElfTypes>::ReadAllHeaders(int64_t* load_bias) {
195
1.71k
  EhdrType ehdr;
196
1.71k
  if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
197
0
    last_error_.code = ERROR_MEMORY_INVALID;
198
0
    last_error_.address = 0;
199
0
    return false;
200
0
  }
201
202
  // If we have enough information that this is an elf file, then allow
203
  // malformed program and section headers.
204
1.71k
  ReadProgramHeaders(ehdr, load_bias);
205
1.71k
  ReadSectionHeaders(ehdr);
206
1.71k
  return true;
207
1.71k
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::ReadAllHeaders(long*)
Line
Count
Source
194
24
bool ElfInterfaceImpl<ElfTypes>::ReadAllHeaders(int64_t* load_bias) {
195
24
  EhdrType ehdr;
196
24
  if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
197
0
    last_error_.code = ERROR_MEMORY_INVALID;
198
0
    last_error_.address = 0;
199
0
    return false;
200
0
  }
201
202
  // If we have enough information that this is an elf file, then allow
203
  // malformed program and section headers.
204
24
  ReadProgramHeaders(ehdr, load_bias);
205
24
  ReadSectionHeaders(ehdr);
206
24
  return true;
207
24
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::ReadAllHeaders(long*)
Line
Count
Source
194
1.68k
bool ElfInterfaceImpl<ElfTypes>::ReadAllHeaders(int64_t* load_bias) {
195
1.68k
  EhdrType ehdr;
196
1.68k
  if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
197
0
    last_error_.code = ERROR_MEMORY_INVALID;
198
0
    last_error_.address = 0;
199
0
    return false;
200
0
  }
201
202
  // If we have enough information that this is an elf file, then allow
203
  // malformed program and section headers.
204
1.68k
  ReadProgramHeaders(ehdr, load_bias);
205
1.68k
  ReadSectionHeaders(ehdr);
206
1.68k
  return true;
207
1.68k
}
208
209
template <typename EhdrType, typename PhdrType>
210
0
int64_t ElfInterface::GetLoadBias(Memory* memory) {
211
0
  EhdrType ehdr;
212
0
  if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
213
0
    return false;
214
0
  }
215
216
0
  uint64_t offset = ehdr.e_phoff;
217
0
  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
218
0
    PhdrType phdr;
219
0
    if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
220
0
      return 0;
221
0
    }
222
223
    // Find the first executable load when looking for the load bias.
224
0
    if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
225
0
      return static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
226
0
    }
227
0
  }
228
0
  return 0;
229
0
}
Unexecuted instantiation: long unwindstack::ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(unwindstack::Memory*)
Unexecuted instantiation: long unwindstack::ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(unwindstack::Memory*)
230
231
template <typename ElfTypes>
232
1.71k
void ElfInterfaceImpl<ElfTypes>::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
233
1.71k
  uint64_t offset = ehdr.e_phoff;
234
1.71k
  bool first_exec_load_header = true;
235
427k
  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
236
427k
    PhdrType phdr;
237
427k
    if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
238
1.70k
      return;
239
1.70k
    }
240
241
426k
    switch (phdr.p_type) {
242
4.04k
    case PT_LOAD:
243
4.04k
    {
244
4.04k
      if ((phdr.p_flags & PF_X) == 0) {
245
2.43k
        continue;
246
2.43k
      }
247
248
1.61k
      pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
249
1.61k
                                          static_cast<size_t>(phdr.p_memsz)};
250
      // Only set the load bias from the first executable load header.
251
1.61k
      if (first_exec_load_header) {
252
171
        *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
253
171
      }
254
1.61k
      first_exec_load_header = false;
255
1.61k
      break;
256
4.04k
    }
257
258
483
    case PT_GNU_EH_FRAME:
259
      // This is really the pointer to the .eh_frame_hdr section.
260
483
      eh_frame_hdr_info_ = {
261
483
          .offset = phdr.p_offset,
262
483
          .size = phdr.p_memsz,
263
483
          .flags = phdr.p_flags,
264
483
          .bias = static_cast<int64_t>(static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset)};
265
483
      break;
266
267
1.00k
    case PT_DYNAMIC:
268
1.00k
      dynamic_offset_ = phdr.p_offset;
269
1.00k
      dynamic_vaddr_start_ = phdr.p_vaddr;
270
1.00k
      if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
271
122
        dynamic_offset_ = 0;
272
122
        dynamic_vaddr_start_ = 0;
273
122
        dynamic_vaddr_end_ = 0;
274
122
      }
275
1.00k
      break;
276
277
420k
    default:
278
420k
      HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
279
420k
      break;
280
426k
    }
281
426k
  }
282
1.71k
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::ReadProgramHeaders(Elf32_Ehdr const&, long*)
Line
Count
Source
232
24
void ElfInterfaceImpl<ElfTypes>::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
233
24
  uint64_t offset = ehdr.e_phoff;
234
24
  bool first_exec_load_header = true;
235
7.08k
  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
236
7.07k
    PhdrType phdr;
237
7.07k
    if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
238
21
      return;
239
21
    }
240
241
7.05k
    switch (phdr.p_type) {
242
305
    case PT_LOAD:
243
305
    {
244
305
      if ((phdr.p_flags & PF_X) == 0) {
245
82
        continue;
246
82
      }
247
248
223
      pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
249
223
                                          static_cast<size_t>(phdr.p_memsz)};
250
      // Only set the load bias from the first executable load header.
251
223
      if (first_exec_load_header) {
252
5
        *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
253
5
      }
254
223
      first_exec_load_header = false;
255
223
      break;
256
305
    }
257
258
0
    case PT_GNU_EH_FRAME:
259
      // This is really the pointer to the .eh_frame_hdr section.
260
0
      eh_frame_hdr_info_ = {
261
0
          .offset = phdr.p_offset,
262
0
          .size = phdr.p_memsz,
263
0
          .flags = phdr.p_flags,
264
0
          .bias = static_cast<int64_t>(static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset)};
265
0
      break;
266
267
59
    case PT_DYNAMIC:
268
59
      dynamic_offset_ = phdr.p_offset;
269
59
      dynamic_vaddr_start_ = phdr.p_vaddr;
270
59
      if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
271
0
        dynamic_offset_ = 0;
272
0
        dynamic_vaddr_start_ = 0;
273
0
        dynamic_vaddr_end_ = 0;
274
0
      }
275
59
      break;
276
277
6.69k
    default:
278
6.69k
      HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
279
6.69k
      break;
280
7.05k
    }
281
7.05k
  }
282
24
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::ReadProgramHeaders(Elf64_Ehdr const&, long*)
Line
Count
Source
232
1.68k
void ElfInterfaceImpl<ElfTypes>::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
233
1.68k
  uint64_t offset = ehdr.e_phoff;
234
1.68k
  bool first_exec_load_header = true;
235
420k
  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
236
420k
    PhdrType phdr;
237
420k
    if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
238
1.68k
      return;
239
1.68k
    }
240
241
419k
    switch (phdr.p_type) {
242
3.74k
    case PT_LOAD:
243
3.74k
    {
244
3.74k
      if ((phdr.p_flags & PF_X) == 0) {
245
2.35k
        continue;
246
2.35k
      }
247
248
1.39k
      pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
249
1.39k
                                          static_cast<size_t>(phdr.p_memsz)};
250
      // Only set the load bias from the first executable load header.
251
1.39k
      if (first_exec_load_header) {
252
166
        *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
253
166
      }
254
1.39k
      first_exec_load_header = false;
255
1.39k
      break;
256
3.74k
    }
257
258
483
    case PT_GNU_EH_FRAME:
259
      // This is really the pointer to the .eh_frame_hdr section.
260
483
      eh_frame_hdr_info_ = {
261
483
          .offset = phdr.p_offset,
262
483
          .size = phdr.p_memsz,
263
483
          .flags = phdr.p_flags,
264
483
          .bias = static_cast<int64_t>(static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset)};
265
483
      break;
266
267
949
    case PT_DYNAMIC:
268
949
      dynamic_offset_ = phdr.p_offset;
269
949
      dynamic_vaddr_start_ = phdr.p_vaddr;
270
949
      if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
271
122
        dynamic_offset_ = 0;
272
122
        dynamic_vaddr_start_ = 0;
273
122
        dynamic_vaddr_end_ = 0;
274
122
      }
275
949
      break;
276
277
413k
    default:
278
413k
      HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
279
413k
      break;
280
419k
    }
281
419k
  }
282
1.68k
}
283
284
template <typename ElfTypes>
285
1.20k
std::string ElfInterfaceImpl<ElfTypes>::ReadBuildID() {
286
  // Ensure there is no overflow in any of the calulations below.
287
1.20k
  uint64_t tmp;
288
1.20k
  if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) {
289
1
    return "";
290
1
  }
291
292
1.20k
  uint64_t offset = 0;
293
1.33k
  while (offset < gnu_build_id_size_) {
294
137
    if (gnu_build_id_size_ - offset < sizeof(NhdrType)) {
295
0
      return "";
296
0
    }
297
137
    NhdrType hdr;
298
137
    if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) {
299
3
      return "";
300
3
    }
301
134
    offset += sizeof(hdr);
302
303
134
    if (gnu_build_id_size_ - offset < hdr.n_namesz) {
304
0
      return "";
305
0
    }
306
134
    if (hdr.n_namesz > 0) {
307
109
      std::string name(hdr.n_namesz, '\0');
308
109
      if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) {
309
6
        return "";
310
6
      }
311
312
      // Trim trailing \0 as GNU is stored as a C string in the ELF file.
313
103
      if (name.back() == '\0')
314
95
        name.resize(name.size() - 1);
315
316
      // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
317
103
      offset += (hdr.n_namesz + 3) & ~3;
318
319
103
      if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
320
0
        if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
321
0
          return "";
322
0
        }
323
0
        std::string build_id(hdr.n_descsz, '\0');
324
0
        if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) {
325
0
          return build_id;
326
0
        }
327
0
        return "";
328
0
      }
329
103
    }
330
    // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
331
128
    offset += (hdr.n_descsz + 3) & ~3;
332
128
  }
333
1.19k
  return "";
334
1.20k
}
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::ReadBuildID()
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::ReadBuildID()
Line
Count
Source
285
1.20k
std::string ElfInterfaceImpl<ElfTypes>::ReadBuildID() {
286
  // Ensure there is no overflow in any of the calulations below.
287
1.20k
  uint64_t tmp;
288
1.20k
  if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) {
289
1
    return "";
290
1
  }
291
292
1.20k
  uint64_t offset = 0;
293
1.33k
  while (offset < gnu_build_id_size_) {
294
137
    if (gnu_build_id_size_ - offset < sizeof(NhdrType)) {
295
0
      return "";
296
0
    }
297
137
    NhdrType hdr;
298
137
    if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) {
299
3
      return "";
300
3
    }
301
134
    offset += sizeof(hdr);
302
303
134
    if (gnu_build_id_size_ - offset < hdr.n_namesz) {
304
0
      return "";
305
0
    }
306
134
    if (hdr.n_namesz > 0) {
307
109
      std::string name(hdr.n_namesz, '\0');
308
109
      if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) {
309
6
        return "";
310
6
      }
311
312
      // Trim trailing \0 as GNU is stored as a C string in the ELF file.
313
103
      if (name.back() == '\0')
314
95
        name.resize(name.size() - 1);
315
316
      // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
317
103
      offset += (hdr.n_namesz + 3) & ~3;
318
319
103
      if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
320
0
        if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
321
0
          return "";
322
0
        }
323
0
        std::string build_id(hdr.n_descsz, '\0');
324
0
        if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) {
325
0
          return build_id;
326
0
        }
327
0
        return "";
328
0
      }
329
103
    }
330
    // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
331
128
    offset += (hdr.n_descsz + 3) & ~3;
332
128
  }
333
1.19k
  return "";
334
1.20k
}
335
template <typename ElfTypes>
336
1.71k
void ElfInterfaceImpl<ElfTypes>::ReadSectionHeaders(const EhdrType& ehdr) {
337
1.71k
  uint64_t offset = ehdr.e_shoff;
338
1.71k
  uint64_t sec_offset = 0;
339
1.71k
  uint64_t sec_size = 0;
340
341
  // Get the location of the section header names.
342
  // If something is malformed in the header table data, we aren't going
343
  // to terminate, we'll simply ignore this part.
344
1.71k
  ShdrType shdr;
345
1.71k
  if (ehdr.e_shstrndx < ehdr.e_shnum) {
346
1.61k
    uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
347
1.61k
    if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
348
1.56k
      sec_offset = shdr.sh_offset;
349
1.56k
      sec_size = shdr.sh_size;
350
1.56k
    }
351
1.61k
  }
352
353
  // Skip the first header, it's always going to be NULL.
354
1.71k
  offset += ehdr.e_shentsize;
355
4.22M
  for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
356
4.22M
    if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
357
1.63k
      return;
358
1.63k
    }
359
360
4.22M
    if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
361
      // Need to go get the information about the section that contains
362
      // the string terminated names.
363
20.6k
      ShdrType str_shdr;
364
20.6k
      if (shdr.sh_link >= ehdr.e_shnum) {
365
8.19k
        continue;
366
8.19k
      }
367
12.4k
      uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
368
12.4k
      if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
369
676
        continue;
370
676
      }
371
11.7k
      if (str_shdr.sh_type != SHT_STRTAB) {
372
3.00k
        continue;
373
3.00k
      }
374
8.76k
      symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
375
8.76k
                                     str_shdr.sh_offset, str_shdr.sh_size));
376
4.19M
    } else if ((shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) && sec_size != 0) {
377
      // Look for the .debug_frame and .gnu_debugdata.
378
59.6k
      if (shdr.sh_name < sec_size) {
379
54.6k
        std::string name;
380
54.6k
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) {
381
16.0k
          if (name == ".debug_frame") {
382
320
            debug_frame_info_ = {
383
320
                .offset = shdr.sh_offset,
384
320
                .size = shdr.sh_size,
385
320
                .flags = shdr.sh_flags,
386
320
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
387
15.7k
          } else if (name == ".gnu_debugdata") {
388
431
            gnu_debugdata_offset_ = shdr.sh_offset;
389
431
            gnu_debugdata_size_ = shdr.sh_size;
390
15.2k
          } else if (name == ".eh_frame") {
391
7.06k
            eh_frame_info_ = {
392
7.06k
                .offset = shdr.sh_offset,
393
7.06k
                .size = shdr.sh_size,
394
7.06k
                .flags = shdr.sh_flags,
395
7.06k
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
396
8.22k
          } else if (eh_frame_hdr_info_.offset == 0 && name == ".eh_frame_hdr") {
397
76
            eh_frame_hdr_info_ = {
398
76
                .offset = shdr.sh_offset,
399
76
                .size = shdr.sh_size,
400
76
                .flags = shdr.sh_flags,
401
76
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
402
8.14k
          } else if (name == ".data") {
403
322
            data_offset_ = shdr.sh_offset;
404
322
            data_vaddr_start_ = shdr.sh_addr;
405
322
            if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
406
104
              data_offset_ = 0;
407
104
              data_vaddr_start_ = 0;
408
104
              data_vaddr_end_ = 0;
409
104
            }
410
7.82k
          } else if (name == ".text") {
411
16
            text_addr_ = shdr.sh_addr;
412
16
            text_size_ = shdr.sh_size;
413
16
          }
414
16.0k
        }
415
54.6k
      }
416
4.14M
    } else if (shdr.sh_type == SHT_STRTAB) {
417
      // In order to read soname, keep track of address to offset mapping.
418
15.2k
      strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
419
15.2k
                                                            static_cast<uint64_t>(shdr.sh_offset)));
420
4.12M
    } else if (shdr.sh_type == SHT_NOTE) {
421
7.46k
      if (shdr.sh_name < sec_size) {
422
7.25k
        std::string name;
423
7.25k
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
424
4.92k
            name == ".note.gnu.build-id") {
425
243
          gnu_build_id_offset_ = shdr.sh_offset;
426
243
          gnu_build_id_size_ = shdr.sh_size;
427
243
        }
428
7.25k
      }
429
7.46k
    }
430
4.22M
  }
431
1.71k
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::ReadSectionHeaders(Elf32_Ehdr const&)
Line
Count
Source
336
24
void ElfInterfaceImpl<ElfTypes>::ReadSectionHeaders(const EhdrType& ehdr) {
337
24
  uint64_t offset = ehdr.e_shoff;
338
24
  uint64_t sec_offset = 0;
339
24
  uint64_t sec_size = 0;
340
341
  // Get the location of the section header names.
342
  // If something is malformed in the header table data, we aren't going
343
  // to terminate, we'll simply ignore this part.
344
24
  ShdrType shdr;
345
24
  if (ehdr.e_shstrndx < ehdr.e_shnum) {
346
23
    uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
347
23
    if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
348
23
      sec_offset = shdr.sh_offset;
349
23
      sec_size = shdr.sh_size;
350
23
    }
351
23
  }
352
353
  // Skip the first header, it's always going to be NULL.
354
24
  offset += ehdr.e_shentsize;
355
26.2k
  for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
356
26.2k
    if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
357
24
      return;
358
24
    }
359
360
26.2k
    if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
361
      // Need to go get the information about the section that contains
362
      // the string terminated names.
363
323
      ShdrType str_shdr;
364
323
      if (shdr.sh_link >= ehdr.e_shnum) {
365
60
        continue;
366
60
      }
367
263
      uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
368
263
      if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
369
182
        continue;
370
182
      }
371
81
      if (str_shdr.sh_type != SHT_STRTAB) {
372
81
        continue;
373
81
      }
374
0
      symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
375
0
                                     str_shdr.sh_offset, str_shdr.sh_size));
376
25.9k
    } else if ((shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) && sec_size != 0) {
377
      // Look for the .debug_frame and .gnu_debugdata.
378
432
      if (shdr.sh_name < sec_size) {
379
343
        std::string name;
380
343
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) {
381
308
          if (name == ".debug_frame") {
382
9
            debug_frame_info_ = {
383
9
                .offset = shdr.sh_offset,
384
9
                .size = shdr.sh_size,
385
9
                .flags = shdr.sh_flags,
386
9
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
387
299
          } else if (name == ".gnu_debugdata") {
388
18
            gnu_debugdata_offset_ = shdr.sh_offset;
389
18
            gnu_debugdata_size_ = shdr.sh_size;
390
281
          } else if (name == ".eh_frame") {
391
0
            eh_frame_info_ = {
392
0
                .offset = shdr.sh_offset,
393
0
                .size = shdr.sh_size,
394
0
                .flags = shdr.sh_flags,
395
0
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
396
281
          } else if (eh_frame_hdr_info_.offset == 0 && name == ".eh_frame_hdr") {
397
0
            eh_frame_hdr_info_ = {
398
0
                .offset = shdr.sh_offset,
399
0
                .size = shdr.sh_size,
400
0
                .flags = shdr.sh_flags,
401
0
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
402
281
          } else if (name == ".data") {
403
128
            data_offset_ = shdr.sh_offset;
404
128
            data_vaddr_start_ = shdr.sh_addr;
405
128
            if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
406
0
              data_offset_ = 0;
407
0
              data_vaddr_start_ = 0;
408
0
              data_vaddr_end_ = 0;
409
0
            }
410
153
          } else if (name == ".text") {
411
0
            text_addr_ = shdr.sh_addr;
412
0
            text_size_ = shdr.sh_size;
413
0
          }
414
308
        }
415
343
      }
416
25.5k
    } else if (shdr.sh_type == SHT_STRTAB) {
417
      // In order to read soname, keep track of address to offset mapping.
418
90
      strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
419
90
                                                            static_cast<uint64_t>(shdr.sh_offset)));
420
25.4k
    } else if (shdr.sh_type == SHT_NOTE) {
421
146
      if (shdr.sh_name < sec_size) {
422
137
        std::string name;
423
137
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
424
129
            name == ".note.gnu.build-id") {
425
0
          gnu_build_id_offset_ = shdr.sh_offset;
426
0
          gnu_build_id_size_ = shdr.sh_size;
427
0
        }
428
137
      }
429
146
    }
430
26.2k
  }
431
24
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::ReadSectionHeaders(Elf64_Ehdr const&)
Line
Count
Source
336
1.68k
void ElfInterfaceImpl<ElfTypes>::ReadSectionHeaders(const EhdrType& ehdr) {
337
1.68k
  uint64_t offset = ehdr.e_shoff;
338
1.68k
  uint64_t sec_offset = 0;
339
1.68k
  uint64_t sec_size = 0;
340
341
  // Get the location of the section header names.
342
  // If something is malformed in the header table data, we aren't going
343
  // to terminate, we'll simply ignore this part.
344
1.68k
  ShdrType shdr;
345
1.68k
  if (ehdr.e_shstrndx < ehdr.e_shnum) {
346
1.58k
    uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
347
1.58k
    if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
348
1.54k
      sec_offset = shdr.sh_offset;
349
1.54k
      sec_size = shdr.sh_size;
350
1.54k
    }
351
1.58k
  }
352
353
  // Skip the first header, it's always going to be NULL.
354
1.68k
  offset += ehdr.e_shentsize;
355
4.19M
  for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
356
4.19M
    if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
357
1.60k
      return;
358
1.60k
    }
359
360
4.19M
    if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
361
      // Need to go get the information about the section that contains
362
      // the string terminated names.
363
20.3k
      ShdrType str_shdr;
364
20.3k
      if (shdr.sh_link >= ehdr.e_shnum) {
365
8.13k
        continue;
366
8.13k
      }
367
12.1k
      uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
368
12.1k
      if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
369
494
        continue;
370
494
      }
371
11.6k
      if (str_shdr.sh_type != SHT_STRTAB) {
372
2.92k
        continue;
373
2.92k
      }
374
8.76k
      symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
375
8.76k
                                     str_shdr.sh_offset, str_shdr.sh_size));
376
4.17M
    } else if ((shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) && sec_size != 0) {
377
      // Look for the .debug_frame and .gnu_debugdata.
378
59.1k
      if (shdr.sh_name < sec_size) {
379
54.3k
        std::string name;
380
54.3k
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) {
381
15.7k
          if (name == ".debug_frame") {
382
311
            debug_frame_info_ = {
383
311
                .offset = shdr.sh_offset,
384
311
                .size = shdr.sh_size,
385
311
                .flags = shdr.sh_flags,
386
311
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
387
15.4k
          } else if (name == ".gnu_debugdata") {
388
413
            gnu_debugdata_offset_ = shdr.sh_offset;
389
413
            gnu_debugdata_size_ = shdr.sh_size;
390
15.0k
          } else if (name == ".eh_frame") {
391
7.06k
            eh_frame_info_ = {
392
7.06k
                .offset = shdr.sh_offset,
393
7.06k
                .size = shdr.sh_size,
394
7.06k
                .flags = shdr.sh_flags,
395
7.06k
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
396
7.94k
          } else if (eh_frame_hdr_info_.offset == 0 && name == ".eh_frame_hdr") {
397
76
            eh_frame_hdr_info_ = {
398
76
                .offset = shdr.sh_offset,
399
76
                .size = shdr.sh_size,
400
76
                .flags = shdr.sh_flags,
401
76
                .bias = static_cast<int64_t>(static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset)};
402
7.86k
          } else if (name == ".data") {
403
194
            data_offset_ = shdr.sh_offset;
404
194
            data_vaddr_start_ = shdr.sh_addr;
405
194
            if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
406
104
              data_offset_ = 0;
407
104
              data_vaddr_start_ = 0;
408
104
              data_vaddr_end_ = 0;
409
104
            }
410
7.67k
          } else if (name == ".text") {
411
16
            text_addr_ = shdr.sh_addr;
412
16
            text_size_ = shdr.sh_size;
413
16
          }
414
15.7k
        }
415
54.3k
      }
416
4.11M
    } else if (shdr.sh_type == SHT_STRTAB) {
417
      // In order to read soname, keep track of address to offset mapping.
418
15.1k
      strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
419
15.1k
                                                            static_cast<uint64_t>(shdr.sh_offset)));
420
4.09M
    } else if (shdr.sh_type == SHT_NOTE) {
421
7.31k
      if (shdr.sh_name < sec_size) {
422
7.11k
        std::string name;
423
7.11k
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
424
4.79k
            name == ".note.gnu.build-id") {
425
243
          gnu_build_id_offset_ = shdr.sh_offset;
426
243
          gnu_build_id_size_ = shdr.sh_size;
427
243
        }
428
7.11k
      }
429
7.31k
    }
430
4.19M
  }
431
1.68k
}
432
433
template <typename ElfTypes>
434
81
std::string ElfInterfaceImpl<ElfTypes>::GetSoname() {
435
81
  if (soname_type_ == SONAME_INVALID) {
436
0
    return "";
437
0
  }
438
81
  if (soname_type_ == SONAME_VALID) {
439
0
    return soname_;
440
0
  }
441
442
81
  soname_type_ = SONAME_INVALID;
443
444
81
  uint64_t soname_offset = 0;
445
81
  uint64_t strtab_addr = 0;
446
81
  uint64_t strtab_size = 0;
447
448
  // Find the soname location from the dynamic headers section.
449
81
  DynType dyn;
450
81
  uint64_t offset = dynamic_offset_;
451
81
  uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
452
3.01k
  for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
453
2.98k
    if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
454
23
      last_error_.code = ERROR_MEMORY_INVALID;
455
23
      last_error_.address = offset;
456
23
      return "";
457
23
    }
458
459
2.96k
    if (dyn.d_tag == DT_STRTAB) {
460
28
      strtab_addr = dyn.d_un.d_ptr;
461
2.93k
    } else if (dyn.d_tag == DT_STRSZ) {
462
3
      strtab_size = dyn.d_un.d_val;
463
2.92k
    } else if (dyn.d_tag == DT_SONAME) {
464
4
      soname_offset = dyn.d_un.d_val;
465
2.92k
    } else if (dyn.d_tag == DT_NULL) {
466
24
      break;
467
24
    }
468
2.96k
  }
469
470
  // Need to map the strtab address to the real offset.
471
641
  for (const auto& entry : strtabs_) {
472
641
    if (entry.first == strtab_addr) {
473
4
      soname_offset = entry.second + soname_offset;
474
4
      uint64_t soname_max = entry.second + strtab_size;
475
4
      if (soname_offset >= soname_max) {
476
1
        return "";
477
1
      }
478
3
      if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
479
0
        return "";
480
0
      }
481
3
      soname_type_ = SONAME_VALID;
482
3
      return soname_;
483
3
    }
484
641
  }
485
54
  return "";
486
58
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::GetSoname()
Line
Count
Source
434
9
std::string ElfInterfaceImpl<ElfTypes>::GetSoname() {
435
9
  if (soname_type_ == SONAME_INVALID) {
436
0
    return "";
437
0
  }
438
9
  if (soname_type_ == SONAME_VALID) {
439
0
    return soname_;
440
0
  }
441
442
9
  soname_type_ = SONAME_INVALID;
443
444
9
  uint64_t soname_offset = 0;
445
9
  uint64_t strtab_addr = 0;
446
9
  uint64_t strtab_size = 0;
447
448
  // Find the soname location from the dynamic headers section.
449
9
  DynType dyn;
450
9
  uint64_t offset = dynamic_offset_;
451
9
  uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
452
79
  for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
453
75
    if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
454
1
      last_error_.code = ERROR_MEMORY_INVALID;
455
1
      last_error_.address = offset;
456
1
      return "";
457
1
    }
458
459
74
    if (dyn.d_tag == DT_STRTAB) {
460
0
      strtab_addr = dyn.d_un.d_ptr;
461
74
    } else if (dyn.d_tag == DT_STRSZ) {
462
3
      strtab_size = dyn.d_un.d_val;
463
71
    } else if (dyn.d_tag == DT_SONAME) {
464
2
      soname_offset = dyn.d_un.d_val;
465
69
    } else if (dyn.d_tag == DT_NULL) {
466
4
      break;
467
4
    }
468
74
  }
469
470
  // Need to map the strtab address to the real offset.
471
16
  for (const auto& entry : strtabs_) {
472
16
    if (entry.first == strtab_addr) {
473
4
      soname_offset = entry.second + soname_offset;
474
4
      uint64_t soname_max = entry.second + strtab_size;
475
4
      if (soname_offset >= soname_max) {
476
1
        return "";
477
1
      }
478
3
      if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
479
0
        return "";
480
0
      }
481
3
      soname_type_ = SONAME_VALID;
482
3
      return soname_;
483
3
    }
484
16
  }
485
4
  return "";
486
8
}
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::GetSoname()
Line
Count
Source
434
72
std::string ElfInterfaceImpl<ElfTypes>::GetSoname() {
435
72
  if (soname_type_ == SONAME_INVALID) {
436
0
    return "";
437
0
  }
438
72
  if (soname_type_ == SONAME_VALID) {
439
0
    return soname_;
440
0
  }
441
442
72
  soname_type_ = SONAME_INVALID;
443
444
72
  uint64_t soname_offset = 0;
445
72
  uint64_t strtab_addr = 0;
446
72
  uint64_t strtab_size = 0;
447
448
  // Find the soname location from the dynamic headers section.
449
72
  DynType dyn;
450
72
  uint64_t offset = dynamic_offset_;
451
72
  uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
452
2.93k
  for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
453
2.90k
    if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
454
22
      last_error_.code = ERROR_MEMORY_INVALID;
455
22
      last_error_.address = offset;
456
22
      return "";
457
22
    }
458
459
2.88k
    if (dyn.d_tag == DT_STRTAB) {
460
28
      strtab_addr = dyn.d_un.d_ptr;
461
2.85k
    } else if (dyn.d_tag == DT_STRSZ) {
462
0
      strtab_size = dyn.d_un.d_val;
463
2.85k
    } else if (dyn.d_tag == DT_SONAME) {
464
2
      soname_offset = dyn.d_un.d_val;
465
2.85k
    } else if (dyn.d_tag == DT_NULL) {
466
20
      break;
467
20
    }
468
2.88k
  }
469
470
  // Need to map the strtab address to the real offset.
471
625
  for (const auto& entry : strtabs_) {
472
625
    if (entry.first == strtab_addr) {
473
0
      soname_offset = entry.second + soname_offset;
474
0
      uint64_t soname_max = entry.second + strtab_size;
475
0
      if (soname_offset >= soname_max) {
476
0
        return "";
477
0
      }
478
0
      if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
479
0
        return "";
480
0
      }
481
0
      soname_type_ = SONAME_VALID;
482
0
      return soname_;
483
0
    }
484
625
  }
485
50
  return "";
486
50
}
487
488
template <typename ElfTypes>
489
bool ElfInterfaceImpl<ElfTypes>::GetFunctionName(uint64_t addr, SharedString* name,
490
1.74k
                                                 uint64_t* func_offset) {
491
1.74k
  if (symbols_.empty()) {
492
1.07k
    return false;
493
1.07k
  }
494
495
9.32k
  for (const auto symbol : symbols_) {
496
9.32k
    if (symbol->template GetName<SymType>(addr, memory_.get(), name, func_offset)) {
497
2
      return true;
498
2
    }
499
9.32k
  }
500
670
  return false;
501
672
}
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::GetFunctionName(unsigned long, unwindstack::SharedString*, unsigned long*)
unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::GetFunctionName(unsigned long, unwindstack::SharedString*, unsigned long*)
Line
Count
Source
490
1.74k
                                                 uint64_t* func_offset) {
491
1.74k
  if (symbols_.empty()) {
492
1.07k
    return false;
493
1.07k
  }
494
495
9.32k
  for (const auto symbol : symbols_) {
496
9.32k
    if (symbol->template GetName<SymType>(addr, memory_.get(), name, func_offset)) {
497
2
      return true;
498
2
    }
499
9.32k
  }
500
670
  return false;
501
672
}
502
503
template <typename ElfTypes>
504
bool ElfInterfaceImpl<ElfTypes>::GetGlobalVariable(const std::string& name,
505
0
                                                   uint64_t* memory_address) {
506
0
  if (symbols_.empty()) {
507
0
    return false;
508
0
  }
509
510
0
  for (const auto symbol : symbols_) {
511
0
    if (symbol->template GetGlobal<SymType>(memory_.get(), name, memory_address)) {
512
0
      return true;
513
0
    }
514
0
  }
515
0
  return false;
516
0
}
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::GetGlobalVariable(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long*)
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::GetGlobalVariable(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long*)
517
518
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
519
1.74k
                        bool* is_signal_frame) {
520
1.74k
  last_error_.code = ERROR_NONE;
521
1.74k
  last_error_.address = 0;
522
523
  // Try the debug_frame first since it contains the most specific unwind
524
  // information.
525
1.74k
  DwarfSection* debug_frame = debug_frame_.get();
526
1.74k
  if (debug_frame != nullptr &&
527
11
      debug_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
528
0
    return true;
529
0
  }
530
531
  // Try the eh_frame next.
532
1.74k
  DwarfSection* eh_frame = eh_frame_.get();
533
1.74k
  if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
534
241
    return true;
535
241
  }
536
537
1.50k
  if (gnu_debugdata_interface_ != nullptr &&
538
0
      gnu_debugdata_interface_->Step(pc, regs, process_memory, finished, is_signal_frame)) {
539
0
    return true;
540
0
  }
541
542
  // Set the error code based on the first error encountered.
543
1.50k
  DwarfSection* section = nullptr;
544
1.50k
  if (debug_frame_ != nullptr) {
545
11
    section = debug_frame_.get();
546
1.49k
  } else if (eh_frame_ != nullptr) {
547
664
    section = eh_frame_.get();
548
826
  } else if (gnu_debugdata_interface_ != nullptr) {
549
0
    last_error_ = gnu_debugdata_interface_->last_error();
550
0
    return false;
551
826
  } else {
552
826
    return false;
553
826
  }
554
555
  // Convert the DWARF ERROR to an external error.
556
675
  DwarfErrorCode code = section->LastErrorCode();
557
675
  switch (code) {
558
0
    case DWARF_ERROR_NONE:
559
0
      last_error_.code = ERROR_NONE;
560
0
      break;
561
562
28
    case DWARF_ERROR_MEMORY_INVALID:
563
28
      last_error_.code = ERROR_MEMORY_INVALID;
564
28
      last_error_.address = section->LastErrorAddress();
565
28
      break;
566
567
92
    case DWARF_ERROR_ILLEGAL_VALUE:
568
560
    case DWARF_ERROR_ILLEGAL_STATE:
569
563
    case DWARF_ERROR_STACK_INDEX_NOT_VALID:
570
563
    case DWARF_ERROR_TOO_MANY_ITERATIONS:
571
647
    case DWARF_ERROR_CFA_NOT_DEFINED:
572
647
    case DWARF_ERROR_NO_FDES:
573
647
      last_error_.code = ERROR_UNWIND_INFO;
574
647
      break;
575
576
0
    case DWARF_ERROR_NOT_IMPLEMENTED:
577
0
    case DWARF_ERROR_UNSUPPORTED_VERSION:
578
0
      last_error_.code = ERROR_UNSUPPORTED;
579
0
      break;
580
675
  }
581
675
  return false;
582
675
}
583
584
// This is an estimation of the size of the elf file using the location
585
// of the section headers and size. This assumes that the section headers
586
// are at the end of the elf file. If the elf has a load bias, the size
587
// will be too large, but this is acceptable.
588
template <typename ElfTypes>
589
0
void ElfInterfaceImpl<ElfTypes>::GetMaxSize(Memory* memory, uint64_t* size) {
590
0
  EhdrType ehdr;
591
0
  if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
592
0
    *size = 0;
593
0
    return;
594
0
  }
595
596
  // If this winds up as zero, the PT_LOAD reading will get a better value.
597
0
  uint64_t elf_size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
598
599
  // Search through the PT_LOAD values and if any result in a larger elf
600
  // size, use that.
601
0
  uint64_t offset = ehdr.e_phoff;
602
0
  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
603
0
    PhdrType phdr;
604
0
    if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
605
0
      break;
606
0
    }
607
0
    if (phdr.p_type == PT_LOAD) {
608
0
      uint64_t end_offset;
609
0
      if (__builtin_add_overflow(phdr.p_offset, phdr.p_memsz, &end_offset)) {
610
0
        continue;
611
0
      }
612
0
      if (end_offset > elf_size) {
613
0
        elf_size = end_offset;
614
0
      }
615
0
    }
616
0
  }
617
618
0
  *size = elf_size;
619
0
}
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes32>::GetMaxSize(unwindstack::Memory*, unsigned long*)
Unexecuted instantiation: unwindstack::ElfInterfaceImpl<unwindstack::ElfTypes64>::GetMaxSize(unwindstack::Memory*, unsigned long*)
620
621
template <typename EhdrType, typename ShdrType>
622
0
bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_id_size) {
623
0
  EhdrType ehdr;
624
0
  if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
625
0
    return false;
626
0
  }
627
628
0
  uint64_t offset = ehdr.e_shoff;
629
0
  uint64_t sec_offset;
630
0
  uint64_t sec_size;
631
0
  ShdrType shdr;
632
0
  if (ehdr.e_shstrndx >= ehdr.e_shnum) {
633
0
    return false;
634
0
  }
635
636
0
  uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
637
0
  if (!memory->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
638
0
    return false;
639
0
  }
640
0
  sec_offset = shdr.sh_offset;
641
0
  sec_size = shdr.sh_size;
642
643
  // Skip the first header, it's always going to be NULL.
644
0
  offset += ehdr.e_shentsize;
645
0
  for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
646
0
    if (!memory->ReadFully(offset, &shdr, sizeof(shdr))) {
647
0
      return false;
648
0
    }
649
0
    std::string name;
650
0
    if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size &&
651
0
        memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
652
0
        name == ".note.gnu.build-id") {
653
0
      *build_id_offset = shdr.sh_offset;
654
0
      *build_id_size = shdr.sh_size;
655
0
      return true;
656
0
    }
657
0
  }
658
659
0
  return false;
660
0
}
Unexecuted instantiation: bool unwindstack::GetBuildIDInfo<Elf32_Ehdr, Elf32_Shdr>(unwindstack::Memory*, unsigned long*, unsigned long*)
Unexecuted instantiation: bool unwindstack::GetBuildIDInfo<Elf64_Ehdr, Elf64_Shdr>(unwindstack::Memory*, unsigned long*, unsigned long*)
661
662
template <typename EhdrType, typename ShdrType, typename NhdrType>
663
0
std::string ElfInterface::ReadBuildIDFromMemory(Memory* memory) {
664
0
  uint64_t note_offset;
665
0
  uint64_t note_size;
666
0
  if (!GetBuildIDInfo<EhdrType, ShdrType>(memory, &note_offset, &note_size)) {
667
0
    return "";
668
0
  }
669
670
  // Ensure there is no overflow in any of the calculations below.
671
0
  uint64_t tmp;
672
0
  if (__builtin_add_overflow(note_offset, note_size, &tmp)) {
673
0
    return "";
674
0
  }
675
676
0
  uint64_t offset = 0;
677
0
  while (offset < note_size) {
678
0
    if (note_size - offset < sizeof(NhdrType)) {
679
0
      return "";
680
0
    }
681
0
    NhdrType hdr;
682
0
    if (!memory->ReadFully(note_offset + offset, &hdr, sizeof(hdr))) {
683
0
      return "";
684
0
    }
685
0
    offset += sizeof(hdr);
686
687
0
    if (note_size - offset < hdr.n_namesz) {
688
0
      return "";
689
0
    }
690
0
    if (hdr.n_namesz > 0) {
691
0
      std::string name(hdr.n_namesz, '\0');
692
0
      if (!memory->ReadFully(note_offset + offset, &(name[0]), hdr.n_namesz)) {
693
0
        return "";
694
0
      }
695
696
      // Trim trailing \0 as GNU is stored as a C string in the ELF file.
697
0
      if (name.back() == '\0') name.resize(name.size() - 1);
698
699
      // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
700
0
      offset += (hdr.n_namesz + 3) & ~3;
701
702
0
      if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
703
0
        if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) {
704
0
          return "";
705
0
        }
706
0
        std::string build_id(hdr.n_descsz, '\0');
707
0
        if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) {
708
0
          return build_id;
709
0
        }
710
0
        return "";
711
0
      }
712
0
    }
713
    // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
714
0
    offset += (hdr.n_descsz + 3) & ~3;
715
0
  }
716
0
  return "";
717
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > unwindstack::ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(unwindstack::Memory*)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > unwindstack::ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(unwindstack::Memory*)
718
719
// Instantiate all of the needed template functions.
720
template class ElfInterfaceImpl<ElfTypes32>;
721
template class ElfInterfaceImpl<ElfTypes64>;
722
723
template int64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
724
template int64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
725
726
template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(
727
    Memory*);
728
template std::string ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(
729
    Memory*);
730
731
}  // namespace unwindstack