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