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