[io-layer] Extract Process runtime support (#3859)
[mono.git] / mono / metadata / w32process-unix-bsd.c
1
2 #include "w32process.h"
3 #include "w32process-unix-internals.h"
4
5 #ifdef USE_BSD_BACKEND
6
7 #include <sys/proc.h>
8 #include <sys/sysctl.h>
9 #if !defined(__OpenBSD__)
10 #include <sys/utsname.h>
11 #endif
12 #if defined(__FreeBSD__)
13 #include <sys/user.h> /* struct kinfo_proc */
14 #endif
15
16 #include <link.h>
17
18 #include "utils/mono-logger-internals.h"
19
20 gchar*
21 mono_w32process_get_name (pid_t pid)
22 {
23         gint mib [6];
24         gsize size;
25         struct kinfo_proc *pi;
26         gchar *ret;
27
28 #if defined(__FreeBSD__)
29         mib [0] = CTL_KERN;
30         mib [1] = KERN_PROC;
31         mib [2] = KERN_PROC_PID;
32         mib [3] = pid;
33         if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) {
34                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno);
35                 return NULL;
36         }
37
38         if ((pi = g_malloc (size)) == NULL)
39                 return NULL;
40
41         if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) {
42                 if (errno == ENOMEM) {
43                         g_free (pi);
44                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__);
45                 }
46                 return NULL;
47         }
48
49         ret = strlen (pi->ki_comm) > 0 ? g_strdup (pi->ki_comm) : NULL;
50
51         g_free (pi);
52 #elif defined(__OpenBSD__)
53         mib [0] = CTL_KERN;
54         mib [1] = KERN_PROC;
55         mib [2] = KERN_PROC_PID;
56         mib [3] = pid;
57         mib [4] = sizeof(struct kinfo_proc);
58         mib [5] = 0;
59
60 retry:
61         if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
62                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno);
63                 return NULL;
64         }
65
66         if ((pi = g_malloc (size)) == NULL)
67                 return NULL;
68
69         mib[5] = (int)(size / sizeof(struct kinfo_proc));
70
71         if ((sysctl (mib, 6, pi, &size, NULL, 0) < 0) ||
72                 (size != sizeof (struct kinfo_proc))) {
73                 if (errno == ENOMEM) {
74                         g_free (pi);
75                         goto retry;
76                 }
77                 return NULL;
78         }
79
80         ret = strlen (pi->p_comm) > 0 ? g_strdup (pi->p_comm) : NULL;
81
82         g_free (pi);
83 #endif
84
85         return ret;
86 }
87
88 gchar*
89 mono_w32process_get_path (pid_t pid)
90 {
91         return mono_w32process_get_name (pid);
92 }
93
94 static gint
95 mono_w32process_get_modules_callback (struct dl_phdr_info *info, gsize size, gpointer ptr)
96 {
97         if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + sizeof (info->dlpi_phnum))
98                 return (-1);
99
100         struct dl_phdr_info *cpy = g_calloc (1, sizeof(struct dl_phdr_info));
101         if (!cpy)
102                 return (-1);
103
104         memcpy(cpy, info, sizeof(*info));
105
106         g_ptr_array_add ((GPtrArray *)ptr, cpy);
107
108         return (0);
109 }
110
111 GSList*
112 mono_w32process_get_modules (pid_t pid)
113 {
114         GSList *ret = NULL;
115         MonoW32ProcessModule *mod;
116         GPtrArray *dlarray = g_ptr_array_new();
117         gint i;
118
119         if (dl_iterate_phdr (mono_w32process_get_modules_callback, dlarray) < 0)
120                 return NULL;
121
122         for (i = 0; i < dlarray->len; i++) {
123                 struct dl_phdr_info *info = g_ptr_array_index (dlarray, i);
124
125                 mod = g_new0 (MonoW32ProcessModule, 1);
126                 mod->address_start = (gpointer)(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
127                 mod->address_end = (gpointer)(info->dlpi_addr + info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr);
128                 mod->perms = g_strdup ("r--p");
129                 mod->address_offset = 0;
130                 mod->inode = i;
131                 mod->filename = g_strdup (info->dlpi_name);
132
133                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: inode=%d, filename=%s, address_start=%p, address_end=%p",
134                         __func__, mod->inode, mod->filename, mod->address_start, mod->address_end);
135
136                 g_free (info);
137
138                 if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) {
139                         ret = g_slist_prepend (ret, mod);
140                 } else {
141                         mono_w32process_module_free (mod);
142                 }
143         }
144
145         g_ptr_array_free (dlarray, TRUE);
146
147         return g_slist_reverse (ret);
148 }
149
150 #endif