| /* Helper routines for libthread_db. |
| Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, write to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. */ |
| |
| #include "thread_dbP.h" |
| #include <byteswap.h> |
| #include <assert.h> |
| |
| 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 && 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_fetch_value (td_thragent_t *ta, |
| db_desc_t desc, int descriptor_name, |
| psaddr_t idx, psaddr_t address, |
| psaddr_t *result) |
| { |
| ps_err_e err; |
| td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); |
| if (terr != TD_OK) |
| return terr; |
| |
| if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) |
| { |
| uint8_t value; |
| err = ps_pdread (ta->ph, address, &value, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == 32) |
| { |
| uint32_t value; |
| err = ps_pdread (ta->ph, address, &value, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == 64) |
| { |
| uint64_t value; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| err = ps_pdread (ta->ph, address, &value, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (32)) |
| { |
| uint32_t value; |
| err = ps_pdread (ta->ph, address, &value, sizeof value); |
| value = bswap_32 (value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (64)) |
| { |
| uint64_t value; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| err = ps_pdread (ta->ph, address, &value, sizeof value); |
| value = bswap_64 (value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else |
| return TD_DBERR; |
| |
| return err == PS_OK ? TD_OK : TD_ERR; |
| } |
| |
| |
| td_err_e |
| _td_store_value (td_thragent_t *ta, |
| uint32_t desc[2], int descriptor_name, psaddr_t idx, |
| psaddr_t address, psaddr_t widened_value) |
| { |
| ps_err_e err; |
| td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); |
| if (terr != TD_OK) |
| return terr; |
| |
| if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) |
| { |
| uint8_t value = widened_value - (psaddr_t) 0; |
| err = ps_pdwrite (ta->ph, address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == 32) |
| { |
| uint32_t value = widened_value - (psaddr_t) 0; |
| err = ps_pdwrite (ta->ph, address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == 64) |
| { |
| uint64_t value = widened_value - (psaddr_t) 0; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| err = ps_pdwrite (ta->ph, address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (32)) |
| { |
| uint32_t value = widened_value - (psaddr_t) 0; |
| value = bswap_32 (value); |
| err = ps_pdwrite (ta->ph, address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (64)) |
| { |
| uint64_t value = widened_value - (psaddr_t) 0; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| value = bswap_64 (value); |
| err = ps_pdwrite (ta->ph, address, &value, sizeof value); |
| } |
| else |
| return TD_DBERR; |
| |
| return err == PS_OK ? TD_OK : TD_ERR; |
| } |
| |
| td_err_e |
| _td_fetch_value_local (td_thragent_t *ta, |
| db_desc_t desc, int descriptor_name, psaddr_t idx, |
| void *address, |
| psaddr_t *result) |
| { |
| td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); |
| if (terr != TD_OK) |
| return terr; |
| |
| if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) |
| { |
| uint8_t value; |
| memcpy (&value, address, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == 32) |
| { |
| uint32_t value; |
| memcpy (&value, address, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == 64) |
| { |
| uint64_t value; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| memcpy (&value, address, sizeof value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (32)) |
| { |
| uint32_t value; |
| memcpy (&value, address, sizeof value); |
| value = bswap_32 (value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (64)) |
| { |
| uint64_t value; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| memcpy (&value, address, sizeof value); |
| value = bswap_64 (value); |
| *result = (psaddr_t) 0 + value; |
| } |
| else |
| return TD_DBERR; |
| |
| return TD_OK; |
| } |
| |
| |
| td_err_e |
| _td_store_value_local (td_thragent_t *ta, |
| uint32_t desc[2], int descriptor_name, psaddr_t idx, |
| void *address, psaddr_t widened_value) |
| { |
| td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); |
| if (terr != TD_OK) |
| return terr; |
| |
| if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) |
| { |
| uint8_t value = widened_value - (psaddr_t) 0; |
| memcpy (address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == 32) |
| { |
| uint32_t value = widened_value - (psaddr_t) 0; |
| memcpy (address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == 64) |
| { |
| uint64_t value = widened_value - (psaddr_t) 0; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| memcpy (address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (32)) |
| { |
| uint32_t value = widened_value - (psaddr_t) 0; |
| value = bswap_32 (value); |
| memcpy (address, &value, sizeof value); |
| } |
| else if (DB_DESC_SIZE (desc) == bswap_32 (64)) |
| { |
| uint64_t value = widened_value - (psaddr_t) 0; |
| if (sizeof (psaddr_t) < 8) |
| return TD_NOCAPAB; |
| value = bswap_64 (value); |
| memcpy (address, &value, sizeof value); |
| } |
| else |
| return TD_DBERR; |
| |
| return TD_OK; |
| } |