1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/* -----------------------------------------------------------------------------
*
* (c) The GHC Team, 1998-2004
*
* Memory-map dumping.
*
* This is intended to be used for reporting the process memory-map
* in diagnostics when the RTS fails to map a block of memory.
*
* ---------------------------------------------------------------------------*/
#include "rts/PosixSource.h"
#include "Rts.h"
#include <string.h>
#if defined(darwin_HOST_OS)
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/vm_region.h>
#include <mach/vm_statistics.h>
#endif
#include "ReportMemoryMap.h"
#if defined(mingw32_HOST_OS)
void reportMemoryMap(void) {
debugBelch("\nMemory map:\n");
uint8_t *addr = NULL;
while (true) {
MEMORY_BASIC_INFORMATION info;
int res = VirtualQuery(addr, &info, sizeof(info));
if (!res && GetLastError() == ERROR_INVALID_PARAMETER) {
return;
} else if (!res) {
sysErrorBelch("VirtualQuery failed");
return;
}
if (info.State & MEM_FREE) {
// free range
} else {
const char *protection;
switch (info.Protect) {
case PAGE_EXECUTE: protection = "--x"; break;
case PAGE_EXECUTE_READ: protection = "r-x"; break;
case PAGE_EXECUTE_READWRITE: protection = "rwx"; break;
case PAGE_EXECUTE_WRITECOPY: protection = "rcx"; break;
case PAGE_NOACCESS: protection = "---"; break;
case PAGE_READONLY: protection = "r--"; break;
case PAGE_READWRITE: protection = "rw-"; break;
case PAGE_WRITECOPY: protection = "rc-"; break;
default: protection = "???"; break;
}
const char *type;
switch (info.Type) {
case MEM_IMAGE: type = "image"; break;
case MEM_MAPPED: type = "mapped"; break;
case MEM_PRIVATE: type = "private"; break;
default: type = "unknown"; break;
}
debugBelch("%08llx-%08llx %8zuK %3s (%s)\n",
(uintptr_t) info.BaseAddress,
(uintptr_t) info.BaseAddress + info.RegionSize,
(size_t) info.RegionSize,
protection, type);
}
addr = (uint8_t *) info.BaseAddress + info.RegionSize;
}
}
#elif defined(darwin_HOST_OS)
void reportMemoryMap(void) {
// Inspired by MacFUSE /proc implementation
debugBelch("\nMemory map:\n");
while (true) {
mach_vm_size_t vmsize;
mach_vm_address_t address;
vm_region_basic_info_data_t info;
vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
memory_object_name_t object;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
kern_return_t kr =
mach_vm_region(mach_task_self(), &address, &vmsize, flavor,
(vm_region_info_t)&info, &info_count, &object);
if (kr == KERN_SUCCESS) {
debugBelch("%p-%p %8zuK %c%c%c/%c%c%c\n",
(void *) address,
(void *) (address + vmsize),
((size_t) vmsize) >> 10,
(info.protection & VM_PROT_READ) ? 'r' : '-',
(info.protection & VM_PROT_WRITE) ? 'w' : '-',
(info.protection & VM_PROT_EXECUTE) ? 'x' : '-',
(info.max_protection & VM_PROT_READ) ? 'r' : '-',
(info.max_protection & VM_PROT_WRITE) ? 'w' : '-',
(info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-');
address += vmsize;
} else if (kr == KERN_INVALID_ADDRESS) {
// We presumably reached the end of address space
break;
} else {
debugBelch(" Error: %s\n", mach_error_string(kr));
break;
}
}
}
#else
// Linux et al.
void reportMemoryMap(void) {
debugBelch("\nMemory map:\n");
FILE *f = fopen("/proc/self/maps", "r");
if (f == NULL) {
debugBelch(" Could not open /proc/self/maps\n");
return;
}
while (true) {
char buf[256];
size_t n = fread(buf, 1, sizeof(buf)-1, f);
if (n <= 0) {
debugBelch(" Error: %s\n", strerror(errno));
break;
}
buf[n] = '\0';
debugBelch("%s", buf);
if (n < sizeof(buf)-1) {
break;
}
}
debugBelch("\n");
fclose(f);
}
#endif
|