Cygwin: Use MEMORY_WORKING_SET_EX_INFORMATION in dumper
Use the (undocumented) MEMORY_WORKING_SET_EX_INFORMATION in dumper to determine if a MEM_IMAGE region is unsharable, and hence has been modified. After this, we will end up dumping memory regions where: - state is MEM_COMMIT (i.e. is not MEM_RESERVE or MEM_FREE), and -- type is MEM_PRIVATE and protection allows reads (i.e. not a guardpage), or -- type is MEM_IMAGE and attribute is non-sharable (i.e. it was WC, got written to, and is now a RW copy)
This commit is contained in:
parent
35227fec97
commit
b245014abd
|
@ -524,11 +524,11 @@ error_start=x:\path\to\dumper.exe
|
||||||
<command>dumper</command> exits, the target process is terminated too. </para>
|
<command>dumper</command> exits, the target process is terminated too. </para>
|
||||||
|
|
||||||
<para> To save space in the core dump, <command>dumper</command> doesn't
|
<para> To save space in the core dump, <command>dumper</command> doesn't
|
||||||
write those portions of target process' memory space that are loaded from
|
write those portions of the target process's memory space that are loaded
|
||||||
executable and dll files and are unchangeable, such as program code and
|
from executable and dll files and are unchanged (e.g. program code).
|
||||||
debug info. Instead, <command>dumper</command> saves paths to files which
|
Instead, <command>dumper</command> saves paths to the files which
|
||||||
contain that data. When a core dump is loaded into gdb, it uses these
|
contain that data. When a core dump is loaded into gdb, it uses these
|
||||||
paths to load appropriate files. That means that if you create a core
|
paths to load the appropriate files. That means that if you create a core
|
||||||
dump on one machine and try to debug it on another, you'll need to place
|
dump on one machine and try to debug it on another, you'll need to place
|
||||||
identical copies of the executable and dlls in the same directories as on
|
identical copies of the executable and dlls in the same directories as on
|
||||||
the machine where the core dump was created. </para>
|
the machine where the core dump was created. </para>
|
||||||
|
|
|
@ -116,7 +116,7 @@ CYGWIN_BINS += dumper.exe
|
||||||
dumper.o module_info.o: CXXFLAGS += -I$(top_srcdir)/include
|
dumper.o module_info.o: CXXFLAGS += -I$(top_srcdir)/include
|
||||||
dumper.o: dumper.h
|
dumper.o: dumper.h
|
||||||
dumper.exe: module_info.o
|
dumper.exe: module_info.o
|
||||||
dumper.exe: CYGWIN_LDFLAGS += -lpsapi -lbfd -lintl -liconv -liberty ${ZLIB}
|
dumper.exe: CYGWIN_LDFLAGS += -lpsapi -lbfd -lintl -liconv -liberty ${ZLIB} -lntdll
|
||||||
else
|
else
|
||||||
all: warn_dumper
|
all: warn_dumper
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -266,6 +266,46 @@ void protect_dump(DWORD protect, char *buf)
|
||||||
strcat (buf, pt[i]);
|
strcat (buf, pt[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum _MEMORY_INFORMATION_CLASS
|
||||||
|
{
|
||||||
|
MemoryWorkingSetExInformation = 4, // MEMORY_WORKING_SET_EX_INFORMATION
|
||||||
|
} MEMORY_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
NTSTATUS
|
||||||
|
NtQueryVirtualMemory(HANDLE ProcessHandle,
|
||||||
|
LPVOID BaseAddress,
|
||||||
|
MEMORY_INFORMATION_CLASS MemoryInformationClass,
|
||||||
|
LPVOID MemoryInformation,
|
||||||
|
SIZE_T MemoryInformationLength,
|
||||||
|
SIZE_T *ReturnLength);
|
||||||
|
|
||||||
|
typedef struct _MEMORY_WORKING_SET_EX_INFORMATION
|
||||||
|
{
|
||||||
|
LPVOID VirtualAddress;
|
||||||
|
ULONG_PTR Long;
|
||||||
|
} MEMORY_WORKING_SET_EX_INFORMATION;
|
||||||
|
|
||||||
|
#define MWSEI_ATTRIB_SHARED (0x1 << 15)
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
getRegionAttributes(HANDLE hProcess, LPVOID address, DWORD &attribs)
|
||||||
|
{
|
||||||
|
MEMORY_WORKING_SET_EX_INFORMATION mwsei = { address };
|
||||||
|
NTSTATUS status = NtQueryVirtualMemory(hProcess, 0,
|
||||||
|
MemoryWorkingSetExInformation,
|
||||||
|
&mwsei, sizeof(mwsei), 0);
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
attribs = mwsei.Long;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
deb_printf("MemoryWorkingSetExInformation failed status %08x\n", status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
dumper::collect_memory_sections ()
|
dumper::collect_memory_sections ()
|
||||||
{
|
{
|
||||||
|
@ -292,10 +332,27 @@ dumper::collect_memory_sections ()
|
||||||
int skip_region_p = 0;
|
int skip_region_p = 0;
|
||||||
const char *disposition = "dumped";
|
const char *disposition = "dumped";
|
||||||
|
|
||||||
if ((mbi.Type & MEM_IMAGE) && !(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
|
if (mbi.Type & MEM_IMAGE)
|
||||||
{
|
{
|
||||||
skip_region_p = 1;
|
DWORD attribs = 0;
|
||||||
disposition = "skipped due to non-writeable MEM_IMAGE";
|
if (getRegionAttributes(hProcess, current_page_address, attribs))
|
||||||
|
{
|
||||||
|
if (attribs & MWSEI_ATTRIB_SHARED)
|
||||||
|
{
|
||||||
|
skip_region_p = 1;
|
||||||
|
disposition = "skipped due to shared MEM_IMAGE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
The undocumented MemoryWorkingSetExInformation is allegedly
|
||||||
|
supported since XP, so should always succeed, but if it fails,
|
||||||
|
fallback to looking at region protection.
|
||||||
|
*/
|
||||||
|
else if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
|
||||||
|
{
|
||||||
|
skip_region_p = 1;
|
||||||
|
disposition = "skipped due to non-writeable MEM_IMAGE";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mbi.Protect & PAGE_NOACCESS)
|
if (mbi.Protect & PAGE_NOACCESS)
|
||||||
|
|
Loading…
Reference in New Issue