td_err_e td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) { psaddr_t versaddr; char versbuf[sizeof (VERSION)]; LOG ("td_ta_new"); /* Check whether the versions match. */ if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK) return TD_NOLIBTHREAD; if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) return TD_ERR; if (memcmp (versbuf, VERSION, sizeof VERSION) != 0) /* Not the right version. */ return TD_VERSION; /* Fill in the appropriate information. */ *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t)); if (*ta == NULL) return TD_MALLOC; /* Store the proc handle which we will pass to the callback functions back into the debugger. */ (*ta)->ph = ps; /* Now add the new agent descriptor to the list. */ list_add (&(*ta)->list, &__td_agent_list); return TD_OK; }
td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name) { if (*sizep == 0) { psaddr_t descptr; ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr); if (err == PS_NOSYM) return TD_NOCAPAB; if (err == PS_OK) err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep); if (err != PS_OK) return TD_ERR; if (*sizep & 0xff000000U) *sizep = bswap_32 (*sizep); } return TD_OK; }
td_err_e _td_locate_field (td_thragent_t *ta, db_desc_t desc, int descriptor_name, psaddr_t idx, psaddr_t *address) { uint32_t elemsize; if (DB_DESC_SIZE (desc) == 0) { /* Read the information about this field from the inferior. */ psaddr_t descptr; ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr); if (err == PS_NOSYM) return TD_NOCAPAB; if (err == PS_OK) err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC); if (err != PS_OK) return TD_ERR; if (DB_DESC_SIZE (desc) == 0) return TD_DBERR; if (DB_DESC_SIZE (desc) & 0xff000000U) { /* Byte-swap these words, though we leave the size word in native order as the handy way to distinguish. */ DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc)); DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc)); } } if (idx != 0 && DB_DESC_NELEM (desc) != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc)) /* This is an internal indicator to callers with nonzero IDX that the IDX value is too big. */ return TD_NOAPLIC; elemsize = DB_DESC_SIZE (desc); if (elemsize & 0xff000000U) elemsize = bswap_32 (elemsize); *address += (int32_t) DB_DESC_OFFSET (desc); *address += (elemsize / 8 * (idx - (psaddr_t) 0)); return TD_OK; }
td_err_e td_ta_get_nthreads (const td_thragent_t *ta, int *np) { psaddr_t addr; LOG ("td_ta_get_nthreads"); /* Test whether the TA parameter is ok. */ if (! ta_ok (ta)) return TD_BADTA; /* Access the variable `__pthread_handles_num'. */ if (td_lookup (ta->ph, PTHREAD_HANDLES_NUM, &addr) != PS_OK) return TD_ERR; /* XXX Other error value? */ if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK) return TD_ERR; /* XXX Other error value? */ return TD_OK; }
td_err_e td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) { psaddr_t addr; psaddr_t versaddr; char versbuf[sizeof (VERSION)]; struct agent_list *elemp; LOG ("td_ta_new"); /* Get the global event mask. This is one of the variables which are new in the thread library to enable debugging. If it is not available we cannot debug. */ if (td_lookup (ps, PTHREAD_THREADS_EVENTS, &addr) != PS_OK) return TD_NOLIBTHREAD; /* Check whether the versions match. */ if (td_lookup (ps, LINUXTHREADS_VERSION, &versaddr) != PS_OK) return TD_VERSION; if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) return TD_ERR; versbuf[sizeof (versbuf) - 1] = '\0'; if (strcmp (versbuf, VERSION) != 0) /* Not the right version. */ return TD_VERSION; /* Fill in the appropriate information. */ *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t)); if (*ta == NULL) return TD_MALLOC; /* Store the proc handle which we will pass to the callback functions back into the debugger. */ (*ta)->ph = ps; /* Remember the address. */ (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr; /* Get the pointer to the variable pointing to the thread descriptor with the last event. */ if (td_lookup (ps, PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event) != PS_OK) { free_return: free (*ta); return TD_ERR; } /* Get the pointer to the variable containing the number of active threads. */ if (td_lookup (ps, PTHREAD_HANDLES_NUM, &(*ta)->pthread_handles_num) != PS_OK) goto free_return; /* See whether the library contains the necessary symbols. */ if (td_lookup (ps, PTHREAD_HANDLES, &addr) != PS_OK) goto free_return; (*ta)->handles = (struct pthread_handle_struct *) addr; if (td_lookup (ps, PTHREAD_KEYS, &addr) != PS_OK) goto free_return; /* Cast to the right type. */ (*ta)->keys = (struct pthread_key_struct *) addr; /* Find out about the maximum number of threads. Old implementations don't provide this information. In this case we assume that the debug library is compiled with the same values. */ if (td_lookup (ps, LINUXTHREADS_PTHREAD_THREADS_MAX, &addr) != PS_OK) (*ta)->pthread_threads_max = PTHREAD_THREADS_MAX; else { if (ps_pdread (ps, addr, &(*ta)->pthread_threads_max, sizeof (int)) != PS_OK) goto free_return; } /* Similar for the maximum number of thread local data keys. */ if (td_lookup (ps, LINUXTHREADS_PTHREAD_KEYS_MAX, &addr) != PS_OK) (*ta)->pthread_keys_max = PTHREAD_KEYS_MAX; else { if (ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) != PS_OK) goto free_return; } /* And for the size of the second level arrays for the keys. */ if (td_lookup (ps, LINUXTHREADS_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK) (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); else { if (ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK) goto free_return; /* Don't let bogons in the inferior make us mess ourselves. */ if ((*ta)->sizeof_descr > sizeof (struct _pthread_descr_struct)) (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); } /* Now add the new agent descriptor to the list. */ elemp = (struct agent_list *) malloc (sizeof (struct agent_list)); if (elemp == NULL) { /* Argh, now that everything else worked... */ free (*ta); return TD_MALLOC; } /* We don't care for thread-safety here. */ elemp->ta = *ta; elemp->next = __td_agent_list; __td_agent_list = elemp; return TD_OK; }