mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-18 20:39:33 +08:00
* fhandler_process.cc (format_process_maps): Rework to report
all mapped address space in a process (committed or reserved), identifying the nature of the mapping (mapped file/image, heap, shared memory) when possible. (dos_drive_mappings): New helper classes. (heap_info): Ditto. * ntdll.h (struct _MEMORY_SECTION_NAME): Define.
This commit is contained in:
parent
34a6eeabff
commit
8285dae540
@ -1,3 +1,13 @@
|
|||||||
|
2011-05-11 Ryan Johnson <ryan.johnson@cs.utoronto.ca>
|
||||||
|
|
||||||
|
* fhandler_process.cc (format_process_maps): Rework to report
|
||||||
|
all mapped address space in a process (committed or reserved),
|
||||||
|
identifying the nature of the mapping (mapped file/image, heap,
|
||||||
|
shared memory) when possible.
|
||||||
|
(dos_drive_mappings): New helper classes.
|
||||||
|
(heap_info): Ditto.
|
||||||
|
* ntdll.h (struct _MEMORY_SECTION_NAME): Define.
|
||||||
|
|
||||||
2011-05-11 Corinna Vinschen <corinna@vinschen.de>
|
2011-05-11 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* autoload.cc (GetProcessMemoryInfo): Remove.
|
* autoload.cc (GetProcessMemoryInfo): Remove.
|
||||||
|
@ -29,6 +29,7 @@ details. */
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
|
||||||
#define _COMPILING_NEWLIB
|
#define _COMPILING_NEWLIB
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@ -527,6 +528,136 @@ format_process_winexename (void *data, char *&destbuf)
|
|||||||
return len + 1;
|
return len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dos_drive_mappings
|
||||||
|
{
|
||||||
|
struct mapping
|
||||||
|
{
|
||||||
|
mapping *next;
|
||||||
|
int len;
|
||||||
|
wchar_t drive_letter;
|
||||||
|
wchar_t mapping[1];
|
||||||
|
};
|
||||||
|
mapping *mappings;
|
||||||
|
|
||||||
|
dos_drive_mappings ()
|
||||||
|
: mappings(0)
|
||||||
|
{
|
||||||
|
/* The logical drive strings buffer holds a list of (at most 26)
|
||||||
|
drive names separated by nulls and terminated by a double-null:
|
||||||
|
|
||||||
|
"a:\\\0b:\\\0...z:\\\0"
|
||||||
|
|
||||||
|
The annoying part is, QueryDosDeviceW wants only "x:" rather
|
||||||
|
than the "x:\" we get back from GetLogicalDriveStringsW, so
|
||||||
|
we'll have to strip out the trailing slash for each mapping.
|
||||||
|
|
||||||
|
The returned mapping a native NT pathname (\Device\...) which
|
||||||
|
we can use to fix up the output of GetMappedFileNameW
|
||||||
|
*/
|
||||||
|
static unsigned const DBUFLEN = 26 * 4;
|
||||||
|
wchar_t dbuf[DBUFLEN + 1];
|
||||||
|
wchar_t pbuf[NT_MAX_PATH];
|
||||||
|
wchar_t drive[] = {L'x', L':', 0};
|
||||||
|
unsigned result = GetLogicalDriveStringsW (DBUFLEN * sizeof (wchar_t),
|
||||||
|
dbuf);
|
||||||
|
if (!result)
|
||||||
|
debug_printf ("Failed to get logical DOS drive names: %lu",
|
||||||
|
GetLastError ());
|
||||||
|
else if (result > DBUFLEN)
|
||||||
|
debug_printf ("Too many mapped drive letters: %u", result);
|
||||||
|
else
|
||||||
|
for (wchar_t *cur = dbuf; (*drive = *cur); cur = wcschr (cur, L'\0')+1)
|
||||||
|
if (QueryDosDeviceW (drive, pbuf, NT_MAX_PATH))
|
||||||
|
{
|
||||||
|
size_t plen = wcslen (pbuf);
|
||||||
|
size_t psize = plen * sizeof (wchar_t);
|
||||||
|
debug_printf ("DOS drive %ls maps to %ls", drive, pbuf);
|
||||||
|
mapping *m = (mapping*) cmalloc (HEAP_FHANDLER,
|
||||||
|
sizeof (mapping) + psize);
|
||||||
|
m->next = mappings;
|
||||||
|
m->len = plen;
|
||||||
|
m->drive_letter = *drive;
|
||||||
|
memcpy (m->mapping, pbuf, psize + sizeof (wchar_t));
|
||||||
|
mappings = m;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug_printf ("Unable to determine the native mapping for %ls "
|
||||||
|
"(error %lu)", drive, GetLastError ());
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *fixup_if_match (wchar_t *path)
|
||||||
|
{
|
||||||
|
for (mapping *m = mappings; m; m = m->next)
|
||||||
|
if (!wcsncmp (m->mapping, path, m->len))
|
||||||
|
{
|
||||||
|
path += m->len - 2;
|
||||||
|
path[0] = m->drive_letter;
|
||||||
|
path[1] = L':';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
~dos_drive_mappings ()
|
||||||
|
{
|
||||||
|
mapping *n = 0;
|
||||||
|
for (mapping *m = mappings; m; m = n)
|
||||||
|
{
|
||||||
|
n = m->next;
|
||||||
|
cfree (m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct heap_info
|
||||||
|
{
|
||||||
|
struct heap
|
||||||
|
{
|
||||||
|
heap *next;
|
||||||
|
void *base;
|
||||||
|
};
|
||||||
|
heap *heaps;
|
||||||
|
|
||||||
|
heap_info (DWORD pid)
|
||||||
|
: heaps (0)
|
||||||
|
{
|
||||||
|
HANDLE hHeapSnap = CreateToolhelp32Snapshot (TH32CS_SNAPHEAPLIST, pid);
|
||||||
|
HEAPLIST32 hl;
|
||||||
|
hl.dwSize = sizeof(hl);
|
||||||
|
|
||||||
|
if (hHeapSnap != INVALID_HANDLE_VALUE && Heap32ListFirst (hHeapSnap, &hl))
|
||||||
|
do
|
||||||
|
{
|
||||||
|
heap *h = (heap *) cmalloc (HEAP_FHANDLER, sizeof (heap));
|
||||||
|
*h = (heap) {heaps, (void*) hl.th32HeapID};
|
||||||
|
heaps = h;
|
||||||
|
} while (Heap32ListNext (hHeapSnap, &hl));
|
||||||
|
CloseHandle (hHeapSnap);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fill_if_match (void *base, char *dest )
|
||||||
|
{
|
||||||
|
long count = 0;
|
||||||
|
for (heap *h = heaps; h && ++count; h = h->next)
|
||||||
|
if (base == h->base)
|
||||||
|
{
|
||||||
|
__small_sprintf (dest, "[heap %ld]", count);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~heap_info ()
|
||||||
|
{
|
||||||
|
heap *n = 0;
|
||||||
|
for (heap *m = heaps; m; m = n)
|
||||||
|
{
|
||||||
|
n = m->next;
|
||||||
|
cfree (m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static _off64_t
|
static _off64_t
|
||||||
format_process_maps (void *data, char *&destbuf)
|
format_process_maps (void *data, char *&destbuf)
|
||||||
{
|
{
|
||||||
@ -538,14 +669,28 @@ format_process_maps (void *data, char *&destbuf)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_off64_t len = 0;
|
_off64_t len = 0;
|
||||||
HMODULE *modules;
|
|
||||||
DWORD needed, i;
|
union access
|
||||||
DWORD_PTR wset_size;
|
{
|
||||||
DWORD_PTR *workingset = NULL;
|
char flags[8];
|
||||||
MODULEINFO info;
|
_off64_t word;
|
||||||
|
} a;
|
||||||
|
|
||||||
|
struct region {
|
||||||
|
access a;
|
||||||
|
char *abase;
|
||||||
|
char *rbase;
|
||||||
|
char *rend;
|
||||||
|
} cur = {{{'\0'}}, (char *)1, 0, 0};
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION mb;
|
||||||
|
dos_drive_mappings drive_maps;
|
||||||
|
heap_info heaps (p->dwProcessId);
|
||||||
|
struct __stat64 st;
|
||||||
|
long last_pass = 0;
|
||||||
|
|
||||||
tmp_pathbuf tp;
|
tmp_pathbuf tp;
|
||||||
PWCHAR modname = tp.w_get ();
|
PMEMORY_SECTION_NAME msi = (PMEMORY_SECTION_NAME) tp.w_get ();
|
||||||
char *posix_modname = tp.c_get ();
|
char *posix_modname = tp.c_get ();
|
||||||
size_t maxsize = 0;
|
size_t maxsize = 0;
|
||||||
|
|
||||||
@ -554,75 +699,92 @@ format_process_maps (void *data, char *&destbuf)
|
|||||||
cfree (destbuf);
|
cfree (destbuf);
|
||||||
destbuf = NULL;
|
destbuf = NULL;
|
||||||
}
|
}
|
||||||
if (!EnumProcessModules (proc, NULL, 0, &needed))
|
|
||||||
|
/* Iterate over each VM region in the address space, coalescing
|
||||||
|
memory regions with the same permissions. Once we run out, do one
|
||||||
|
last_pass to trigger output of the last accumulated region. */
|
||||||
|
for (char *i = 0;
|
||||||
|
VirtualQueryEx (proc, i, &mb, sizeof(mb)) || (1 == ++last_pass);
|
||||||
|
i = cur.rend)
|
||||||
{
|
{
|
||||||
__seterrno ();
|
if (mb.State == MEM_FREE)
|
||||||
len = -1;
|
a.word = 0;
|
||||||
goto out;
|
else
|
||||||
}
|
{
|
||||||
modules = (HMODULE*) alloca (needed);
|
static DWORD const RW = (PAGE_EXECUTE_READWRITE | PAGE_READWRITE
|
||||||
if (!EnumProcessModules (proc, modules, needed, &needed))
|
| PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY);
|
||||||
{
|
DWORD p = mb.Protect;
|
||||||
__seterrno ();
|
a = (access) {{
|
||||||
len = -1;
|
(p & (RW | PAGE_EXECUTE_READ | PAGE_READONLY))? 'r' : '-',
|
||||||
goto out;
|
(p & (RW))? 'w' : '-',
|
||||||
}
|
(p & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ
|
||||||
|
| PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE))? 'x' : '-',
|
||||||
|
(p & (PAGE_GUARD))? 's' : 'p',
|
||||||
|
'\0', // zero-fill the remaining bytes
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
QueryWorkingSet (proc, (void *) &wset_size, sizeof wset_size);
|
region next = { a,
|
||||||
if (GetLastError () == ERROR_BAD_LENGTH)
|
(char *) mb.AllocationBase,
|
||||||
{
|
(char *) mb.BaseAddress,
|
||||||
workingset = (DWORD_PTR *) alloca (sizeof (DWORD_PTR) * ++wset_size);
|
(char *) mb.BaseAddress+mb.RegionSize
|
||||||
if (!QueryWorkingSet (proc, (void *) workingset,
|
};
|
||||||
sizeof (DWORD_PTR) * wset_size))
|
|
||||||
workingset = NULL;
|
/* Windows permissions are more fine-grained than the unix rwxp,
|
||||||
}
|
so we reduce clutter by manually coalescing regions sharing
|
||||||
for (i = 0; i < needed / sizeof (HMODULE); i++)
|
the same allocation base and effective permissions. */
|
||||||
if (GetModuleInformation (proc, modules[i], &info, sizeof info)
|
bool newbase = (next.abase != cur.abase);
|
||||||
&& GetModuleFileNameExW (proc, modules[i], modname, NT_MAX_PATH))
|
if (!last_pass && !newbase && next.a.word == cur.a.word)
|
||||||
{
|
cur.rend = next.rend; // merge with previous
|
||||||
char access[5];
|
else
|
||||||
strcpy (access, "r--p");
|
{
|
||||||
struct __stat64 st;
|
// output the current region if it's "interesting"
|
||||||
if (mount_table->conv_to_posix_path (modname, posix_modname, 0))
|
if (cur.a.word)
|
||||||
sys_wcstombs (posix_modname, NT_MAX_PATH, modname);
|
|
||||||
if (stat64 (posix_modname, &st))
|
|
||||||
{
|
|
||||||
st.st_dev = 0;
|
|
||||||
st.st_ino = 0;
|
|
||||||
}
|
|
||||||
size_t newlen = strlen (posix_modname) + 62;
|
|
||||||
if (len + newlen >= maxsize)
|
|
||||||
destbuf = (char *) crealloc_abort (destbuf,
|
|
||||||
maxsize += roundup2 (newlen, 2048));
|
|
||||||
if (workingset)
|
|
||||||
for (unsigned i = 1; i <= wset_size; ++i)
|
|
||||||
{
|
{
|
||||||
DWORD_PTR addr = workingset[i] & 0xfffff000UL;
|
size_t newlen = strlen (posix_modname) + 62;
|
||||||
if ((char *)addr >= info.lpBaseOfDll
|
if (len + newlen >= maxsize)
|
||||||
&& (char *)addr < (char *)info.lpBaseOfDll + info.SizeOfImage)
|
destbuf = (char *) crealloc_abort (destbuf,
|
||||||
{
|
maxsize += roundup2 (newlen,
|
||||||
access[0] = (workingset[i] & 0x5) ? 'r' : '-';
|
2048));
|
||||||
access[1] = (workingset[i] & 0x4) ? 'w' : '-';
|
int written = __small_sprintf (destbuf + len,
|
||||||
access[2] = (workingset[i] & 0x2) ? 'x' : '-';
|
"%08lx-%08lx %s %08lx %04x:%04x %U ",
|
||||||
access[3] = (workingset[i] & 0x100) ? 's' : 'p';
|
cur.rbase, cur.rend, cur.a.flags,
|
||||||
}
|
cur.rbase - cur.abase,
|
||||||
|
st.st_dev >> 16,
|
||||||
|
st.st_dev & 0xffff,
|
||||||
|
st.st_ino);
|
||||||
|
while (written < 62)
|
||||||
|
destbuf[len + written++] = ' ';
|
||||||
|
len += written;
|
||||||
|
len += __small_sprintf (destbuf + len, "%s\n", posix_modname);
|
||||||
}
|
}
|
||||||
int written = __small_sprintf (destbuf + len,
|
// start of a new region (but possibly still the same allocation)
|
||||||
"%08lx-%08lx %s %08lx %04x:%04x %U ",
|
cur = next;
|
||||||
info.lpBaseOfDll,
|
// if a new allocation, figure out what kind it is
|
||||||
(unsigned long)info.lpBaseOfDll
|
if (newbase && !last_pass)
|
||||||
+ info.SizeOfImage,
|
{
|
||||||
access,
|
st.st_dev = 0;
|
||||||
info.EntryPoint,
|
st.st_ino = 0;
|
||||||
st.st_dev >> 16,
|
if ((mb.Type & (MEM_MAPPED | MEM_IMAGE))
|
||||||
st.st_dev & 0xffff,
|
&& NT_SUCCESS (NtQueryVirtualMemory (proc, cur.abase,
|
||||||
st.st_ino);
|
MemorySectionName,
|
||||||
while (written < 62)
|
msi, 65536, NULL)))
|
||||||
destbuf[len + written++] = ' ';
|
{
|
||||||
len += written;
|
PWCHAR dosname =
|
||||||
len += __small_sprintf (destbuf + len, "%s\n", posix_modname);
|
drive_maps.fixup_if_match (msi->SectionFileName.Buffer);
|
||||||
}
|
if (mount_table->conv_to_posix_path (dosname,
|
||||||
out:
|
posix_modname, 0))
|
||||||
|
sys_wcstombs (posix_modname, NT_MAX_PATH, dosname);
|
||||||
|
stat64 (posix_modname, &st);
|
||||||
|
}
|
||||||
|
else if (mb.Type & MEM_MAPPED)
|
||||||
|
strcpy (posix_modname, "[shareable]");
|
||||||
|
else if (!(mb.Type & MEM_PRIVATE
|
||||||
|
&& heaps.fill_if_match (cur.abase, posix_modname)))
|
||||||
|
posix_modname[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
CloseHandle (proc);
|
CloseHandle (proc);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
@ -645,6 +645,11 @@ typedef struct _MEMORY_WORKING_SET_LIST
|
|||||||
ULONG WorkingSetList[1];
|
ULONG WorkingSetList[1];
|
||||||
} MEMORY_WORKING_SET_LIST, *PMEMORY_WORKING_SET_LIST;
|
} MEMORY_WORKING_SET_LIST, *PMEMORY_WORKING_SET_LIST;
|
||||||
|
|
||||||
|
typedef struct _MEMORY_SECTION_NAME
|
||||||
|
{
|
||||||
|
UNICODE_STRING SectionFileName;
|
||||||
|
} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
|
||||||
|
|
||||||
typedef struct _FILE_BASIC_INFORMATION {
|
typedef struct _FILE_BASIC_INFORMATION {
|
||||||
LARGE_INTEGER CreationTime;
|
LARGE_INTEGER CreationTime;
|
||||||
LARGE_INTEGER LastAccessTime;
|
LARGE_INTEGER LastAccessTime;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user