3bc10906b8cf008b7dfeac476ec147708730d5e7
[mono.git] / mono / metadata / w32process-unix-default.c
1 /**
2  * \file
3  */
4
5 #include "w32process.h"
6 #include "w32process-unix-internals.h"
7
8 #ifdef USE_DEFAULT_BACKEND
9
10 #include <unistd.h>
11
12 #ifdef PLATFORM_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
22
23 /* makedev() macro */
24 #ifdef MAJOR_IN_MKDEV
25 #include <sys/mkdev.h>
26 #elif defined MAJOR_IN_SYSMACROS
27 #include <sys/sysmacros.h>
28 #endif
29
30 #include "utils/mono-logger-internals.h"
31
32 #ifndef MAXPATHLEN
33 #define MAXPATHLEN 242
34 #endif
35
36 gchar*
37 mono_w32process_get_name (pid_t pid)
38 {
39         FILE *fp;
40         gchar *filename;
41         gchar buf[256];
42         gchar *ret = NULL;
43
44 #if defined(PLATFORM_SOLARIS)
45         filename = g_strdup_printf ("/proc/%d/psinfo", pid);
46         if ((fp = fopen (filename, "r")) != NULL) {
47                 struct psinfo info;
48                 int nread;
49
50                 nread = fread (&info, sizeof (info), 1, fp);
51                 if (nread == 1) {
52                         ret = g_strdup (info.pr_fname);
53                 }
54
55                 fclose (fp);
56         }
57         g_free (filename);
58 #else
59         memset (buf, '\0', sizeof(buf));
60         filename = g_strdup_printf ("/proc/%d/exe", pid);
61         if (readlink (filename, buf, 255) > 0) {
62                 ret = g_strdup (buf);
63         }
64         g_free (filename);
65
66         if (ret != NULL) {
67                 return(ret);
68         }
69
70         filename = g_strdup_printf ("/proc/%d/cmdline", pid);
71         if ((fp = fopen (filename, "r")) != NULL) {
72                 if (fgets (buf, 256, fp) != NULL) {
73                         ret = g_strdup (buf);
74                 }
75
76                 fclose (fp);
77         }
78         g_free (filename);
79
80         if (ret != NULL) {
81                 return(ret);
82         }
83
84         filename = g_strdup_printf ("/proc/%d/stat", pid);
85         if ((fp = fopen (filename, "r")) != NULL) {
86                 if (fgets (buf, 256, fp) != NULL) {
87                         char *start, *end;
88
89                         start = strchr (buf, '(');
90                         if (start != NULL) {
91                                 end = strchr (start + 1, ')');
92
93                                 if (end != NULL) {
94                                         ret = g_strndup (start + 1,
95                                                          end - start - 1);
96                                 }
97                         }
98                 }
99
100                 fclose (fp);
101         }
102         g_free (filename);
103 #endif
104
105         return ret;
106 }
107
108 gchar*
109 mono_w32process_get_path (pid_t pid)
110 {
111         return mono_w32process_get_name (pid);
112 }
113
114 static FILE *
115 open_process_map (int pid, const char *mode)
116 {
117         gint i;
118         const gchar *proc_path[] = {
119                 "/proc/%d/maps", /* GNU/Linux */
120                 "/proc/%d/map",  /* FreeBSD */
121                 NULL
122         };
123
124         for (i = 0; proc_path [i]; i++) {
125                 gchar *filename;
126                 FILE *fp;
127
128                 filename = g_strdup_printf (proc_path[i], pid);
129                 fp = fopen (filename, mode);
130                 g_free (filename);
131
132                 if (fp)
133                         return fp;
134         }
135
136         return NULL;
137 }
138
139
140 GSList*
141 mono_w32process_get_modules (pid_t pid)
142 {
143         GSList *ret = NULL;
144         FILE *fp;
145         MonoW32ProcessModule *mod;
146         gchar buf[MAXPATHLEN + 1], *p, *endp;
147         gchar *start_start, *end_start, *prot_start, *offset_start;
148         gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
149         gpointer address_start, address_end, address_offset;
150         guint32 maj_dev, min_dev;
151         guint64 inode;
152         guint64 device;
153
154         fp = open_process_map (pid, "r");
155         if (!fp) {
156                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't open process map file for pid %d", __func__, pid);
157                 return NULL;
158         }
159
160         while (fgets (buf, sizeof(buf), fp)) {
161                 p = buf;
162                 while (g_ascii_isspace (*p)) ++p;
163                 start_start = p;
164                 if (!g_ascii_isxdigit (*start_start)) {
165                         continue;
166                 }
167                 address_start = (gpointer)strtoul (start_start, &endp, 16);
168                 p = endp;
169                 if (*p != '-') {
170                         continue;
171                 }
172
173                 ++p;
174                 end_start = p;
175                 if (!g_ascii_isxdigit (*end_start)) {
176                         continue;
177                 }
178                 address_end = (gpointer)strtoul (end_start, &endp, 16);
179                 p = endp;
180                 if (!g_ascii_isspace (*p)) {
181                         continue;
182                 }
183
184                 while (g_ascii_isspace (*p)) ++p;
185                 prot_start = p;
186                 if (*prot_start != 'r' && *prot_start != '-') {
187                         continue;
188                 }
189                 memcpy (prot_buf, prot_start, 4);
190                 prot_buf[4] = '\0';
191                 while (!g_ascii_isspace (*p)) ++p;
192
193                 while (g_ascii_isspace (*p)) ++p;
194                 offset_start = p;
195                 if (!g_ascii_isxdigit (*offset_start)) {
196                         continue;
197                 }
198                 address_offset = (gpointer)strtoul (offset_start, &endp, 16);
199                 p = endp;
200                 if (!g_ascii_isspace (*p)) {
201                         continue;
202                 }
203
204                 while(g_ascii_isspace (*p)) ++p;
205                 maj_dev_start = p;
206                 if (!g_ascii_isxdigit (*maj_dev_start)) {
207                         continue;
208                 }
209                 maj_dev = strtoul (maj_dev_start, &endp, 16);
210                 p = endp;
211                 if (*p != ':') {
212                         continue;
213                 }
214
215                 ++p;
216                 min_dev_start = p;
217                 if (!g_ascii_isxdigit (*min_dev_start)) {
218                         continue;
219                 }
220                 min_dev = strtoul (min_dev_start, &endp, 16);
221                 p = endp;
222                 if (!g_ascii_isspace (*p)) {
223                         continue;
224                 }
225
226                 while (g_ascii_isspace (*p)) ++p;
227                 inode_start = p;
228                 if (!g_ascii_isxdigit (*inode_start)) {
229                         continue;
230                 }
231                 inode = (guint64)strtol (inode_start, &endp, 10);
232                 p = endp;
233                 if (!g_ascii_isspace (*p)) {
234                         continue;
235                 }
236
237                 device = makedev ((int)maj_dev, (int)min_dev);
238                 if ((device == 0) && (inode == 0)) {
239                         continue;
240                 }
241
242                 while(g_ascii_isspace (*p)) ++p;
243                 /* p now points to the filename */
244
245                 mod = g_new0 (MonoW32ProcessModule, 1);
246                 mod->address_start = address_start;
247                 mod->address_end = address_end;
248                 mod->perms = g_strdup (prot_buf);
249                 mod->address_offset = address_offset;
250                 mod->device = device;
251                 mod->inode = inode;
252                 mod->filename = g_strdup (g_strstrip (p));
253
254                 if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) {
255                         ret = g_slist_prepend (ret, mod);
256                 } else {
257                         mono_w32process_module_free (mod);
258                 }
259         }
260
261         ret = g_slist_reverse (ret);
262
263         fclose (fp);
264
265         return(ret);
266 }
267
268 #endif