From 13547ab600a0929b12f354dc144f1aef37938f30 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 12 Jul 2006 18:13:45 +0000 Subject: [PATCH] * target.c (target_read): Stop if target_read_partial returns 0 when some bytes have already been read. (target_write): Likewise for target_write_partial. (target_read_partial, target_write_partial): Make static. (target_read_alloc): New. * target.h: Doc fixes. (target_read_partial, target_write_partial): Delete prototypes. (target_read_alloc): New prototype. * auxv.c (target_auxv_read): Delete. (target_auxv_search, fprint_target_auxv): Use target_read_alloc. * auxv.h (target_auxv_read): Delete prototype. * avr-tdep.c (avr_io_reg_read_command): Use target_read_alloc. * ia64-tdep.c (getunwind_table, get_kernel_table): Likewise. * linux-nat.c (linux_nat_make_corefile_notes): Likewise. * procfs.c (procfs_make_note_section): Likewise. * remote.c (remote_xfer_partial): Don't loop here. * sparc-tdep.c (sparc_fetch_wcookie): Use target_read. --- gdb/ChangeLog | 21 +++++++++++ gdb/auxv.c | 44 ++-------------------- gdb/auxv.h | 8 +--- gdb/avr-tdep.c | 36 +++++++----------- gdb/ia64-tdep.c | 30 ++++++++------- gdb/linux-nat.c | 3 +- gdb/procfs.c | 3 +- gdb/remote.c | 46 +++++++++-------------- gdb/sparc-tdep.c | 2 +- gdb/target.c | 80 ++++++++++++++++++++++++++++++++++++--- gdb/target.h | 98 ++++++++++++++++++++++++++---------------------- 11 files changed, 206 insertions(+), 165 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index fdad78fe077..c1445bc6178 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +2006-07-12 Daniel Jacobowitz + + * target.c (target_read): Stop if target_read_partial returns 0 + when some bytes have already been read. + (target_write): Likewise for target_write_partial. + (target_read_partial, target_write_partial): Make static. + (target_read_alloc): New. + * target.h: Doc fixes. + (target_read_partial, target_write_partial): Delete prototypes. + (target_read_alloc): New prototype. + + * auxv.c (target_auxv_read): Delete. + (target_auxv_search, fprint_target_auxv): Use target_read_alloc. + * auxv.h (target_auxv_read): Delete prototype. + * avr-tdep.c (avr_io_reg_read_command): Use target_read_alloc. + * ia64-tdep.c (getunwind_table, get_kernel_table): Likewise. + * linux-nat.c (linux_nat_make_corefile_notes): Likewise. + * procfs.c (procfs_make_note_section): Likewise. + * remote.c (remote_xfer_partial): Don't loop here. + * sparc-tdep.c (sparc_fetch_wcookie): Use target_read. + 2006-07-12 Daniel Jacobowitz * arm-linux-tdep.c: Doc fixes. diff --git a/gdb/auxv.c b/gdb/auxv.c index 557da3d416d..d822c7f24aa 100644 --- a/gdb/auxv.c +++ b/gdb/auxv.c @@ -1,6 +1,6 @@ /* Auxiliary vector support for GDB, the GNU debugger. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -76,43 +76,6 @@ procfs_xfer_auxv (struct target_ops *ops, return n; } -/* Read all the auxv data into a contiguous xmalloc'd buffer, - stored in *DATA. Return the size in bytes of this data. - If zero, there is no data and *DATA is null. - if < 0, there was an error and *DATA is null. */ -LONGEST -target_auxv_read (struct target_ops *ops, gdb_byte **data) -{ - size_t auxv_alloc = 512, auxv_pos = 0; - gdb_byte *auxv = xmalloc (auxv_alloc); - int n; - - while (1) - { - n = target_read_partial (ops, TARGET_OBJECT_AUXV, - NULL, &auxv[auxv_pos], 0, - auxv_alloc - auxv_pos); - if (n <= 0) - break; - auxv_pos += n; - if (auxv_pos < auxv_alloc) /* Read all there was. */ - break; - gdb_assert (auxv_pos == auxv_alloc); - auxv_alloc *= 2; - auxv = xrealloc (auxv, auxv_alloc); - } - - if (auxv_pos == 0) - { - xfree (auxv); - *data = NULL; - return n; - } - - *data = auxv; - return auxv_pos; -} - /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. Return 0 if *READPTR is already at the end of the buffer. Return -1 if there is insufficient buffer for a whole entry. @@ -148,7 +111,7 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) { CORE_ADDR type, val; gdb_byte *data; - int n = target_auxv_read (ops, &data); + LONGEST n = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, &data); gdb_byte *ptr = data; int ents = 0; @@ -184,7 +147,8 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) { CORE_ADDR type, val; gdb_byte *data; - int len = target_auxv_read (ops, &data); + LONGEST len = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, + &data); gdb_byte *ptr = data; int ents = 0; diff --git a/gdb/auxv.h b/gdb/auxv.h index 92f7b541a6f..49723b81a06 100644 --- a/gdb/auxv.h +++ b/gdb/auxv.h @@ -1,6 +1,6 @@ /* Auxiliary vector support for GDB, the GNU debugger. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -31,12 +31,6 @@ struct target_ops; /* Forward declaration. */ -/* Read all the auxv data into a contiguous xmalloc'd buffer, - stored in *DATA. Return the size in bytes of this data. - If zero, there is no data and *DATA is null. - if < 0, there was an error and *DATA is null. */ -extern LONGEST target_auxv_read (struct target_ops *ops, gdb_byte **data); - /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. Return 0 if *READPTR is already at the end of the buffer. Return -1 if there is insufficient buffer for a whole entry. diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c index 9c6566e9210..f61e5a0b639 100644 --- a/gdb/avr-tdep.c +++ b/gdb/avr-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for Atmel AVR, for GDB. Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005 Free Software Foundation, Inc. + 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -1323,35 +1323,22 @@ static void avr_io_reg_read_command (char *args, int from_tty) { LONGEST bufsiz = 0; - char buf[400]; + gdb_byte *buf; char query[400]; char *p; unsigned int nreg = 0; unsigned int val; int i, j, k, step; - /* Just get the maximum buffer size. */ - bufsiz = target_read_partial (¤t_target, TARGET_OBJECT_AVR, - NULL, NULL, 0, 0); - if (bufsiz < 0) - { - fprintf_unfiltered (gdb_stderr, - _("ERR: info io_registers NOT supported " - "by current target\n")); - return; - } - if (bufsiz > sizeof (buf)) - bufsiz = sizeof (buf); - /* Find out how many io registers the target has. */ - strcpy (query, "avr.io_reg"); - target_read_partial (¤t_target, TARGET_OBJECT_AVR, query, buf, 0, - bufsiz); + bufsiz = target_read_alloc (¤t_target, TARGET_OBJECT_AVR, + "avr.io_reg", &buf); - if (strncmp (buf, "", bufsiz) == 0) + if (bufsiz <= 0) { fprintf_unfiltered (gdb_stderr, - _("info io_registers NOT supported by target\n")); + _("ERR: info io_registers NOT supported " + "by current target\n")); return; } @@ -1359,9 +1346,12 @@ avr_io_reg_read_command (char *args, int from_tty) { fprintf_unfiltered (gdb_stderr, _("Error fetching number of io registers\n")); + xfree (buf); return; } + xfree (buf); + reinitialize_more_filter (); printf_unfiltered (_("Target has %u io registers:\n\n"), nreg); @@ -1377,8 +1367,8 @@ avr_io_reg_read_command (char *args, int from_tty) j = nreg - i; /* last block is less than 8 registers */ snprintf (query, sizeof (query) - 1, "avr.io_reg:%x,%x", i, j); - target_read_partial (¤t_target, TARGET_OBJECT_AVR, query, buf, - 0, bufsiz); + bufsiz = target_read_alloc (¤t_target, TARGET_OBJECT_AVR, + query, &buf); p = buf; for (k = i; k < (i + j); k++) @@ -1393,6 +1383,8 @@ avr_io_reg_read_command (char *args, int from_tty) break; } } + + xfree (buf); } } diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c index 897d272d918..a65c56f9589 100644 --- a/gdb/ia64-tdep.c +++ b/gdb/ia64-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for the IA-64 for GDB, the GNU debugger. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software - Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GDB. @@ -2458,8 +2458,8 @@ ia64_access_mem (unw_addr_space_t as, } /* Call low-level function to access the kernel unwind table. */ -static int -getunwind_table (void *buf, size_t len) +static LONGEST +getunwind_table (gdb_byte **buf_p) { LONGEST x; @@ -2470,10 +2470,11 @@ getunwind_table (void *buf, size_t len) we want to preserve fall back to the running kernel's table, then we should find a way to override the corefile layer's xfer_partial method. */ - x = target_read_partial (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL, - buf, 0, len); - return (int)x; + x = target_read_alloc (¤t_target, TARGET_OBJECT_UNWIND_TABLE, + NULL, buf_p); + + return x; } /* Get the kernel unwind table. */ @@ -2484,14 +2485,15 @@ get_kernel_table (unw_word_t ip, unw_dyn_info_t *di) if (!ktab) { + gdb_byte *ktab_buf; size_t size; - size = getunwind_table (NULL, 0); - if ((int)size < 0) - return -UNW_ENOINFO; - ktab_size = size; - ktab = xmalloc (ktab_size); - getunwind_table (ktab, ktab_size); - + + ktab_size = getunwind_table (&ktab_buf); + if (ktab_size <= 0) + return -UNW_ENOINFO; + else + ktab = (struct ia64_table_entry *) ktab_buf; + for (etab = ktab; etab->start_offset; ++etab) etab->info_offset += KERNEL_START; } diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 932119edfc5..6c63ba97a85 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -2697,7 +2697,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size) note_data = thread_args.note_data; } - auxv_len = target_auxv_read (¤t_target, &auxv); + auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV, + NULL, &auxv); if (auxv_len > 0) { note_data = elfcore_write_note (obfd, note_data, note_size, diff --git a/gdb/procfs.c b/gdb/procfs.c index 03fcadd017a..23ee3fb9250 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -6130,7 +6130,8 @@ procfs_make_note_section (bfd *obfd, int *note_size) note_data = thread_args.note_data; } - auxv_len = target_auxv_read (¤t_target, &auxv); + auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV, + NULL, &auxv); if (auxv_len > 0) { note_data = elfcore_write_note (obfd, note_data, note_size, diff --git a/gdb/remote.c b/gdb/remote.c index da0f5ca7d11..eef8bf2f5f4 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -5147,35 +5147,23 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object, case TARGET_OBJECT_AUXV: if (remote_protocol_packets[PACKET_qPart_auxv].support != PACKET_DISABLE) { - unsigned int total = 0; - while (len > 0) - { - LONGEST n = min ((get_remote_packet_size () - 2) / 2, len); - snprintf (rs->buf, get_remote_packet_size (), - "qPart:auxv:read::%s,%s", - phex_nz (offset, sizeof offset), - phex_nz (n, sizeof n)); - i = putpkt (rs->buf); - if (i < 0) - return total > 0 ? total : i; - rs->buf[0] = '\0'; - getpkt (&rs->buf, &rs->buf_size, 0); - if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_qPart_auxv]) - != PACKET_OK) - return total > 0 ? total : -1; - if (strcmp (rs->buf, "OK") == 0) - break; /* Got EOF indicator. */ - /* Got some data. */ - i = hex2bin (rs->buf, readbuf, len); - if (i > 0) - { - readbuf = (void *) ((char *) readbuf + i); - offset += i; - len -= i; - total += i; - } - } - return total; + LONGEST n = min ((get_remote_packet_size () - 2) / 2, len); + snprintf (rs->buf, get_remote_packet_size (), + "qPart:auxv:read::%s,%s", + phex_nz (offset, sizeof offset), + phex_nz (n, sizeof n)); + i = putpkt (rs->buf); + if (i < 0) + return i; + rs->buf[0] = '\0'; + getpkt (&rs->buf, &rs->buf_size, 0); + if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_qPart_auxv]) + != PACKET_OK) + return -1; + if (strcmp (rs->buf, "OK") == 0) + return 0; /* Got EOF indicator. */ + /* Got some data. */ + return hex2bin (rs->buf, readbuf, len); } return -1; diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 797e2400536..6c6f27692e0 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -158,7 +158,7 @@ sparc_fetch_wcookie (void) gdb_byte buf[8]; int len; - len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8); + len = target_read (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8); if (len == -1) return 0; diff --git a/gdb/target.c b/gdb/target.c index bcb47deec38..c378ce56f74 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1341,7 +1341,7 @@ default_xfer_partial (struct target_ops *ops, enum target_object object, (inbuf, outbuf)", instead of separate read/write methods, make life easier. */ -LONGEST +static LONGEST target_read_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *buf, @@ -1350,7 +1350,7 @@ target_read_partial (struct target_ops *ops, return target_xfer_partial (ops, object, annex, buf, NULL, offset, len); } -LONGEST +static LONGEST target_write_partial (struct target_ops *ops, enum target_object object, const char *annex, const gdb_byte *buf, @@ -1373,8 +1373,9 @@ target_read (struct target_ops *ops, (gdb_byte *) buf + xfered, offset + xfered, len - xfered); /* Call an observer, notifying them of the xfer progress? */ - if (xfer <= 0) - /* Call memory_error? */ + if (xfer == 0) + return xfered; + if (xfer < 0) return -1; xfered += xfer; QUIT; @@ -1395,8 +1396,9 @@ target_write (struct target_ops *ops, (gdb_byte *) buf + xfered, offset + xfered, len - xfered); /* Call an observer, notifying them of the xfer progress? */ - if (xfer <= 0) - /* Call memory_error? */ + if (xfer == 0) + return xfered; + if (xfer < 0) return -1; xfered += xfer; QUIT; @@ -1404,6 +1406,72 @@ target_write (struct target_ops *ops, return len; } +/* Wrapper to perform a full read of unknown size. OBJECT/ANNEX will + be read using OPS. The return value will be -1 if the transfer + fails or is not supported; 0 if the object is empty; or the length + of the object otherwise. If a positive value is returned, a + sufficiently large buffer will be allocated using xmalloc and + returned in *BUF_P containing the contents of the object. + + This method should be used for objects sufficiently small to store + in a single xmalloc'd buffer, when no fixed bound on the object's + size is known in advance. Don't try to read TARGET_OBJECT_MEMORY + through this function. */ + +LONGEST +target_read_alloc (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte **buf_p) +{ + size_t buf_alloc, buf_pos; + gdb_byte *buf; + LONGEST n; + + /* This function does not have a length parameter; it reads the + entire OBJECT). Also, it doesn't support objects fetched partly + from one target and partly from another (in a different stratum, + e.g. a core file and an executable). Both reasons make it + unsuitable for reading memory. */ + gdb_assert (object != TARGET_OBJECT_MEMORY); + + /* Start by reading up to 4K at a time. The target will throttle + this number down if necessary. */ + buf_alloc = 4096; + buf = xmalloc (buf_alloc); + buf_pos = 0; + while (1) + { + n = target_read_partial (ops, object, annex, &buf[buf_pos], + buf_pos, buf_alloc - buf_pos); + if (n < 0) + { + /* An error occurred. */ + xfree (buf); + return -1; + } + else if (n == 0) + { + /* Read all there was. */ + if (buf_pos == 0) + xfree (buf); + else + *buf_p = buf; + return buf_pos; + } + + buf_pos += n; + + /* If the buffer is filling up, expand it. */ + if (buf_alloc < buf_pos * 2) + { + buf_alloc *= 2; + buf = xrealloc (buf, buf_alloc); + } + + QUIT; + } +} + /* Memory transfer methods. */ void diff --git a/gdb/target.h b/gdb/target.h index 7018c52ce82..2bb47fb2389 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -180,38 +180,8 @@ extern char *target_signal_to_name (enum target_signal); /* Given a name (SIGHUP, etc.), return its signal. */ enum target_signal target_signal_from_name (char *); -/* Request the transfer of up to LEN 8-bit bytes of the target's - OBJECT. The OFFSET, for a seekable object, specifies the starting - point. The ANNEX can be used to provide additional data-specific - information to the target. - - Return the number of bytes actually transfered, zero when no - further transfer is possible, and -1 when the transfer is not - supported. - - NOTE: cagney/2003-10-17: The current interface does not support a - "retry" mechanism. Instead it assumes that at least one byte will - be transfered on each call. - - NOTE: cagney/2003-10-17: The current interface can lead to - fragmented transfers. Lower target levels should not implement - hacks, such as enlarging the transfer, in an attempt to compensate - for this. Instead, the target stack should be extended so that it - implements supply/collect methods and a look-aside object cache. - With that available, the lowest target can safely and freely "push" - data up the stack. - - NOTE: cagney/2003-10-17: Unlike the old query and the memory - transfer mechanisms, these methods are explicitly parameterized by - the target that it should be applied to. - - NOTE: cagney/2003-10-17: Just like the old query and memory xfer - methods, these new methods perform partial transfers. The only - difference is that these new methods thought to include "partial" - in the name. The old code's failure to do this lead to much - confusion and duplication of effort as each target object attempted - to locally take responsibility for something it didn't have to - worry about. */ +/* Target objects which can be transfered using target_read, + target_write, et cetera. */ enum target_object { @@ -229,17 +199,17 @@ enum target_object /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */ }; -extern LONGEST target_read_partial (struct target_ops *ops, - enum target_object object, - const char *annex, gdb_byte *buf, - ULONGEST offset, LONGEST len); +/* Request that OPS transfer up to LEN 8-bit bytes of the target's + OBJECT. The OFFSET, for a seekable object, specifies the + starting point. The ANNEX can be used to provide additional + data-specific information to the target. -extern LONGEST target_write_partial (struct target_ops *ops, - enum target_object object, - const char *annex, const gdb_byte *buf, - ULONGEST offset, LONGEST len); + Return the number of bytes actually transfered, or -1 if the + transfer is not supported or otherwise fails. Return of a positive + value less than LEN indicates that no further transfer is possible. + Unlike the raw to_xfer_partial interface, callers of these + functions do not need to retry partial transfers. */ -/* Wrappers to perform the full transfer. */ extern LONGEST target_read (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *buf, @@ -250,6 +220,22 @@ extern LONGEST target_write (struct target_ops *ops, const char *annex, const gdb_byte *buf, ULONGEST offset, LONGEST len); +/* Wrapper to perform a full read of unknown size. OBJECT/ANNEX will + be read using OPS. The return value will be -1 if the transfer + fails or is not supported; 0 if the object is empty; or the length + of the object otherwise. If a positive value is returned, a + sufficiently large buffer will be allocated using xmalloc and + returned in *BUF_P containing the contents of the object. + + This method should be used for objects sufficiently small to store + in a single xmalloc'd buffer, when no fixed bound on the object's + size is known in advance. Don't try to read TARGET_OBJECT_MEMORY + through this function. */ + +extern LONGEST target_read_alloc (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte **buf_p); + /* Wrappers to target read/write that perform memory transfers. They throw an error if the memory transfer fails. @@ -409,9 +395,33 @@ struct target_ops CORE_ADDR load_module_addr, CORE_ADDR offset); - /* Perform partial transfers on OBJECT. See target_read_partial - and target_write_partial for details of each variant. One, and - only one, of readbuf or writebuf must be non-NULL. */ + /* Request that OPS transfer up to LEN 8-bit bytes of the target's + OBJECT. The OFFSET, for a seekable object, specifies the + starting point. The ANNEX can be used to provide additional + data-specific information to the target. + + Return the number of bytes actually transfered, zero when no + further transfer is possible, and -1 when the transfer is not + supported. Return of a positive value smaller than LEN does + not indicate the end of the object, only the end of the + transfer; higher level code should continue transferring if + desired. This is handled in target.c. + + The interface does not support a "retry" mechanism. Instead it + assumes that at least one byte will be transfered on each + successful call. + + NOTE: cagney/2003-10-17: The current interface can lead to + fragmented transfers. Lower target levels should not implement + hacks, such as enlarging the transfer, in an attempt to + compensate for this. Instead, the target stack should be + extended so that it implements supply/collect methods and a + look-aside object cache. With that available, the lowest + target can safely and freely "push" data up the stack. + + See target_read and target_write for more information. One, + and only one, of readbuf or writebuf must be non-NULL. */ + LONGEST (*to_xfer_partial) (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, -- 2.30.2