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