[2020-02] Avoid following invalid pointers in mono_w32process_get_modules on Darwin...
[mono-project.git] / mono / metadata / w32process-unix-default.c
blob0f148aec286a7c1886889740ffea4eef8bf9d381
1 /**
2 * \file
3 */
5 #include "w32process.h"
6 #include "w32process-unix-internals.h"
8 #ifdef USE_DEFAULT_BACKEND
10 #include <unistd.h>
12 #ifdef HOST_SOLARIS
13 /* procfs.h cannot be included if this define is set, but it seems to work fine if it is undefined */
14 #if _FILE_OFFSET_BITS == 64
15 #undef _FILE_OFFSET_BITS
16 #include <procfs.h>
17 #define _FILE_OFFSET_BITS 64
18 #else
19 #include <procfs.h>
20 #endif
21 #endif
23 #ifdef _AIX
24 /* like solaris, just different */
25 #include <sys/procfs.h>
26 /* fallback for procfs-less i */
27 #include <procinfo.h>
28 #include <sys/types.h>
29 #endif
31 /* makedev() macro */
32 #ifdef MAJOR_IN_MKDEV
33 #include <sys/mkdev.h>
34 #elif defined MAJOR_IN_SYSMACROS
35 #include <sys/sysmacros.h>
36 #endif
38 #include "utils/mono-logger-internals.h"
39 #include "icall-decl.h"
41 #ifndef MAXPATHLEN
42 #define MAXPATHLEN 242
43 #endif
45 /* XXX: why don't we just use proclib? */
46 gchar*
47 mono_w32process_get_name (pid_t pid)
49 FILE *fp;
50 gchar *filename;
51 gchar buf[256];
52 gchar *ret = NULL;
54 #if defined(HOST_SOLARIS) || (defined(_AIX) && !defined(__PASE__))
55 filename = g_strdup_printf ("/proc/%d/psinfo", pid);
56 if ((fp = fopen (filename, "r")) != NULL) {
57 struct psinfo info;
58 int nread;
60 nread = fread (&info, sizeof (info), 1, fp);
61 if (nread == 1) {
62 ret = g_strdup (info.pr_fname);
65 fclose (fp);
67 g_free (filename);
68 #elif defined(__PASE__)
69 /* AIX has a procfs, but it's not available on i */
70 struct procentry64 proc;
71 pid_t newpid;
73 newpid = pid;
74 if (getprocs64(&proc, sizeof (proc), NULL, NULL, &newpid, 1) == 1) {
75 ret = g_strdup (proc.pi_comm);
77 #else
78 memset (buf, '\0', sizeof(buf));
79 filename = g_strdup_printf ("/proc/%d/exe", pid);
80 #if defined(HAVE_READLINK)
81 if (readlink (filename, buf, 255) > 0) {
82 ret = g_strdup (buf);
84 #endif
85 g_free (filename);
87 if (ret != NULL) {
88 return(ret);
91 filename = g_strdup_printf ("/proc/%d/cmdline", pid);
92 if ((fp = fopen (filename, "r")) != NULL) {
93 if (fgets (buf, 256, fp) != NULL) {
94 ret = g_strdup (buf);
97 fclose (fp);
99 g_free (filename);
101 if (ret != NULL) {
102 return(ret);
105 filename = g_strdup_printf ("/proc/%d/stat", pid);
106 if ((fp = fopen (filename, "r")) != NULL) {
107 if (fgets (buf, 256, fp) != NULL) {
108 char *start, *end;
110 start = strchr (buf, '(');
111 if (start != NULL) {
112 end = strchr (start + 1, ')');
114 if (end != NULL) {
115 ret = g_strndup (start + 1,
116 end - start - 1);
121 fclose (fp);
123 g_free (filename);
124 #endif
126 return ret;
129 gchar*
130 mono_w32process_get_path (pid_t pid)
132 return mono_w32process_get_name (pid);
135 static FILE *
136 open_process_map (int pid, const char *mode)
138 gint i;
139 const gchar *proc_path[] = {
140 "/proc/%d/maps", /* GNU/Linux */
141 "/proc/%d/map", /* FreeBSD */
142 NULL
145 for (i = 0; proc_path [i]; i++) {
146 gchar *filename;
147 FILE *fp;
149 filename = g_strdup_printf (proc_path[i], pid);
150 fp = fopen (filename, mode);
151 g_free (filename);
153 if (fp)
154 return fp;
157 return NULL;
161 GSList*
162 mono_w32process_get_modules (pid_t pid)
164 #if defined(_AIX)
165 /* due to procfs, this won't work on i */
166 GSList *ret = NULL;
167 FILE *fp;
168 MonoW32ProcessModule *mod;
169 struct prmap module;
170 int i;
171 fpos64_t curpos;
173 char pidpath[32]; /* "/proc/<uint64_t max>/map" plus null, rounded */
174 char libpath[MAXPATHLEN + 1];
175 char membername[MAXPATHLEN + 1];
176 char combinedname[(MAXPATHLEN * 2) + 3]; /* lib, member, (), and nul */
178 sprintf (pidpath, "/proc/%d/map", pid);
179 if ((fp = fopen(pidpath, "r"))) {
180 while (fread (&module, sizeof (module), 1, fp) == 1
181 /* proc(4) declares such a struct to be the array terminator */
182 && (module.pr_size != 0 && module.pr_mflags != 0)
183 && (module.pr_mflags & MA_READ)) {
185 fgetpos64 (fp, &curpos); /* save our position */
186 fseeko (fp, module.pr_pathoff, SEEK_SET);
187 while ((libpath[i++] = fgetc (fp)));
188 i = 0;
189 while ((membername[i++] = fgetc (fp)));
190 i = 0;
191 fsetpos64 (fp, &curpos); /* back to normal */
193 mod = g_new0 (MonoW32ProcessModule, 1);
194 mod->address_start = module.pr_vaddr;
195 mod->address_end = module.pr_vaddr + module.pr_size;
196 mod->address_offset = (void*)module.pr_off;
197 mod->perms = g_strdup ("r--p"); /* XXX? */
199 /* AIX has what appears to be device, channel and inode information,
200 * but it's in a string. Try parsing it.
202 * XXX: I believe it's fstype.devno.chano.inode, but I'm uncertain
203 * as to how that maps out, so I only fill in the inode (like BSD)
205 sscanf (module.pr_mapname, "%*[^.].%*lu.%*u.%lu", &(mod->inode));
207 if (membername[0]) {
208 snprintf(combinedname, MAXPATHLEN, "%s(%s)", libpath, membername);
209 mod->filename = g_strdup (combinedname);
210 } else {
211 mod->filename = g_strdup (libpath);
214 if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) {
215 ret = g_slist_prepend (ret, mod);
216 } else {
217 mono_w32process_module_free (mod);
220 } else {
221 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't open process map file for pid %d", __func__, pid);
222 return NULL;
225 if (ret)
226 ret = g_slist_reverse (ret);
228 fclose (fp);
230 return(ret);
231 #else
232 GSList *ret = NULL;
233 FILE *fp;
234 MonoW32ProcessModule *mod;
235 gchar buf[MAXPATHLEN + 1], *p, *endp;
236 gchar *start_start, *end_start, *prot_start, *offset_start;
237 gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
238 gpointer address_start, address_end, address_offset;
239 guint32 maj_dev, min_dev;
240 guint64 inode;
241 guint64 device;
243 fp = open_process_map (pid, "r");
244 if (!fp) {
245 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't open process map file for pid %d", __func__, pid);
246 return NULL;
249 while (fgets (buf, sizeof(buf), fp)) {
250 p = buf;
251 while (g_ascii_isspace (*p)) ++p;
252 start_start = p;
253 if (!g_ascii_isxdigit (*start_start)) {
254 continue;
256 address_start = (gpointer)strtoul (start_start, &endp, 16);
257 p = endp;
258 if (*p != '-') {
259 continue;
262 ++p;
263 end_start = p;
264 if (!g_ascii_isxdigit (*end_start)) {
265 continue;
267 address_end = (gpointer)strtoul (end_start, &endp, 16);
268 p = endp;
269 if (!g_ascii_isspace (*p)) {
270 continue;
273 while (g_ascii_isspace (*p)) ++p;
274 prot_start = p;
275 if (*prot_start != 'r' && *prot_start != '-') {
276 continue;
278 memcpy (prot_buf, prot_start, 4);
279 prot_buf[4] = '\0';
280 while (!g_ascii_isspace (*p)) ++p;
282 while (g_ascii_isspace (*p)) ++p;
283 offset_start = p;
284 if (!g_ascii_isxdigit (*offset_start)) {
285 continue;
287 address_offset = (gpointer)strtoul (offset_start, &endp, 16);
288 p = endp;
289 if (!g_ascii_isspace (*p)) {
290 continue;
293 while(g_ascii_isspace (*p)) ++p;
294 maj_dev_start = p;
295 if (!g_ascii_isxdigit (*maj_dev_start)) {
296 continue;
298 maj_dev = strtoul (maj_dev_start, &endp, 16);
299 p = endp;
300 if (*p != ':') {
301 continue;
304 ++p;
305 min_dev_start = p;
306 if (!g_ascii_isxdigit (*min_dev_start)) {
307 continue;
309 min_dev = strtoul (min_dev_start, &endp, 16);
310 p = endp;
311 if (!g_ascii_isspace (*p)) {
312 continue;
315 while (g_ascii_isspace (*p)) ++p;
316 inode_start = p;
317 if (!g_ascii_isxdigit (*inode_start)) {
318 continue;
320 inode = (guint64)strtol (inode_start, &endp, 10);
321 p = endp;
322 if (!g_ascii_isspace (*p)) {
323 continue;
325 #if defined(MAJOR_IN_MKDEV) || defined(MAJOR_IN_SYSMACROS)
326 device = makedev ((int)maj_dev, (int)min_dev);
327 #else
328 (void)maj_dev;
329 (void)min_dev;
330 device = 0;
331 #endif
332 if ((device == 0) && (inode == 0)) {
333 continue;
336 while(g_ascii_isspace (*p)) ++p;
337 /* p now points to the filename */
339 mod = g_new0 (MonoW32ProcessModule, 1);
340 mod->address_start = address_start;
341 mod->address_end = address_end;
342 mod->perms = g_strdup (prot_buf);
343 mod->address_offset = address_offset;
344 mod->device = device;
345 mod->inode = inode;
346 mod->filename = g_strdup (g_strstrip (p));
348 if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) {
349 ret = g_slist_prepend (ret, mod);
350 } else {
351 mono_w32process_module_free (mod);
355 ret = g_slist_reverse (ret);
357 fclose (fp);
359 return(ret);
360 #endif
363 void
364 mono_w32process_platform_init_once (void)
368 #endif