Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / w32process-unix-osx.c
blob2568a44223e3343aafffef3a66f8c6852e9dd659
1 /**
2 * \file
3 */
5 #include "w32process.h"
6 #include "w32process-unix-internals.h"
8 #ifdef USE_OSX_BACKEND
10 #include <errno.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13 #include <sys/proc.h>
14 #include <sys/sysctl.h>
15 #include <sys/utsname.h>
16 #include <mach-o/dyld.h>
17 #include <mach-o/getsect.h>
18 #include <dlfcn.h>
20 /* sys/resource.h (for rusage) is required when using osx 10.3 (but not 10.4) */
21 #ifdef __APPLE__
22 #include <TargetConditionals.h>
23 #include <sys/resource.h>
24 #ifdef HAVE_LIBPROC_H
25 /* proc_name */
26 #include <libproc.h>
27 #endif
28 #endif
30 #include "utils/mono-logger-internals.h"
31 #include "icall-decl.h"
33 gchar*
34 mono_w32process_get_name (pid_t pid)
36 gchar *ret = NULL;
38 #if defined (__mono_ppc__) || !defined (TARGET_OSX)
39 size_t size;
40 struct kinfo_proc *pi;
41 gint mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
43 if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0)
44 return(ret);
46 if ((pi = g_malloc (size)) == NULL)
47 return(ret);
49 if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) {
50 if (errno == ENOMEM) {
51 g_free (pi);
52 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't allocate enough memory for kproc info", __func__);
54 return(ret);
57 if (strlen (pi->kp_proc.p_comm) > 0)
58 ret = g_strdup (pi->kp_proc.p_comm);
60 g_free (pi);
61 #else
62 gchar buf[256];
63 gint res;
65 /* No proc name on OSX < 10.5 nor ppc nor iOS */
66 memset (buf, '\0', sizeof(buf));
67 res = proc_name (pid, buf, sizeof(buf));
68 if (res == 0) {
69 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: proc_name failed, error (%d) \"%s\"", __func__, errno, g_strerror (errno));
70 return NULL;
73 // Fixes proc_name triming values to 15 characters #32539
74 if (strlen (buf) >= MAXCOMLEN - 1) {
75 gchar path_buf [PROC_PIDPATHINFO_MAXSIZE];
76 gchar *name_buf;
77 gint path_len;
79 memset (path_buf, '\0', sizeof(path_buf));
80 path_len = proc_pidpath (pid, path_buf, sizeof(path_buf));
82 if (path_len > 0 && path_len < sizeof(path_buf)) {
83 name_buf = path_buf + path_len;
84 for(;name_buf > path_buf; name_buf--) {
85 if (name_buf [0] == '/') {
86 name_buf++;
87 break;
91 if (memcmp (buf, name_buf, MAXCOMLEN - 1) == 0)
92 ret = g_strdup (name_buf);
96 if (ret == NULL && strlen (buf) > 0)
97 ret = g_strdup (buf);
98 #endif
100 return ret;
103 gchar*
104 mono_w32process_get_path (pid_t pid)
106 #if defined(__mono_ppc__) || !defined(TARGET_OSX)
107 return mono_w32process_get_name (pid);
108 #else
109 gchar buf [PROC_PIDPATHINFO_MAXSIZE];
110 gint res;
112 res = proc_pidpath (pid, buf, sizeof (buf));
113 if (res <= 0)
114 return NULL;
115 if (buf [0] == '\0')
116 return NULL;
117 return g_strdup (buf);
118 #endif
121 struct mono_dyld_image_info
123 const void *header_addr;
124 const void *data_section_start;
125 const void *data_section_end;
126 const char *name;
127 guint64 order;
130 static guint64 dyld_order = 0;
131 static GHashTable *images;
132 static mono_mutex_t images_mutex;
134 static int
135 sort_modules_by_load_order (gconstpointer a, gconstpointer b)
137 MonoW32ProcessModule *ma = (MonoW32ProcessModule *) a;
138 MonoW32ProcessModule *mb = (MonoW32ProcessModule *) b;
139 return ma->inode == mb->inode ? 0 : ma->inode < mb->inode ? -1 : 1;
142 GSList *
143 mono_w32process_get_modules (pid_t pid)
145 GSList *ret = NULL;
146 MONO_ENTER_GC_SAFE;
147 if (pid != getpid ())
148 goto done;
150 GHashTableIter it;
151 g_hash_table_iter_init (&it, images);
153 gpointer val;
155 mono_os_mutex_lock (&images_mutex);
156 while (g_hash_table_iter_next (&it, NULL, &val)) {
157 struct mono_dyld_image_info *info = (struct mono_dyld_image_info *) val;
158 MonoW32ProcessModule *mod = g_new0 (MonoW32ProcessModule, 1);
159 mod->address_start = GINT_TO_POINTER (info->data_section_start);
160 mod->address_end = GINT_TO_POINTER (info->data_section_end);
161 mod->perms = g_strdup ("r--p");
162 mod->address_offset = 0;
163 mod->device = 0;
164 mod->inode = info->order;
165 mod->filename = g_strdup (info->name);
166 ret = g_slist_prepend (ret, mod);
168 mono_os_mutex_unlock (&images_mutex);
169 ret = g_slist_sort (ret, &sort_modules_by_load_order);
170 done:
171 MONO_EXIT_GC_SAFE;
172 return ret;
175 static void
176 mono_dyld_image_info_free (void *info)
178 struct mono_dyld_image_info *dinfo = (struct mono_dyld_image_info *) info;
179 g_free ((void *) dinfo->name);
180 g_free (dinfo);
183 static void
184 image_added (const struct mach_header *hdr32, intptr_t vmaddr_slide)
186 #if SIZEOF_VOID_P == 8
187 const struct mach_header_64 *hdr64 = (const struct mach_header_64 *)hdr32;
188 const struct section_64 *sec = getsectbynamefromheader_64 (hdr64, SEG_DATA, SECT_DATA);
189 #else
190 const struct section *sec = getsectbynamefromheader (hdr32, SEG_DATA, SECT_DATA);
191 #endif
192 Dl_info dlinfo;
193 if (!dladdr (hdr32, &dlinfo)) return;
194 if (sec == NULL) return;
196 mono_os_mutex_lock (&images_mutex);
197 gpointer found = g_hash_table_lookup (images, (gpointer) hdr32);
198 mono_os_mutex_unlock (&images_mutex);
200 if (found == NULL) {
201 struct mono_dyld_image_info *info = g_new0 (struct mono_dyld_image_info, 1);
202 info->header_addr = hdr32;
203 info->data_section_start = GINT_TO_POINTER (sec->addr);
204 info->data_section_end = GINT_TO_POINTER (sec->addr + sec->size);
205 info->name = g_strdup (dlinfo.dli_fname);
206 info->order = dyld_order;
207 ++dyld_order;
209 mono_os_mutex_lock (&images_mutex);
210 g_hash_table_insert (images, (gpointer) hdr32, info);
211 mono_os_mutex_unlock (&images_mutex);
215 static void
216 image_removed (const struct mach_header *hdr32, intptr_t vmaddr_slide)
218 mono_os_mutex_lock (&images_mutex);
219 g_hash_table_remove (images, hdr32);
220 mono_os_mutex_unlock (&images_mutex);
223 void
224 mono_w32process_platform_init_once (void)
226 mono_os_mutex_init (&images_mutex);
227 images = g_hash_table_new_full (NULL, NULL, NULL, &mono_dyld_image_info_free);
229 /* Ensure that the functions used within the lock-protected region in
230 * mono_w32process_get_modules have been loaded, in case these symbols
231 * are lazily bound. g_new0 and g_strdup will be called by
232 * _dyld_register_func_for_add_image when it calls image_added with the
233 * current list of all loaded dynamic libraries
235 GSList *dummy = g_slist_prepend (NULL, NULL);
236 g_slist_free (dummy);
237 GHashTableIter it;
238 g_hash_table_iter_init (&it, images);
239 g_hash_table_iter_next (&it, NULL, NULL);
241 _dyld_register_func_for_add_image (&image_added);
242 _dyld_register_func_for_remove_image (&image_removed);
245 #else
247 MONO_EMPTY_SOURCE_FILE (w32process_unix_osx);
249 #endif