[process] Improve error message for inaccessible process (#4354)
[mono.git] / mono / metadata / w32process-unix-osx.c
1
2 #include "w32process.h"
3 #include "w32process-unix-internals.h"
4
5 #ifdef USE_OSX_BACKEND
6
7 #include <errno.h>
8 #include <sys/time.h>
9 #include <sys/proc.h>
10 #include <sys/sysctl.h>
11 #include <sys/utsname.h>
12 #include <mach-o/dyld.h>
13 #include <mach-o/getsect.h>
14
15 /* sys/resource.h (for rusage) is required when using osx 10.3 (but not 10.4) */
16 #ifdef __APPLE__
17 #include <TargetConditionals.h>
18 #include <sys/resource.h>
19 #ifdef HAVE_LIBPROC_H
20 /* proc_name */
21 #include <libproc.h>
22 #endif
23 #endif
24
25 #include "utils/mono-logger-internals.h"
26
27 gchar*
28 mono_w32process_get_name (pid_t pid)
29 {
30         gchar *ret = NULL;
31
32 #if defined (__mono_ppc__) || !defined (TARGET_OSX)
33         size_t size;
34         struct kinfo_proc *pi;
35         gint mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
36
37         if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0)
38                 return(ret);
39
40         if ((pi = g_malloc (size)) == NULL)
41                 return(ret);
42
43         if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) {
44                 if (errno == ENOMEM) {
45                         g_free (pi);
46                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__);
47                 }
48                 return(ret);
49         }
50
51         if (strlen (pi->kp_proc.p_comm) > 0)
52                 ret = g_strdup (pi->kp_proc.p_comm);
53
54         g_free (pi);
55 #else
56         gchar buf[256];
57         gint res;
58
59         /* No proc name on OSX < 10.5 nor ppc nor iOS */
60         memset (buf, '\0', sizeof(buf));
61         res = proc_name (pid, buf, sizeof(buf));
62         if (res == 0) {
63                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: proc_name failed, error (%d) \"%s\"", __func__, errno, g_strerror (errno));
64                 return NULL;
65         }
66
67         // Fixes proc_name triming values to 15 characters #32539
68         if (strlen (buf) >= MAXCOMLEN - 1) {
69                 gchar path_buf [PROC_PIDPATHINFO_MAXSIZE];
70                 gchar *name_buf;
71                 gint path_len;
72
73                 memset (path_buf, '\0', sizeof(path_buf));
74                 path_len = proc_pidpath (pid, path_buf, sizeof(path_buf));
75
76                 if (path_len > 0 && path_len < sizeof(path_buf)) {
77                         name_buf = path_buf + path_len;
78                         for(;name_buf > path_buf; name_buf--) {
79                                 if (name_buf [0] == '/') {
80                                         name_buf++;
81                                         break;
82                                 }
83                         }
84
85                         if (memcmp (buf, name_buf, MAXCOMLEN - 1) == 0)
86                                 ret = g_strdup (name_buf);
87                 }
88         }
89
90         if (ret == NULL && strlen (buf) > 0)
91                 ret = g_strdup (buf);
92 #endif
93
94         return ret;
95 }
96
97 gchar*
98 mono_w32process_get_path (pid_t pid)
99 {
100 #if defined(__mono_ppc__) || !defined(TARGET_OSX)
101         return mono_w32process_get_name (pid);
102 #else
103         gchar buf [PROC_PIDPATHINFO_MAXSIZE];
104         gint res;
105
106         res = proc_pidpath (pid, buf, sizeof (buf));
107         if (res <= 0)
108                 return NULL;
109         if (buf [0] == '\0')
110                 return NULL;
111         return g_strdup (buf);
112 #endif
113 }
114
115 GSList*
116 mono_w32process_get_modules (pid_t pid)
117 {
118         GSList *ret = NULL;
119         MonoW32ProcessModule *mod;
120         guint32 count = _dyld_image_count ();
121         int i = 0;
122
123         for (i = 0; i < count; i++) {
124 #if SIZEOF_VOID_P == 8
125                 const struct mach_header_64 *hdr;
126                 const struct section_64 *sec;
127 #else
128                 const struct mach_header *hdr;
129                 const struct section *sec;
130 #endif
131                 const char *name;
132
133                 name = _dyld_get_image_name (i);
134 #if SIZEOF_VOID_P == 8
135                 hdr = (const struct mach_header_64*)_dyld_get_image_header (i);
136                 sec = getsectbynamefromheader_64 (hdr, SEG_DATA, SECT_DATA);
137 #else
138                 hdr = _dyld_get_image_header (i);
139                 sec = getsectbynamefromheader (hdr, SEG_DATA, SECT_DATA);
140 #endif
141
142                 /* Some dynlibs do not have data sections on osx (#533893) */
143                 if (sec == 0)
144                         continue;
145
146                 mod = g_new0 (MonoW32ProcessModule, 1);
147                 mod->address_start = GINT_TO_POINTER (sec->addr);
148                 mod->address_end = GINT_TO_POINTER (sec->addr+sec->size);
149                 mod->perms = g_strdup ("r--p");
150                 mod->address_offset = 0;
151                 mod->device = makedev (0, 0);
152                 mod->inode = i;
153                 mod->filename = g_strdup (name);
154
155                 if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) {
156                         ret = g_slist_prepend (ret, mod);
157                 } else {
158                         mono_w32process_module_free (mod);
159                 }
160         }
161
162         return g_slist_reverse (ret);
163 }
164
165 #endif