📄 dumper.cc
字号:
/* dumper.cc Copyright 1999, 2001, 2002 Red Hat Inc. Written by Egor Duda <deo@logos-m.ru> This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */#include <bfd.h>#include <elf/common.h>#include <elf/external.h>#include <sys/procfs.h>#include <sys/cygwin.h>#include <getopt.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <windows.h>#include "dumper.h"#define NOTE_NAME_SIZE 16typedef struct _note_header { Elf_External_Note elf_note_header; char name[NOTE_NAME_SIZE - 1]; /* external note contains first byte of data */ }#ifdef __GNUC____attribute__ ((packed))#endif note_header;static const char version[] = "$Revision: 1.9 $";BOOL verbose = FALSE;int deb_printf (const char *format,...){ if (!verbose) return 0; va_list va; va_start (va, format); int ret_val = vprintf (format, va); va_end (va); return ret_val;}dumper::dumper (DWORD pid, DWORD tid, const char *file_name){ this->file_name = strdup (file_name); this->pid = pid; this->tid = tid; core_bfd = NULL; excl_list = new exclusion (20); list = last = NULL; status_section = NULL; memory_num = module_num = thread_num = 0; hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, /* no inheritance */ pid); if (!hProcess) { fprintf (stderr, "Failed to open process #%lu, error %ld\n", pid, GetLastError ()); return; } init_core_dump (); if (!sane ()) dumper_abort ();}dumper::~dumper (){ close (); free (file_name);}voiddumper::dumper_abort (){ close (); unlink (file_name);}voiddumper::close (){ if (core_bfd) bfd_close (core_bfd); if (excl_list) delete excl_list; if (hProcess) CloseHandle (hProcess); core_bfd = NULL; hProcess = NULL; excl_list = NULL;}intdumper::sane (){ if (hProcess == NULL || core_bfd == NULL || excl_list == NULL) return 0; return 1;}voidprint_section_name (bfd* abfd, asection* sect, PTR obj){ deb_printf (" %s", bfd_get_section_name (abfd, sect));}voiddumper::print_core_section_list (){ deb_printf ("current sections:"); bfd_map_over_sections (core_bfd, &print_section_name, NULL); deb_printf ("\n");}process_entity *dumper::add_process_entity_to_list (process_entity_type type){ if (!sane ()) return NULL; process_entity *new_entity = (process_entity *) malloc (sizeof (process_entity)); if (new_entity == NULL) return NULL; new_entity->next = NULL; new_entity->section = NULL; if (last == NULL) list = new_entity; else last->next = new_entity; last = new_entity; return new_entity;}intdumper::add_thread (DWORD tid, HANDLE hThread){ if (!sane ()) return 0; CONTEXT *pcontext; process_entity *new_entity = add_process_entity_to_list (pr_ent_thread); if (new_entity == NULL) return 0; new_entity->type = pr_ent_thread; thread_num++; new_entity->u.thread.tid = tid; new_entity->u.thread.hThread = hThread; pcontext = &(new_entity->u.thread.context); pcontext->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; if (!GetThreadContext (hThread, pcontext)) { deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid, GetLastError ()); return 0; } deb_printf ("added thread %u\n", tid); return 1;}intdumper::add_mem_region (LPBYTE base, DWORD size){ if (!sane ()) return 0; if (base == NULL || size == 0) return 1; // just ignore empty regions process_entity *new_entity = add_process_entity_to_list (pr_ent_memory); if (new_entity == NULL) return 0; new_entity->type = pr_ent_memory; memory_num++; new_entity->u.memory.base = base; new_entity->u.memory.size = size; deb_printf ("added memory region %08x-%08x\n", (DWORD) base, (DWORD) base + size); return 1;}/* split_add_mem_region scans list of regions to be excluded from dumping process (excl_list) and removes all "excluded" parts from given region. */intdumper::split_add_mem_region (LPBYTE base, DWORD size){ if (!sane ()) return 0; if (base == NULL || size == 0) return 1; // just ignore empty regions LPBYTE last_base = base; for (process_mem_region * p = excl_list->region; p < excl_list->region + excl_list->last; p++) { if (p->base >= base + size || p->base + p->size <= base) continue; if (p->base <= base) { last_base = p->base + p->size; continue; } add_mem_region (last_base, p->base - last_base); last_base = p->base + p->size; } if (last_base < base + size) add_mem_region (last_base, base + size - last_base); return 1;}intdumper::add_module (LPVOID base_address){ if (!sane ()) return 0; char *module_name = psapi_get_module_name (hProcess, (DWORD) base_address); if (module_name == NULL) return 1; process_entity *new_entity = add_process_entity_to_list (pr_ent_module); if (new_entity == NULL) return 0; new_entity->type = pr_ent_module; module_num++; new_entity->u.module.base_address = base_address; new_entity->u.module.name = module_name; parse_pe (module_name, excl_list); deb_printf ("added module %08x %s\n", base_address, module_name); return 1;}#define PAGE_BUFFER_SIZE 4096intdumper::collect_memory_sections (){ if (!sane ()) return 0; LPBYTE current_page_address; LPBYTE last_base = (LPBYTE) 0xFFFFFFFF; DWORD last_size = 0; DWORD done; char mem_buf[PAGE_BUFFER_SIZE]; MEMORY_BASIC_INFORMATION mbi; if (hProcess == NULL) return 0; for (current_page_address = 0; current_page_address < (LPBYTE) 0xFFFF0000;) { if (!VirtualQueryEx (hProcess, current_page_address, &mbi, sizeof (mbi))) break; int skip_region_p = 0; if (mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD) || mbi.State != MEM_COMMIT) skip_region_p = 1; if (!skip_region_p) { /* just to make sure that later we'll be able to read it. According to MS docs either region is all-readable or all-nonreadable */ if (!ReadProcessMemory (hProcess, current_page_address, mem_buf, sizeof (mem_buf), &done)) { DWORD err = GetLastError (); const char *pt[10]; pt[0] = (mbi.Protect & PAGE_READONLY) ? "RO " : ""; pt[1] = (mbi.Protect & PAGE_READWRITE) ? "RW " : ""; pt[2] = (mbi.Protect & PAGE_WRITECOPY) ? "WC " : ""; pt[3] = (mbi.Protect & PAGE_EXECUTE) ? "EX " : ""; pt[4] = (mbi.Protect & PAGE_EXECUTE_READ) ? "EXRO " : ""; pt[5] = (mbi.Protect & PAGE_EXECUTE_READWRITE) ? "EXRW " : ""; pt[6] = (mbi.Protect & PAGE_EXECUTE_WRITECOPY) ? "EXWC " : ""; pt[7] = (mbi.Protect & PAGE_GUARD) ? "GRD " : ""; pt[8] = (mbi.Protect & PAGE_NOACCESS) ? "NA " : ""; pt[9] = (mbi.Protect & PAGE_NOCACHE) ? "NC " : ""; char buf[10 * 6]; buf[0] = '\0'; for (int i = 0; i < 10; i++) strcat (buf, pt[i]); deb_printf ("warning: failed to read memory at %08x-%08x (protect = %s), error %ld.\n", (DWORD) current_page_address, (DWORD) current_page_address + mbi.RegionSize, buf, err); skip_region_p = 1; } } if (!skip_region_p) { if (last_base + last_size == current_page_address) last_size += mbi.RegionSize; else { split_add_mem_region (last_base, last_size); last_base = (LPBYTE) mbi.BaseAddress; last_size = mbi.RegionSize; } } else { split_add_mem_region (last_base, last_size); last_base = NULL; last_size = 0; } current_page_address += mbi.RegionSize; } /* dump last sections, if any */ split_add_mem_region (last_base, last_size); return 1;};intdumper::dump_memory_region (asection * to, process_mem_region * memory){ if (!sane ()) return 0; DWORD size = memory->size; DWORD todo; DWORD done; LPBYTE pos = memory->base; DWORD sect_pos = 0; if (to == NULL || memory == NULL) return 0; char mem_buf[PAGE_BUFFER_SIZE]; while (size > 0) { todo = min (size, PAGE_BUFFER_SIZE); if (!ReadProcessMemory (hProcess, pos, mem_buf, todo, &done)) { deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos, todo, GetLastError ()); return 0; } size -= done; pos += done; if (!bfd_set_section_contents (core_bfd, to, mem_buf, sect_pos, done)) { bfd_perror ("writing memory region to bfd"); dumper_abort (); return 0; }; sect_pos += done; } return 1;}intdumper::dump_thread (asection * to, process_thread * thread){ if (!sane ()) return 0; if (to == NULL || thread == NULL) return 0; win32_pstatus thread_pstatus; note_header header; bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz); bfd_putl32 (sizeof (thread_pstatus), header.elf_note_header.descsz); bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type); strncpy ((char *) &header.elf_note_header.name, "win32thread", NOTE_NAME_SIZE); thread_pstatus.data_type = NOTE_INFO_THREAD; thread_pstatus.data.thread_info.tid = thread->tid; if (tid == 0) { /* this is a special case. we don't know, which thread was active when exception occured, so let's blame the first one */ thread_pstatus.data.thread_info.is_active_thread = TRUE; tid = (DWORD) - 1; } else if (tid > 0 && thread->tid == tid) thread_pstatus.data.thread_info.is_active_thread = TRUE; else thread_pstatus.data.thread_info.is_active_thread = FALSE; memcpy (&(thread_pstatus.data.thread_info.thread_context), &(thread->context), sizeof (thread->context)); if (!bfd_set_section_contents (core_bfd, to, &header, 0, sizeof (header)) || !bfd_set_section_contents (core_bfd, to, &thread_pstatus, sizeof (header), sizeof (thread_pstatus))) { bfd_perror ("writing thread info to bfd"); dumper_abort (); return 0; }; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -