static inline int local_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, void *arg) { unw_dyn_info_list_t *list; unw_dyn_info_t *di; # pragma weak _U_dyn_info_list_addr if (!_U_dyn_info_list_addr) return -UNW_ENOINFO; list = (unw_dyn_info_list_t *) (uintptr_t) _U_dyn_info_list_addr (); for (di = list->first; di; di = di->next) if (ip >= di->start_ip && ip < di->end_ip) return unwi_extract_dynamic_proc_info (as, ip, pi, di, need_unwind_info, arg); return -UNW_ENOINFO; }
HIDDEN int unwi_dyn_remote_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, void *arg) { unw_accessors_t *a = unw_get_accessors (as); unw_word_t dyn_list_addr, addr, next_addr, gen1, gen2, start_ip, end_ip; unw_dyn_info_t *di = NULL; int ret; if (as->dyn_info_list_addr) dyn_list_addr = as->dyn_info_list_addr; else { if ((*a->get_dyn_info_list_addr) (as, &dyn_list_addr, arg) < 0) return -UNW_ENOINFO; if (as->caching_policy != UNW_CACHE_NONE) as->dyn_info_list_addr = dyn_list_addr; } do { addr = dyn_list_addr; ret = -UNW_ENOINFO; if (fetchw (as, a, &addr, &gen1, arg) < 0 || fetchw (as, a, &addr, &next_addr, arg) < 0) return ret; for (addr = next_addr; addr != 0; addr = next_addr) { if (fetchw (as, a, &addr, &next_addr, arg) < 0) goto recheck; /* only fail if generation # didn't change */ addr += WSIZE; /* skip over prev_addr */ if (fetchw (as, a, &addr, &start_ip, arg) < 0 || fetchw (as, a, &addr, &end_ip, arg) < 0) goto recheck; /* only fail if generation # didn't change */ if (ip >= start_ip && ip < end_ip) { if (!di) di = calloc (1, sizeof (*di)); di->start_ip = start_ip; di->end_ip = end_ip; if (fetchw (as, a, &addr, &di->gp, arg) < 0 || fetch32 (as, a, &addr, &di->format, arg) < 0) goto recheck; /* only fail if generation # didn't change */ addr += 4; /* skip over padding */ if (need_unwind_info && intern_dyn_info (as, a, &addr, di, arg) < 0) goto recheck; /* only fail if generation # didn't change */ if (unwi_extract_dynamic_proc_info (as, ip, pi, di, need_unwind_info, arg) < 0) { free_dyn_info (di); goto recheck; /* only fail if generation # didn't change */ } ret = 0; /* OK, found it */ break; } } /* Re-check generation number to ensure the data we have is consistent. */ recheck: addr = dyn_list_addr; if (fetchw (as, a, &addr, &gen2, arg) < 0) return ret; } while (gen1 != gen2); if (ret < 0 && di) free (di); return ret; }