1// Copyright (c) 2012, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "common/linux/elfutils.h"
31
32#include <assert.h>
33#include <string.h>
34
35#include "common/linux/linux_libc_support.h"
36#include "common/linux/elfutils-inl.h"
37
38namespace google_breakpad {
39
40namespace {
41
42template<typename ElfClass>
43void FindElfClassSection(const char* elf_base,
44 const char* section_name,
45 typename ElfClass::Word section_type,
46 const void** section_start,
47 size_t* section_size) {
48 typedef typename ElfClass::Ehdr Ehdr;
49 typedef typename ElfClass::Shdr Shdr;
50
51 assert(elf_base);
52 assert(section_start);
53 assert(section_size);
54
55 assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
56
57 const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
58 assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
59
60 if (elf_header->e_shoff == 0) {
61 *section_start = NULL;
62 *section_size = 0;
63 return;
64 }
65
66 const Shdr* sections =
67 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
68 const Shdr* section_names = sections + elf_header->e_shstrndx;
69 const char* names =
70 GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
71 const char* names_end = names + section_names->sh_size;
72
73 const Shdr* section =
74 FindElfSectionByName<ElfClass>(section_name, section_type,
75 sections, names, names_end,
76 elf_header->e_shnum);
77
78 if (section != NULL && section->sh_size > 0) {
79 *section_start = elf_base + section->sh_offset;
80 *section_size = section->sh_size;
81 }
82}
83
84template<typename ElfClass>
85void FindElfClassSegment(const char* elf_base,
86 typename ElfClass::Word segment_type,
87 wasteful_vector<ElfSegment>* segments) {
88 typedef typename ElfClass::Ehdr Ehdr;
89 typedef typename ElfClass::Phdr Phdr;
90
91 assert(elf_base);
92 assert(segments);
93
94 assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
95
96 const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
97 assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
98
99 const Phdr* phdrs =
100 GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff);
101
102 for (int i = 0; i < elf_header->e_phnum; ++i) {
103 if (phdrs[i].p_type == segment_type) {
104 ElfSegment seg = {};
105 seg.start = elf_base + phdrs[i].p_offset;
106 seg.size = phdrs[i].p_filesz;
107 segments->push_back(seg);
108 }
109 }
110}
111
112} // namespace
113
114bool IsValidElf(const void* elf_base) {
115 return my_strncmp(reinterpret_cast<const char*>(elf_base),
116 ELFMAG, SELFMAG) == 0;
117}
118
119int ElfClass(const void* elf_base) {
120 const ElfW(Ehdr)* elf_header =
121 reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
122
123 return elf_header->e_ident[EI_CLASS];
124}
125
126bool FindElfSection(const void* elf_mapped_base,
127 const char* section_name,
128 uint32_t section_type,
129 const void** section_start,
130 size_t* section_size) {
131 assert(elf_mapped_base);
132 assert(section_start);
133 assert(section_size);
134
135 *section_start = NULL;
136 *section_size = 0;
137
138 if (!IsValidElf(elf_mapped_base))
139 return false;
140
141 int cls = ElfClass(elf_mapped_base);
142 const char* elf_base =
143 static_cast<const char*>(elf_mapped_base);
144
145 if (cls == ELFCLASS32) {
146 FindElfClassSection<ElfClass32>(elf_base, section_name, section_type,
147 section_start, section_size);
148 return *section_start != NULL;
149 } else if (cls == ELFCLASS64) {
150 FindElfClassSection<ElfClass64>(elf_base, section_name, section_type,
151 section_start, section_size);
152 return *section_start != NULL;
153 }
154
155 return false;
156}
157
158bool FindElfSegments(const void* elf_mapped_base,
159 uint32_t segment_type,
160 wasteful_vector<ElfSegment>* segments) {
161 assert(elf_mapped_base);
162 assert(segments);
163
164 if (!IsValidElf(elf_mapped_base))
165 return false;
166
167 int cls = ElfClass(elf_mapped_base);
168 const char* elf_base =
169 static_cast<const char*>(elf_mapped_base);
170
171 if (cls == ELFCLASS32) {
172 FindElfClassSegment<ElfClass32>(elf_base, segment_type, segments);
173 return true;
174 } else if (cls == ELFCLASS64) {
175 FindElfClassSegment<ElfClass64>(elf_base, segment_type, segments);
176 return true;
177 }
178
179 return false;
180}
181
182template <typename ElfClass>
183bool FindElfSoNameFromDynamicSection(const void* section_start,
184 size_t section_size,
185 const void* dynstr_start,
186 size_t dynstr_size,
187 char* soname,
188 size_t soname_size) {
189 typedef typename ElfClass::Dyn Dyn;
190
191 auto* dynamic = static_cast<const Dyn*>(section_start);
192 size_t dcount = section_size / sizeof(Dyn);
193 for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
194 if (dyn->d_tag == DT_SONAME) {
195 const char* dynstr = static_cast<const char*>(dynstr_start);
196 if (dyn->d_un.d_val >= dynstr_size) {
197 // Beyond the end of the dynstr section
198 return false;
199 }
200 const char* str = dynstr + dyn->d_un.d_val;
201 const size_t maxsize = dynstr_size - dyn->d_un.d_val;
202 my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
203 return true;
204 }
205 }
206
207 return false;
208}
209
210bool ElfFileSoNameFromMappedFile(const void* elf_base,
211 char* soname,
212 size_t soname_size) {
213 if (!IsValidElf(elf_base)) {
214 // Not ELF
215 return false;
216 }
217
218 const void* segment_start;
219 size_t segment_size;
220 if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start,
221 &segment_size)) {
222 // No dynamic section
223 return false;
224 }
225
226 const void* dynstr_start;
227 size_t dynstr_size;
228 if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start,
229 &dynstr_size)) {
230 // No dynstr section
231 return false;
232 }
233
234 int cls = ElfClass(elf_base);
235 return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection<ElfClass32>(
236 segment_start, segment_size, dynstr_start,
237 dynstr_size, soname, soname_size)
238 : FindElfSoNameFromDynamicSection<ElfClass64>(
239 segment_start, segment_size, dynstr_start,
240 dynstr_size, soname, soname_size);
241}
242
243} // namespace google_breakpad
244