| /* Helper routines for libthread_db. | 
 |    Copyright (C) 2003-2016 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, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "thread_dbP.h" | 
 | #include <byteswap.h> | 
 | #include <assert.h> | 
 | #include <stdint.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 && 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_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; | 
 | } |