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