xref: /aosp_15_r20/external/google-breakpad/src/common/linux/elf_core_dump.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2011 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 // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump.
30 // See elf_core_dump.h for details.
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>  // Must come first
34 #endif
35 
36 #include "common/linux/elf_core_dump.h"
37 
38 #include <stddef.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 namespace google_breakpad {
43 
44 // Implementation of ElfCoreDump::Note.
45 
Note()46 ElfCoreDump::Note::Note() {}
47 
Note(const MemoryRange & content)48 ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {}
49 
IsValid() const50 bool ElfCoreDump::Note::IsValid() const {
51   return GetHeader() != NULL;
52 }
53 
GetHeader() const54 const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const {
55   return content_.GetData<Nhdr>(0);
56 }
57 
GetType() const58 ElfCoreDump::Word ElfCoreDump::Note::GetType() const {
59   const Nhdr* header = GetHeader();
60   // 0 is not being used as a NOTE type.
61   return header ? header->n_type : 0;
62 }
63 
GetName() const64 MemoryRange ElfCoreDump::Note::GetName() const {
65   const Nhdr* header = GetHeader();
66   if (header) {
67       return content_.Subrange(sizeof(Nhdr), header->n_namesz);
68   }
69   return MemoryRange();
70 }
71 
GetDescription() const72 MemoryRange ElfCoreDump::Note::GetDescription() const {
73   const Nhdr* header = GetHeader();
74   if (header) {
75     return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz),
76                              header->n_descsz);
77   }
78   return MemoryRange();
79 }
80 
GetNextNote() const81 ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const {
82   MemoryRange next_content;
83   const Nhdr* header = GetHeader();
84   if (header) {
85     size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz);
86     next_offset = AlignedSize(next_offset + header->n_descsz);
87     next_content =
88         content_.Subrange(next_offset, content_.length() - next_offset);
89   }
90   return Note(next_content);
91 }
92 
93 // static
AlignedSize(size_t size)94 size_t ElfCoreDump::Note::AlignedSize(size_t size) {
95   size_t mask = sizeof(Word) - 1;
96   return (size + mask) & ~mask;
97 }
98 
99 
100 // Implementation of ElfCoreDump.
101 
ElfCoreDump()102 ElfCoreDump::ElfCoreDump() : proc_mem_fd_(-1) {}
103 
ElfCoreDump(const MemoryRange & content)104 ElfCoreDump::ElfCoreDump(const MemoryRange& content)
105     : content_(content), proc_mem_fd_(-1) {}
106 
~ElfCoreDump()107 ElfCoreDump::~ElfCoreDump() {
108   if (proc_mem_fd_ != -1) {
109     close(proc_mem_fd_);
110     proc_mem_fd_ = -1;
111   }
112 }
113 
SetContent(const MemoryRange & content)114 void ElfCoreDump::SetContent(const MemoryRange& content) {
115   content_ = content;
116 }
117 
SetProcMem(int fd)118 void ElfCoreDump::SetProcMem(int fd) {
119   if (proc_mem_fd_ != -1) {
120     close(proc_mem_fd_);
121   }
122   proc_mem_fd_ = fd;
123 }
124 
IsValid() const125 bool ElfCoreDump::IsValid() const {
126   const Ehdr* header = GetHeader();
127   return (header &&
128           header->e_ident[0] == ELFMAG0 &&
129           header->e_ident[1] == ELFMAG1 &&
130           header->e_ident[2] == ELFMAG2 &&
131           header->e_ident[3] == ELFMAG3 &&
132           header->e_ident[4] == kClass &&
133           header->e_version == EV_CURRENT &&
134           header->e_type == ET_CORE);
135 }
136 
GetHeader() const137 const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const {
138   return content_.GetData<Ehdr>(0);
139 }
140 
GetProgramHeader(unsigned index) const141 const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const {
142   const Ehdr* header = GetHeader();
143   if (header) {
144     return reinterpret_cast<const Phdr*>(content_.GetArrayElement(
145         header->e_phoff, header->e_phentsize, index));
146   }
147   return NULL;
148 }
149 
GetFirstProgramHeaderOfType(Word type) const150 const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType(
151     Word type) const {
152   for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
153     const Phdr* program = GetProgramHeader(i);
154     if (program->p_type == type) {
155       return program;
156     }
157   }
158   return NULL;
159 }
160 
GetProgramHeaderCount() const161 unsigned ElfCoreDump::GetProgramHeaderCount() const {
162   const Ehdr* header = GetHeader();
163   return header ? header->e_phnum : 0;
164 }
165 
CopyData(void * buffer,Addr virtual_address,size_t length)166 bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
167   for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
168     const Phdr* program = GetProgramHeader(i);
169     if (program->p_type != PT_LOAD)
170       continue;
171 
172     size_t offset_in_segment = virtual_address - program->p_vaddr;
173     if (virtual_address >= program->p_vaddr &&
174         offset_in_segment < program->p_filesz) {
175       const void* data =
176           content_.GetData(program->p_offset + offset_in_segment, length);
177       if (data) {
178         memcpy(buffer, data, length);
179         return true;
180       }
181     }
182   }
183 
184   /* fallback: if available, read from /proc/<pid>/mem */
185   if (proc_mem_fd_ != -1) {
186     off_t offset = virtual_address;
187     ssize_t r = pread(proc_mem_fd_, buffer, length, offset);
188     if (r < ssize_t(length)) {
189       return false;
190     }
191     return true;
192   }
193   return false;
194 }
195 
GetFirstNote() const196 ElfCoreDump::Note ElfCoreDump::GetFirstNote() const {
197   MemoryRange note_content;
198   const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE);
199   if (program_header) {
200     note_content = content_.Subrange(program_header->p_offset,
201                                      program_header->p_filesz);
202   }
203   return Note(note_content);
204 }
205 
206 }  // namespace google_breakpad
207