+typedef struct
+{
+ gpointer address_start;
+ gpointer address_end;
+ gchar *perms;
+ gpointer address_offset;
+ dev_t device;
+ ino_t inode;
+ gchar *filename;
+} WapiProcModule;
+
+static void free_procmodule (WapiProcModule *mod)
+{
+ if (mod->perms != NULL) {
+ g_free (mod->perms);
+ }
+ if (mod->filename != NULL) {
+ g_free (mod->filename);
+ }
+ g_free (mod);
+}
+
+static gint find_procmodule (gconstpointer a, gconstpointer b)
+{
+ WapiProcModule *want = (WapiProcModule *)a;
+ WapiProcModule *compare = (WapiProcModule *)b;
+
+ if ((want->device == compare->device) &&
+ (want->inode == compare->inode)) {
+ return(0);
+ } else {
+ return(1);
+ }
+}
+
+#ifdef PLATFORM_MACOSX
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+
+static GSList *load_modules (void)
+{
+ GSList *ret = NULL;
+ WapiProcModule *mod;
+ uint32_t count = _dyld_image_count ();
+ int i = 0;
+
+ for (i = 0; i < count; i++) {
+#if SIZEOF_VOID_P == 8
+ const struct mach_header_64 *hdr;
+ const struct section_64 *sec;
+#else
+ const struct mach_header *hdr;
+ const struct section *sec;
+#endif
+ const char *name;
+ intptr_t slide;
+
+ slide = _dyld_get_image_vmaddr_slide (i);
+ name = _dyld_get_image_name (i);
+ hdr = _dyld_get_image_header (i);
+#if SIZEOF_VOID_P == 8
+ sec = getsectbynamefromheader_64 (hdr, SEG_DATA, SECT_DATA);
+#else
+ sec = getsectbynamefromheader (hdr, SEG_DATA, SECT_DATA);
+#endif
+
+ /* Some dynlibs do not have data sections on osx (#533893) */
+ if (sec == 0) {
+ continue;
+ }
+
+ mod = g_new0 (WapiProcModule, 1);
+ mod->address_start = GINT_TO_POINTER (sec->addr);
+ mod->address_end = GINT_TO_POINTER (sec->addr+sec->size);
+ mod->perms = g_strdup ("r--p");
+ mod->address_offset = 0;
+ mod->device = makedev (0, 0);
+ mod->inode = (ino_t) i;
+ mod->filename = g_strdup (name);
+
+ if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) {
+ ret = g_slist_prepend (ret, mod);
+ } else {
+ free_procmodule (mod);
+ }
+ }
+
+ ret = g_slist_reverse (ret);
+
+ return(ret);
+}
+#elif defined(__OpenBSD__)
+#include <link.h>
+static int load_modules_callback (struct dl_phdr_info *info, size_t size, void *ptr)
+{
+ if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+ + sizeof (info->dlpi_phnum))
+ return (-1);
+
+ struct dl_phdr_info *cpy = calloc(1, sizeof(struct dl_phdr_info));
+ if (!cpy)
+ return (-1);
+
+ memcpy(cpy, info, sizeof(*info));
+
+ g_ptr_array_add ((GPtrArray *)ptr, cpy);
+
+ return (0);
+}
+
+static GSList *load_modules (void)
+{
+ GSList *ret = NULL;
+ WapiProcModule *mod;
+ GPtrArray *dlarray = g_ptr_array_new();
+ int i;
+
+ if (dl_iterate_phdr(load_modules_callback, dlarray) < 0)
+ return (ret);
+
+ for (i = 0; i < dlarray->len; i++) {
+ struct dl_phdr_info *info = g_ptr_array_index (dlarray, i);
+
+ mod = g_new0 (WapiProcModule, 1);
+ mod->address_start = (gpointer)(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
+ mod->address_end = (gpointer)(info->dlpi_addr +
+ info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr);
+ mod->perms = g_strdup ("r--p");
+ mod->address_offset = 0;
+ mod->inode = (ino_t) i;
+ mod->filename = g_strdup (info->dlpi_name);
+
+#ifdef DEBUG
+ g_message ("%s: inode=%d, filename=%s, address_start=%p, address_end=%p", __func__,
+ mod->inode, mod->filename, mod->address_start, mod->address_end);
+#endif
+
+ free(info);
+
+ if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) {
+ ret = g_slist_prepend (ret, mod);
+ } else {
+ free_procmodule (mod);
+ }
+ }
+
+ g_ptr_array_free (dlarray, TRUE);
+
+ ret = g_slist_reverse (ret);
+
+ return(ret);
+}
+#elif defined(__HAIKU__)
+
+static GSList *load_modules (void)
+{
+ GSList *ret = NULL;
+ WapiProcModule *mod;
+ int32 cookie = 0;
+ image_info imageInfo;
+
+ while (get_next_image_info (B_CURRENT_TEAM, &cookie, &imageInfo) == B_OK) {
+ mod = g_new0 (WapiProcModule, 1);
+ mod->device = imageInfo.device;
+ mod->inode = imageInfo.node;
+ mod->filename = g_strdup (imageInfo.name);
+ mod->address_start = MIN (imageInfo.text, imageInfo.data);
+ mod->address_end = MAX ((uint8_t*)imageInfo.text + imageInfo.text_size,
+ (uint8_t*)imageInfo.data + imageInfo.data_size);
+ mod->perms = g_strdup ("r--p");
+ mod->address_offset = 0;
+
+ if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) {
+ ret = g_slist_prepend (ret, mod);
+ } else {
+ free_procmodule (mod);
+ }
+ }
+
+ ret = g_slist_reverse (ret);
+
+ return ret;
+}
+#else
+static GSList *load_modules (FILE *fp)
+{
+ GSList *ret = NULL;
+ WapiProcModule *mod;
+ gchar buf[MAXPATHLEN + 1], *p, *endp;
+ gchar *start_start, *end_start, *prot_start, *offset_start;
+ gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
+ gpointer address_start, address_end, address_offset;
+ guint32 maj_dev, min_dev;
+ ino_t inode;
+ dev_t device;
+
+ while (fgets (buf, sizeof(buf), fp)) {
+ p = buf;
+ while (g_ascii_isspace (*p)) ++p;
+ start_start = p;
+ if (!g_ascii_isxdigit (*start_start)) {
+ continue;
+ }
+ address_start = (gpointer)strtoul (start_start, &endp, 16);
+ p = endp;
+ if (*p != '-') {
+ continue;
+ }
+
+ ++p;
+ end_start = p;
+ if (!g_ascii_isxdigit (*end_start)) {
+ continue;
+ }
+ address_end = (gpointer)strtoul (end_start, &endp, 16);
+ p = endp;
+ if (!g_ascii_isspace (*p)) {
+ continue;
+ }
+
+ while (g_ascii_isspace (*p)) ++p;
+ prot_start = p;
+ if (*prot_start != 'r' && *prot_start != '-') {
+ continue;
+ }
+ memcpy (prot_buf, prot_start, 4);
+ prot_buf[4] = '\0';
+ while (!g_ascii_isspace (*p)) ++p;
+
+ while (g_ascii_isspace (*p)) ++p;
+ offset_start = p;
+ if (!g_ascii_isxdigit (*offset_start)) {
+ continue;
+ }
+ address_offset = (gpointer)strtoul (offset_start, &endp, 16);
+ p = endp;
+ if (!g_ascii_isspace (*p)) {
+ continue;
+ }
+
+ while(g_ascii_isspace (*p)) ++p;
+ maj_dev_start = p;
+ if (!g_ascii_isxdigit (*maj_dev_start)) {
+ continue;
+ }
+ maj_dev = strtoul (maj_dev_start, &endp, 16);
+ p = endp;
+ if (*p != ':') {
+ continue;
+ }
+
+ ++p;
+ min_dev_start = p;
+ if (!g_ascii_isxdigit (*min_dev_start)) {
+ continue;
+ }
+ min_dev = strtoul (min_dev_start, &endp, 16);
+ p = endp;
+ if (!g_ascii_isspace (*p)) {
+ continue;
+ }
+
+ while (g_ascii_isspace (*p)) ++p;
+ inode_start = p;
+ if (!g_ascii_isxdigit (*inode_start)) {
+ continue;
+ }
+ inode = (ino_t)strtol (inode_start, &endp, 10);
+ p = endp;
+ if (!g_ascii_isspace (*p)) {
+ continue;
+ }
+
+ device = makedev ((int)maj_dev, (int)min_dev);
+ if ((device == 0) &&
+ (inode == 0)) {
+ continue;
+ }
+
+ while(g_ascii_isspace (*p)) ++p;
+ /* p now points to the filename */
+
+ mod = g_new0 (WapiProcModule, 1);
+ mod->address_start = address_start;
+ mod->address_end = address_end;
+ mod->perms = g_strdup (prot_buf);
+ mod->address_offset = address_offset;
+ mod->device = device;
+ mod->inode = inode;
+ mod->filename = g_strdup (g_strstrip (p));
+
+ if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) {
+ ret = g_slist_prepend (ret, mod);
+ } else {
+ free_procmodule (mod);
+ }
+ }
+
+ ret = g_slist_reverse (ret);
+
+ return(ret);
+}
+#endif
+
+static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename)
+{
+ char* lastsep = NULL;
+ char* pname = NULL;
+ char* mname = NULL;
+ gboolean result = FALSE;
+
+ if (procname == NULL || modulename == NULL)
+ return (FALSE);
+
+ pname = mono_path_resolve_symlinks (procname);
+ mname = mono_path_resolve_symlinks (modulename);
+
+ if (!strcmp (pname, mname))
+ result = TRUE;
+
+ if (!result) {
+ lastsep = strrchr (mname, '/');
+ if (lastsep)
+ if (!strcmp (lastsep+1, pname))
+ result = TRUE;
+ }
+
+ g_free (pname);
+ g_free (mname);
+
+ return result;
+}
+
+#if !defined(__OpenBSD__)
+static FILE *
+open_process_map (int pid, const char *mode)
+{
+ FILE *fp = NULL;
+ const gchar *proc_path[] = {
+ "/proc/%d/maps", /* GNU/Linux */
+ "/proc/%d/map", /* FreeBSD */
+ NULL
+ };
+ int i;
+ gchar *filename;
+
+ for (i = 0; fp == NULL && proc_path [i]; i++) {
+ filename = g_strdup_printf (proc_path[i], pid);
+ fp = fopen (filename, mode);
+ g_free (filename);
+ }
+
+ return fp;
+}
+#endif
+