|  | /* Cell-based print utility routines for GDB, the GNU debugger. | 
|  |  | 
|  | Copyright (C) 1986-2025 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 <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "print-utils.h" | 
|  | /* Temporary storage using circular buffer.  */ | 
|  |  | 
|  | /* Number of cells in the circular buffer.  */ | 
|  | #define NUMCELLS 16 | 
|  |  | 
|  | /* Return the next entry in the circular buffer.  */ | 
|  |  | 
|  | char * | 
|  | get_print_cell (void) | 
|  | { | 
|  | static char buf[NUMCELLS][PRINT_CELL_SIZE]; | 
|  | static int cell = 0; | 
|  |  | 
|  | if (++cell >= NUMCELLS) | 
|  | cell = 0; | 
|  | return buf[cell]; | 
|  | } | 
|  |  | 
|  | static char * | 
|  | decimal2str (const char *sign, ULONGEST addr, int width) | 
|  | { | 
|  | /* Steal code from valprint.c:print_decimal().  Should this worry | 
|  | about the real size of addr as the above does?  */ | 
|  | unsigned long temp[3]; | 
|  | char *str = get_print_cell (); | 
|  | int i = 0; | 
|  |  | 
|  | do | 
|  | { | 
|  | temp[i] = addr % (1000 * 1000 * 1000); | 
|  | addr /= (1000 * 1000 * 1000); | 
|  | i++; | 
|  | width -= 9; | 
|  | } | 
|  | while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); | 
|  |  | 
|  | width += 9; | 
|  | if (width < 0) | 
|  | width = 0; | 
|  |  | 
|  | switch (i) | 
|  | { | 
|  | case 1: | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu", sign, width, temp[0]); | 
|  | break; | 
|  | case 2: | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu", sign, width, | 
|  | temp[1], temp[0]); | 
|  | break; | 
|  | case 3: | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu%09lu", sign, width, | 
|  | temp[2], temp[1], temp[0]); | 
|  | break; | 
|  | default: | 
|  | internal_error (_("failed internal consistency check")); | 
|  | } | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | static char * | 
|  | octal2str (ULONGEST addr, int width) | 
|  | { | 
|  | unsigned long temp[3]; | 
|  | char *str = get_print_cell (); | 
|  | int i = 0; | 
|  |  | 
|  | do | 
|  | { | 
|  | temp[i] = addr % (0100000 * 0100000); | 
|  | addr /= (0100000 * 0100000); | 
|  | i++; | 
|  | width -= 10; | 
|  | } | 
|  | while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0]))); | 
|  |  | 
|  | width += 10; | 
|  | if (width < 0) | 
|  | width = 0; | 
|  |  | 
|  | switch (i) | 
|  | { | 
|  | case 1: | 
|  | if (temp[0] == 0) | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%*o", width, 0); | 
|  | else | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo", width, temp[0]); | 
|  | break; | 
|  | case 2: | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo", width, temp[1], temp[0]); | 
|  | break; | 
|  | case 3: | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo%010lo", width, | 
|  | temp[2], temp[1], temp[0]); | 
|  | break; | 
|  | default: | 
|  | internal_error (_("failed internal consistency check")); | 
|  | } | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | pulongest (ULONGEST u) | 
|  | { | 
|  | return decimal2str ("", u, 0); | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | plongest (LONGEST l) | 
|  | { | 
|  | if (l < 0) | 
|  | return decimal2str ("-", -l, 0); | 
|  | else | 
|  | return decimal2str ("", l, 0); | 
|  | } | 
|  |  | 
|  | /* Eliminate warning from compiler on 32-bit systems.  */ | 
|  | static int thirty_two = 32; | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | phex_ulongest (ULONGEST l, int sizeof_l) | 
|  | { | 
|  | char *str; | 
|  |  | 
|  | switch (sizeof_l) | 
|  | { | 
|  | case 8: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%08lx%08lx", | 
|  | (unsigned long) (l >> thirty_two), | 
|  | (unsigned long) (l & 0xffffffff)); | 
|  | break; | 
|  | case 4: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%08lx", (unsigned long) l); | 
|  | break; | 
|  | case 2: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%04x", (unsigned short) (l & 0xffff)); | 
|  | break; | 
|  | case 1: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%02x", (unsigned short) (l & 0xff)); | 
|  | break; | 
|  | default: | 
|  | return phex (l); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | phex_nz_ulongest (ULONGEST l, int sizeof_l) | 
|  | { | 
|  | char *str; | 
|  |  | 
|  | switch (sizeof_l) | 
|  | { | 
|  | case 8: | 
|  | { | 
|  | unsigned long high = (unsigned long) (l >> thirty_two); | 
|  |  | 
|  | str = get_print_cell (); | 
|  | if (high == 0) | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%lx", | 
|  | (unsigned long) (l & 0xffffffff)); | 
|  | else | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%lx%08lx", high, | 
|  | (unsigned long) (l & 0xffffffff)); | 
|  | break; | 
|  | } | 
|  | case 4: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%lx", (unsigned long) l); | 
|  | break; | 
|  | case 2: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%x", (unsigned short) (l & 0xffff)); | 
|  | break; | 
|  | case 1: | 
|  | str = get_print_cell (); | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "%x", (unsigned short) (l & 0xff)); | 
|  | break; | 
|  | default: | 
|  | return phex_nz (l); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | hex_string (LONGEST num) | 
|  | { | 
|  | char *result = get_print_cell (); | 
|  |  | 
|  | xsnprintf (result, PRINT_CELL_SIZE, "0x%s", phex_nz (num)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | hex_string_custom (LONGEST num, int width) | 
|  | { | 
|  | char *result = get_print_cell (); | 
|  | char *result_end = result + PRINT_CELL_SIZE - 1; | 
|  | const char *hex = phex_nz (num); | 
|  | int hex_len = strlen (hex); | 
|  |  | 
|  | if (hex_len > width) | 
|  | width = hex_len; | 
|  | if (width + 2 >= PRINT_CELL_SIZE) | 
|  | internal_error (_("\ | 
|  | hex_string_custom: insufficient space to store result")); | 
|  |  | 
|  | strcpy (result_end - width - 2, "0x"); | 
|  | memset (result_end - width, '0', width); | 
|  | strcpy (result_end - hex_len, hex); | 
|  | return result_end - width - 2; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | int_string (LONGEST val, int radix, int is_signed, int width, | 
|  | int use_c_format) | 
|  | { | 
|  | switch (radix) | 
|  | { | 
|  | case 16: | 
|  | { | 
|  | const char *result; | 
|  |  | 
|  | if (width == 0) | 
|  | result = hex_string (val); | 
|  | else | 
|  | result = hex_string_custom (val, width); | 
|  | if (! use_c_format) | 
|  | result += 2; | 
|  | return result; | 
|  | } | 
|  | case 10: | 
|  | { | 
|  | if (is_signed && val < 0) | 
|  | /* Cast to unsigned before negating, to prevent runtime error: | 
|  | negation of -9223372036854775808 cannot be represented in type | 
|  | 'long int'; cast to an unsigned type to negate this value to | 
|  | itself.  */ | 
|  | return decimal2str ("-", -(ULONGEST)val, width); | 
|  | else | 
|  | return decimal2str ("", val, width); | 
|  | } | 
|  | case 8: | 
|  | { | 
|  | char *result = octal2str (val, width); | 
|  |  | 
|  | if (use_c_format || val == 0) | 
|  | return result; | 
|  | else | 
|  | return result + 1; | 
|  | } | 
|  | default: | 
|  | internal_error (_("failed internal consistency check")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | core_addr_to_string (const CORE_ADDR addr) | 
|  | { | 
|  | char *str = get_print_cell (); | 
|  |  | 
|  | strcpy (str, "0x"); | 
|  | strcat (str, phex (addr)); | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | core_addr_to_string_nz (const CORE_ADDR addr) | 
|  | { | 
|  | char *str = get_print_cell (); | 
|  |  | 
|  | strcpy (str, "0x"); | 
|  | strcat (str, phex_nz (addr)); | 
|  | return str; | 
|  | } | 
|  |  | 
|  | /* See print-utils.h.  */ | 
|  |  | 
|  | const char * | 
|  | host_address_to_string_1 (const void *addr) | 
|  | { | 
|  | char *str = get_print_cell (); | 
|  |  | 
|  | xsnprintf (str, PRINT_CELL_SIZE, "0x%s", | 
|  | phex_nz ((uintptr_t) addr, sizeof (addr))); | 
|  | return str; | 
|  | } |