This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
Value.string method
- From: Thiago Jung Bauermann <bauerman at br dot ibm dot com>
- To: archer ml <archer at sourceware dot org>
- Date: Wed, 19 Nov 2008 18:26:19 -0200
- Subject: Value.string method
Hi,
I just pushed the patch below to the python branch. It provides a string
method to gdb.Value, which assumes the object is holding a string in the
inferior, and converts it to a Unicode python object. It fills the void
we had until now where there was no easy way to convert a Value string
to a Python string.
It's a big patch because I wanted to implement the method in a
language-independent way. This is achieved by providing a la_getstr
function to language_defn. Each language supported by GDB can provide a
way to read strings from a value by suppling its version of the
function. I implemented it for C, in c_getstr. It assumes
NULL-terminated strings, but doesn't assume that characters are 1-byte
wide.
I also factored out a read_string function out of val_print_string,
which is handy to use as a base for la_getstr implementations.
Since it's a big patch, I'm testing it for regressions, but the run
didn't finish yet. An older version of the patch had only one
regression, which from a cursory look is possibly a limitation in the
testcase rather than a real regression. I'll look it further.
One thing which just crossed my mind is that this code doesn't take into
accound values which are internal to GDB, just values which live in the
inferior's memory. I'll write a followup patch fixing that, or if
someone wants to outperform me here is welcome to work on this
first. :-)
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
commit 326adae41f469dbfd6df447ed985760e7484f165
Author: Thiago Jung Bauermann <bauerman@br.ibm.com>
Date: Wed Nov 12 14:20:28 2008 -0200
Create LA_GETSTR method for languages, and provide C implementation.
* language.h (language_dfn): Add la_getstr member.
(LA_GET_STRING): New macro.
(default_getstr): New prototype.
* language.c (default_getstr): New function.
(unknown_language_defn, auto_language_defn, local_language_defn): Use
default_getstr for la_getstr.
* c-lang.c (c_getstr): New function.
(c_language_defn, cplus_language_defn, asm_language_defn): Use
c_getstr for la_getstr.
(minimal_language_defn): Use default_getstr for la_getstr.
* ada-lang.c (ada_language_defn): Likewise.
* f-lang.c (f_language_defn): Likewise.
* 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.
(read_string): New function.
* valprint.h (read_string): New prototype.
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f8aaea4..b88905f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,29 @@
+2008-11-19 Thiago Jung Bauermann <bauerman@br.ibm.com>
+
+ * language.h (language_dfn): Add la_getstr member.
+ (LA_GET_STRING): New macro.
+ (default_getstr): New prototype.
+ * language.c (default_getstr): New function.
+ (unknown_language_defn, auto_language_defn, local_language_defn): Use
+ default_getstr for la_getstr.
+ * c-lang.c (c_getstr): New function.
+ (c_language_defn, cplus_language_defn, asm_language_defn): Use
+ c_getstr for la_getstr.
+ (minimal_language_defn): Use default_getstr for la_getstr.
+ * ada-lang.c (ada_language_defn): Likewise.
+ * f-lang.c (f_language_defn): Likewise.
+ * 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.
+ (read_string): New function.
+ * valprint.h (read_string): New prototype.
+
2008-11-18 Tom Tromey <tromey@redhat.com>
* python/python.c (_initialize_python): Add gdb path to sys.path.
@@ -189,7 +215,7 @@
* python/python-function.c (fnpy_call): Fix syntax error
in last checkin.
-
+
2008-11-07 Thiago Jung Bauerman <bauerman@br.ibm.com>
* python/python-function.c (fnpy_call): Fix silly mistake in previous
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index a7730d8..f94e452 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10940,6 +10940,7 @@ const struct language_defn ada_language_defn = {
ada_language_arch_info,
ada_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index a9cd9c2..ffba774 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -180,6 +180,87 @@ 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. If VALUE is an
+ array with known length, the function will copy all of its contents to
+ the buffer. If the length is not known, read until a null byte is found.
+ LENGTH will contain the size of the string (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.
+
+ 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 LENGTH to recognize this situation.
+
+ Return 0 on success, errno on failure. */
+
+int
+c_getstr (struct value *value, gdb_byte **buffer, int *length)
+{
+ int fetchlimit, errno, width;
+ struct type *type = 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 = -1;
+ }
+ else if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR)
+ fetchlimit = -1;
+ 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);
+
+ errno = read_string (value_as_address (value), -1, width, fetchlimit, buffer,
+ length);
+
+ /* If the last character is NULL, subtract it from length. */
+ if (extract_unsigned_integer (*buffer + *length - width, width) == 0)
+ *length -= width;
+
+ return errno;
+
+error:
+ {
+ char *type_str;
+ struct cleanup *old_chain;
+
+ type_str = type_to_string (type);
+ if (type_str)
+ old_chain = make_cleanup (xfree, type_str);
+ error (_("Trying to read string with inappropriate type `%s'."), type_str);
+ }
+}
+
/* Preprocessing and parsing C and C++ expressions. */
@@ -417,6 +498,7 @@ const struct language_defn c_language_defn =
c_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ c_getstr,
LANG_MAGIC
};
@@ -534,6 +616,7 @@ const struct language_defn cplus_language_defn =
cplus_language_arch_info,
default_print_array_index,
cp_pass_by_reference,
+ c_getstr,
LANG_MAGIC
};
@@ -570,6 +653,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_getstr,
LANG_MAGIC
};
@@ -611,6 +695,7 @@ const struct language_defn minimal_language_defn =
c_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 4e2f3c4..63db3e5 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -341,6 +341,7 @@ const struct language_defn f_language_defn =
f_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index fa3f174..611cf26 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1130,6 +1130,7 @@ const struct language_defn java_language_defn =
java_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/language.c b/gdb/language.c
index 0b21dc3..036ef91 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -1042,6 +1042,12 @@ default_print_array_index (struct value *index_value, struct ui_file *stream,
fprintf_filtered (stream, "] = ");
}
+int
+default_getstr (struct value *value, gdb_byte **buffer, int *length)
+{
+ error (_("Getting a string is unsupported in this language."));
+}
+
/* Define the language that is no language. */
static int
@@ -1162,6 +1168,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_getstr,
LANG_MAGIC
};
@@ -1199,6 +1206,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_getstr,
LANG_MAGIC
};
@@ -1235,6 +1243,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_getstr,
LANG_MAGIC
};
diff --git a/gdb/language.h b/gdb/language.h
index ba28540..b6d097f 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -267,6 +267,12 @@ 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 NULL terminating character). */
+ int (*la_getstr) (struct value *value, gdb_byte **buffer, int *length);
+
/* Add fields above this point, so the magic number is always last. */
/* Magic number for compat checking */
@@ -364,6 +370,8 @@ extern enum language set_language (enum language);
(current_language->la_printstr(stream, string, length, width, force_ellipses))
#define LA_EMIT_CHAR(ch, stream, quoter) \
(current_language->la_emitchar(ch, stream, quoter))
+#define LA_GET_STRING(value, buffer, length) \
+ (current_language->la_getstr(value, buffer, length))
#define LA_PRINT_ARRAY_INDEX(index_value, stream, format, pretty) \
(current_language->la_print_array_index(index_value, stream, format, pretty))
@@ -474,4 +482,6 @@ int default_pass_by_reference (struct type *type);
void default_print_typedef (struct type *type, struct symbol *new_symbol,
struct ui_file *stream);
+int default_getstr (struct value *value, gdb_byte **buffer, int *length);
+
#endif /* defined (LANGUAGE_H) */
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 2b3ca6a..022186a 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -392,6 +392,7 @@ const struct language_defn m2_language_defn =
m2_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 4608168..ad9292b 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -529,6 +529,7 @@ const struct language_defn objc_language_defn = {
c_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index b829f8d..2c13707 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -431,6 +431,7 @@ const struct language_defn pascal_language_defn =
pascal_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c
index 607efb6..afcdee7 100644
--- a/gdb/scm-lang.c
+++ b/gdb/scm-lang.c
@@ -271,6 +271,7 @@ const struct language_defn scm_language_defn =
c_language_arch_info,
default_print_array_index,
default_pass_by_reference,
+ default_getstr,
LANG_MAGIC
};
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 44f1a77..3eebf63 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -33,6 +33,7 @@
#include "cp-abi.h"
#include "typeprint.h"
#include "gdb_string.h"
+#include "exceptions.h"
#include <errno.h>
/* For real-type printing in whatis_exp() */
@@ -81,6 +82,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. */
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 37e5efc..02e3c2d 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -1203,39 +1203,40 @@ 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. */
-
-/* FIXME: Use target_read_string. */
+/* 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.
+
+ If LEN is -1, stops at the first null character (not necessarily the first
+ null byte), otherwise reading proceeds (including null characters) until
+ FETCHLIMIT characters have been read. 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 target_read_string should be rewritten to
+ use this function? */
int
-val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream)
+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 found_nul; /* Non-zero if we found the nul char */
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 */
- /* 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 ? print_max : min (len, 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
@@ -1254,9 +1255,9 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream)
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;
@@ -1266,26 +1267,30 @@ 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. */
nfetch = partial_memory_read (addr, bufptr, nfetch * width, &errcode)
- / width;
+ / width;
/* Scan this chunk for the null byte that terminates the string
to print. If found, we don't need to fetch any more. Note
@@ -1312,21 +1317,62 @@ 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 */
+ && bufptr - *buffer < fetchlimit * width /* no overrun */
&& !found_nul); /* haven't found nul yet */
}
else
{ /* length of string is really 0! */
- buffer = bufptr = NULL;
+ *buffer = bufptr = NULL;
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)
+{
+ 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 ? print_max : min (len, print_max));
+
+ errcode = read_string (addr, len, width, fetchlimit, &buffer, &bytes_read);
+ old_chain = make_cleanup (xfree, buffer);
/* 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. */
+ /* 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;
@@ -1341,7 +1387,7 @@ 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
@@ -1349,18 +1395,16 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream)
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 (addressprint)
{
fputs_filtered (" ", stream);
}
- LA_PRINT_STRING (stream, buffer, (bufptr - buffer) / width, width, force_ellipsis);
+ LA_PRINT_STRING (stream, buffer, bytes_read / width, width, force_ellipsis);
}
if (errcode != 0)
@@ -1378,9 +1422,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);
}
diff --git a/gdb/valprint.h b/gdb/valprint.h
index a84bba5..7e4644b 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -85,4 +85,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
diff --git a/gdb/value.h b/gdb/value.h
index df4c795..82f81a1 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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);