xref: /aosp_15_r20/external/google-breakpad/src/common/linux/elfutils.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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