Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Replace sprintf by snprintf.
[simgrid.git] / src / xbt / memory_map.cpp
1 /* Copyright (c) 2008-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <cstdlib>
8 #include <cstdio>
9 #include <cstring>
10
11 #include <sys/types.h>
12 #ifdef __linux__
13 # include <sys/mman.h>
14 #endif
15
16 #include <xbt/sysdep.h>
17 #include <xbt/base.h>
18 #include <xbt/file.h>
19 #include <xbt/log.h>
20
21 #include "memory_map.hpp"
22
23 extern "C" {
24 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_memory_map, xbt, "Logging specific to algorithms for memory_map");
25 }
26
27 namespace simgrid {
28 namespace xbt {
29
30 XBT_PRIVATE std::vector<VmMap> get_memory_map(pid_t pid)
31 {
32 #ifdef __linux__
33   /* Open the actual process's proc maps file and create the memory_map_t */
34   /* to be returned. */
35   char* path = bprintf("/proc/%i/maps", (int) pid);
36   FILE *fp = std::fopen(path, "r");
37   if(fp == NULL)
38     std::perror("fopen failed");
39   xbt_assert(fp, "Cannot open %s to investigate the memory map of the process.", path);
40   free(path);
41   setbuf(fp, NULL);
42
43   std::vector<VmMap> ret;
44
45   /* Read one line at the time, parse it and add it to the memory map to be returned */
46   ssize_t read; /* Number of bytes readed */
47   char* line = NULL;
48   std::size_t n = 0; /* Amount of bytes to read by xbt_getline */
49   while ((read = xbt_getline(&line, &n, fp)) != -1) {
50
51     //fprintf(stderr,"%s", line);
52
53     /* Wipeout the new line character */
54     line[read - 1] = '\0';
55
56     /* Tokenize the line using spaces as delimiters and store each token in lfields array. We expect 5 tokens/fields */
57     char* lfields[6];
58     lfields[0] = strtok(line, " ");
59
60     int i;
61     for (i = 1; i < 6 && lfields[i - 1] != NULL; i++) {
62       lfields[i] = std::strtok(NULL, " ");
63     }
64
65     /* Check to see if we got the expected amount of columns */
66     if (i < 6)
67       xbt_abort();
68
69     /* Ok we are good enough to try to get the info we need */
70     /* First get the start and the end address of the map   */
71     char *tok = std::strtok(lfields[0], "-");
72     if (tok == NULL)
73       xbt_abort();
74
75     VmMap memreg;
76     char *endptr;
77     memreg.start_addr = std::strtoull(tok, &endptr, 16);
78     /* Make sure that the entire string was an hex number */
79     if (*endptr != '\0')
80       xbt_abort();
81
82     tok = std::strtok(NULL, "-");
83     if (tok == NULL)
84       xbt_abort();
85
86     memreg.end_addr = std::strtoull(tok, &endptr, 16);
87     /* Make sure that the entire string was an hex number */
88     if (*endptr != '\0')
89       xbt_abort();
90
91     /* Get the permissions flags */
92     if (std::strlen(lfields[1]) < 4)
93       xbt_abort();
94
95     memreg.prot = 0;
96
97     for (i = 0; i < 3; i++){
98       switch(lfields[1][i]){
99         case 'r':
100           memreg.prot |= PROT_READ;
101           break;
102         case 'w':
103           memreg.prot |= PROT_WRITE;
104           break;
105         case 'x':
106           memreg.prot |= PROT_EXEC;
107           break;
108         default:
109           break;
110       }
111     }
112     if (memreg.prot == 0)
113       memreg.prot |= PROT_NONE;
114
115     if (lfields[1][4] == 'p')
116       memreg.flags |= MAP_PRIVATE;
117     else if (lfields[1][4] == 's')
118       memreg.flags |= MAP_SHARED;
119
120     /* Get the offset value */
121     memreg.offset = std::strtoull(lfields[2], &endptr, 16);
122     /* Make sure that the entire string was an hex number */
123     if (*endptr != '\0')
124       xbt_abort();
125
126     /* Get the device major:minor bytes */
127     tok = std::strtok(lfields[3], ":");
128     if (tok == NULL)
129       xbt_abort();
130
131     memreg.dev_major = (char) strtoul(tok, &endptr, 16);
132     /* Make sure that the entire string was an hex number */
133     if (*endptr != '\0')
134       xbt_abort();
135
136     tok = std::strtok(NULL, ":");
137     if (tok == NULL)
138       xbt_abort();
139
140     memreg.dev_minor = (char) std::strtoul(tok, &endptr, 16);
141     /* Make sure that the entire string was an hex number */
142     if (*endptr != '\0')
143       xbt_abort();
144
145     /* Get the inode number and make sure that the entire string was a long int */
146     memreg.inode = strtoul(lfields[4], &endptr, 10);
147     if (*endptr != '\0')
148       xbt_abort();
149
150     /* And finally get the pathname */
151     if (lfields[5])
152       memreg.pathname = lfields[5];
153
154     /* Create space for a new map region in the region's array and copy the */
155     /* parsed stuff from the temporal memreg variable */
156     XBT_DEBUG("Found region for %s", !memreg.pathname.empty() ? memreg.pathname.c_str() : "(null)");
157
158     ret.push_back(std::move(memreg));
159   }
160
161   std::free(line);
162   std::fclose(fp);
163   return ret;
164 #else
165   /* On FreeBSD, kinfo_getvmmap() could be used but mmap() support is disabled anyway. */
166   xbt_die("Could not get memory map from process %lli", (long long int) pid);
167 #endif
168 }
169
170 }
171 }