summaryrefslogtreecommitdiff
path: root/rts/ReportMemoryMap.c
blob: c5e7a92c4d139fe1bdc7170e6e6ea60e69f511d6 (plain)
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() {
    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() {
    // 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() {
    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