2009-02-05 Thiago Jung Bauermann <bauerman@br.ibm.com>
* language.h (language_dfn): Add la_get_string member. (LA_GET_STRING): New macro. (default_get_string): New prototype. * language.c (default_get_string): New function. (unknown_language_defn, auto_language_defn, local_language_defn): Use default_get_string for la_get_string. * c-lang.c (c_get_string): New function. (c_language_defn, cplus_language_defn, asm_language_defn): Use c_get_string for la_get_string. (minimal_language_defn): Likewise * ada-lang.c (ada_language_defn): Likewise. * f-lang.c (f_language_defn): Use default_get_string for la_get_string. * jv-lang.c (java_language_defn): Likewise. * m2-lang.c (m2_language_defn): Likewise. * objc-lang.c (objc_language_defn): Likewise. * p-lang.c (p_language_defn): Likewise. * scm-lang.c (scm_language_defn): Likewise. * typeprint.c (type_to_string): New function. * value.h (type_to_string): New prototype. * valprint.c (val_print_string): Factor out code for reading string from the inferior into its own function. Put 2 spaces after period in comments. (read_string): New function. * valprint.h (read_string): New prototype.
This commit is contained in:
parent
fa8a61dc87
commit
ae6a3a4c2a
15 changed files with 326 additions and 61 deletions
|
@ -1,3 +1,31 @@
|
|||
2009-02-05 Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||
|
||||
* language.h (language_dfn): Add la_get_string member.
|
||||
(LA_GET_STRING): New macro.
|
||||
(default_get_string): New prototype.
|
||||
* language.c (default_get_string): New function.
|
||||
(unknown_language_defn, auto_language_defn, local_language_defn): Use
|
||||
default_get_string for la_get_string.
|
||||
* c-lang.c (c_get_string): New function.
|
||||
(c_language_defn, cplus_language_defn, asm_language_defn): Use
|
||||
c_get_string for la_get_string.
|
||||
(minimal_language_defn): Likewise
|
||||
* ada-lang.c (ada_language_defn): Likewise.
|
||||
* f-lang.c (f_language_defn): Use default_get_string for
|
||||
la_get_string.
|
||||
* jv-lang.c (java_language_defn): Likewise.
|
||||
* m2-lang.c (m2_language_defn): Likewise.
|
||||
* objc-lang.c (objc_language_defn): Likewise.
|
||||
* p-lang.c (p_language_defn): Likewise.
|
||||
* scm-lang.c (scm_language_defn): Likewise.
|
||||
* typeprint.c (type_to_string): New function.
|
||||
* value.h (type_to_string): New prototype.
|
||||
* valprint.c (val_print_string): Factor out code for reading string
|
||||
from the inferior into its own function. Put 2 spaces after period
|
||||
in comments.
|
||||
(read_string): New function.
|
||||
* valprint.h (read_string): New prototype.
|
||||
|
||||
2009-01-07 Pierre Muller <muller@ics.u-strasbg.fr>
|
||||
Tom Tromey <tromey@redhat.com>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Ada language support routines for GDB, the GNU debugger. Copyright (C)
|
||||
|
||||
1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2007
|
||||
Free Software Foundation, Inc.
|
||||
1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2007, 2008,
|
||||
2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
|
@ -11063,6 +11063,7 @@ const struct language_defn ada_language_defn = {
|
|||
ada_language_arch_info,
|
||||
ada_print_array_index,
|
||||
default_pass_by_reference,
|
||||
c_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
120
gdb/c-lang.c
120
gdb/c-lang.c
|
@ -181,6 +181,122 @@ c_printstr (struct ui_file *stream, const gdb_byte *string,
|
|||
if (force_ellipses || i < length)
|
||||
fputs_filtered ("...", stream);
|
||||
}
|
||||
|
||||
/* Obtain a C string from the inferior storing it in a newly allocated
|
||||
buffer in BUFFER, which should be freed by the caller. The string is
|
||||
read until a null character is found. If VALUE is an array with known
|
||||
length, the function will not read past the end of the array. LENGTH
|
||||
will contain the size of the string in bytes (not counting the null
|
||||
character).
|
||||
|
||||
Assumes strings are terminated by a null character. The size of a character
|
||||
is determined by the length of the target type of the pointer or array.
|
||||
This means that a null byte present in a multi-byte character will not
|
||||
terminate the string unless the whole character is null.
|
||||
|
||||
CHARSET is always set to the target charset. */
|
||||
|
||||
void
|
||||
c_get_string (struct value *value, gdb_byte **buffer, int *length,
|
||||
const char **charset)
|
||||
{
|
||||
int err, width;
|
||||
unsigned int fetchlimit;
|
||||
struct type *type = check_typedef (value_type (value));
|
||||
struct type *element_type = TYPE_TARGET_TYPE (type);
|
||||
|
||||
if (element_type == NULL)
|
||||
goto error;
|
||||
|
||||
if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
|
||||
{
|
||||
/* If we know the size of the array, we can use it as a limit on the
|
||||
number of characters to be fetched. */
|
||||
if (TYPE_NFIELDS (type) == 1
|
||||
&& TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_RANGE)
|
||||
{
|
||||
LONGEST low_bound, high_bound;
|
||||
|
||||
get_discrete_bounds (TYPE_FIELD_TYPE (type, 0),
|
||||
&low_bound, &high_bound);
|
||||
fetchlimit = high_bound - low_bound + 1;
|
||||
}
|
||||
else
|
||||
fetchlimit = UINT_MAX;
|
||||
}
|
||||
else if (TYPE_CODE (type) == TYPE_CODE_PTR)
|
||||
fetchlimit = UINT_MAX;
|
||||
else
|
||||
/* We work only with arrays and pointers. */
|
||||
goto error;
|
||||
|
||||
element_type = check_typedef (element_type);
|
||||
if (TYPE_CODE (element_type) != TYPE_CODE_INT
|
||||
&& TYPE_CODE (element_type) != TYPE_CODE_CHAR)
|
||||
/* If the elements are not integers or characters, we don't consider it
|
||||
a string. */
|
||||
goto error;
|
||||
|
||||
width = TYPE_LENGTH (element_type);
|
||||
|
||||
/* If the string lives in GDB's memory intead of the inferior's, then we
|
||||
just need to copy it to BUFFER. Also, since such strings are arrays
|
||||
with known size, FETCHLIMIT will hold the size of the array. */
|
||||
if ((VALUE_LVAL (value) == not_lval
|
||||
|| VALUE_LVAL (value) == lval_internalvar)
|
||||
&& fetchlimit != UINT_MAX)
|
||||
{
|
||||
int i;
|
||||
const gdb_byte *contents = value_contents (value);
|
||||
|
||||
/* Look for a null character. */
|
||||
for (i = 0; i < fetchlimit; i++)
|
||||
if (extract_unsigned_integer (contents + i * width, width) == 0)
|
||||
break;
|
||||
|
||||
/* I is now either the number of non-null characters, or FETCHLIMIT. */
|
||||
*length = i * width;
|
||||
*buffer = xmalloc (*length);
|
||||
memcpy (*buffer, contents, *length);
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = read_string (value_as_address (value), -1, width, fetchlimit,
|
||||
buffer, length);
|
||||
if (err)
|
||||
{
|
||||
xfree (buffer);
|
||||
error (_("Error reading string from inferior: %s"),
|
||||
safe_strerror (err));
|
||||
}
|
||||
}
|
||||
|
||||
/* If the last character is null, subtract it from LENGTH. */
|
||||
if (*length > 0
|
||||
&& extract_unsigned_integer (*buffer + *length - width, width) == 0)
|
||||
*length -= width;
|
||||
|
||||
*charset = target_charset ();
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
{
|
||||
char *type_str;
|
||||
|
||||
type_str = type_to_string (type);
|
||||
if (type_str)
|
||||
{
|
||||
make_cleanup (xfree, type_str);
|
||||
error (_("Trying to read string with inappropriate type `%s'."),
|
||||
type_str);
|
||||
}
|
||||
else
|
||||
error (_("Trying to read string with inappropriate type."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Preprocessing and parsing C and C++ expressions. */
|
||||
|
||||
|
@ -314,6 +430,7 @@ const struct language_defn c_language_defn =
|
|||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
c_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
@ -432,6 +549,7 @@ const struct language_defn cplus_language_defn =
|
|||
cplus_language_arch_info,
|
||||
default_print_array_index,
|
||||
cp_pass_by_reference,
|
||||
c_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
@ -469,6 +587,7 @@ const struct language_defn asm_language_defn =
|
|||
c_language_arch_info, /* FIXME: la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
c_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
@ -511,6 +630,7 @@ const struct language_defn minimal_language_defn =
|
|||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
c_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -343,6 +343,7 @@ const struct language_defn f_language_defn =
|
|||
f_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -1128,6 +1128,7 @@ const struct language_defn java_language_defn =
|
|||
java_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -1043,6 +1043,13 @@ default_print_array_index (struct value *index_value, struct ui_file *stream,
|
|||
fprintf_filtered (stream, "] = ");
|
||||
}
|
||||
|
||||
void
|
||||
default_get_string (struct value *value, gdb_byte **buffer, int *length,
|
||||
const char **charset)
|
||||
{
|
||||
error (_("Getting a string is unsupported in this language."));
|
||||
}
|
||||
|
||||
/* Define the language that is no language. */
|
||||
|
||||
static int
|
||||
|
@ -1165,6 +1172,7 @@ const struct language_defn unknown_language_defn =
|
|||
unknown_language_arch_info, /* la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
@ -1203,6 +1211,7 @@ const struct language_defn auto_language_defn =
|
|||
unknown_language_arch_info, /* la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
@ -1240,6 +1249,7 @@ const struct language_defn local_language_defn =
|
|||
unknown_language_arch_info, /* la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -282,6 +282,14 @@ struct language_defn
|
|||
reference at the language level. */
|
||||
int (*la_pass_by_reference) (struct type *type);
|
||||
|
||||
/* Obtain a string from the inferior, storing it in a newly allocated
|
||||
buffer in BUFFER, which should be freed by the caller. LENGTH will
|
||||
hold the size in bytes of the string (only actual characters, excluding
|
||||
an eventual terminating null character). CHARSET will hold the encoding
|
||||
used in the string. */
|
||||
void (*la_get_string) (struct value *value, gdb_byte **buffer, int *length,
|
||||
const char **charset);
|
||||
|
||||
/* Add fields above this point, so the magic number is always last. */
|
||||
/* Magic number for compat checking */
|
||||
|
||||
|
@ -380,6 +388,8 @@ extern enum language set_language (enum language);
|
|||
force_ellipses,options))
|
||||
#define LA_EMIT_CHAR(ch, stream, quoter) \
|
||||
(current_language->la_emitchar(ch, stream, quoter))
|
||||
#define LA_GET_STRING(value, buffer, length, encoding) \
|
||||
(current_language->la_get_string(value, buffer, length, encoding))
|
||||
|
||||
#define LA_PRINT_ARRAY_INDEX(index_value, stream, optins) \
|
||||
(current_language->la_print_array_index(index_value, stream, options))
|
||||
|
@ -489,4 +499,10 @@ int default_pass_by_reference (struct type *type);
|
|||
void default_print_typedef (struct type *type, struct symbol *new_symbol,
|
||||
struct ui_file *stream);
|
||||
|
||||
void default_get_string (struct value *value, gdb_byte **buffer, int *length,
|
||||
const char **charset);
|
||||
|
||||
void c_get_string (struct value *value, gdb_byte **buffer, int *length,
|
||||
const char **charset);
|
||||
|
||||
#endif /* defined (LANGUAGE_H) */
|
||||
|
|
|
@ -394,6 +394,7 @@ const struct language_defn m2_language_defn =
|
|||
m2_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -531,6 +531,7 @@ const struct language_defn objc_language_defn = {
|
|||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -433,6 +433,7 @@ const struct language_defn pascal_language_defn =
|
|||
pascal_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -273,6 +273,7 @@ const struct language_defn scm_language_defn =
|
|||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
default_pass_by_reference,
|
||||
default_get_string,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cp-abi.h"
|
||||
#include "typeprint.h"
|
||||
#include "gdb_string.h"
|
||||
#include "exceptions.h"
|
||||
#include "valprint.h"
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -78,6 +79,34 @@ type_print (struct type *type, char *varstring, struct ui_file *stream,
|
|||
LA_PRINT_TYPE (type, varstring, stream, show, 0);
|
||||
}
|
||||
|
||||
/* Print TYPE to a string, returning it. The caller is responsible for
|
||||
freeing the string. */
|
||||
|
||||
char *
|
||||
type_to_string (struct type *type)
|
||||
{
|
||||
char *s = NULL;
|
||||
long dummy;
|
||||
struct ui_file *stb;
|
||||
struct cleanup *old_chain;
|
||||
volatile struct gdb_exception except;
|
||||
|
||||
stb = mem_fileopen ();
|
||||
old_chain = make_cleanup_ui_file_delete (stb);
|
||||
|
||||
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||
{
|
||||
type_print (type, "", stb, -1);
|
||||
s = ui_file_xstrdup (stb, &dummy);
|
||||
}
|
||||
if (except.reason < 0)
|
||||
s = NULL;
|
||||
|
||||
do_cleanups (old_chain);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Print type of EXP, or last thing in value history if EXP == NULL.
|
||||
show is passed to type_print. */
|
||||
|
||||
|
|
168
gdb/valprint.c
168
gdb/valprint.c
|
@ -1177,43 +1177,44 @@ partial_memory_read (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int *errnoptr
|
|||
return (nread);
|
||||
}
|
||||
|
||||
/* Print a string from the inferior, starting at ADDR and printing up to LEN
|
||||
characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, printing
|
||||
stops at the first null byte, otherwise printing proceeds (including null
|
||||
bytes) until either print_max or LEN characters have been printed,
|
||||
whichever is smaller. */
|
||||
/* Read a string from the inferior, at ADDR, with LEN characters of WIDTH bytes
|
||||
each. Fetch at most FETCHLIMIT characters. BUFFER will be set to a newly
|
||||
allocated buffer containing the string, which the caller is responsible to
|
||||
free, and BYTES_READ will be set to the number of bytes read. Returns 0 on
|
||||
success, or errno on failure.
|
||||
|
||||
/* FIXME: Use target_read_string. */
|
||||
If LEN > 0, reads exactly LEN characters (including eventual NULs in
|
||||
the middle or end of the string). If LEN is -1, stops at the first
|
||||
null character (not necessarily the first null byte) up to a maximum
|
||||
of FETCHLIMIT characters. Set FETCHLIMIT to UINT_MAX to read as many
|
||||
characters as possible from the string.
|
||||
|
||||
Unless an exception is thrown, BUFFER will always be allocated, even on
|
||||
failure. In this case, some characters might have been read before the
|
||||
failure happened. Check BYTES_READ to recognize this situation.
|
||||
|
||||
Note: There was a FIXME asking to make this code use target_read_string,
|
||||
but this function is more general (can read past null characters, up to
|
||||
given LEN). Besides, it is used much more often than target_read_string
|
||||
so it is more tested. Perhaps callers of target_read_string should use
|
||||
this function instead? */
|
||||
|
||||
int
|
||||
val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
||||
const struct value_print_options *options)
|
||||
read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit,
|
||||
gdb_byte **buffer, int *bytes_read)
|
||||
{
|
||||
int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */
|
||||
int errcode; /* Errno returned from bad reads. */
|
||||
unsigned int fetchlimit; /* Maximum number of chars to print. */
|
||||
unsigned int nfetch; /* Chars to fetch / chars fetched. */
|
||||
unsigned int chunksize; /* Size of each fetch, in chars. */
|
||||
gdb_byte *buffer = NULL; /* Dynamically growable fetch buffer. */
|
||||
gdb_byte *bufptr; /* Pointer to next available byte in buffer. */
|
||||
gdb_byte *limit; /* First location past end of fetch buffer. */
|
||||
struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */
|
||||
int found_nul; /* Non-zero if we found the nul char */
|
||||
int found_nul; /* Non-zero if we found the nul char. */
|
||||
int errcode; /* Errno returned from bad reads. */
|
||||
unsigned int nfetch; /* Chars to fetch / chars fetched. */
|
||||
unsigned int chunksize; /* Size of each fetch, in chars. */
|
||||
gdb_byte *bufptr; /* Pointer to next available byte in buffer. */
|
||||
gdb_byte *limit; /* First location past end of fetch buffer. */
|
||||
struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */
|
||||
|
||||
/* First we need to figure out the limit on the number of characters we are
|
||||
going to attempt to fetch and print. This is actually pretty simple. If
|
||||
LEN >= zero, then the limit is the minimum of LEN and print_max. If
|
||||
LEN is -1, then the limit is print_max. This is true regardless of
|
||||
whether print_max is zero, UINT_MAX (unlimited), or something in between,
|
||||
because finding the null byte (or available memory) is what actually
|
||||
limits the fetch. */
|
||||
|
||||
fetchlimit = (len == -1 ? options->print_max : min (len, options->print_max));
|
||||
|
||||
/* Now decide how large of chunks to try to read in one operation. This
|
||||
/* Decide how large of chunks to try to read in one operation. This
|
||||
is also pretty simple. If LEN >= zero, then we want fetchlimit chars,
|
||||
so we might as well read them all in one operation. If LEN is -1, we
|
||||
are looking for a null terminator to end the fetching, so we might as
|
||||
are looking for a NUL terminator to end the fetching, so we might as
|
||||
well read in blocks that are large enough to be efficient, but not so
|
||||
large as to be slow if fetchlimit happens to be large. So we choose the
|
||||
minimum of 8 and fetchlimit. We used to use 200 instead of 8 but
|
||||
|
@ -1221,17 +1222,17 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
|
||||
chunksize = (len == -1 ? min (8, fetchlimit) : fetchlimit);
|
||||
|
||||
/* Loop until we either have all the characters to print, or we encounter
|
||||
some error, such as bumping into the end of the address space. */
|
||||
/* Loop until we either have all the characters, or we encounter
|
||||
some error, such as bumping into the end of the address space. */
|
||||
|
||||
found_nul = 0;
|
||||
old_chain = make_cleanup (null_cleanup, 0);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
buffer = (gdb_byte *) xmalloc (len * width);
|
||||
bufptr = buffer;
|
||||
old_chain = make_cleanup (xfree, buffer);
|
||||
*buffer = (gdb_byte *) xmalloc (len * width);
|
||||
bufptr = *buffer;
|
||||
old_chain = make_cleanup (xfree, *buffer);
|
||||
|
||||
nfetch = partial_memory_read (addr, bufptr, len * width, &errcode)
|
||||
/ width;
|
||||
|
@ -1241,32 +1242,36 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
else if (len == -1)
|
||||
{
|
||||
unsigned long bufsize = 0;
|
||||
|
||||
*buffer = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
QUIT;
|
||||
nfetch = min (chunksize, fetchlimit - bufsize);
|
||||
|
||||
if (buffer == NULL)
|
||||
buffer = (gdb_byte *) xmalloc (nfetch * width);
|
||||
if (*buffer == NULL)
|
||||
*buffer = (gdb_byte *) xmalloc (nfetch * width);
|
||||
else
|
||||
{
|
||||
discard_cleanups (old_chain);
|
||||
buffer = (gdb_byte *) xrealloc (buffer, (nfetch + bufsize) * width);
|
||||
*buffer = (gdb_byte *) xrealloc (*buffer,
|
||||
(nfetch + bufsize) * width);
|
||||
}
|
||||
|
||||
old_chain = make_cleanup (xfree, buffer);
|
||||
bufptr = buffer + bufsize * width;
|
||||
old_chain = make_cleanup (xfree, *buffer);
|
||||
bufptr = *buffer + bufsize * width;
|
||||
bufsize += nfetch;
|
||||
|
||||
/* Read as much as we can. */
|
||||
/* Read as much as we can. */
|
||||
nfetch = partial_memory_read (addr, bufptr, nfetch * width, &errcode)
|
||||
/ width;
|
||||
/ width;
|
||||
|
||||
/* Scan this chunk for the null byte that terminates the string
|
||||
/* Scan this chunk for the null character that terminates the string
|
||||
to print. If found, we don't need to fetch any more. Note
|
||||
that bufptr is explicitly left pointing at the next character
|
||||
after the null byte, or at the next character after the end of
|
||||
the buffer. */
|
||||
after the null character, or at the next character after the end
|
||||
of the buffer. */
|
||||
|
||||
limit = bufptr + nfetch * width;
|
||||
while (bufptr < limit)
|
||||
|
@ -1279,7 +1284,7 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
if (c == 0)
|
||||
{
|
||||
/* We don't care about any error which happened after
|
||||
the NULL terminator. */
|
||||
the NUL terminator. */
|
||||
errcode = 0;
|
||||
found_nul = 1;
|
||||
break;
|
||||
|
@ -1287,26 +1292,71 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
}
|
||||
}
|
||||
while (errcode == 0 /* no error */
|
||||
&& bufptr - buffer < fetchlimit * width /* no overrun */
|
||||
&& !found_nul); /* haven't found nul yet */
|
||||
&& bufptr - *buffer < fetchlimit * width /* no overrun */
|
||||
&& !found_nul); /* haven't found NUL yet */
|
||||
}
|
||||
else
|
||||
{ /* length of string is really 0! */
|
||||
buffer = bufptr = NULL;
|
||||
{ /* Length of string is really 0! */
|
||||
/* We always allocate *buffer. */
|
||||
*buffer = bufptr = xmalloc (1);
|
||||
errcode = 0;
|
||||
}
|
||||
|
||||
/* bufptr and addr now point immediately beyond the last byte which we
|
||||
consider part of the string (including a '\0' which ends the string). */
|
||||
*bytes_read = bufptr - *buffer;
|
||||
|
||||
QUIT;
|
||||
|
||||
discard_cleanups (old_chain);
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
/* Print a string from the inferior, starting at ADDR and printing up to LEN
|
||||
characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, printing
|
||||
stops at the first null byte, otherwise printing proceeds (including null
|
||||
bytes) until either print_max or LEN characters have been printed,
|
||||
whichever is smaller. */
|
||||
|
||||
int
|
||||
val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
||||
const struct value_print_options *options)
|
||||
{
|
||||
int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */
|
||||
int errcode; /* Errno returned from bad reads. */
|
||||
int found_nul; /* Non-zero if we found the nul char */
|
||||
unsigned int fetchlimit; /* Maximum number of chars to print. */
|
||||
int bytes_read;
|
||||
gdb_byte *buffer = NULL; /* Dynamically growable fetch buffer. */
|
||||
struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */
|
||||
|
||||
/* First we need to figure out the limit on the number of characters we are
|
||||
going to attempt to fetch and print. This is actually pretty simple. If
|
||||
LEN >= zero, then the limit is the minimum of LEN and print_max. If
|
||||
LEN is -1, then the limit is print_max. This is true regardless of
|
||||
whether print_max is zero, UINT_MAX (unlimited), or something in between,
|
||||
because finding the null byte (or available memory) is what actually
|
||||
limits the fetch. */
|
||||
|
||||
fetchlimit = (len == -1 ? options->print_max : min (len, options->print_max));
|
||||
|
||||
errcode = read_string (addr, len, width, fetchlimit, &buffer, &bytes_read);
|
||||
old_chain = make_cleanup (xfree, buffer);
|
||||
|
||||
addr += bytes_read;
|
||||
|
||||
/* We now have either successfully filled the buffer to fetchlimit, or
|
||||
terminated early due to an error or finding a null char when LEN is -1. */
|
||||
terminated early due to an error or finding a null char when LEN is -1. */
|
||||
|
||||
/* Determine found_nul by looking at the last character read. */
|
||||
found_nul = extract_unsigned_integer (buffer + bytes_read - width, width) == 0;
|
||||
|
||||
if (len == -1 && !found_nul)
|
||||
{
|
||||
gdb_byte *peekbuf;
|
||||
|
||||
/* We didn't find a null terminator we were looking for. Attempt
|
||||
/* We didn't find a NUL terminator we were looking for. Attempt
|
||||
to peek at the next character. If not successful, or it is not
|
||||
a null byte, then force ellipsis to be printed. */
|
||||
|
||||
|
@ -1316,26 +1366,24 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
&& extract_unsigned_integer (peekbuf, width) != 0)
|
||||
force_ellipsis = 1;
|
||||
}
|
||||
else if ((len >= 0 && errcode != 0) || (len > (bufptr - buffer) / width))
|
||||
else if ((len >= 0 && errcode != 0) || (len > bytes_read / width))
|
||||
{
|
||||
/* Getting an error when we have a requested length, or fetching less
|
||||
than the number of characters actually requested, always make us
|
||||
print ellipsis. */
|
||||
print ellipsis. */
|
||||
force_ellipsis = 1;
|
||||
}
|
||||
|
||||
QUIT;
|
||||
|
||||
/* If we get an error before fetching anything, don't print a string.
|
||||
But if we fetch something and then get an error, print the string
|
||||
and then the error message. */
|
||||
if (errcode == 0 || bufptr > buffer)
|
||||
if (errcode == 0 || bytes_read > 0)
|
||||
{
|
||||
if (options->addressprint)
|
||||
{
|
||||
fputs_filtered (" ", stream);
|
||||
}
|
||||
LA_PRINT_STRING (stream, buffer, (bufptr - buffer) / width, width, force_ellipsis, options);
|
||||
LA_PRINT_STRING (stream, buffer, bytes_read / width, width, force_ellipsis, options);
|
||||
}
|
||||
|
||||
if (errcode != 0)
|
||||
|
@ -1353,9 +1401,11 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream,
|
|||
fprintf_filtered (stream, ": %s>", safe_strerror (errcode));
|
||||
}
|
||||
}
|
||||
|
||||
gdb_flush (stream);
|
||||
do_cleanups (old_chain);
|
||||
return ((bufptr - buffer) / width);
|
||||
|
||||
return (bytes_read / width);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -136,4 +136,7 @@ extern void print_hex_chars (struct ui_file *, const gdb_byte *,
|
|||
|
||||
extern void print_char_chars (struct ui_file *, const gdb_byte *,
|
||||
unsigned int, enum bfd_endian);
|
||||
|
||||
int read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit,
|
||||
gdb_byte **buffer, int *bytes_read);
|
||||
#endif
|
||||
|
|
|
@ -524,6 +524,8 @@ extern void modify_field (gdb_byte *addr, LONGEST fieldval, int bitpos,
|
|||
extern void type_print (struct type *type, char *varstring,
|
||||
struct ui_file *stream, int show);
|
||||
|
||||
extern char *type_to_string (struct type *type);
|
||||
|
||||
extern gdb_byte *baseclass_addr (struct type *type, int index,
|
||||
gdb_byte *valaddr,
|
||||
struct value **valuep, int *errp);
|
||||
|
|
Loading…
Reference in a new issue