Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: breakpad/linux/linux_dumper.cc

Issue 147032: Add linux-gate.so to the minidump mappings list by checking for the load addr.... Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « breakpad/linux/linux_dumper.h ('k') | breakpad/linux/linux_dumper_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009, Google Inc. 1 // Copyright (c) 2009, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 bool LinuxDumper::ThreadsResume() { 103 bool LinuxDumper::ThreadsResume() {
104 if (!threads_suspened_) 104 if (!threads_suspened_)
105 return false; 105 return false;
106 bool good = true; 106 bool good = true;
107 for (size_t i = 0; i < threads_.size(); ++i) 107 for (size_t i = 0; i < threads_.size(); ++i)
108 good &= ResumeThread(threads_[i]); 108 good &= ResumeThread(threads_[i]);
109 threads_suspened_ = false; 109 threads_suspened_ = false;
110 return good; 110 return good;
111 } 111 }
112 112
113 void
114 LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
115 assert(path);
116 if (!path) {
117 return;
118 }
119
120 path[0] = '\0';
121
122 const unsigned pid_len = my_int_len(pid);
123
124 assert(node);
125 if (!node) {
126 return;
127 }
128
129 size_t node_len = my_strlen(node);
130 assert(node_len < NAME_MAX);
131 if (node_len >= NAME_MAX) {
132 return;
133 }
134
135 assert(node_len > 0);
136 if (node_len == 0) {
137 return;
138 }
139
140 assert(pid > 0);
141 if (pid <= 0) {
142 return;
143 }
144
145 const size_t total_length = 6 + pid_len + 1 + node_len;
146
147 assert(total_length < NAME_MAX);
148 if (total_length >= NAME_MAX) {
149 return;
150 }
151
152 memcpy(path, "/proc/", 6);
153 my_itos(path + 6, pid, pid_len);
154 memcpy(path + 6 + pid_len, "/", 1);
155 memcpy(path + 6 + pid_len + 1, node, node_len);
156 memcpy(path + total_length, "\0", 1);
157 }
158
159 void*
160 LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
161 char auxv_path[80];
162 BuildProcPath(auxv_path, pid, "auxv");
163
164 // If BuildProcPath errors out due to invalid input, we'll handle it when
165 // we try to sys_open the file.
166
167 // Find the AT_SYSINFO_EHDR entry for linux-gate.so
168 // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
169 // information.
170 int fd = sys_open(auxv_path, O_RDONLY, 0);
171 if (fd < 0) {
172 return NULL;
173 }
174
175 elf_aux_entry one_aux_entry;
176 while (sys_read(fd,
177 &one_aux_entry,
178 sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
179 one_aux_entry.a_type != AT_NULL) {
180 if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
181 close(fd);
182 return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
183 }
184 }
185 close(fd);
186 return NULL;
187 }
188
113 bool 189 bool
114 LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*> *result) const { 190 LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
115 char maps_path[80]; 191 char maps_path[80];
116 memcpy(maps_path, "/proc/", 6); 192 BuildProcPath(maps_path, pid_, "maps");
117 const unsigned pid_len = my_int_len(pid_); 193
118 my_itos(maps_path + 6, pid_, pid_len); 194 // linux_gate_loc is the beginning of the kernel's mapping of
119 memcpy(maps_path + 6 + pid_len, "/maps", 6); 195 // linux-gate.so in the process. It doesn't actually show up in the
196 // maps list as a filename, so we use the aux vector to find it's
197 // load location and special case it's entry when creating the list
198 // of mappings.
199 const void* linux_gate_loc;
200 linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
120 201
121 const int fd = sys_open(maps_path, O_RDONLY, 0); 202 const int fd = sys_open(maps_path, O_RDONLY, 0);
122 if (fd < 0) 203 if (fd < 0)
123 return false; 204 return false;
124 LineReader *const line_reader = new(allocator_) LineReader(fd); 205 LineReader* const line_reader = new(allocator_) LineReader(fd);
125 206
126 const char *line; 207 const char* line;
127 unsigned line_len; 208 unsigned line_len;
128 while (line_reader->GetNextLine(&line, &line_len)) { 209 while (line_reader->GetNextLine(&line, &line_len)) {
129 uintptr_t start_addr, end_addr, offset; 210 uintptr_t start_addr, end_addr, offset;
130 211
131 const char* i1 = my_read_hex_ptr(&start_addr, line); 212 const char* i1 = my_read_hex_ptr(&start_addr, line);
132 if (*i1 == '-') { 213 if (*i1 == '-') {
133 const char *i2 = my_read_hex_ptr(&end_addr, i1 + 1); 214 const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
134 if (*i2 == ' ') { 215 if (*i2 == ' ') {
135 const char *i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); 216 const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
136 if (*i3 == ' ') { 217 if (*i3 == ' ') {
137 MappingInfo *const module = new(allocator_) MappingInfo; 218 MappingInfo* const module = new(allocator_) MappingInfo;
138 memset(module, 0, sizeof(MappingInfo)); 219 memset(module, 0, sizeof(MappingInfo));
139 module->start_addr = start_addr; 220 module->start_addr = start_addr;
140 module->size = end_addr - start_addr; 221 module->size = end_addr - start_addr;
141 module->offset = offset; 222 module->offset = offset;
142 const char *name = NULL; 223 const char* name = NULL;
143 // Only copy name if the name is a valid path name. 224 // Only copy name if the name is a valid path name, or if
225 // we've found the VDSO image
144 if ((name = my_strchr(line, '/')) != NULL) { 226 if ((name = my_strchr(line, '/')) != NULL) {
145 const unsigned l = my_strlen(name); 227 const unsigned l = my_strlen(name);
146 if (l < sizeof(module->name)) 228 if (l < sizeof(module->name))
147 memcpy(module->name, name, l); 229 memcpy(module->name, name, l);
230 } else if (linux_gate_loc &&
231 reinterpret_cast<void*>(module->start_addr) ==
232 linux_gate_loc) {
233 memcpy(module->name,
234 kLinuxGateLibraryName,
235 my_strlen(kLinuxGateLibraryName));
236 module->offset = 0;
148 } 237 }
149
150 result->push_back(module); 238 result->push_back(module);
151 } 239 }
152 } 240 }
153 } 241 }
154
155 line_reader->PopLine(line_len); 242 line_reader->PopLine(line_len);
156 } 243 }
157 244
158 sys_close(fd); 245 sys_close(fd);
246
159 return result->size() > 0; 247 return result->size() > 0;
160 } 248 }
161 249
162 // Parse /proc/$pid/task to list all the threads of the process identified by 250 // Parse /proc/$pid/task to list all the threads of the process identified by
163 // pid. 251 // pid.
164 bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t> *result) const { 252 bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t>* result) const {
165 char task_path[80]; 253 char task_path[80];
166 memcpy(task_path, "/proc/", 6); 254 BuildProcPath(task_path, pid_, "task");
167 const unsigned pid_len = my_int_len(pid_);
168 my_itos(task_path + 6, pid_, pid_len);
169 memcpy(task_path + 6 + pid_len, "/task", 6);
170 255
171 const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0); 256 const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
172 if (fd < 0) 257 if (fd < 0)
173 return false; 258 return false;
174 DirectoryReader *dir_reader = new(allocator_) DirectoryReader(fd); 259 DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
175 260
176 // The directory may contain duplicate entries which we filter by assuming 261 // The directory may contain duplicate entries which we filter by assuming
177 // that they are consecutive 262 // that they are consecutive.
178 int last_tid = -1; 263 int last_tid = -1;
179 const char *dent_name; 264 const char* dent_name;
180 while (dir_reader->GetNextEntry(&dent_name)) { 265 while (dir_reader->GetNextEntry(&dent_name)) {
181 if (my_strcmp(dent_name, ".") && 266 if (my_strcmp(dent_name, ".") &&
182 my_strcmp(dent_name, "..")) { 267 my_strcmp(dent_name, "..")) {
183 int tid = 0; 268 int tid = 0;
184 if (my_strtoui(&tid, dent_name) && 269 if (my_strtoui(&tid, dent_name) &&
185 last_tid != tid) { 270 last_tid != tid) {
186 last_tid = tid; 271 last_tid = tid;
187 result->push_back(tid); 272 result->push_back(tid);
188 } 273 }
189 } 274 }
190 dir_reader->PopEntry(); 275 dir_reader->PopEntry();
191 } 276 }
192 277
193 sys_close(fd); 278 sys_close(fd);
194 return true; 279 return true;
195 } 280 }
196 281
197 // Read thread info from /proc/$pid/status. 282 // Read thread info from /proc/$pid/status.
198 // Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailible, 283 // Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailible,
199 // these members are set to -1. Returns true iff all three members are 284 // these members are set to -1. Returns true iff all three members are
200 // availible. 285 // availible.
201 bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo *info) { 286 bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
202 assert(info != NULL); 287 assert(info != NULL);
203 char status_path[80]; 288 char status_path[80];
204 memcpy(status_path, "/proc/", 6); 289 BuildProcPath(status_path, tid, "status");
205 const unsigned tid_len = my_int_len(tid); 290
206 my_itos(status_path + 6, tid, tid_len);
207 memcpy(status_path + 6 + tid_len, "/status", 8);
208 const int fd = open(status_path, O_RDONLY); 291 const int fd = open(status_path, O_RDONLY);
209 if (fd < 0) 292 if (fd < 0)
210 return false; 293 return false;
211 294
212 LineReader *const line_reader = new(allocator_) LineReader(fd); 295 LineReader* const line_reader = new(allocator_) LineReader(fd);
213 const char *line; 296 const char* line;
214 unsigned line_len; 297 unsigned line_len;
215 298
216 info->ppid = info->tgid = -1; 299 info->ppid = info->tgid = -1;
217 300
218 while (line_reader->GetNextLine(&line, &line_len)) { 301 while (line_reader->GetNextLine(&line, &line_len)) {
219 if (my_strncmp("Tgid:\t", line, 6) == 0) { 302 if (my_strncmp("Tgid:\t", line, 6) == 0) {
220 my_strtoui(&info->tgid, line + 6); 303 my_strtoui(&info->tgid, line + 6);
221 } else if (my_strncmp("PPid:\t", line, 6) == 0) { 304 } else if (my_strncmp("PPid:\t", line, 6) == 0) {
222 my_strtoui(&info->ppid, line + 6); 305 my_strtoui(&info->ppid, line + 6);
223 } 306 }
224 307
225 line_reader->PopLine(line_len); 308 line_reader->PopLine(line_len);
226 } 309 }
227 310
228 if (info->ppid == -1 || info->tgid == -1) 311 if (info->ppid == -1 || info->tgid == -1)
229 return false; 312 return false;
230 313
231 if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 || 314 if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 ||
232 sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { 315 sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
233 return false; 316 return false;
234 } 317 }
235 318
236 #if defined(__i386) || defined(__x86_64) 319 #if defined(__i386) || defined(__x86_64)
237 if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) 320 if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
238 return false; 321 return false;
239 322
240 for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) { 323 for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
241 if (sys_ptrace( 324 if (sys_ptrace(
242 PTRACE_PEEKUSER, tid, 325 PTRACE_PEEKUSER, tid,
243 (void *) (offsetof(struct user, 326 reinterpret_cast<void*> (offsetof(struct user,
244 u_debugreg[0]) + i * sizeof(debugreg_t)), 327 u_debugreg[0]) + i *
328 sizeof(debugreg_t)),
245 &info->dregs[i]) == -1) { 329 &info->dregs[i]) == -1) {
246 return false; 330 return false;
247 } 331 }
248 } 332 }
249 #endif 333 #endif
250 334
251 const uint8_t *stack_pointer; 335 const uint8_t* stack_pointer;
252 #if defined(__i386) 336 #if defined(__i386)
253 memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); 337 memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
254 #elif defined(__x86_64) 338 #elif defined(__x86_64)
255 memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); 339 memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
256 #else 340 #else
257 #error "This code hasn't been ported to your platform yet." 341 #error "This code hasn't been ported to your platform yet."
258 #endif 342 #endif
259 343
260 if (!GetStackInfo(&info->stack, &info->stack_len, 344 if (!GetStackInfo(&info->stack, &info->stack_len,
261 (uintptr_t) stack_pointer)) 345 (uintptr_t) stack_pointer))
262 return false; 346 return false;
263 347
264 return true; 348 return true;
265 } 349 }
266 350
267 // Get information about the stack, given the stack pointer. We don't try to 351 // Get information about the stack, given the stack pointer. We don't try to
268 // walk the stack since we might not have all the information needed to do 352 // walk the stack since we might not have all the information needed to do
269 // unwind. So we just grab, up to, 32k of stack. 353 // unwind. So we just grab, up to, 32k of stack.
270 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, 354 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
271 uintptr_t int_stack_pointer) { 355 uintptr_t int_stack_pointer) {
272 #if defined(__i386) || defined(__x86_64) 356 #if defined(__i386) || defined(__x86_64)
273 static const bool stack_grows_down = true; 357 static const bool stack_grows_down = true;
274 static const uintptr_t page_size = 4096; 358 static const uintptr_t page_size = 4096;
275 #else 359 #else
276 #error "This code has not been ported to your platform yet." 360 #error "This code has not been ported to your platform yet."
277 #endif 361 #endif
278 // Move the stack pointer to the bottom of the page that it's in. 362 // Move the stack pointer to the bottom of the page that it's in.
279 uint8_t* const stack_pointer = 363 uint8_t* const stack_pointer =
280 (uint8_t *) (int_stack_pointer & ~(page_size - 1)); 364 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
281 365
282 // The number of bytes of stack which we try to capture. 366 // The number of bytes of stack which we try to capture.
283 static unsigned kStackToCapture = 32 * 1024; 367 static unsigned kStackToCapture = 32 * 1024;
284 368
285 const MappingInfo *mapping = FindMapping(stack_pointer); 369 const MappingInfo* mapping = FindMapping(stack_pointer);
286 if (!mapping) 370 if (!mapping)
287 return false; 371 return false;
288 if (stack_grows_down) { 372 if (stack_grows_down) {
289 const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr; 373 const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
290 const ptrdiff_t distance_to_end = 374 const ptrdiff_t distance_to_end =
291 static_cast<ptrdiff_t>(mapping->size) - offset; 375 static_cast<ptrdiff_t>(mapping->size) - offset;
292 *stack_len = distance_to_end > kStackToCapture ? 376 *stack_len = distance_to_end > kStackToCapture ?
293 kStackToCapture : distance_to_end; 377 kStackToCapture : distance_to_end;
294 *stack = stack_pointer; 378 *stack = stack_pointer;
295 } else { 379 } else {
(...skipping 17 matching lines...) Expand all
313 while (done < length) { 397 while (done < length) {
314 const size_t l = length - done > word_size ? word_size : length - done; 398 const size_t l = length - done > word_size ? word_size : length - done;
315 if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) 399 if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1)
316 tmp = 0; 400 tmp = 0;
317 memcpy(local + done, &tmp, l); 401 memcpy(local + done, &tmp, l);
318 done += l; 402 done += l;
319 } 403 }
320 } 404 }
321 405
322 // Find the mapping which the given memory address falls in. 406 // Find the mapping which the given memory address falls in.
323 const MappingInfo *LinuxDumper::FindMapping(const void *address) const { 407 const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
324 const uintptr_t addr = (uintptr_t) address; 408 const uintptr_t addr = (uintptr_t) address;
325 409
326 for (size_t i = 0; i < mappings_.size(); ++i) { 410 for (size_t i = 0; i < mappings_.size(); ++i) {
327 const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr); 411 const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
328 if (addr >= start && addr - start < mappings_[i]->size) 412 if (addr >= start && addr - start < mappings_[i]->size)
329 return mappings_[i]; 413 return mappings_[i];
330 } 414 }
331 415
332 return NULL; 416 return NULL;
333 } 417 }
334 418
335 } // namespace google_breakpad 419 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « breakpad/linux/linux_dumper.h ('k') | breakpad/linux/linux_dumper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698