/* Basic byte-swapping routines, for GDB, the GNU debugger. Copyright (C) 1986-2016 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "common-defs.h" #include "gdb-byteswap.h" #include "host-defs.h" /* See gdb-byteswap.h. */ LONGEST extract_signed_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order) { LONGEST retval; const unsigned char *p; const unsigned char *startaddr = addr; const unsigned char *endaddr = startaddr + len; if (len > (int) sizeof (LONGEST)) error (_("\ That operation is not available on integers of more than %d bytes."), (int) sizeof (LONGEST)); /* Start at the most significant end of the integer, and work towards the least significant. */ if (byte_order == BFD_ENDIAN_BIG) { p = startaddr; /* Do the sign extension once at the start. */ retval = ((LONGEST) * p ^ 0x80) - 0x80; for (++p; p < endaddr; ++p) retval = (retval << 8) | *p; } else { p = endaddr - 1; /* Do the sign extension once at the start. */ retval = ((LONGEST) * p ^ 0x80) - 0x80; for (--p; p >= startaddr; --p) retval = (retval << 8) | *p; } return retval; } /* See gdb-byteswap.h. */ ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order) { ULONGEST retval; const unsigned char *p; const unsigned char *startaddr = addr; const unsigned char *endaddr = startaddr + len; if (len > (int) sizeof (ULONGEST)) error (_("\ That operation is not available on integers of more than %d bytes."), (int) sizeof (ULONGEST)); /* Start at the most significant end of the integer, and work towards the least significant. */ retval = 0; if (byte_order == BFD_ENDIAN_BIG) { for (p = startaddr; p < endaddr; ++p) retval = (retval << 8) | *p; } else { for (p = endaddr - 1; p >= startaddr; --p) retval = (retval << 8) | *p; } return retval; } /* See gdb_byteswap.h. */ int extract_long_unsigned_integer (const gdb_byte *addr, int orig_len, enum bfd_endian byte_order, LONGEST *pval) { const gdb_byte *p; const gdb_byte *first_addr; int len; len = orig_len; if (byte_order == BFD_ENDIAN_BIG) { for (p = addr; len > (int) sizeof (LONGEST) && p < addr + orig_len; p++) { if (*p == 0) len--; else break; } first_addr = p; } else { first_addr = addr; for (p = addr + orig_len - 1; len > (int) sizeof (LONGEST) && p >= addr; p--) { if (*p == 0) len--; else break; } } if (len <= (int) sizeof (LONGEST)) { *pval = (LONGEST) extract_unsigned_integer (first_addr, sizeof (LONGEST), byte_order); return 1; } return 0; } /* See gdb-byteswap.h. */ void store_signed_integer (gdb_byte *addr, int len, enum bfd_endian byte_order, LONGEST val) { gdb_byte *p; gdb_byte *startaddr = addr; gdb_byte *endaddr = startaddr + len; /* Start at the least significant end of the integer, and work towards the most significant. */ if (byte_order == BFD_ENDIAN_BIG) { for (p = endaddr - 1; p >= startaddr; --p) { *p = val & 0xff; val >>= 8; } } else { for (p = startaddr; p < endaddr; ++p) { *p = val & 0xff; val >>= 8; } } } /* See gdb-byteswap.h. */ void store_unsigned_integer (gdb_byte *addr, int len, enum bfd_endian byte_order, ULONGEST val) { unsigned char *p; unsigned char *startaddr = (unsigned char *) addr; unsigned char *endaddr = startaddr + len; /* Start at the least significant end of the integer, and work towards the most significant. */ if (byte_order == BFD_ENDIAN_BIG) { for (p = endaddr - 1; p >= startaddr; --p) { *p = val & 0xff; val >>= 8; } } else { for (p = startaddr; p < endaddr; ++p) { *p = val & 0xff; val >>= 8; } } }