* [PATCH 0/8] v2 - validate binary before use
@ 2013-04-09 16:15 Aleksandar Ristovski
2013-04-09 15:53 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski
` (9 more replies)
0 siblings, 10 replies; 42+ messages in thread
From: Aleksandar Ristovski @ 2013-04-09 16:15 UTC (permalink / raw)
To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski
Hello,
This patchset is updated patchset for using build-id to validate
symbol file before use.
I started the new thread as it unifies two other threads
(see References below).
Summary:
Patchset introduces validation of symbol files prior to their use.
If validation fails, symbol file is discarded.
Validation is performed by comparing build-id from the target memory
and that from the symbol-file.
There are two methods for fetching build-id from the target memory:
- using TARGET_OBJECT_LIBRARIES_SVR4 if target supports it
- reading build-id directly if the above method is not supported.
Core support:
- core will use second method. Note, however, that due to (at least
on ubuntu) not dumping page containing buid-id in the core, the
validation can not be performed (it will always default to valid).
This is misfortunate but outside the scope of this patch.
References:
http://sourceware.org/ml/gdb-patches/2013-04/msg00153.html
http://sourceware.org/ml/gdb-patches/2013-04/msg00113.html
Thank you,
Aleksandar Ristovski
QNX Software Systems
^ permalink raw reply [flat|nested] 42+ messages in thread* [PATCH 1/8] Move utility functions to common/ 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski @ 2013-04-09 15:53 ` Aleksandar Ristovski 2013-04-09 16:01 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski ` (8 subsequent siblings) 9 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 15:53 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to common/common-utils.c. * cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to common/common-utils.h. * common/common-utils.c (ctype.h): Include. (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move from utils.c. (fromhex): Copy from remote.c. (hex2bin): Move from remote.c. (tohex): Copy from remote.c. (bin2hex): Move from remote.c. (skip_spaces, skip_spaces_const): Move from cli/cli-utils.c. * common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved from defs.h. (strtoulst): Move decl from utils.h. (hex2bin, bin2hex): Move decls from remote.h. (skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h. * defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to common/common-utils.h * remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c. * remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h. * utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move to common/common-utils.c. * utils.h (strtoulst): Moved decl to common/common-utils.h. --- gdb/cli/cli-utils.c | 24 ------ gdb/cli/cli-utils.h | 9 --- gdb/common/common-utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++ gdb/common/common-utils.h | 34 +++++++++ gdb/defs.h | 19 ----- gdb/remote.c | 36 --------- gdb/remote.h | 4 - gdb/utils.c | 99 ------------------------ gdb/utils.h | 2 - 9 files changed, 221 insertions(+), 193 deletions(-) diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c index f74e6b1..60f7553 100644 --- a/gdb/cli/cli-utils.c +++ b/gdb/cli/cli-utils.c @@ -213,30 +213,6 @@ number_is_in_list (char *list, int number) /* See documentation in cli-utils.h. */ -char * -skip_spaces (char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* A const-correct version of the above. */ - -const char * -skip_spaces_const (const char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* See documentation in cli-utils.h. */ - const char * skip_to_space_const (const char *chp) { diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h index 152fb89..2a8850d 100644 --- a/gdb/cli/cli-utils.h +++ b/gdb/cli/cli-utils.h @@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state); extern int number_is_in_list (char *list, int number); -/* Skip leading whitespace characters in INP, returning an updated - pointer. If INP is NULL, return NULL. */ - -extern char *skip_spaces (char *inp); - -/* A const-correct version of the above. */ - -extern const char *skip_spaces_const (const char *inp); - /* Skip leading non-whitespace characters in INP, returning an updated pointer. If INP is NULL, return NULL. */ diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c index 4204abf..5e96692 100644 --- a/gdb/common/common-utils.c +++ b/gdb/common/common-utils.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <stdio.h> +#include <ctype.h> /* The xmalloc() (libiberty.h) family of memory management routines. @@ -161,3 +162,189 @@ savestring (const char *ptr, size_t len) p[len] = 0; return p; } + +/* The bit offset of the highest byte in a ULONGEST, for overflow + checking. */ + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 36. */ + +static int +is_digit_in_base (unsigned char digit, int base) +{ + if (!isalnum (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (unsigned char c) +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ + +ULONGEST +strtoulst (const char *num, const char **trailer, int base) +{ + unsigned int high_part; + ULONGEST result; + int minus = 0; + int i = 0; + + /* Skip leading whitespace. */ + while (isspace (num[i])) + i++; + + /* Handle prefixes. */ + if (num[i] == '+') + i++; + else if (num[i] == '-') + { + minus = 1; + i++; + } + + if (base == 0 || base == 16) + { + if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) + { + i += 2; + if (base == 0) + base = 16; + } + } + + if (base == 0 && num[i] == '0') + base = 8; + + if (base == 0) + base = 10; + + if (base < 2 || base > 36) + { + errno = EINVAL; + return 0; + } + + result = high_part = 0; + for (; is_digit_in_base (num[i], base); i += 1) + { + result = result * base + digit_to_int (num[i]); + high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = ~ (ULONGEST) 0; + high_part = 0; + minus = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); + if (minus) + return -result; + else + return result; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else + error (_("Reply contains invalid hex digit %d"), a); +} + +int +hex2bin (const char *hex, gdb_byte *bin, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +int +bin2hex (const gdb_byte *bin, char *hex, int count) +{ + int i; + + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen ((char *) bin); + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +/* See documentation in cli-utils.h. */ + +char * +skip_spaces (char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} + +/* A const-correct version of the above. */ + +const char * +skip_spaces_const (const char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h index 9b659d8..ee7870e 100644 --- a/gdb/common/common-utils.h +++ b/gdb/common/common-utils.h @@ -25,6 +25,25 @@ #include <stddef.h> #include <stdarg.h> +/* Static target-system-dependent parameters for GDB. */ + +/* Number of bits in a char or unsigned char for the target machine. + Just like CHAR_BIT in <limits.h> but describes the target machine. */ +#if !defined (TARGET_CHAR_BIT) +#define TARGET_CHAR_BIT 8 +#endif + +/* If we picked up a copy of CHAR_BIT from a configuration file + (which may get it by including <limits.h>) then use it to set + the number of bits in a host char. If not, use the same size + as the target. */ + +#if defined (CHAR_BIT) +#define HOST_CHAR_BIT CHAR_BIT +#else +#define HOST_CHAR_BIT TARGET_CHAR_BIT +#endif + extern void malloc_failure (long size) ATTRIBUTE_NORETURN; extern void internal_error (const char *file, int line, const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4); @@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...) char *savestring (const char *ptr, size_t len); +ULONGEST strtoulst (const char *num, const char **trailer, int base); + +extern int hex2bin (const char *hex, gdb_byte *bin, int count); + +extern int bin2hex (const gdb_byte *bin, char *hex, int count); + +/* Skip leading whitespace characters in INP, returning an updated + pointer. If INP is NULL, return NULL. */ + +extern char *skip_spaces (char *inp); + +/* A const-correct version of the above. */ + +extern const char *skip_spaces_const (const char *inp); + #endif diff --git a/gdb/defs.h b/gdb/defs.h index d8a1adb..ec7e4f3 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -648,25 +648,6 @@ extern void *alloca (); enum { MAX_REGISTER_SIZE = 64 }; -/* Static target-system-dependent parameters for GDB. */ - -/* Number of bits in a char or unsigned char for the target machine. - Just like CHAR_BIT in <limits.h> but describes the target machine. */ -#if !defined (TARGET_CHAR_BIT) -#define TARGET_CHAR_BIT 8 -#endif - -/* If we picked up a copy of CHAR_BIT from a configuration file - (which may get it by including <limits.h>) then use it to set - the number of bits in a host char. If not, use the same size - as the target. */ - -#if defined (CHAR_BIT) -#define HOST_CHAR_BIT CHAR_BIT -#else -#define HOST_CHAR_BIT TARGET_CHAR_BIT -#endif - /* In findvar.c. */ extern LONGEST extract_signed_integer (const gdb_byte *, int, diff --git a/gdb/remote.c b/gdb/remote.c index 740324b..92aa141 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -4569,25 +4569,6 @@ fromhex (int a) error (_("Reply contains invalid hex digit %d"), a); } -int -hex2bin (const char *hex, gdb_byte *bin, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - if (hex[0] == 0 || hex[1] == 0) - { - /* Hex string is short, or of uneven length. - Return the count that has been converted so far. */ - return i; - } - *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - return i; -} - /* Convert number NIB to a hex digit. */ static int @@ -4599,23 +4580,6 @@ tohex (int nib) return 'a' + nib - 10; } -int -bin2hex (const gdb_byte *bin, char *hex, int count) -{ - int i; - - /* May use a length, or a nul-terminated string as input. */ - if (count == 0) - count = strlen ((char *) bin); - - for (i = 0; i < count; i++) - { - *hex++ = tohex ((*bin >> 4) & 0xf); - *hex++ = tohex (*bin++ & 0xf); - } - *hex = 0; - return i; -} \f /* Check for the availability of vCont. This function should also check the response. */ diff --git a/gdb/remote.h b/gdb/remote.h index b95370c..d49b427 100644 --- a/gdb/remote.h +++ b/gdb/remote.h @@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever); extern int putpkt (char *buf); -extern int hex2bin (const char *hex, gdb_byte *bin, int count); - -extern int bin2hex (const gdb_byte *bin, char *hex, int count); - extern char *unpack_varlen_hex (char *buff, ULONGEST *result); extern void async_remote_interrupt_twice (void *arg); diff --git a/gdb/utils.c b/gdb/utils.c index a222c59..e1ced2c 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -3233,105 +3233,6 @@ dummy_obstack_deallocate (void *object, void *data) return; } -/* The bit offset of the highest byte in a ULONGEST, for overflow - checking. */ - -#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) - -/* True (non-zero) iff DIGIT is a valid digit in radix BASE, - where 2 <= BASE <= 36. */ - -static int -is_digit_in_base (unsigned char digit, int base) -{ - if (!isalnum (digit)) - return 0; - if (base <= 10) - return (isdigit (digit) && digit < base + '0'); - else - return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); -} - -static int -digit_to_int (unsigned char c) -{ - if (isdigit (c)) - return c - '0'; - else - return tolower (c) - 'a' + 10; -} - -/* As for strtoul, but for ULONGEST results. */ - -ULONGEST -strtoulst (const char *num, const char **trailer, int base) -{ - unsigned int high_part; - ULONGEST result; - int minus = 0; - int i = 0; - - /* Skip leading whitespace. */ - while (isspace (num[i])) - i++; - - /* Handle prefixes. */ - if (num[i] == '+') - i++; - else if (num[i] == '-') - { - minus = 1; - i++; - } - - if (base == 0 || base == 16) - { - if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) - { - i += 2; - if (base == 0) - base = 16; - } - } - - if (base == 0 && num[i] == '0') - base = 8; - - if (base == 0) - base = 10; - - if (base < 2 || base > 36) - { - errno = EINVAL; - return 0; - } - - result = high_part = 0; - for (; is_digit_in_base (num[i], base); i += 1) - { - result = result * base + digit_to_int (num[i]); - high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); - result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; - if (high_part > 0xff) - { - errno = ERANGE; - result = ~ (ULONGEST) 0; - high_part = 0; - minus = 0; - break; - } - } - - if (trailer != NULL) - *trailer = &num[i]; - - result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); - if (minus) - return -result; - else - return result; -} - /* Simple, portable version of dirname that does not modify its argument. */ diff --git a/gdb/utils.h b/gdb/utils.h index ad5bea4..e3b6fbf 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -39,8 +39,6 @@ extern int streq (const char *, const char *); extern int subset_compare (char *, char *); -ULONGEST strtoulst (const char *num, const char **trailer, int base); - int compare_positive_ints (const void *ap, const void *bp); int compare_strings (const void *ap, const void *bp); -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 2/8] Merge multiple hex conversions 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski 2013-04-09 15:53 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski @ 2013-04-09 16:01 ` Aleksandar Ristovski 2013-04-09 16:03 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski ` (7 subsequent siblings) 9 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 16:01 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * common/common-utils.c (fromhex): Make externally linkable. Change error message. (tohex): Make externally linkable. * common/common-utils.h (fromhex, tohex): New declaration. * gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'. (logchar): Use fromhex. * gdbserver/remote-utils.c (fromhex, unhexify): Remove. (tohex, hexify): Remove. (look_up_one_symbol, monitor_output): Use bin2hex instead of hexify. * gdbserver/server.c (handle_query): Use bin2hex instead of hexify. (handle_v_run): Ditto. * gdbserver/server.h (unhexify, hexify): Remove declarations. * gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin instead of unhexify. (cmd_qtstatus): Use bin2hex instead of hexify. (cmd_qtnotes): Use hex2bin instead of unhexify. * monitor.c (fromhex): Remove definition. * remote.c (tohex, fromhex): Remove fwd declarations, remove definitions. --- gdb/common/common-utils.c | 6 ++-- gdb/common/common-utils.h | 4 +++ gdb/gdbserver/gdbreplay.c | 6 ++-- gdb/gdbserver/remote-utils.c | 67 ++---------------------------------------- gdb/gdbserver/server.c | 5 ++-- gdb/gdbserver/server.h | 2 -- gdb/gdbserver/tracepoint.c | 16 +++++----- gdb/monitor.c | 15 ---------- gdb/remote.c | 30 ------------------- 9 files changed, 24 insertions(+), 127 deletions(-) diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c index 5e96692..c123ed7 100644 --- a/gdb/common/common-utils.c +++ b/gdb/common/common-utils.c @@ -264,7 +264,7 @@ strtoulst (const char *num, const char **trailer, int base) /* Convert hex digit A to a number. */ -static int +int fromhex (int a) { if (a >= '0' && a <= '9') @@ -274,7 +274,7 @@ fromhex (int a) else if (a >= 'A' && a <= 'F') return a - 'A' + 10; else - error (_("Reply contains invalid hex digit %d"), a); + error (_("Invalid hex digit %d"), a); } int @@ -298,7 +298,7 @@ hex2bin (const char *hex, gdb_byte *bin, int count) /* Convert number NIB to a hex digit. */ -static int +int tohex (int nib) { if (nib < 10) diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h index ee7870e..2c95d34 100644 --- a/gdb/common/common-utils.h +++ b/gdb/common/common-utils.h @@ -74,6 +74,10 @@ char *savestring (const char *ptr, size_t len); ULONGEST strtoulst (const char *num, const char **trailer, int base); +extern int fromhex (int a); + +extern int tohex (int nib); + extern int hex2bin (const char *hex, gdb_byte *bin, int count); extern int bin2hex (const gdb_byte *bin, char *hex, int count); diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c index 0aa52d8..d0ff8c4 100644 --- a/gdb/gdbserver/gdbreplay.c +++ b/gdb/gdbserver/gdbreplay.c @@ -273,7 +273,7 @@ remote_open (char *name) } static int -tohex (int ch) +fromhex (int ch) { if (ch >= '0' && ch <= '9') { @@ -336,11 +336,11 @@ logchar (FILE *fp) ch2 = fgetc (fp); fputc (ch2, stdout); fflush (stdout); - ch = tohex (ch2) << 4; + ch = fromhex (ch2) << 4; ch2 = fgetc (fp); fputc (ch2, stdout); fflush (stdout); - ch |= tohex (ch2); + ch |= fromhex (ch2); break; default: /* Treat any other char as just itself */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 42c6a54..6ff491e 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -416,20 +416,6 @@ remote_close (void) reset_readchar (); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else - error ("Reply contains invalid hex digit"); - return 0; -} - #endif static const char hexchars[] = "0123456789abcdef"; @@ -457,25 +443,6 @@ ishex (int ch, int *val) #ifndef IN_PROCESS_AGENT -int -unhexify (char *bin, const char *hex, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - if (hex[0] == 0 || hex[1] == 0) - { - /* Hex string is short, or of uneven length. - Return the count that has been converted so far. */ - return i; - } - *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - return i; -} - void decode_address (CORE_ADDR *addrp, const char *start, int len) { @@ -511,37 +478,8 @@ decode_address_to_semicolon (CORE_ADDR *addrp, const char *start) #endif -/* Convert number NIB to a hex digit. */ - -static int -tohex (int nib) -{ - if (nib < 10) - return '0' + nib; - else - return 'a' + nib - 10; -} - #ifndef IN_PROCESS_AGENT -int -hexify (char *hex, const char *bin, int count) -{ - int i; - - /* May use a length, or a nul-terminated string as input. */ - if (count == 0) - count = strlen (bin); - - for (i = 0; i < count; i++) - { - *hex++ = tohex ((*bin >> 4) & 0xf); - *hex++ = tohex (*bin++ & 0xf); - } - *hex = 0; - return i; -} - /* Convert BUFFER, binary data at least LEN bytes long, into escaped binary data in OUT_BUF. Set *OUT_LEN to the length of the data encoded in OUT_BUF, and return the number of bytes in OUT_BUF @@ -1608,7 +1546,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) /* Send the request. */ strcpy (own_buf, "qSymbol:"); - hexify (own_buf + strlen ("qSymbol:"), name, strlen (name)); + bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"), + strlen (name)); if (putpkt (own_buf) < 0) return -1; @@ -1770,7 +1709,7 @@ monitor_output (const char *msg) char *buf = xmalloc (strlen (msg) * 2 + 2); buf[0] = 'O'; - hexify (buf + 1, msg, 0); + bin2hex ((const gdb_byte *) msg, buf + 1, 0); putpkt (buf); free (buf); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 6bb36d8..8b586dd 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1920,7 +1920,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } - if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2) + if ((len % 2) != 0 + || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2) { write_enn (own_buf); free (mon); @@ -2214,7 +2215,7 @@ handle_v_run (char *own_buf) { /* FIXME: Fail request if out of memory instead of dying. */ new_argv[i] = xmalloc (1 + (next_p - p) / 2); - unhexify (new_argv[i], p, (next_p - p) / 2); + hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2); new_argv[i][(next_p - p) / 2] = '\0'; } diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 139cd49..5e16088 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -322,8 +322,6 @@ int decode_search_memory_packet (const char *buf, int packet_len, gdb_byte *pattern, unsigned int *pattern_lenp); -int unhexify (char *bin, const char *hex, int count); -int hexify (char *hex, const char *bin, int count); int remote_escape_output (const gdb_byte *buffer, int len, gdb_byte *out_buf, int *out_len, int out_maxlen); diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 419765b..f48e3b6 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -2679,7 +2679,7 @@ cmd_qtdpsrc (char *own_buf) packet = unpack_varlen_hex (packet, &slen); ++packet; /* skip a colon */ src = xmalloc (slen + 1); - nbytes = unhexify (src, packet, strlen (packet) / 2); + nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2); src[nbytes] = '\0'; newlast = xmalloc (sizeof (struct source_string)); @@ -2721,7 +2721,7 @@ cmd_qtdv (char *own_buf) nbytes = strlen (packet) / 2; varname = xmalloc (nbytes + 1); - nbytes = unhexify (varname, packet, nbytes); + nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes); varname[nbytes] = '\0'; tsv = create_trace_state_variable (num, 1); @@ -3594,17 +3594,17 @@ cmd_qtstatus (char *packet) str = (tracing_user_name ? tracing_user_name : ""); slen = strlen (str); buf1 = (char *) alloca (slen * 2 + 1); - hexify (buf1, str, slen); + bin2hex ((const gdb_byte *) str, buf1, slen); str = (tracing_notes ? tracing_notes : ""); slen = strlen (str); buf2 = (char *) alloca (slen * 2 + 1); - hexify (buf2, str, slen); + bin2hex ((const gdb_byte *) str, buf2, slen); str = (tracing_stop_note ? tracing_stop_note : ""); slen = strlen (str); buf3 = (char *) alloca (slen * 2 + 1); - hexify (buf3, str, slen); + bin2hex ((const gdb_byte *) str, buf3, slen); trace_debug ("Returning trace status as %d, stop reason %s", tracing, tracing_stop_reason); @@ -4078,7 +4078,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; user = xmalloc (nbytes + 1); - nbytes = unhexify (user, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) user, nbytes); user[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("User is '%s'", user); @@ -4092,7 +4092,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; notes = xmalloc (nbytes + 1); - nbytes = unhexify (notes, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes); notes[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("Notes is '%s'", notes); @@ -4106,7 +4106,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; stopnote = xmalloc (nbytes + 1); - nbytes = unhexify (stopnote, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes); stopnote[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("tstop note is '%s'", stopnote); diff --git a/gdb/monitor.c b/gdb/monitor.c index 0337075..c3c623b 100644 --- a/gdb/monitor.c +++ b/gdb/monitor.c @@ -226,21 +226,6 @@ monitor_error (char *function, char *message, message, safe_string); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error (_("Invalid hex digit %d"), a); -} - /* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses This function exists to get around the problem that many host platforms diff --git a/gdb/remote.c b/gdb/remote.c index 92aa141..5a679c1 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -126,8 +126,6 @@ static void remote_serial_write (const char *str, int len); static void remote_kill (struct target_ops *ops); -static int tohex (int nib); - static int remote_can_async_p (void); static int remote_is_async_p (void); @@ -184,8 +182,6 @@ static void remote_find_new_threads (void); static void record_currthread (ptid_t currthread); -static int fromhex (int a); - static int putpkt_binary (char *buf, int cnt); static void check_binary_download (CORE_ADDR addr); @@ -4554,32 +4550,6 @@ extended_remote_attach (struct target_ops *ops, char *args, int from_tty) extended_remote_attach_1 (ops, args, from_tty); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error (_("Reply contains invalid hex digit %d"), a); -} - -/* Convert number NIB to a hex digit. */ - -static int -tohex (int nib) -{ - if (nib < 10) - return '0' + nib; - else - return 'a' + nib - 10; -} - \f /* Check for the availability of vCont. This function should also check the response. */ -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski 2013-04-09 15:53 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski 2013-04-09 16:01 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski @ 2013-04-09 16:03 ` Aleksandar Ristovski 2013-04-15 13:34 ` Jan Kratochvil 2013-04-09 16:39 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski ` (6 subsequent siblings) 9 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 16:03 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Most notable changes: addition of common-target.[ch] files, to receive read_alloc and read_stralloc in patch #5. * Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h, common/common-target.h. (COMMON_OBS): Add common-target.o. (linux-maps.o, common-target.o): New. * common/common-target.c: New file. * common/common-target.h: New file. * common/linux-maps.c: New file. * common/linux-maps.h: New file. * config/i386/linux.mh (NATDEPFILES): Add linux-maps.o. * config/i386/linux64.mh (NATDEPFILES): Ditto. * gdbserver/Makefile.in (OBS): Add common-taret.o. (linux-maps.o, common-target.o): New. * gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o. --- gdb/Makefile.in | 15 ++++++-- gdb/common/common-target.c | 27 +++++++++++++++ gdb/common/common-target.h | 24 +++++++++++++ gdb/common/linux-maps.c | 25 ++++++++++++++ gdb/common/linux-maps.h | 22 ++++++++++++ gdb/config/i386/linux.mh | 2 +- gdb/config/i386/linux64.mh | 2 +- gdb/gdbserver/Makefile.in | 8 ++++- gdb/gdbserver/configure.srv | 79 ++++++++++++++++++++++++++++++++----------- 9 files changed, 180 insertions(+), 24 deletions(-) create mode 100644 gdb/common/common-target.c create mode 100644 gdb/common/common-target.h create mode 100644 gdb/common/linux-maps.c create mode 100644 gdb/common/linux-maps.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 498d42a..5f5ddca 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -772,7 +772,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c HFILES_NO_SRCDIR = \ common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \ -common/i386-xstate.h common/linux-ptrace.h \ +common/i386-xstate.h common/linux-maps.h common/linux-ptrace.h \ proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \ ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \ exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \ @@ -838,7 +838,9 @@ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \ common/format.h common/host-defs.h utils.h common/queue.h common/gdb_string.h \ common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \ gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \ -ctf.h +ctf.h \ +common/common-target.h + # Header files that already have srcdir in them, or which are in objdir. @@ -931,6 +933,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \ gdb_vecs.o jit.o progspace.o skip.o probe.o \ common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \ + common-target.o \ format.o registry.o btrace.o record-btrace.o TSOBS = inflow.o @@ -1939,6 +1942,10 @@ format.o: ${srcdir}/common/format.c $(COMPILE) $(srcdir)/common/format.c $(POSTCOMPILE) +linux-maps.o: ${srcdir}/common/linux-maps.c + $(COMPILE) $(srcdir)/common/linux-maps.c + $(POSTCOMPILE) + linux-osdata.o: ${srcdir}/common/linux-osdata.c $(COMPILE) $(srcdir)/common/linux-osdata.c $(POSTCOMPILE) @@ -1955,6 +1962,10 @@ common-agent.o: $(srcdir)/common/agent.c $(COMPILE) $(srcdir)/common/agent.c $(POSTCOMPILE) +common-target.o: ${srcdir}/common/common-target.c + $(COMPILE) $(srcdir)/common/common-target.c + $(POSTCOMPILE) + vec.o: ${srcdir}/common/vec.c $(COMPILE) $(srcdir)/common/vec.c $(POSTCOMPILE) diff --git a/gdb/common/common-target.c b/gdb/common/common-target.c new file mode 100644 index 0000000..a24953e --- /dev/null +++ b/gdb/common/common-target.c @@ -0,0 +1,27 @@ +/* Utility target functions for GDB, and GDBserver. + + Copyright (C) 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "common-target.h" + diff --git a/gdb/common/common-target.h b/gdb/common/common-target.h new file mode 100644 index 0000000..f56cb72 --- /dev/null +++ b/gdb/common/common-target.h @@ -0,0 +1,24 @@ +/* Utility target functions for GDB, and GDBserver. + + Copyright (C) 2013 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/>. */ + +#ifndef COMMON_COMMON_TARGET_H +#define COMMON_COMMON_TARGET_H + +#endif /* COMMON_COMMON_TARGET_H */ + diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c new file mode 100644 index 0000000..efb0875 --- /dev/null +++ b/gdb/common/linux-maps.c @@ -0,0 +1,25 @@ +/* Linux-specific memory maps manipulation routines. + Copyright (C) 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "linux-maps.h" diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h new file mode 100644 index 0000000..da426e5 --- /dev/null +++ b/gdb/common/linux-maps.h @@ -0,0 +1,22 @@ +/* Linux-specific memory maps manipulation routines. + Copyright (C) 2013 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/>. */ + +#ifndef COMMON_LINUX_MAPS_H +#define COMMON_LINUX_MAPS_H + +#endif /* COMMON_LINUX_MAPS_H */ diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh index 7c64e83..e34f1dc 100644 --- a/gdb/config/i386/linux.mh +++ b/gdb/config/i386/linux.mh @@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o i386-linux-nat.o \ - proc-service.o linux-thread-db.o \ + proc-service.o linux-thread-db.o linux-maps.o \ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ linux-btrace.o NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh index 8d782c1..78ecf30 100644 --- a/gdb/config/i386/linux64.mh +++ b/gdb/config/i386/linux64.mh @@ -1,7 +1,7 @@ # Host: GNU/Linux x86-64 NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o amd64-nat.o amd64-linux-nat.o \ - linux-nat.o linux-osdata.o \ + linux-maps.o linux-nat.o linux-osdata.o \ proc-service.o linux-thread-db.o linux-fork.o \ linux-procfs.o linux-ptrace.o linux-btrace.o NAT_FILE= config/nm-linux.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 6c3d7bd..b08d401 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -167,7 +167,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o target.o \ utils.o version.o vec.o gdb_vecs.o \ mem-break.o hostio.o event-loop.o tracepoint.o \ - xml-utils.o common-utils.o ptid.o buffer.o format.o \ + xml-utils.o common-target.o common-utils.o ptid.o buffer.o format.o \ dll.o notif.o \ $(XML_BUILTIN) \ $(DEPFILES) $(LIBOBJS) @@ -510,12 +510,18 @@ ax.o: ax.c signals.o: ../common/signals.c $(COMPILE) $< $(POSTCOMPILE) +linux-maps.o: ../common/linux-maps.c + $(COMPILE) $< + $(POSTCOMPILE) linux-procfs.o: ../common/linux-procfs.c $(COMPILE) $< $(POSTCOMPILE) linux-ptrace.o: ../common/linux-ptrace.c $(COMPILE) $< $(POSTCOMPILE) +common-target.o: ../common/common-target.c + $(COMPILE) $< + $(POSTCOMPILE) common-utils.o: ../common/common-utils.c $(COMPILE) $< $(POSTCOMPILE) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 271a0fe..f3669d6 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -46,6 +46,7 @@ case "${target}" in srv_regobj="aarch64.o aarch64-without-fpu.o" srv_tgtobj="linux-aarch64-low.o" srv_tgtobj="${srv_tgtobj} linux-low.o" + srv_tgtobj="${srv_tgtobj} linux-maps.o" srv_tgtobj="${srv_tgtobj} linux-osdata.o" srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" @@ -61,7 +62,9 @@ case "${target}" in srv_regobj="${srv_regobj} arm-with-vfpv2.o" srv_regobj="${srv_regobj} arm-with-vfpv3.o" srv_regobj="${srv_regobj} arm-with-neon.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-arm-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="arm-with-iwmmxt.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml" @@ -84,19 +87,25 @@ case "${target}" in srv_mingwce=yes ;; bfin-*-*linux*) srv_regobj=reg-bfin.o - srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-bfin-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes ;; crisv32-*-linux*) srv_regobj=reg-crisv32.o - srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-crisv32-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes ;; cris-*-linux*) srv_regobj=reg-cris.o - srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-cris-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes @@ -111,7 +120,10 @@ case "${target}" in srv_regobj="$srv_regobj $srv_amd64_linux_regobj" srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles" fi - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-x86-low.o" + srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -147,12 +159,16 @@ case "${target}" in srv_qnx="yes" ;; ia64-*-linux*) srv_regobj=reg-ia64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-ia64-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes ;; m32r*-*-linux*) srv_regobj=reg-m32r.o - srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m32r-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes @@ -162,7 +178,9 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m68k-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -173,7 +191,9 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m68k-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -183,7 +203,10 @@ case "${target}" in srv_regobj="${srv_regobj} mips-dsp-linux.o" srv_regobj="${srv_regobj} mips64-linux.o" srv_regobj="${srv_regobj} mips64-dsp-linux.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o" + srv_tgtobj="${srv_tgtobj} linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-mips-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="mips-linux.xml" srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" @@ -216,7 +239,9 @@ case "${target}" in srv_regobj="${srv_regobj} powerpc-isa205-64l.o" srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o" srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-ppc-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="rs6000/powerpc-32l.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml" @@ -262,7 +287,9 @@ case "${target}" in srv_regobj="${srv_regobj} s390x-linux64.o" srv_regobj="${srv_regobj} s390x-linux64v1.o" srv_regobj="${srv_regobj} s390x-linux64v2.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-s390-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="s390-linux32.xml" srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml" @@ -283,14 +310,18 @@ case "${target}" in srv_linux_thread_db=yes ;; sh*-*-linux*) srv_regobj=reg-sh.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-sh-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes ;; sparc*-*-linux*) srv_regobj=reg-sparc64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-sparc-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes @@ -307,15 +338,20 @@ case "${target}" in srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml" - srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-tic6x-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_usrregs=yes srv_linux_thread_db=yes ;; x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj" - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-x86-low.o i386-low.o" + srv_tgtobj="${srv_tgtobj} i387-fp.o linux-procfs.o" + srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="${srv_tgtobj} linux-btrace.o" srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles" srv_linux_usrregs=yes # This is for i386 progs. srv_linux_regsets=yes @@ -334,13 +370,18 @@ case "${target}" in ;; xtensa*-*-linux*) srv_regobj=reg-xtensa.o - srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-xtensa-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes ;; tilegx-*-linux*) srv_regobj=reg-tilegx.o srv_regobj="${srv_regobj} reg-tilegx32.o" - srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o" + srv_tgtobj="${srv_tgtobj} linux-tile-low.o" + srv_tgtobj="${srv_tgtobj} linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] 2013-04-09 16:03 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski @ 2013-04-15 13:34 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 13:34 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:40 +0200, Aleksandar Ristovski wrote: > Most notable changes: addition of common-target.[ch] files, to > receive read_alloc and read_stralloc in patch #5. > > * Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h, > common/common-target.h. > (COMMON_OBS): Add common-target.o. > (linux-maps.o, common-target.o): New. > * common/common-target.c: New file. > * common/common-target.h: New file. > * common/linux-maps.c: New file. > * common/linux-maps.h: New file. > * config/i386/linux.mh (NATDEPFILES): Add linux-maps.o. > * config/i386/linux64.mh (NATDEPFILES): Ditto. > * gdbserver/Makefile.in (OBS): Add common-taret.o. > (linux-maps.o, common-target.o): New. > * gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o. Just be sure to put then these lines into gdb/gdbserver/ChangeLog (and not gdb/ChangeLog) and without the "gdbserver/" prefix. Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (2 preceding siblings ...) 2013-04-09 16:03 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski @ 2013-04-09 16:39 ` Aleksandar Ristovski 2013-04-15 13:36 ` Jan Kratochvil 2013-04-09 16:48 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski ` (5 subsequent siblings) 9 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 16:39 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * linux-tdep.c (linux_find_memory_region_ftype): Comment. (linux_find_memory_regions_full): Change signature and prepare for moving to linux-maps. (linux_find_memory_regions_data): Rename field 'obfd' to 'data'. (linux_find_memory_regions_thunk): New. (linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'. (linux_find_memory_regions_gdb): New. (linux_find_memory_regions): Rename argument 'obfd' to 'func_data'. (linux_make_mappings_corefile_notes): Use linux_find_memory_regions_gdb. * target.c (target_fileio_read_alloc_1_pread): New function. (read_alloc_pread_ftype): New typedef. (read_alloc): Refactor from target_fileio_read_alloc_1. (target_fileio_read_alloc_1): New implementation. Use read_alloc. (read_stralloc_func_ftype): New typedef. (read_stralloc): Refactored from target_fileio_read_stralloc. (target_fileio_read_stralloc): New implementation, use read_stralloc. --- gdb/linux-tdep.c | 98 ++++++++++++++++++++++++++++++++++++--------------- gdb/target.c | 102 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 58 deletions(-) diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 9def108..77c98d2 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args, error (_("unable to handle request")); } +/* Callback function for linux_find_memory_regions_full. If it returns + non-zero linux_find_memory_regions_full returns immediately with that + value. */ + typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, ULONGEST offset, ULONGEST inode, int read, int write, @@ -668,34 +672,41 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, const char *filename, void *data); -/* List memory regions in the inferior for a corefile. */ +/* List memory regions in the inferior PID for a corefile. Call FUNC + with FUNC_DATA for each such region. Return immediately with the + value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should + be registered to be freed automatically if called FUNC throws an + exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is + not used. Return -1 if error occurs, 0 if all memory regions have + been processed or return the value from FUNC if FUNC returns + non-zero. */ static int -linux_find_memory_regions_full (struct gdbarch *gdbarch, - linux_find_memory_region_ftype *func, - void *obfd) +linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr) { char mapsfilename[100]; - gdb_byte *data; - - /* We need to know the real target PID to access /proc. */ - if (current_inferior ()->fake_pid_p) - return 1; + char *data; - xsnprintf (mapsfilename, sizeof mapsfilename, - "/proc/%d/smaps", current_inferior ()->pid); + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); data = target_fileio_read_stralloc (mapsfilename); if (data == NULL) { /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, - "/proc/%d/maps", current_inferior ()->pid); + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", + (int) pid); data = target_fileio_read_stralloc (mapsfilename); } if (data) { - struct cleanup *cleanup = make_cleanup (xfree, data); char *line; + int retval = 0; + + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = data; + } line = strtok (data, "\n"); while (line) @@ -752,15 +763,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch, modified = 1; /* Invoke the callback function to create the corefile segment. */ - func (addr, endaddr - addr, offset, inode, - read, write, exec, modified, filename, obfd); + retval = func (addr, endaddr - addr, offset, inode, + read, write, exec, modified, filename, func_data); + if (retval != 0) + break; } - do_cleanups (cleanup); - return 0; + if (memory_to_free_ptr != NULL) + { + gdb_assert (data == *memory_to_free_ptr); + *memory_to_free_ptr = NULL; + } + xfree (data); + return retval; } - return 1; + return -1; } /* A structure for passing information through @@ -774,9 +792,11 @@ struct linux_find_memory_regions_data /* The original datum. */ - void *obfd; + void *data; }; +static linux_find_memory_region_ftype linux_find_memory_regions_thunk; + /* A callback for linux_find_memory_regions that converts between the "full"-style callback and find_memory_region_ftype. */ @@ -788,7 +808,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size, { struct linux_find_memory_regions_data *data = arg; - return data->func (vaddr, size, read, write, exec, modified, data->obfd); + return data->func (vaddr, size, read, write, exec, modified, data->data); +} + +/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */ + +static int +linux_find_memory_regions_gdb (struct gdbarch *gdbarch, + linux_find_memory_region_ftype *func, + void *func_data) +{ + void *memory_to_free = NULL; + struct cleanup *cleanup; + int retval; + + /* We need to know the real target PID so + linux_find_memory_regions_full can access /proc. */ + if (current_inferior ()->fake_pid_p) + return 1; + + cleanup = make_cleanup (free_current_contents, &memory_to_free); + retval = linux_find_memory_regions_full (current_inferior ()->pid, + func, func_data, &memory_to_free); + do_cleanups (cleanup); + return retval; } /* A variant of linux_find_memory_regions_full that is suitable as the @@ -796,16 +839,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size, static int linux_find_memory_regions (struct gdbarch *gdbarch, - find_memory_region_ftype func, void *obfd) + find_memory_region_ftype func, void *func_data) { struct linux_find_memory_regions_data data; data.func = func; - data.obfd = obfd; + data.data = func_data; - return linux_find_memory_regions_full (gdbarch, - linux_find_memory_regions_thunk, - &data); + return linux_find_memory_regions_gdb (gdbarch, + linux_find_memory_regions_thunk, &data); } /* Determine which signal stopped execution. */ @@ -987,8 +1029,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, pack_long (buf, long_type, 1); obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type)); - linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback, - &mapping_data); + linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback, + &mapping_data); if (mapping_data.file_count != 0) { diff --git a/gdb/target.c b/gdb/target.c index 8f8e46a..b5b5ee2 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -3476,55 +3476,67 @@ target_fileio_close_cleanup (void *opaque) target_fileio_close (fd, &target_errno); } +/* Helper for target_fileio_read_alloc_1 to make it interruptible. */ + +static int +target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno) +{ + QUIT; + + return target_fileio_pread (handle, read_buf, len, offset, target_errno); +} + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. PADDING additional bytes are available in *BUF_P. This is a helper function for target_fileio_read_alloc; see the declaration of that function for more information. */ +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno); + static LONGEST -target_fileio_read_alloc_1 (const char *filename, - gdb_byte **buf_p, int padding) +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, + int padding, void **memory_to_free_ptr) { - struct cleanup *close_cleanup; size_t buf_alloc, buf_pos; gdb_byte *buf; LONGEST n; - int fd; int target_errno; - fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); - if (fd == -1) - return -1; - - close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); - /* 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); + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = buf; + } buf_pos = 0; while (1) { - n = target_fileio_pread (fd, &buf[buf_pos], - buf_alloc - buf_pos - padding, buf_pos, - &target_errno); - if (n < 0) + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, + buf_pos, &target_errno); + if (n <= 0) { - /* An error occurred. */ - do_cleanups (close_cleanup); - xfree (buf); - return -1; - } - else if (n == 0) - { - /* Read all there was. */ - do_cleanups (close_cleanup); - if (buf_pos == 0) + if (n < 0 || (n == 0 && buf_pos == 0)) xfree (buf); else *buf_p = buf; - return buf_pos; + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = NULL; + if (n < 0) + { + /* An error occurred. */ + return -1; + } + else + { + /* Read all there was. */ + return buf_pos; + } } buf_pos += n; @@ -3534,12 +3546,34 @@ target_fileio_read_alloc_1 (const char *filename, { buf_alloc *= 2; buf = xrealloc (buf, buf_alloc); + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = buf; } - - QUIT; } } +static LONGEST +target_fileio_read_alloc_1 (const char *filename, + gdb_byte **buf_p, int padding) +{ + struct cleanup *close_cleanup; + int fd, target_errno; + void *memory_to_free = NULL; + LONGEST retval; + + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); + if (fd == -1) + return -1; + + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); + + make_cleanup (free_current_contents, &memory_to_free); + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding, + &memory_to_free); + do_cleanups (close_cleanup); + return retval; +} + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. See the declaration in "target.h" function for more information about the return value. */ @@ -3556,14 +3590,17 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) are returned as allocated but empty strings. A warning is issued if the result contains any embedded NUL bytes. */ -char * -target_fileio_read_stralloc (const char *filename) +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); + +static char * +read_stralloc (const char *filename, read_stralloc_func_ftype *func) { gdb_byte *buffer; char *bufstr; LONGEST i, transferred; - transferred = target_fileio_read_alloc_1 (filename, &buffer, 1); + transferred = func (filename, &buffer, 1); bufstr = (char *) buffer; if (transferred < 0) @@ -3587,6 +3624,11 @@ target_fileio_read_stralloc (const char *filename) return bufstr; } +char * +target_fileio_read_stralloc (const char *filename) +{ + return read_stralloc (filename, target_fileio_read_alloc_1); +} static int default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move 2013-04-09 16:39 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski @ 2013-04-15 13:36 ` Jan Kratochvil 2013-04-16 17:19 ` Aleksandar Ristovski 0 siblings, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 13:36 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:41 +0200, Aleksandar Ristovski wrote: [...] > --- a/gdb/target.c > +++ b/gdb/target.c > @@ -3476,55 +3476,67 @@ target_fileio_close_cleanup (void *opaque) > target_fileio_close (fd, &target_errno); > } > > +/* Helper for target_fileio_read_alloc_1 to make it interruptible. */ Here should be added (reason: so that one can easily find all the read_alloc_pread_ftype instances): static read_alloc_pread_ftype target_fileio_read_alloc_1_pread; (And move the read_alloc_pread_ftype definition above.) > + > +static int > +target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, > + ULONGEST offset, int *target_errno) > +{ > + QUIT; > + > + return target_fileio_pread (handle, read_buf, len, offset, target_errno); > +} > + > /* Read target file FILENAME. Store the result in *BUF_P and > return the size of the transferred data. PADDING additional bytes are > available in *BUF_P. This is a helper function for > target_fileio_read_alloc; see the declaration of that function for more > information. */ > > +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, > + ULONGEST offset, int *target_errno); Use tabs. > + > static LONGEST > -target_fileio_read_alloc_1 (const char *filename, > - gdb_byte **buf_p, int padding) > +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, > + int padding, void **memory_to_free_ptr) > { > - struct cleanup *close_cleanup; > size_t buf_alloc, buf_pos; > gdb_byte *buf; > LONGEST n; > - int fd; > int target_errno; > > - fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); > - if (fd == -1) > - return -1; > - > - close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); > - > /* 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); > + if (memory_to_free_ptr != NULL) > + { > + gdb_assert (*memory_to_free_ptr == NULL); > + *memory_to_free_ptr = buf; > + } > buf_pos = 0; > while (1) > { > - n = target_fileio_pread (fd, &buf[buf_pos], > - buf_alloc - buf_pos - padding, buf_pos, > - &target_errno); > - if (n < 0) > + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, > + buf_pos, &target_errno); > + if (n <= 0) > { > - /* An error occurred. */ > - do_cleanups (close_cleanup); > - xfree (buf); > - return -1; > - } > - else if (n == 0) > - { > - /* Read all there was. */ > - do_cleanups (close_cleanup); > - if (buf_pos == 0) > + if (n < 0 || (n == 0 && buf_pos == 0)) > xfree (buf); > else > *buf_p = buf; > - return buf_pos; > + if (memory_to_free_ptr != NULL) > + *memory_to_free_ptr = NULL; > + if (n < 0) > + { > + /* An error occurred. */ > + return -1; > + } > + else > + { > + /* Read all there was. */ > + return buf_pos; > + } > } > > buf_pos += n; > @@ -3534,12 +3546,34 @@ target_fileio_read_alloc_1 (const char *filename, > { > buf_alloc *= 2; > buf = xrealloc (buf, buf_alloc); > + if (memory_to_free_ptr != NULL) > + *memory_to_free_ptr = buf; > } > - > - QUIT; > } > } > Here could be (so that one can easily find all the read_stralloc_func_ftype instances): static read_stralloc_func_ftype target_fileio_read_alloc_1; (And move the read_stralloc_func_ftype definition above.) > +static LONGEST > +target_fileio_read_alloc_1 (const char *filename, > + gdb_byte **buf_p, int padding) > +{ > + struct cleanup *close_cleanup; > + int fd, target_errno; > + void *memory_to_free = NULL; > + LONGEST retval; > + > + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); > + if (fd == -1) > + return -1; > + > + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); > + > + make_cleanup (free_current_contents, &memory_to_free); > + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding, > + &memory_to_free); > + do_cleanups (close_cleanup); > + return retval; > +} > + > /* Read target file FILENAME. Store the result in *BUF_P and return > the size of the transferred data. See the declaration in "target.h" > function for more information about the return value. */ [...] Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move 2013-04-15 13:36 ` Jan Kratochvil @ 2013-04-16 17:19 ` Aleksandar Ristovski 0 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 17:19 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-14 10:15 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:41 +0200, Aleksandar Ristovski wrote: > [...] >> --- a/gdb/target.c >> +++ b/gdb/target.c >> @@ -3476,55 +3476,67 @@ target_fileio_close_cleanup (void *opaque) >> target_fileio_close (fd, &target_errno); >> } >> >> +/* Helper for target_fileio_read_alloc_1 to make it interruptible. */ > > Here should be added (reason: so that one can easily find all the > read_alloc_pread_ftype instances): > > static read_alloc_pread_ftype target_fileio_read_alloc_1_pread; > > (And move the read_alloc_pread_ftype definition above.) Ok. >> +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, >> + ULONGEST offset, int *target_errno); > > Use tabs. Ok. > > ... > > > Here could be (so that one can easily find all the read_stralloc_func_ftype > instances): > > static read_stralloc_func_ftype target_fileio_read_alloc_1; > > (And move the read_stralloc_func_ftype definition above.) Ok. Thanks, Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 5/8] Move linux_find_memory_regions_full & co. 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (3 preceding siblings ...) 2013-04-09 16:39 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski @ 2013-04-09 16:48 ` Aleksandar Ristovski 2013-04-15 13:52 ` Jan Kratochvil 2013-04-09 16:55 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski ` (4 subsequent siblings) 9 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 16:48 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Most notable change: read_alloc and read_stralloc are moved to new common-target.[ch] files. * common/common-target.c (gdb_assert.h, gdb_string.h): Include. (read_alloc, read_stralloc): Move definitions from target.c. * common/common-target.h (read_alloc_pread_ftype): New typedef. (read_alloc): New declaration. (read_stralloc_func_ftype): New typedef. (read_stralloc): New declaration. * common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h, ctype.h, string.h, common-target.h): Include. (read_mapping): Move from linux-tdep.c. (linux_find_memory_read_stralloc_1_pread): New function. (linux_find_memory_read_stralloc_1): New function. (linux_find_memory_read_stralloc): New function. * common/linux-maps.h (read_mapping): New declaration. (linux_find_memory_region_ftype): Moved typedef from linux-tdep.c. (linux_find_memory_regions_full): New declaration. * linux-tdep.c (linux-maps.h): Include. (read_mapping): Moved to common/linux-maps.c. (linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h. (linux_find_memory_regions_full): Moved definition to common/linux-maps.c. * target.c (common-target.h): Include. (read_alloc_pread_ftype): Moved typedef to common/common-target.h. (read_alloc, read_stralloc): Moved definitions to common/common-target.c. --- gdb/common/common-target.c | 89 +++++++++++++++++++++ gdb/common/common-target.h | 11 +++ gdb/common/linux-maps.c | 187 ++++++++++++++++++++++++++++++++++++++++++++ gdb/common/linux-maps.h | 25 ++++++ gdb/linux-tdep.c | 159 +------------------------------------ gdb/target.c | 94 +--------------------- 6 files changed, 314 insertions(+), 251 deletions(-) diff --git a/gdb/common/common-target.c b/gdb/common/common-target.c index a24953e..d0b3138 100644 --- a/gdb/common/common-target.c +++ b/gdb/common/common-target.c @@ -24,4 +24,93 @@ #endif #include "common-target.h" +#include "gdb_assert.h" +#include "gdb_string.h" + +LONGEST +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, + int padding, void **memory_to_free_ptr) +{ + size_t buf_alloc, buf_pos; + gdb_byte *buf; + LONGEST n; + int target_errno; + + /* 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); + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = buf; + } + buf_pos = 0; + while (1) + { + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, + buf_pos, &target_errno); + if (n <= 0) + { + if (n < 0 || (n == 0 && buf_pos == 0)) + xfree (buf); + else + *buf_p = buf; + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = NULL; + if (n < 0) + { + /* An error occurred. */ + return -1; + } + else + { + /* Read all there was. */ + 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); + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = buf; + } + } +} + +char * +read_stralloc (const char *filename, read_stralloc_func_ftype *func) +{ + gdb_byte *buffer; + char *bufstr; + LONGEST i, transferred; + + transferred = func (filename, &buffer, 1); + bufstr = (char *) buffer; + + if (transferred < 0) + return NULL; + + if (transferred == 0) + return xstrdup (""); + + bufstr[transferred] = 0; + + /* Check for embedded NUL bytes; but allow trailing NULs. */ + for (i = strlen (bufstr); i < transferred; i++) + if (bufstr[i] != 0) + { + warning (_("target file %s " + "contained unexpected null characters"), + filename); + break; + } + + return bufstr; +} diff --git a/gdb/common/common-target.h b/gdb/common/common-target.h index f56cb72..21f21ef 100644 --- a/gdb/common/common-target.h +++ b/gdb/common/common-target.h @@ -20,5 +20,16 @@ #ifndef COMMON_COMMON_TARGET_H #define COMMON_COMMON_TARGET_H +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno); +extern LONGEST read_alloc (gdb_byte **buf_p, int handle, + read_alloc_pread_ftype *pread_func, int padding, + void **memory_to_free_ptr); + +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); +extern char *read_stralloc (const char *filename, + read_stralloc_func_ftype *func); + #endif /* COMMON_COMMON_TARGET_H */ diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c index efb0875..3fcd316 100644 --- a/gdb/common/linux-maps.c +++ b/gdb/common/linux-maps.c @@ -18,8 +18,195 @@ #ifdef GDBSERVER #include "server.h" +#include <fcntl.h> +#include <unistd.h> #else #include "defs.h" +#include "target.h" #endif #include "linux-maps.h" +#include "gdb_assert.h" +#include <ctype.h> +#include <string.h> +#include "common-target.h" + +/* Service function for corefiles and info proc. */ + +void +read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename) +{ + const char *p = line; + + *addr = strtoulst (p, &p, 16); + if (*p == '-') + p++; + *endaddr = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *permissions = p; + while (*p && !isspace (*p)) + p++; + *permissions_len = p - *permissions; + + *offset = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *device = p; + while (*p && !isspace (*p)) + p++; + *device_len = p - *device; + + *inode = strtoulst (p, &p, 10); + + p = skip_spaces_const (p); + *filename = p; +} + +#ifdef GDBSERVER + +static int +linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf, + int len, ULONGEST offset, + int *target_errno) +{ + int retval = pread (handle, read_buf, len, offset); + + *target_errno = errno; + return retval; +} + +static LONGEST +linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p, + int padding) +{ + int fd; + LONGEST retval; + + fd = open (filename, O_RDONLY); + if (fd == -1) + return -1; + + retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread, + padding, NULL); + + close (fd); + + return retval; +} + +#endif /* GDBSERVER */ + +static char * +linux_find_memory_read_stralloc (const char *filename) +{ +#ifndef GDBSERVER + return target_fileio_read_stralloc (filename); +#else /* GDBSERVER */ + return read_stralloc (filename, linux_find_memory_read_stralloc_1); +#endif /* GDBSERVER */ +} + +/* List memory regions in the inferior PID for a corefile. Call FUNC + with FUNC_DATA for each such region. Return immediately with the + value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should + be registered to be freed automatically if called FUNC throws an + exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is + not used. Return -1 if error occurs, 0 if all memory regions have + been processed or return the value from FUNC if FUNC returns + non-zero. */ + +int +linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr) +{ + char filename[100]; + char *data; + + xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid); + data = linux_find_memory_read_stralloc (filename); + if (data == NULL) + { + /* Older Linux kernels did not support /proc/PID/smaps. */ + xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid); + data = linux_find_memory_read_stralloc (filename); + } + if (data) + { + char *line; + int retval = 0; + + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = data; + } + + line = strtok (data, "\n"); + while (line) + { + ULONGEST addr, endaddr, offset, inode; + const char *permissions, *device, *filename; + size_t permissions_len, device_len; + int read, write, exec; + int modified = 0, has_anonymous = 0; + + read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, + &offset, &device, &device_len, &inode, &filename); + + /* Decode permissions. */ + read = (memchr (permissions, 'r', permissions_len) != 0); + write = (memchr (permissions, 'w', permissions_len) != 0); + exec = (memchr (permissions, 'x', permissions_len) != 0); + + /* Try to detect if region was modified by parsing smaps counters. */ + for (line = strtok (NULL, "\n"); + line && line[0] >= 'A' && line[0] <= 'Z'; + line = strtok (NULL, "\n")) + { + char keyword[64 + 1]; + unsigned long number; + + if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2) + { + warning (_("Error parsing {s,}maps file '%s'"), filename); + break; + } + if (strcmp (keyword, "Anonymous:") == 0) + has_anonymous = 1; + if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0)) + modified = 1; + } + + /* Older Linux kernels did not support the "Anonymous:" counter. + If it is missing, we can't be sure - dump all the pages. */ + if (!has_anonymous) + modified = 1; + + /* Invoke the callback function to create the corefile segment. */ + retval = func (addr, endaddr - addr, offset, inode, + read, write, exec, modified, filename, func_data); + if (retval != 0) + break; + } + + if (memory_to_free_ptr != NULL) + { + gdb_assert (data == *memory_to_free_ptr); + *memory_to_free_ptr = NULL; + } + xfree (data); + return retval; + } + + return -1; +} diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h index da426e5..e989376 100644 --- a/gdb/common/linux-maps.h +++ b/gdb/common/linux-maps.h @@ -19,4 +19,29 @@ #ifndef COMMON_LINUX_MAPS_H #define COMMON_LINUX_MAPS_H +extern void + read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename); + +/* Callback function for linux_find_memory_regions_full. If it returns + non-zero linux_find_memory_regions_full returns immediately with that + value. */ + +typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, + ULONGEST offset, ULONGEST inode, + int read, int write, + int exec, int modified, + const char *filename, + void *data); + +extern int + linux_find_memory_regions_full (pid_t pid, + linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr); + #endif /* COMMON_LINUX_MAPS_H */ diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 77c98d2..4544e5f 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -33,6 +33,7 @@ #include "arch-utils.h" #include "gdb_obstack.h" #include "cli/cli-utils.h" +#include "linux-maps.h" #include <ctype.h> @@ -207,44 +208,6 @@ linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) return normal_pid_to_str (ptid); } -/* Service function for corefiles and info proc. */ - -static void -read_mapping (const char *line, - ULONGEST *addr, ULONGEST *endaddr, - const char **permissions, size_t *permissions_len, - ULONGEST *offset, - const char **device, size_t *device_len, - ULONGEST *inode, - const char **filename) -{ - const char *p = line; - - *addr = strtoulst (p, &p, 16); - if (*p == '-') - p++; - *endaddr = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *permissions = p; - while (*p && !isspace (*p)) - p++; - *permissions_len = p - *permissions; - - *offset = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *device = p; - while (*p && !isspace (*p)) - p++; - *device_len = p - *device; - - *inode = strtoulst (p, &p, 10); - - p = skip_spaces_const (p); - *filename = p; -} - /* Implement the "info proc" command. */ static void @@ -661,126 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args, error (_("unable to handle request")); } -/* Callback function for linux_find_memory_regions_full. If it returns - non-zero linux_find_memory_regions_full returns immediately with that - value. */ - -typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, - ULONGEST offset, ULONGEST inode, - int read, int write, - int exec, int modified, - const char *filename, - void *data); - -/* List memory regions in the inferior PID for a corefile. Call FUNC - with FUNC_DATA for each such region. Return immediately with the - value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should - be registered to be freed automatically if called FUNC throws an - exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is - not used. Return -1 if error occurs, 0 if all memory regions have - been processed or return the value from FUNC if FUNC returns - non-zero. */ - -static int -linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, - void *func_data, void **memory_to_free_ptr) -{ - char mapsfilename[100]; - char *data; - - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - if (data == NULL) - { - /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", - (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - } - if (data) - { - char *line; - int retval = 0; - - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = data; - } - - line = strtok (data, "\n"); - while (line) - { - ULONGEST addr, endaddr, offset, inode; - const char *permissions, *device, *filename; - size_t permissions_len, device_len; - int read, write, exec; - int modified = 0, has_anonymous = 0; - - read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, - &offset, &device, &device_len, &inode, &filename); - - /* Decode permissions. */ - read = (memchr (permissions, 'r', permissions_len) != 0); - write = (memchr (permissions, 'w', permissions_len) != 0); - exec = (memchr (permissions, 'x', permissions_len) != 0); - - /* Try to detect if region was modified by parsing smaps counters. */ - for (line = strtok (NULL, "\n"); - line && line[0] >= 'A' && line[0] <= 'Z'; - line = strtok (NULL, "\n")) - { - char keyword[64 + 1]; - - if (sscanf (line, "%64s", keyword) != 1) - { - warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); - break; - } - if (strcmp (keyword, "Anonymous:") == 0) - has_anonymous = 1; - if (strcmp (keyword, "Shared_Dirty:") == 0 - || strcmp (keyword, "Private_Dirty:") == 0 - || strcmp (keyword, "Swap:") == 0 - || strcmp (keyword, "Anonymous:") == 0) - { - unsigned long number; - - if (sscanf (line, "%*s%lu", &number) != 1) - { - warning (_("Error parsing {s,}maps file '%s' number"), - mapsfilename); - break; - } - if (number != 0) - modified = 1; - } - } - - /* Older Linux kernels did not support the "Anonymous:" counter. - If it is missing, we can't be sure - dump all the pages. */ - if (!has_anonymous) - modified = 1; - - /* Invoke the callback function to create the corefile segment. */ - retval = func (addr, endaddr - addr, offset, inode, - read, write, exec, modified, filename, func_data); - if (retval != 0) - break; - } - - if (memory_to_free_ptr != NULL) - { - gdb_assert (data == *memory_to_free_ptr); - *memory_to_free_ptr = NULL; - } - xfree (data); - return retval; - } - - return -1; -} - /* A structure for passing information through linux_find_memory_regions_full. */ diff --git a/gdb/target.c b/gdb/target.c index b5b5ee2..1a7e091 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -43,6 +43,7 @@ #include "tracepoint.h" #include "gdb/fileio.h" #include "agent.h" +#include "common-target.h" static void target_info (char *, int); @@ -3493,65 +3494,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, target_fileio_read_alloc; see the declaration of that function for more information. */ -typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, - ULONGEST offset, int *target_errno); - -static LONGEST -read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, - int padding, void **memory_to_free_ptr) -{ - size_t buf_alloc, buf_pos; - gdb_byte *buf; - LONGEST n; - int target_errno; - - /* 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); - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = buf; - } - buf_pos = 0; - while (1) - { - n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, - buf_pos, &target_errno); - if (n <= 0) - { - if (n < 0 || (n == 0 && buf_pos == 0)) - xfree (buf); - else - *buf_p = buf; - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = NULL; - if (n < 0) - { - /* An error occurred. */ - return -1; - } - else - { - /* Read all there was. */ - 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); - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = buf; - } - } -} - static LONGEST target_fileio_read_alloc_1 (const char *filename, gdb_byte **buf_p, int padding) @@ -3590,40 +3532,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) are returned as allocated but empty strings. A warning is issued if the result contains any embedded NUL bytes. */ -typedef LONGEST (read_stralloc_func_ftype) (const char *filename, - gdb_byte **buf_p, int padding); - -static char * -read_stralloc (const char *filename, read_stralloc_func_ftype *func) -{ - gdb_byte *buffer; - char *bufstr; - LONGEST i, transferred; - - transferred = func (filename, &buffer, 1); - bufstr = (char *) buffer; - - if (transferred < 0) - return NULL; - - if (transferred == 0) - return xstrdup (""); - - bufstr[transferred] = 0; - - /* Check for embedded NUL bytes; but allow trailing NULs. */ - for (i = strlen (bufstr); i < transferred; i++) - if (bufstr[i] != 0) - { - warning (_("target file %s " - "contained unexpected null characters"), - filename); - break; - } - - return bufstr; -} - char * target_fileio_read_stralloc (const char *filename) { -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 5/8] Move linux_find_memory_regions_full & co. 2013-04-09 16:48 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski @ 2013-04-15 13:52 ` Jan Kratochvil 2013-04-16 15:46 ` Aleksandar Ristovski 0 siblings, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 13:52 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:42 +0200, Aleksandar Ristovski wrote: > > Most notable change: read_alloc and read_stralloc are moved to new > common-target.[ch] files. This is not a move, it removes - and therefore regresses - this change: commit d8c11845465f076c6ae8078d2e8fb7c1d31f1181 Fix compatibility with Linux kernel 3.8.3. commit 01a16f9b83c29db2c63106bbefeb505cbac17bd4 Fix variable name shadowing. When you git merge gdb/master you got a conflict on linux-tdep.c. Therefore you have to apply the non-applicable trunk change of linux-tdep.c to the new file common/linux-maps.c instead. You apparently had to drop the linux-tdep.c conflict without updating common/linux-maps.c. Regards, Jan This is the regression this patch introduced: --- m 2013-04-12 21:26:21.953472657 +0200 +++ p 2013-04-14 08:00:04.284665296 +0200 @@ -56,21 +56,20 @@ typedef int linux_find_memory_region_fty been processed or return the value from FUNC if FUNC returns non-zero. */ -static int +int linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, void *func_data, void **memory_to_free_ptr) { - char mapsfilename[100]; + char filename[100]; char *data; - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); - data = target_fileio_read_stralloc (mapsfilename); + xsnprintf (filename, sizeof filename, "/proc/%d/smaps", (int) pid); + data = linux_find_memory_read_stralloc (filename); if (data == NULL) { /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", - (int) pid); - data = target_fileio_read_stralloc (mapsfilename); + xsnprintf (filename, sizeof filename, "/proc/%d/maps", (int) pid); + data = linux_find_memory_read_stralloc (filename); } if (data) { @@ -106,30 +105,20 @@ linux_find_memory_regions_full (pid_t pi line = strtok (NULL, "\n")) { char keyword[64 + 1]; + unsigned long number; - if (sscanf (line, "%64s", keyword) != 1) + if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2) { - warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); + warning (_("Error parsing {s,}maps file '%s'"), filename); break; } if (strcmp (keyword, "Anonymous:") == 0) has_anonymous = 1; - if (strcmp (keyword, "Shared_Dirty:") == 0 - || strcmp (keyword, "Private_Dirty:") == 0 - || strcmp (keyword, "Swap:") == 0 - || strcmp (keyword, "Anonymous:") == 0) - { - unsigned long number; - - if (sscanf (line, "%*s%lu", &number) != 1) - { - warning (_("Error parsing {s,}maps file '%s' number"), - mapsfilename); - break; - } - if (number != 0) - modified = 1; - } + if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0)) + modified = 1; } /* Older Linux kernels did not support the "Anonymous:" counter. ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 5/8] Move linux_find_memory_regions_full & co. 2013-04-15 13:52 ` Jan Kratochvil @ 2013-04-16 15:46 ` Aleksandar Ristovski 0 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 15:46 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-14 10:16 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:42 +0200, Aleksandar Ristovski wrote: >> >> Most notable change: read_alloc and read_stralloc are moved to new >> common-target.[ch] files. > > This is not a move, it removes - and therefore regresses - this change: > > commit d8c11845465f076c6ae8078d2e8fb7c1d31f1181 > Fix compatibility with Linux kernel 3.8.3. > commit 01a16f9b83c29db2c63106bbefeb505cbac17bd4 > Fix variable name shadowing. > > When you git merge gdb/master you got a conflict on linux-tdep.c. Therefore > you have to apply the non-applicable trunk change of linux-tdep.c to the new > file common/linux-maps.c instead. You apparently had to drop the linux-tdep.c > conflict without updating common/linux-maps.c. Sorry about that. Wrong merge. I'm not sure if I messed it up or automerge did it, but it's fixed now. --- Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 6/8] gdbserver build-id attribute generator 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (4 preceding siblings ...) 2013-04-09 16:48 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski @ 2013-04-09 16:55 ` Aleksandar Ristovski 2013-04-09 18:52 ` Eli Zaretskii 2013-04-15 14:23 ` Jan Kratochvil 2013-04-09 17:37 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski ` (3 subsequent siblings) 9 siblings, 2 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 16:55 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Notable changes: removed predicated find_phdr_p and changed find_phdr to look for a given p_type. * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add 'build-id' in description, example, new attribute in dtd. * features/library-list-svr4.dtd (library-list-svr4): New 'build-id' attribute. * linux-low.c (linux-maps.h, search.h): Include. (ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New. (ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New. (find_phdr): New. (get_dynamic): Use find_pdhr to traverse program headers. (struct mapping_entry): New structure. (mapping_entry_s): New typedef, new vector type def. (free_mapping_entry, compare_mapping_entry, compare_mapping_entry_range, compare_mapping_entry_inode): New. (struct find_memory_region_callback_data): New. (find_memory_region_callback): New fwd. declaration. (read_build_id, find_memory_region_callback, get_hex_build_id): New. (linux_qxfer_libraries_svr4): Add optional build-id attribute to reply XML document. --- gdb/doc/gdb.texinfo | 17 +- gdb/features/library-list-svr4.dtd | 13 +- gdb/gdbserver/linux-low.c | 373 +++++++++++++++++++++++++++++++++--- 3 files changed, 366 insertions(+), 37 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index bf7e25e..2920f63 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40359,6 +40359,8 @@ memory address. It is a displacement of absolute memory address against address the file was prelinked to during the library load. @item @code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment +@item +@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if it exists. @end itemize Additionally the single @code{main-lm} attribute specifies address of @@ -40376,7 +40378,7 @@ looks like this: <library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000" l_ld="0xe4eefc"/> <library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000" - l_ld="0x152350"/> + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> </library-list-svr> @end smallexample @@ -40385,13 +40387,14 @@ The format of an SVR4 library list is described by this DTD: @smallexample <!-- library-list-svr4: Root element with versioning --> <!ELEMENT library-list-svr4 (library)*> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> <!ELEMENT library EMPTY> -<!ATTLIST library name CDATA #REQUIRED> -<!ATTLIST library lm CDATA #REQUIRED> -<!ATTLIST library l_addr CDATA #REQUIRED> -<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library name CDATA #REQUIRED> +<!ATTLIST library lm CDATA #REQUIRED> +<!ATTLIST library l_addr CDATA #REQUIRED> +<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library build-id CDATA #IMPLIED> @end smallexample @node Memory Map Format diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd index cae7fd8..fdd6ec0 100644 --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -6,11 +6,12 @@ <!-- library-list-svr4: Root element with versioning --> <!ELEMENT library-list-svr4 (library)*> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> <!ELEMENT library EMPTY> -<!ATTLIST library name CDATA #REQUIRED> -<!ATTLIST library lm CDATA #REQUIRED> -<!ATTLIST library l_addr CDATA #REQUIRED> -<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library name CDATA #REQUIRED> +<!ATTLIST library lm CDATA #REQUIRED> +<!ATTLIST library l_addr CDATA #REQUIRED> +<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library build-id CDATA #IMPLIED> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 72c51e0..d819b21 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -20,6 +20,7 @@ #include "linux-low.h" #include "linux-osdata.h" #include "agent.h" +#include "linux-maps.h" #include "gdb_wait.h" #include <stdio.h> @@ -43,6 +44,7 @@ #include "gdb_stat.h" #include <sys/vfs.h> #include <sys/uio.h> +#include <search.h> #ifndef ELFMAG0 /* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h then ELFMAG0 will have been defined. If it didn't get included by @@ -118,6 +120,33 @@ typedef struct } Elf64_auxv_t; #endif +typedef union ElfXX_Ehdr +{ + Elf32_Ehdr _32; + Elf64_Ehdr _64; +} ElfXX_Ehdr; + +typedef union ElfXX_Phdr +{ + Elf32_Phdr _32; + Elf64_Phdr _64; +} ElfXX_Phdr; + +typedef union ElfXX_Nhdr +{ + Elf32_Nhdr _32; + Elf64_Nhdr _64; +} ElfXX_Nhdr; + +#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld) +#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \ + : sizeof ((hdr)._32)) +#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \ + & ~(sizeof (Elf64_Word) - 1)) \ + : (((what) + sizeof (Elf32_Word) - 1) \ + & ~(sizeof (Elf32_Word) - 1))) +#define BUILD_ID_INVALID "?" + /* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol representation of the thread ID. @@ -5432,15 +5461,43 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, return 0; } +/* Linearly traverse pheaders given in PHDR until supplied + predicate function returns 1. If supplied predicate function + did return 1, stop traversal and return that PHDR. */ + +static const void * +find_phdr (const int is_elf64, const void *const phdr_begin, + const void *const phdr_end, const ULONGEST p_type) +{ +#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \ + ELFXX_SIZEOF (*hdrp))) + + const ElfXX_Phdr *phdr = phdr_begin; + + if (phdr == NULL) + return NULL; + + while (PHDR_NEXT (phdr) <= phdr_end) + { + if (ELFXX_FLD (*phdr, p_type) == p_type) + return phdr; + phdr = PHDR_NEXT (phdr); + } + + return NULL; +#undef PHDR_NEXT +} + /* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ static CORE_ADDR get_dynamic (const int pid, const int is_elf64) { CORE_ADDR phdr_memaddr, relocation; - int num_phdr, i; + int num_phdr; unsigned char *phdr_buf; const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + const void *phdr; if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) return 0; @@ -5454,21 +5511,23 @@ get_dynamic (const int pid, const int is_elf64) /* Compute relocation: it is expected to be 0 for "regular" executables, non-zero for PIE ones. */ relocation = -1; - for (i = 0; relocation == -1 && i < num_phdr; i++) - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + PT_PHDR); + if (phdr != NULL) + { + if (is_elf64) + { + const Elf64_Phdr *const p = phdr; - if (p->p_type == PT_PHDR) relocation = phdr_memaddr - p->p_vaddr; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + } + else + { + const Elf32_Phdr *const p = phdr; - if (p->p_type == PT_PHDR) relocation = phdr_memaddr - p->p_vaddr; - } + } + } if (relocation == -1) { @@ -5485,21 +5544,22 @@ get_dynamic (const int pid, const int is_elf64) return 0; } - for (i = 0; i < num_phdr; i++) + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + PT_DYNAMIC); + + if (phdr != NULL) { if (is_elf64) { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + const Elf64_Phdr *const p = phdr; - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; + return p->p_vaddr + relocation; } else { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + const Elf32_Phdr *const p = phdr; - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; + return p->p_vaddr + relocation; } } @@ -5641,6 +5701,253 @@ struct link_map_offsets int l_prev_offset; }; + +/* Structure for holding a mapping. Only mapping + containing l_ld can have hex_build_id set. */ + +struct mapping_entry +{ + /* Fields are populated from linux_find_memory_region parameters. */ + + ULONGEST vaddr; + ULONGEST size; + ULONGEST offset; + ULONGEST inode; + + /* Hex encoded string allocated using xmalloc, and + needs to be freed. It can be NULL. */ + + char *hex_build_id; +}; + +typedef struct mapping_entry mapping_entry_s; + +DEF_VEC_O(mapping_entry_s); + +static void +free_mapping_entry (VEC (mapping_entry_s) *lst) +{ + int ix; + mapping_entry_s *p; + + for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix) + xfree (p->hex_build_id); + + VEC_free (mapping_entry_s, lst); +} + +/* Used for finding a mapping containing the given + l_ld passed in K. */ + +static int +compare_mapping_entry_range (const void *const k, const void *const b) +{ + const ULONGEST key = *(CORE_ADDR*) k; + const mapping_entry_s *const p = b; + + if (key < p->vaddr) + return -1; + + if (key < p->vaddr + p->size) + return 0; + + return 1; +} + +struct find_memory_region_callback_data +{ + unsigned is_elf64; + + /* Return. Ordered list of all object mappings sorted in + ascending order by VADDR. Must be freed with free_mapping_entry. */ + VEC (mapping_entry_s) *list; +}; + +static linux_find_memory_region_ftype find_memory_region_callback; + +/* Read build-id from PT_NOTE. */ + +static void +read_build_id (struct find_memory_region_callback_data *const p, + mapping_entry_s *const bil, const CORE_ADDR load_addr, + const CORE_ADDR l_addr) +{ + const int is_elf64 = p->is_elf64; + ElfXX_Ehdr ehdr; + + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, + ELFXX_SIZEOF (ehdr)) == 0 + && ELFXX_FLD (ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && ELFXX_FLD (ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && ELFXX_FLD (ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && ELFXX_FLD (ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + const ElfXX_Phdr *phdr; + void *phdr_buf; + const unsigned e_phentsize = ELFXX_FLD (ehdr, e_phentsize); + + gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */ + gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr)); + phdr_buf = alloca (ELFXX_FLD (ehdr, e_phnum) * e_phentsize); + + if (linux_read_memory (load_addr + ELFXX_FLD (ehdr, e_phoff), phdr_buf, + ELFXX_FLD (ehdr, e_phnum) * e_phentsize) != 0) + { + warning ("Could not read program header."); + return; + } + + phdr = phdr_buf; + + for (;;) + { + gdb_byte *pt_note; + const gdb_byte *pt_end; + const ElfXX_Nhdr *nhdr; + + phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf + + ELFXX_FLD (ehdr, e_phnum) * e_phentsize, + PT_NOTE); + if (phdr == NULL) + break; + pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz)); + pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz); + + if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note, + ELFXX_FLD (*phdr, p_memsz)) != 0) + { + xfree (pt_note); + warning ("Could not read note."); + break; + } + + nhdr = (void *) pt_note; + while ((void *) nhdr < (void *) pt_end) + { + const size_t namesz + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz)); + const size_t descsz + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz)); + const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz; + + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 + || descsz == 0) + { + warning ("Malformed PT_NOTE\n"); + break; + } + if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID + && ELFXX_FLD (*nhdr, n_namesz) == 4) + { + const char gnu[4] = "GNU\0"; + const char *const pname + = (char *) nhdr + ELFXX_SIZEOF (*nhdr); + + if (memcmp (pname, gnu, 4) == 0) + { + const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz); + + bil->hex_build_id = xmalloc (n_descsz * 2 + 1); + bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id, + n_descsz); + xfree (pt_note); + return; + } + } + nhdr = (void*) ((gdb_byte *) nhdr + note_sz); + } + xfree (pt_note); + } + } +} + +/* Add mapping_entry. */ + +static int +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset, + ULONGEST inode, int read, int write, int exec, + int modified, const char *filename, void *data) +{ + if (inode != 0) + { + struct find_memory_region_callback_data *const p = data; + mapping_entry_s bil; + + bil.vaddr = vaddr; + bil.size = size; + bil.offset = offset; + bil.inode = inode; + bil.hex_build_id = NULL; + + VEC_safe_push (mapping_entry_s, p->list, &bil); + } + + /* Continue the traversal. */ + return 0; +} + +/* Linear reverse find starting from RBEGIN towards REND looking for + the lowest vaddr mapping of the same inode and zero offset. */ + +static mapping_entry_s * +lrfind_mapping_entry (mapping_entry_s *const rbegin, + const mapping_entry_s *const rend) +{ + mapping_entry_s *p; + + for (p = rbegin - 1; p >= rend; --p) + if (p->offset == 0 && p->inode == rbegin->inode) + return p; + + return NULL; +} + +/* Get build-id for the given L_LD. DATA must point to + already filled list of mapping_entry elements. + + Return build_id as stored in the list element corresponding + to L_LD. + + NULL may be returned if build-id could not be fetched. + + Returned string must not be freed explicitly. */ + +static const char * +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, + struct find_memory_region_callback_data *const data) +{ + mapping_entry_s *bil; + + if (VEC_address (mapping_entry_s, data->list) == NULL) + return NULL; + + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list), + VEC_length (mapping_entry_s, data->list), + sizeof (mapping_entry_s), compare_mapping_entry_range); + + if (bil == NULL) + return NULL; + + if (bil->hex_build_id == NULL) + { + mapping_entry_s *bil_min; + + bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s, + data->list)); + if (bil_min != NULL) + read_build_id (data, bil, bil_min->vaddr, l_addr); + else + { + /* Do not try to find hex_build_id again. */ + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); + warning ("Could not determine load address; " + "build-id can not be used."); + } + } + + return bil->hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5653,6 +5960,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, struct process_info_private *const priv = current_process ()->private; char filename[PATH_MAX]; int pid, is_elf64; + struct find_memory_region_callback_data data; static const struct link_map_offsets lmo_32bit_offsets = { @@ -5688,6 +5996,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, is_elf64 = elf_64_file_p (filename, &machine); lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + data.is_elf64 = is_elf64; + data.list = NULL; + VEC_reserve (mapping_entry_s, data.list, 16); + if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data, + NULL) < 0) + warning ("Finding memory regions failed"); + if (priv->r_debug == 0) priv->r_debug = get_r_debug (pid, is_elf64); @@ -5762,6 +6077,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, /* 6x the size for xml_escape_text below. */ size_t len = 6 * strlen ((char *) libname); char *name; + const char *hex_enc_build_id = NULL; if (!header_done) { @@ -5770,21 +6086,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, header_done = 1; } - while (allocated < p - document + len + 200) + name = xml_escape_text ((char *) libname); + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data); + + while (allocated < (p - document + len + 200 + + (hex_enc_build_id != NULL + ? strlen (hex_enc_build_id) : 0))) { /* Expand to guarantee sufficient storage. */ - uintptr_t document_len = p - document; + const ptrdiff_t document_len = p - document; - document = xrealloc (document, 2 * allocated); allocated *= 2; + document = xrealloc (document, allocated); p = document + document_len; } - name = xml_escape_text ((char *) libname); p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" " - "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>", + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"", name, (unsigned long) lm_addr, (unsigned long) l_addr, (unsigned long) l_ld); + if (hex_enc_build_id != NULL + && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0) + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); + p += sprintf(p, "/>"); free (name); } else if (lm_prev == 0) @@ -5819,6 +6143,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, memcpy (readbuf, document + offset, len); xfree (document); + free_mapping_entry (data.list); return len; } -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 6/8] gdbserver build-id attribute generator 2013-04-09 16:55 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski @ 2013-04-09 18:52 ` Eli Zaretskii 2013-04-15 14:23 ` Jan Kratochvil 1 sibling, 0 replies; 42+ messages in thread From: Eli Zaretskii @ 2013-04-09 18:52 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches, jan.kratochvil, ARistovski > From: Aleksandar Ristovski <ARistovski@qnx.com> > CC: <jan.kratochvil@redhat.com>, Aleksandar Ristovski <ARistovski@qnx.com> > Date: Tue, 9 Apr 2013 11:27:43 -0400 > > Notable changes: removed predicated find_phdr_p and changed find_phdr > to look for a given p_type. > > * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add > 'build-id' in description, example, new attribute in dtd. > * features/library-list-svr4.dtd (library-list-svr4): New > 'build-id' attribute. The documentation parts are OK. Thanks. ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 6/8] gdbserver build-id attribute generator 2013-04-09 16:55 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski 2013-04-09 18:52 ` Eli Zaretskii @ 2013-04-15 14:23 ` Jan Kratochvil 2013-04-16 16:40 ` Aleksandar Ristovski 1 sibling, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 14:23 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:43 +0200, Aleksandar Ristovski wrote: [...] > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c [...] > @@ -118,6 +120,33 @@ typedef struct > } Elf64_auxv_t; > #endif > > +typedef union ElfXX_Ehdr > +{ > + Elf32_Ehdr _32; > + Elf64_Ehdr _64; > +} ElfXX_Ehdr; > + > +typedef union ElfXX_Phdr > +{ > + Elf32_Phdr _32; > + Elf64_Phdr _64; > +} ElfXX_Phdr; > + > +typedef union ElfXX_Nhdr > +{ > + Elf32_Nhdr _32; > + Elf64_Nhdr _64; > +} ElfXX_Nhdr; > + > +#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld) > +#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \ > + : sizeof ((hdr)._32)) Macros should not depend on external variables, that makes them tricky, it was acceptable when the variable was present in the scope where the macro was defined. But that is no longer true when the macro is global. is_elf64 should be a parameter of each of these macros. > +#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \ > + & ~(sizeof (Elf64_Word) - 1)) \ > + : (((what) + sizeof (Elf32_Word) - 1) \ > + & ~(sizeof (Elf32_Word) - 1))) This is overcomplicated. The ELF standard defines it as "4-byte alignment". While both sizeof (Elf64_Word) == 4 and sizeof (Elf32_Word) == 4 I find that incorrect, the standard talks about 4 bytes (for both elf32 and elf64), not about sizeof of anything. > +#define BUILD_ID_INVALID "?" > + > /* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol > representation of the thread ID. > > @@ -5432,15 +5461,43 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, > return 0; > } > > +/* Linearly traverse pheaders given in PHDR until supplied > + predicate function returns 1. If supplied predicate function > + did return 1, stop traversal and return that PHDR. */ There is no predicate function anymore. > + > +static const void * > +find_phdr (const int is_elf64, const void *const phdr_begin, > + const void *const phdr_end, const ULONGEST p_type) > +{ > +#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \ > + ELFXX_SIZEOF (*hdrp))) > + > + const ElfXX_Phdr *phdr = phdr_begin; > + > + if (phdr == NULL) > + return NULL; I do not see a reason for this check, callers never pass it NULL. It should be rather gdb_assert in such case if anything. > + > + while (PHDR_NEXT (phdr) <= phdr_end) > + { > + if (ELFXX_FLD (*phdr, p_type) == p_type) > + return phdr; > + phdr = PHDR_NEXT (phdr); > + } > + > + return NULL; > +#undef PHDR_NEXT > +} > + > /* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ > > static CORE_ADDR > get_dynamic (const int pid, const int is_elf64) > { > CORE_ADDR phdr_memaddr, relocation; > - int num_phdr, i; > + int num_phdr; > unsigned char *phdr_buf; > const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); > + const void *phdr; > > if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) > return 0; > @@ -5454,21 +5511,23 @@ get_dynamic (const int pid, const int is_elf64) > /* Compute relocation: it is expected to be 0 for "regular" executables, > non-zero for PIE ones. */ > relocation = -1; > - for (i = 0; relocation == -1 && i < num_phdr; i++) > - if (is_elf64) > - { > - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); > + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, > + PT_PHDR); > + if (phdr != NULL) > + { > + if (is_elf64) > + { > + const Elf64_Phdr *const p = phdr; When the 32-vs-64 ELF framework is provided here I expected this existing code could be simplified on top of it. Provided such patch at the end of this mail. > > - if (p->p_type == PT_PHDR) > relocation = phdr_memaddr - p->p_vaddr; > - } > - else > - { > - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); > + } > + else > + { > + const Elf32_Phdr *const p = phdr; > > - if (p->p_type == PT_PHDR) > relocation = phdr_memaddr - p->p_vaddr; > - } > + } > + } > > if (relocation == -1) > { > @@ -5485,21 +5544,22 @@ get_dynamic (const int pid, const int is_elf64) > return 0; > } > > - for (i = 0; i < num_phdr; i++) > + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, > + PT_DYNAMIC); > + > + if (phdr != NULL) > { > if (is_elf64) > { > - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); > + const Elf64_Phdr *const p = phdr; > > - if (p->p_type == PT_DYNAMIC) > - return p->p_vaddr + relocation; > + return p->p_vaddr + relocation; > } > else > { > - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); > + const Elf32_Phdr *const p = phdr; > > - if (p->p_type == PT_DYNAMIC) > - return p->p_vaddr + relocation; > + return p->p_vaddr + relocation; > } > } > > @@ -5641,6 +5701,253 @@ struct link_map_offsets > int l_prev_offset; > }; > > + > +/* Structure for holding a mapping. Only mapping > + containing l_ld can have hex_build_id set. */ > + > +struct mapping_entry > +{ > + /* Fields are populated from linux_find_memory_region parameters. */ > + > + ULONGEST vaddr; > + ULONGEST size; > + ULONGEST offset; > + ULONGEST inode; > + > + /* Hex encoded string allocated using xmalloc, and > + needs to be freed. It can be NULL. */ > + > + char *hex_build_id; > +}; > + > +typedef struct mapping_entry mapping_entry_s; > + > +DEF_VEC_O(mapping_entry_s); > + > +static void > +free_mapping_entry (VEC (mapping_entry_s) *lst) It does not free mapping_entry. It frees the vector of them. Therefore it should be name for example free_mapping_entry_vec. And the function is missing comment. > +{ > + int ix; > + mapping_entry_s *p; > + > + for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix) > + xfree (p->hex_build_id); > + > + VEC_free (mapping_entry_s, lst); > +} > + > +/* Used for finding a mapping containing the given > + l_ld passed in K. */ > + > +static int > +compare_mapping_entry_range (const void *const k, const void *const b) > +{ > + const ULONGEST key = *(CORE_ADDR*) k; GNU Coding Standards: const ULONGEST key = *(CORE_ADDR *) k; And when it is all const it should not be temporarily de-const-ed: const ULONGEST key = *(const CORE_ADDR *) k; > + const mapping_entry_s *const p = b; > + > + if (key < p->vaddr) > + return -1; > + > + if (key < p->vaddr + p->size) > + return 0; > + > + return 1; > +} > + > +struct find_memory_region_callback_data > +{ > + unsigned is_elf64; > + > + /* Return. Ordered list of all object mappings sorted in > + ascending order by VADDR. Must be freed with free_mapping_entry. */ free_mapping_entry name should be updated after the rename above. > + VEC (mapping_entry_s) *list; > +}; > + > +static linux_find_memory_region_ftype find_memory_region_callback; Why is it here? It should be before the find_memory_region_callback definition. > + > +/* Read build-id from PT_NOTE. */ Describe function parameters. It is essential to see the LOAD_ADDR vs. L_ADDR difference. > + > +static void > +read_build_id (struct find_memory_region_callback_data *const p, > + mapping_entry_s *const bil, const CORE_ADDR load_addr, > + const CORE_ADDR l_addr) > +{ > + const int is_elf64 = p->is_elf64; > + ElfXX_Ehdr ehdr; > + > + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, > + ELFXX_SIZEOF (ehdr)) == 0 > + && ELFXX_FLD (ehdr, e_ident[EI_MAG0]) == ELFMAG0 > + && ELFXX_FLD (ehdr, e_ident[EI_MAG1]) == ELFMAG1 > + && ELFXX_FLD (ehdr, e_ident[EI_MAG2]) == ELFMAG2 > + && ELFXX_FLD (ehdr, e_ident[EI_MAG3]) == ELFMAG3) > + { > + const ElfXX_Phdr *phdr; > + void *phdr_buf; > + const unsigned e_phentsize = ELFXX_FLD (ehdr, e_phentsize); > + > + gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */ I am aware a similar gdb_assert is in get_dynamic but that is a bug. gdbserver should not crash on weird inferior data. There should be a warning + return. Also comments should be on their own line: /* Basic sanity check. */ gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); > + gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr)); Likewise. > + phdr_buf = alloca (ELFXX_FLD (ehdr, e_phnum) * e_phentsize); > + > + if (linux_read_memory (load_addr + ELFXX_FLD (ehdr, e_phoff), phdr_buf, > + ELFXX_FLD (ehdr, e_phnum) * e_phentsize) != 0) > + { > + warning ("Could not read program header."); > + return; > + } > + > + phdr = phdr_buf; > + > + for (;;) > + { > + gdb_byte *pt_note; > + const gdb_byte *pt_end; > + const ElfXX_Nhdr *nhdr; > + > + phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf > + + ELFXX_FLD (ehdr, e_phnum) * e_phentsize, > + PT_NOTE); > + if (phdr == NULL) > + break; > + pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz)); > + pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz); GNU Coding Standards: pt_end = (gdb_byte *) pt_note + ELFXX_FLD (*phdr, p_memsz); But pt_note is already gdb_byte * so that cast is useless, therefore: pt_end = pt_note + ELFXX_FLD (*phdr, p_memsz); > + > + if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note, > + ELFXX_FLD (*phdr, p_memsz)) != 0) > + { > + xfree (pt_note); > + warning ("Could not read note."); Print also the note address when there is a warning at all. > + break; > + } > + > + nhdr = (void *) pt_note; > + while ((void *) nhdr < (void *) pt_end) When it is all const there should be (const void *). But in fact it is easier to use const gdb_byte * when pt_end is already such type: while ((const gdb_byte *) nhdr < pt_end) > + { > + const size_t namesz > + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz)); > + const size_t descsz > + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz)); > + const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz; > + > + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 It should be (const gdb_byte *) because nhdr is already const *. > + || descsz == 0) > + { > + warning ("Malformed PT_NOTE\n"); Print also the note address when there is a warning at all. > + break; > + } > + if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID > + && ELFXX_FLD (*nhdr, n_namesz) == 4) > + { > + const char gnu[4] = "GNU\0"; > + const char *const pname > + = (char *) nhdr + ELFXX_SIZEOF (*nhdr); It should be (const char *) because nhdr is already const *. > + > + if (memcmp (pname, gnu, 4) == 0) > + { > + const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz); > + > + bil->hex_build_id = xmalloc (n_descsz * 2 + 1); > + bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id, It should be (const gdb_byte *) because pname is already const *. Additionally according to the GNU Coding Standards spacing it should be: bin2hex ((const gdb_byte *) pname + namesz, bil->hex_build_id, > + n_descsz); > + xfree (pt_note); > + return; > + } > + } > + nhdr = (void*) ((gdb_byte *) nhdr + note_sz); > + } > + xfree (pt_note); > + } > + } > +} > + > +/* Add mapping_entry. */ When the line static linux_find_memory_region_ftype find_memory_region_callback; will be here the parameters would be described. But still one could write: /* Add mapping_entry. See linux_find_memory_region_ftype for the parameters description. */ > + > +static int > +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset, > + ULONGEST inode, int read, int write, int exec, > + int modified, const char *filename, void *data) > +{ > + if (inode != 0) > + { > + struct find_memory_region_callback_data *const p = data; > + mapping_entry_s bil; > + > + bil.vaddr = vaddr; > + bil.size = size; > + bil.offset = offset; > + bil.inode = inode; > + bil.hex_build_id = NULL; > + > + VEC_safe_push (mapping_entry_s, p->list, &bil); > + } > + > + /* Continue the traversal. */ > + return 0; > +} > + > +/* Linear reverse find starting from RBEGIN towards REND looking for > + the lowest vaddr mapping of the same inode and zero offset. */ > + > +static mapping_entry_s * > +lrfind_mapping_entry (mapping_entry_s *const rbegin, > + const mapping_entry_s *const rend) > +{ > + mapping_entry_s *p; > + > + for (p = rbegin - 1; p >= rend; --p) > + if (p->offset == 0 && p->inode == rbegin->inode) > + return p; > + > + return NULL; > +} > + > +/* Get build-id for the given L_LD. DATA must point to Maybe one could describe more what is "L_LD". L_LD is the link_map.l_ld field from libc shared library list. And that L_ADDR parameter is also: L_ADDR is the link_map.l_addr field from libc shared library list. > + already filled list of mapping_entry elements. > + > + Return build_id as stored in the list element corresponding > + to L_LD. > + > + NULL may be returned if build-id could not be fetched. > + > + Returned string must not be freed explicitly. */ > + > +static const char * > +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, > + struct find_memory_region_callback_data *const data) > +{ > + mapping_entry_s *bil; > + > + if (VEC_address (mapping_entry_s, data->list) == NULL) > + return NULL; I do not think this check should be / needs to be here. bsearch with NMEMB == 0 should return NULL. > + > + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list), > + VEC_length (mapping_entry_s, data->list), > + sizeof (mapping_entry_s), compare_mapping_entry_range); > + > + if (bil == NULL) > + return NULL; > + > + if (bil->hex_build_id == NULL) > + { > + mapping_entry_s *bil_min; > + > + bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s, > + data->list)); > + if (bil_min != NULL) > + read_build_id (data, bil, bil_min->vaddr, l_addr); > + else > + { > + /* Do not try to find hex_build_id again. */ > + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); > + warning ("Could not determine load address; " > + "build-id can not be used."); You should print some identification for troubleshooting when the warning is there at all, probably L_LD here is the best one. > + } > + } > + > + return bil->hex_build_id; > +} > + > /* Construct qXfer:libraries-svr4:read reply. */ > > static int > @@ -5653,6 +5960,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > struct process_info_private *const priv = current_process ()->private; > char filename[PATH_MAX]; > int pid, is_elf64; > + struct find_memory_region_callback_data data; > > static const struct link_map_offsets lmo_32bit_offsets = > { > @@ -5688,6 +5996,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > is_elf64 = elf_64_file_p (filename, &machine); > lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; > > + data.is_elf64 = is_elf64; > + data.list = NULL; > + VEC_reserve (mapping_entry_s, data.list, 16); > + if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data, > + NULL) < 0) > + warning ("Finding memory regions failed"); > + > if (priv->r_debug == 0) > priv->r_debug = get_r_debug (pid, is_elf64); > > @@ -5762,6 +6077,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > /* 6x the size for xml_escape_text below. */ > size_t len = 6 * strlen ((char *) libname); > char *name; > + const char *hex_enc_build_id = NULL; > > if (!header_done) > { > @@ -5770,21 +6086,29 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > header_done = 1; > } > > - while (allocated < p - document + len + 200) > + name = xml_escape_text ((char *) libname); > + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data); > + > + while (allocated < (p - document + len + 200 > + + (hex_enc_build_id != NULL > + ? strlen (hex_enc_build_id) : 0))) > { > /* Expand to guarantee sufficient storage. */ > - uintptr_t document_len = p - document; > + const ptrdiff_t document_len = p - document; > > - document = xrealloc (document, 2 * allocated); > allocated *= 2; > + document = xrealloc (document, allocated); > p = document + document_len; > } This "code cleanup" change is unrelated to this patch. But it is IMO not worth checking in separately, it does not improve it anyhow IMO. > > - name = xml_escape_text ((char *) libname); Why did you move this line to several lines above? It is a needless change. > p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" " > - "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>", > + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"", > name, (unsigned long) lm_addr, > (unsigned long) l_addr, (unsigned long) l_ld); > + if (hex_enc_build_id != NULL > + && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0) > + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); > + p += sprintf(p, "/>"); GNU Coding Standards: p += sprintf (p, "/>"); > free (name); > } > else if (lm_prev == 0) > @@ -5819,6 +6143,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, > > memcpy (readbuf, document + offset, len); > xfree (document); > + free_mapping_entry (data.list); > > return len; > } > -- > 1.7.10.4 Thanks, Jan diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index d819b21..cf5be8c 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -5465,7 +5465,7 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, predicate function returns 1. If supplied predicate function did return 1, stop traversal and return that PHDR. */ -static const void * +static const ElfXX_Phdr * find_phdr (const int is_elf64, const void *const phdr_begin, const void *const phdr_end, const ULONGEST p_type) { @@ -5496,8 +5496,8 @@ get_dynamic (const int pid, const int is_elf64) CORE_ADDR phdr_memaddr, relocation; int num_phdr; unsigned char *phdr_buf; - const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); - const void *phdr; + const ElfXX_Phdr *phdr; + const int phdr_size = ELFXX_SIZEOF (*phdr); if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) return 0; @@ -5510,26 +5510,9 @@ get_dynamic (const int pid, const int is_elf64) /* Compute relocation: it is expected to be 0 for "regular" executables, non-zero for PIE ones. */ - relocation = -1; phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, PT_PHDR); - if (phdr != NULL) - { - if (is_elf64) - { - const Elf64_Phdr *const p = phdr; - - relocation = phdr_memaddr - p->p_vaddr; - } - else - { - const Elf32_Phdr *const p = phdr; - - relocation = phdr_memaddr - p->p_vaddr; - } - } - - if (relocation == -1) + if (phdr == NULL) { /* PT_PHDR is optional, but necessary for PIE in general. Fortunately any real world executables, including PIE executables, have always @@ -5543,27 +5526,13 @@ get_dynamic (const int pid, const int is_elf64) return 0; } + relocation = phdr_memaddr - ELFXX_FLD (*phdr, p_vaddr); phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, PT_DYNAMIC); - - if (phdr != NULL) - { - if (is_elf64) - { - const Elf64_Phdr *const p = phdr; - - return p->p_vaddr + relocation; - } - else - { - const Elf32_Phdr *const p = phdr; - - return p->p_vaddr + relocation; - } - } - - return 0; + if (phdr == NULL) + return 0; + return ELFXX_FLD (*phdr, p_vaddr) + relocation; } /* Return &_r_debug in the inferior, or -1 if not present. Return value ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 6/8] gdbserver build-id attribute generator 2013-04-15 14:23 ` Jan Kratochvil @ 2013-04-16 16:40 ` Aleksandar Ristovski 2013-04-18 10:08 ` Jan Kratochvil 0 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 16:40 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-14 10:16 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:43 +0200, Aleksandar Ristovski wrote: > [...] >> + >> +#define ELFXX_FLD(hdr, fld) ((is_elf64) ? (hdr)._64.fld : (hdr)._32.fld) >> +#define ELFXX_SIZEOF(hdr) ((is_elf64) ? sizeof ((hdr)._64) \ >> + : sizeof ((hdr)._32)) > > Macros should not depend on external variables, that makes them tricky, it was > acceptable when the variable was present in the scope where the macro was > defined. But that is no longer true when the macro is global. > > is_elf64 should be a parameter of each of these macros. > Ok. > >> +#define ELFXX_ROUNDUP(what) ((is_elf64) ? (((what) + sizeof (Elf64_Word) - 1) \ >> + & ~(sizeof (Elf64_Word) - 1)) \ >> + : (((what) + sizeof (Elf32_Word) - 1) \ >> + & ~(sizeof (Elf32_Word) - 1))) > > This is overcomplicated. The ELF standard defines it as "4-byte alignment". > While both sizeof (Elf64_Word) == 4 and sizeof (Elf32_Word) == 4 I find that > incorrect, the standard talks about 4 bytes (for both elf32 and elf64), not > about sizeof of anything. Ok. I re-read it and indeed it says 4 bytes, and not how I mis-remembered, word boundary. > > ... >> >> +/* Linearly traverse pheaders given in PHDR until supplied >> + predicate function returns 1. If supplied predicate function >> + did return 1, stop traversal and return that PHDR. */ > > There is no predicate function anymore. Ok. > > >> + >> ... > >> + if (phdr == NULL) >> + return NULL; > > I do not see a reason for this check, callers never pass it NULL. It should > be rather gdb_assert in such case if anything. Ok. removed. > > ... >> + { >> + if (is_elf64) >> + { >> + const Elf64_Phdr *const p = phdr; > > When the 32-vs-64 ELF framework is provided here I expected this existing code > could be simplified on top of it. Provided such patch at the end of this > mail. Yes, indeed. Incorporated. > > ... >> +static void >> +free_mapping_entry (VEC (mapping_entry_s) *lst) > > It does not free mapping_entry. It frees the vector of them. Therefore it > should be name for example free_mapping_entry_vec. And the function is > missing comment. I consider this nitpicking - argument type does convey this very clearly. But added _vec as per your suggestion. > > ... >> + const ULONGEST key = *(CORE_ADDR*) k; > > GNU Coding Standards: > const ULONGEST key = *(CORE_ADDR *) k; > And when it is all const it should not be temporarily de-const-ed: > const ULONGEST key = *(const CORE_ADDR *) k; > Ok. ... >> + VEC (mapping_entry_s) *list; >> +}; >> + >> +static linux_find_memory_region_ftype find_memory_region_callback; > > Why is it here? It should be before the find_memory_region_callback > definition. > Ok. > >> + >> +/* Read build-id from PT_NOTE. */ > > Describe function parameters. It is essential to see the LOAD_ADDR vs. L_ADDR > difference. Ok. > > ... >> + gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); /* Basic sanity check. */ > > I am aware a similar gdb_assert is in get_dynamic but that is a bug. > gdbserver should not crash on weird inferior data. > There should be a warning + return. > > Also comments should be on their own line: > /* Basic sanity check. */ > gdb_assert (ELFXX_FLD (ehdr, e_phnum) < 100); > > >> + gdb_assert (e_phentsize == ELFXX_SIZEOF (*phdr)); > > Likewise. Ok, replaced with a check + warning. > > ... >> + pt_note = xmalloc (ELFXX_FLD (*phdr, p_memsz)); >> + pt_end = (gdb_byte*) pt_note + ELFXX_FLD (*phdr, p_memsz); > > GNU Coding Standards: > pt_end = (gdb_byte *) pt_note + ELFXX_FLD (*phdr, p_memsz); > But pt_note is already gdb_byte * so that cast is useless, therefore: > pt_end = pt_note + ELFXX_FLD (*phdr, p_memsz); > Ok. > >> + >> + if (linux_read_memory (ELFXX_FLD (*phdr, p_vaddr) + l_addr, pt_note, >> + ELFXX_FLD (*phdr, p_memsz)) != 0) >> + { >> + xfree (pt_note); >> + warning ("Could not read note."); > > Print also the note address when there is a warning at all. Ok. > > >> + break; >> + } >> + >> + nhdr = (void *) pt_note; >> + while ((void *) nhdr < (void *) pt_end) > > When it is all const there should be (const void *). But in fact it is easier > to use const gdb_byte * when pt_end is already such type: > while ((const gdb_byte *) nhdr < pt_end) gdb_byte * is o.k., but there is no really a need for const - when casting is for the purpose of pointer comparison, IMO const only clutters the reading. > > >> + { >> + const size_t namesz >> + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz)); >> + const size_t descsz >> + = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz)); >> + const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz; >> + >> + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 > > It should be (const gdb_byte *) because nhdr is already const *. I like using const, as you may have noticed, unless it only clutters, like is the case when casting is used for the purpose of pointer comparison like here. > > >> + || descsz == 0) >> + { >> + warning ("Malformed PT_NOTE\n"); > > Print also the note address when there is a warning at all. Ok. > > >> + break; >> + } >> + if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID >> + && ELFXX_FLD (*nhdr, n_namesz) == 4) >> + { >> + const char gnu[4] = "GNU\0"; >> + const char *const pname >> + = (char *) nhdr + ELFXX_SIZEOF (*nhdr); > > It should be (const char *) because nhdr is already const *. When assigning to const, then const in the cast for pointer arithmetic does not matter and IMO only clutters. > > >> + >> + if (memcmp (pname, gnu, 4) == 0) >> + { >> + const size_t n_descsz = ELFXX_FLD (*nhdr, n_descsz); >> + >> + bil->hex_build_id = xmalloc (n_descsz * 2 + 1); >> + bin2hex ((gdb_byte*) pname + namesz, bil->hex_build_id, > > It should be (const gdb_byte *) because pname is already const *. Ok. > > Additionally according to the GNU Coding Standards spacing it should be: > bin2hex ((const gdb_byte *) pname + namesz, bil->hex_build_id, > > >> + n_descsz); >> + xfree (pt_note); >> + return; >> + } >> + } >> + nhdr = (void*) ((gdb_byte *) nhdr + note_sz); >> + } >> + xfree (pt_note); >> + } >> + } >> +} >> + >> +/* Add mapping_entry. */ > > When the line > static linux_find_memory_region_ftype find_memory_region_callback; > will be here the parameters would be described. But still one could write: > /* Add mapping_entry. See linux_find_memory_region_ftype for the > parameters description. */ Ok. > > ... >> + >> +/* Get build-id for the given L_LD. DATA must point to > > Maybe one could describe more what is "L_LD". > L_LD is the link_map.l_ld field from libc shared library list. > > And that L_ADDR parameter is also: > L_ADDR is the link_map.l_addr field from libc shared library list. > Ok. > >> + already filled list of mapping_entry elements. >> + >> + Return build_id as stored in the list element corresponding >> + to L_LD. >> + >> + NULL may be returned if build-id could not be fetched. >> + >> + Returned string must not be freed explicitly. */ >> + >> +static const char * >> +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, >> + struct find_memory_region_callback_data *const data) >> +{ >> + mapping_entry_s *bil; >> + >> + if (VEC_address (mapping_entry_s, data->list) == NULL) >> + return NULL; > > I do not think this check should be / needs to be here. bsearch with NMEMB == > 0 should return NULL. You are probably right. Removed. > > ... >> + { >> + /* Do not try to find hex_build_id again. */ >> + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); >> + warning ("Could not determine load address; " >> + "build-id can not be used."); > > You should print some identification for troubleshooting when the warning is > there at all, probably L_LD here is the best one. Ok. > > ... >> + } >> { >> /* Expand to guarantee sufficient storage. */ >> - uintptr_t document_len = p - document; >> + const ptrdiff_t document_len = p - document; >> >> - document = xrealloc (document, 2 * allocated); >> allocated *= 2; >> + document = xrealloc (document, allocated); >> p = document + document_len; >> } > > This "code cleanup" change is unrelated to this patch. But it is IMO not > worth checking in separately, it does not improve it anyhow IMO. It uses correct type for pointer difference and does not repeat arithmetic. I removed it, it will probably reduce clash with Gary's patch. > > >> >> - name = xml_escape_text ((char *) libname); > > Why did you move this line to several lines above? It is a needless change. Ok. > > >> p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" " >> - "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>", >> + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"", >> name, (unsigned long) lm_addr, >> (unsigned long) l_addr, (unsigned long) l_ld); >> + if (hex_enc_build_id != NULL >> + && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0) >> + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); > >> + p += sprintf(p, "/>"); > > GNU Coding Standards: > p += sprintf (p, "/>"); > Ok. --- Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 6/8] gdbserver build-id attribute generator 2013-04-16 16:40 ` Aleksandar Ristovski @ 2013-04-18 10:08 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 10:08 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:14:47 +0200, Aleksandar Ristovski wrote: > On 13-04-14 10:16 AM, Jan Kratochvil wrote: > >On Tue, 09 Apr 2013 17:27:43 +0200, Aleksandar Ristovski wrote: > >>+ break; > >>+ } > >>+ > >>+ nhdr = (void *) pt_note; > >>+ while ((void *) nhdr < (void *) pt_end) > > > >When it is all const there should be (const void *). But in fact it is easier > >to use const gdb_byte * when pt_end is already such type: > > while ((const gdb_byte *) nhdr < pt_end) > > gdb_byte * is o.k., but there is no really a need for const - when > casting is for the purpose of pointer comparison, IMO const only > clutters the reading. As stated also elsewhere in this review one of the review purposes is to keep the GDB (and GNU) coding unified (when not explicitly defined by GNU Coding Standards). GDB was not formerly using const at all, it is moving now towards to const-correct typing. AFAIK const is never used for values in GDB, only for targets. Too many const attributes are a problem for GNU Coding Standards compliant code as the narrow 80 columns formatting then needs multi-line statements which are difficult to read. But when I agreed even with const values when you are used to it please do not break the const-correctness afterwards. I do not see what is a purpose of all the const attributes when in the end there are free de-const-ing casts. > >>+ { > >>+ const size_t namesz > >>+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_namesz)); > >>+ const size_t descsz > >>+ = ELFXX_ROUNDUP (ELFXX_FLD (*nhdr, n_descsz)); > >>+ const size_t note_sz = ELFXX_SIZEOF (*nhdr) + namesz + descsz; > >>+ > >>+ if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 > > > >It should be (const gdb_byte *) because nhdr is already const *. > > I like using const, as you may have noticed, unless it only > clutters, like is the case when casting is used for the purpose of > pointer comparison like here. It really does not matter what you like, it matters what is the current GDB coding practice. And when a pointer is const type * I find a bug to cast it to non-const type *. What if the caller really pointed it to a read-only segment. non-const type * is at least confusing in such case. > >>+ break; > >>+ } > >>+ if (ELFXX_FLD (*nhdr, n_type) == NT_GNU_BUILD_ID > >>+ && ELFXX_FLD (*nhdr, n_namesz) == 4) > >>+ { > >>+ const char gnu[4] = "GNU\0"; > >>+ const char *const pname > >>+ = (char *) nhdr + ELFXX_SIZEOF (*nhdr); > > > >It should be (const char *) because nhdr is already const *. > > When assigning to const, then const in the cast for pointer > arithmetic does not matter and IMO only clutters. const * cast to non-const * cast is a bug. When there is even no agreement on how to use const it is better to keep the GDB standards and not to use too many const keywords. > >>+ } > >> { > >> /* Expand to guarantee sufficient storage. */ > >>- uintptr_t document_len = p - document; > >>+ const ptrdiff_t document_len = p - document; > >> > >>- document = xrealloc (document, 2 * allocated); > >> allocated *= 2; > >>+ document = xrealloc (document, allocated); > >> p = document + document_len; > >> } > > > >This "code cleanup" change is unrelated to this patch. But it is IMO not > >worth checking in separately, it does not improve it anyhow IMO. > > It uses correct type for pointer difference and does not repeat > arithmetic. I removed it, it will probably reduce clash with Gary's > patch. You are right ptrdiff_t is more correct there but this 64-bit correctness is unreal to be ever violated. GDB has more serious 64-bit sizes violations... Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (5 preceding siblings ...) 2013-04-09 16:55 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski @ 2013-04-09 17:37 ` Aleksandar Ristovski 2013-04-15 15:12 ` Jan Kratochvil 2013-04-09 17:50 ` [PATCH 7/8] Validate " Aleksandar Ristovski ` (2 subsequent siblings) 9 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 17:37 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Notable changes: Changed regexp to expect Yes/No and ${solibfile} on a single line only. * gdb.base/solib-mismatch-lib.c: New file. * gdb.base/solib-mismatch-libmod.c: New file. * gdb.base/solib-mismatch.c: New file. * gdb.base/solib-mismatch.exp: New file. --- gdb/testsuite/gdb.base/solib-mismatch-lib.c | 29 +++++ gdb/testsuite/gdb.base/solib-mismatch-libmod.c | 29 +++++ gdb/testsuite/gdb.base/solib-mismatch.c | 68 +++++++++++ gdb/testsuite/gdb.base/solib-mismatch.exp | 144 ++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-lib.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-libmod.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.exp diff --git a/gdb/testsuite/gdb.base/solib-mismatch-lib.c b/gdb/testsuite/gdb.base/solib-mismatch-lib.c new file mode 100644 index 0000000..19f1545 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch-lib.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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/>. */ + + +int _bar = 42; + +int bar(void) +{ + return _bar + 21; +} + +int foo(void) +{ + return _bar; +} diff --git a/gdb/testsuite/gdb.base/solib-mismatch-libmod.c b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c new file mode 100644 index 0000000..3b025a8 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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/>. */ + + +int _bar = 21; + +int bar(void) +{ + return 42 - _bar; +} + +int foo(void) +{ + return 24 + bar(); +} diff --git a/gdb/testsuite/gdb.base/solib-mismatch.c b/gdb/testsuite/gdb.base/solib-mismatch.c new file mode 100644 index 0000000..8a7f58f --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch.c @@ -0,0 +1,68 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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 <dlfcn.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> + +/* The following defines must correspond to solib-mismatch.exp */ + +#define DIRNAME "solib-mismatch_wd" +#define LIB "./solib-mismatch.so" + +int main(int argc, char *argv[]) +{ + void *h; + int (*foo)(void); + char buff[1024]; + char *p; + + p = strstr (argv[0], DIRNAME); + + if (p == NULL) + { + printf ("ERROR - %s could not be found in argv[0]\n", DIRNAME); + return 1; + } + + p += strlen (DIRNAME); + + memcpy (buff, argv[0], p - argv[0]); + + buff[p - argv[0]] = '\0'; + + if (chdir (buff) != 0) + { + printf ("ERROR - Could not cd to %s\n", buff); + return 1; + } + + h = dlopen(LIB, RTLD_NOW); + + if (h == NULL) + { + printf ("ERROR - could not open lib %s\n", LIB); + return 1; + } + foo = dlsym(h, "foo"); /* set breakpoint 1 here */ + dlclose(h); + return 0; +} + diff --git a/gdb/testsuite/gdb.base/solib-mismatch.exp b/gdb/testsuite/gdb.base/solib-mismatch.exp new file mode 100644 index 0000000..6d30632 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch.exp @@ -0,0 +1,144 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# 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/>. */ + +standard_testfile +set executable $testfile + +# Test overview: +# generate two shared objects. One that will be used by the process +# and another, modified, that will be found by gdb. Gdb should +# detect the mismatch and refuse to use mismatched shared object. + +if { [get_compiler_info] } { + untested "get_compiler_info failed." +} + +# First version of the object, to be loaded by ld +set srclibfilerun ${testfile}-lib.c + +# Modified version of the object to be loaded by gdb +# Code in -libmod.c is tuned so it gives a mismatch but +# leaves .dynamic at the same point. +set srclibfilegdb ${testfile}-libmod.c + +# So file name: +set binlibfilebase ${testfile}.so + +# Setup run directory (where program is run from) +# It contains executable and '-lib' version of the library. +set binlibfiledirrun [standard_output_file ${testfile}_wd] +set binlibfilerun ${binlibfiledirrun}/${binlibfilebase} + +# Second solib version is in current directory, '-libmod' version. +set binlibfiledirgdb [standard_output_file ""] +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase} + +# Executeable +set srcfile ${testfile}.c +set executable ${testfile} +set objfile [standard_output_file ${executable}.o] +set binfile [standard_output_file ${executable}] + +file mkdir "${binlibfiledirrun}" + +set exec_opts {} + +if { ![istarget "*-*-nto-*"] } { + set exec_opts [list debug shlib_load] +} + +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } { + return -1 +} + +if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" + || [gdb_gnu_strip_debug "${binlibfilerun}"] + || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" } { + untested "gdb_compile_shlib failed." + return -1 +} + +proc solib_matching_test { solibfile symsloaded msg } { + global gdb_prompt + global testfile + global executable + global srcdir + global subdir + global binlibfiledirrun + global binlibfiledirgdb + global srcfile + + clean_restart ${binlibfiledirrun}/${executable} + + send_gdb "set solib-search-path \"${binlibfiledirgdb}\"\n" + send_gdb "cd ${binlibfiledirgdb}\n" +# Do not auto load shared libraries, the test needs to have control +# over when the relevant output gets printed + send_gdb "set auto-solib-add off\n" + + set bp_location [gdb_get_line_number "set breakpoint 1 here"] + + gdb_breakpoint ${srcfile}:${bp_location} temporary no-message + + gdb_run_cmd { ${binlibfiledirrun} } + gdb_test "" "set breakpoint 1 here.*" "" + + send_gdb "sharedlibrary\n" + gdb_test "" "" "" + + set nocrlf "\[^\r\n\]*" + set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" + set expected_line "${symsloaded}${nocrlf}${solibfile}" + + gdb_test "info sharedlibrary ${solibfile}" \ + "${expected_header}\r\n.*${expected_line}.*" \ + "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" + return 0 +} + +# Copy binary to working dir so it pulls in the library from that dir +# (by the virtue of $ORIGIN). +file copy -force "${binlibfiledirgdb}/${executable}" \ + "${binlibfiledirrun}/${executable}" + +# Test unstripped, .dynamic matching +solib_matching_test "${binlibfilebase}" "No" \ + "test unstripped, .dynamic matching" + +# Keep original so for debugging purposes +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig" +set objcopy_program [transform objcopy] +set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"] +if {$result != 0} { + untested "test --only-keep-debug" + return -1 +} + +# Test --only-keep-debug, .dynamic matching so +solib_matching_test "${binlibfilebase}" "No" \ + "test --only-keep-debug" + +# Keep previous so for debugging puroses +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1" + +# Copy loaded so over the one gdb will find +file copy -force "${binlibfilerun}" "${binlibfilegdb}" + +# Now test it does not mis-invalidate matching libraries +solib_matching_test "${binlibfilebase}" "Yes" \ + "test matching libraries" + + + -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-09 17:37 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski @ 2013-04-15 15:12 ` Jan Kratochvil 2013-04-16 17:25 ` Aleksandar Ristovski 0 siblings, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 15:12 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:45 +0200, Aleksandar Ristovski wrote: [...] > --- /dev/null > +++ b/gdb/testsuite/gdb.base/solib-mismatch.c > @@ -0,0 +1,68 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2013 Free Software Foundation, Inc. > + > + 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 <dlfcn.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <signal.h> > +#include <string.h> > + > +/* The following defines must correspond to solib-mismatch.exp */ > + > +#define DIRNAME "solib-mismatch_wd" > +#define LIB "./solib-mismatch.so" > + > +int main(int argc, char *argv[]) GNU Coding Standards: int main (int argc, char *argv[]) > +{ > + void *h; > + int (*foo)(void); GNU Coding Standards: int (*foo) (void); > + char buff[1024]; > + char *p; > + > + p = strstr (argv[0], DIRNAME); I find it overcomplicated, maybe even fragile, not sure how argv[0] is passed on various platforms. I was already suggesting before the way already used many times in the GDB testsuite: gdb_compile / prepare_for_testing / etc.: additional_flags=-DDIRNAME\=\"${binlibfiledirrun}\" And then you can just: if (chdir (DIRNAME) != 0) and that's all. > + > + if (p == NULL) > + { > + printf ("ERROR - %s could not be found in argv[0]\n", DIRNAME); > + return 1; > + } > + > + p += strlen (DIRNAME); > + > + memcpy (buff, argv[0], p - argv[0]); > + > + buff[p - argv[0]] = '\0'; > + > + if (chdir (buff) != 0) > + { > + printf ("ERROR - Could not cd to %s\n", buff); > + return 1; > + } > + > + h = dlopen(LIB, RTLD_NOW); GNU Coding Standards: h = dlopen (LIB, RTLD_NOW); > + > + if (h == NULL) > + { > + printf ("ERROR - could not open lib %s\n", LIB); > + return 1; > + } > + foo = dlsym(h, "foo"); /* set breakpoint 1 here */ GNU Coding Standards: foo = dlsym (h, "foo"); /* set breakpoint 1 here */ > + dlclose(h); GNU Coding Standards: dlclose (h); > + return 0; > +} > + > diff --git a/gdb/testsuite/gdb.base/solib-mismatch.exp b/gdb/testsuite/gdb.base/solib-mismatch.exp > new file mode 100644 > index 0000000..6d30632 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/solib-mismatch.exp > @@ -0,0 +1,144 @@ > +# Copyright 2013 Free Software Foundation, Inc. > + > +# 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/>. */ > + > +standard_testfile > +set executable $testfile > + > +# Test overview: > +# generate two shared objects. One that will be used by the process > +# and another, modified, that will be found by gdb. Gdb should > +# detect the mismatch and refuse to use mismatched shared object. > + > +if { [get_compiler_info] } { > + untested "get_compiler_info failed." Missing: return -1 untested does not return on its own. > +} > + > +# First version of the object, to be loaded by ld > +set srclibfilerun ${testfile}-lib.c > + > +# Modified version of the object to be loaded by gdb > +# Code in -libmod.c is tuned so it gives a mismatch but > +# leaves .dynamic at the same point. > +set srclibfilegdb ${testfile}-libmod.c > + > +# So file name: > +set binlibfilebase ${testfile}.so > + > +# Setup run directory (where program is run from) > +# It contains executable and '-lib' version of the library. > +set binlibfiledirrun [standard_output_file ${testfile}_wd] > +set binlibfilerun ${binlibfiledirrun}/${binlibfilebase} > + > +# Second solib version is in current directory, '-libmod' version. > +set binlibfiledirgdb [standard_output_file ""] > +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase} > + > +# Executeable typo: # Executable > +set srcfile ${testfile}.c > +set executable ${testfile} > +set objfile [standard_output_file ${executable}.o] > +set binfile [standard_output_file ${executable}] stcfile and binfile are already set by standard_testfile. Here should be: file delete -force -- "${binlibfiledirrun}" otherwise the testcase errors out on: rm -rf gdb.base/solib-mismatch_wd; touch gdb.base/solib-mismatch_wd; runtest gdb.base/solib-mismatch.exp > + > +file mkdir "${binlibfiledirrun}" > + > +set exec_opts {} > + > +if { ![istarget "*-*-nto-*"] } { > + set exec_opts [list debug shlib_load] Rather lappend. > +} > + > +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } { > + return -1 > +} I already wrote: Use build_executable here as prepare_for_testing just additionally calls clean_restart but you do prepare_for_testing on your own later. > + > +if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" > + || [gdb_gnu_strip_debug "${binlibfilerun}"] > + || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" } { -soname is already set by gdb_compile_shlib, why do you set it yourself here? > + untested "gdb_compile_shlib failed." > + return -1 > +} > + > +proc solib_matching_test { solibfile symsloaded msg } { > + global gdb_prompt > + global testfile > + global executable > + global srcdir > + global subdir > + global binlibfiledirrun > + global binlibfiledirgdb > + global srcfile > + > + clean_restart ${binlibfiledirrun}/${executable} > + > + send_gdb "set solib-search-path \"${binlibfiledirgdb}\"\n" > + send_gdb "cd ${binlibfiledirgdb}\n" Empty line before a comment. > +# Do not auto load shared libraries, the test needs to have control > +# over when the relevant output gets printed Missing final dot. Indent the comment by two spaces right to align with the code. > + send_gdb "set auto-solib-add off\n" Already written before: Never (only in some exceptional cases) use send_gdb, it creates races wrt syncing on end of the commands. Use gdb_test or gdb_test_no_output. The testcase even does not run for me with send_gdb when I use the "read1" reproducer catching such racy testcases behavior from: reproducer for races of expect incomplete reads http://sourceware.org/bugzilla/show_bug.cgi?id=12649 > + > + set bp_location [gdb_get_line_number "set breakpoint 1 here"] > + > + gdb_breakpoint ${srcfile}:${bp_location} temporary no-message I already explained in detail why no-message is inappropriate here. > + > + gdb_run_cmd { ${binlibfiledirrun} } main() no longer uses argv[1] so you can remove this parameter here. > + gdb_test "" "set breakpoint 1 here.*" "" But all these commands here, specifically these: set bp_location [gdb_get_line_number "set breakpoint 1 here"] gdb_breakpoint ${srcfile}:${bp_location} temporary no-message gdb_run_cmd { ${binlibfiledirrun} } gdb_test "" "set breakpoint 1 here.*" "" seem overcomplicated to me, it is enough to use: if ![runto "${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]"] { return } > + send_gdb "sharedlibrary\n" > + gdb_test "" "" "" Again never use send_gdb. > + > + set nocrlf "\[^\r\n\]*" > + set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" > + set expected_line "${symsloaded}${nocrlf}${solibfile}" > + > + gdb_test "info sharedlibrary ${solibfile}" \ > + "${expected_header}\r\n.*${expected_line}.*" \ > + "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" Those .* around ${expected_line} destroy the whole purpose of ${nocrlf} as they can match anything. To make it really single-line one can use for example: set footer_line {\(\*\): Shared library is missing debugging information\.} + "${expected_header}\r\n${nocrlf}${expected_line}${nocrlf}(?:\r\n$footer_line)?" \ > + return 0 The return value (0) is not used by any caller. And also just "return" at and of proc is redundant, remove it. > +} > + > +# Copy binary to working dir so it pulls in the library from that dir > +# (by the virtue of $ORIGIN). > +file copy -force "${binlibfiledirgdb}/${executable}" \ > + "${binlibfiledirrun}/${executable}" > + > +# Test unstripped, .dynamic matching > +solib_matching_test "${binlibfilebase}" "No" \ > + "test unstripped, .dynamic matching" > + > +# Keep original so for debugging purposes > +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig" > +set objcopy_program [transform objcopy] > +set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"] > +if {$result != 0} { > + untested "test --only-keep-debug" > + return -1 > +} > + > +# Test --only-keep-debug, .dynamic matching so > +solib_matching_test "${binlibfilebase}" "No" \ > + "test --only-keep-debug" > + > +# Keep previous so for debugging puroses > +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1" > + > +# Copy loaded so over the one gdb will find > +file copy -force "${binlibfilerun}" "${binlibfilegdb}" > + > +# Now test it does not mis-invalidate matching libraries > +solib_matching_test "${binlibfilebase}" "Yes" \ > + "test matching libraries" > + > + > + It is a nitpick but you leave in almost all files trailing empty lines. Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-15 15:12 ` Jan Kratochvil @ 2013-04-16 17:25 ` Aleksandar Ristovski 2013-04-18 5:37 ` Jan Kratochvil 0 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 17:25 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-14 10:18 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:45 +0200, Aleksandar Ristovski wrote: .... >> +#define LIB "./solib-mismatch.so" >> + >> +int main(int argc, char *argv[]) > > GNU Coding Standards: > int main (int argc, char *argv[]) Ok. > > >> +{ >> + void *h; > >> + int (*foo)(void); > GNU Coding Standards: > int (*foo) (void); Ok. > > ... > And then you can just: > if (chdir (DIRNAME) != 0) > and that's all. Ok. Also, LIB is now communicated the same way. > > ... >> + h = dlopen(LIB, RTLD_NOW); > > GNU Coding Standards: > h = dlopen (LIB, RTLD_NOW); > Ok. > ... > GNU Coding Standards: > foo = dlsym (h, "foo"); /* set breakpoint 1 here */ > Ok. > ... > GNU Coding Standards: > dlclose (h); > Ok. > ... >> + untested "get_compiler_info failed." > > Missing: > return -1 > > untested does not return on its own. Ok. > ... >> +# Executeable > > typo: > # Executable Ok. > > >> +set srcfile ${testfile}.c >> +set executable ${testfile} >> +set objfile [standard_output_file ${executable}.o] >> +set binfile [standard_output_file ${executable}] > > stcfile and binfile are already set by standard_testfile. > > > Here should be: > file delete -force -- "${binlibfiledirrun}" > otherwise the testcase errors out on: > rm -rf gdb.base/solib-mismatch_wd; touch gdb.base/solib-mismatch_wd; runtest gdb.base/solib-mismatch.exp Ok. > > >> + >> +file mkdir "${binlibfiledirrun}" >> + >> +set exec_opts {} >> + >> +if { ![istarget "*-*-nto-*"] } { >> + set exec_opts [list debug shlib_load] > > Rather lappend. > Ok. > >> +} >> + >> +if { [prepare_for_testing $testfile.exp $executable $srcfile $exec_opts] != 0 } { >> + return -1 >> +} > > I already wrote: > Use build_executable here as prepare_for_testing just additionally calls > clean_restart but you do prepare_for_testing on your own later. Ok. > > >> + >> +if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" >> + || [gdb_gnu_strip_debug "${binlibfilerun}"] >> + || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,-soname,${binlibfilebase},--build-id]] != "" } { > > -soname is already set by gdb_compile_shlib, why do you set it yourself here? > I don't need to. Rearranged. > ... > > Empty line before a comment. Ok. > >> +# Do not auto load shared libraries, the test needs to have control >> +# over when the relevant output gets printed > > Missing final dot. > > Indent the comment by two spaces right to align with the code. Ok. > > >> + send_gdb "set auto-solib-add off\n" > > Already written before: > > Never (only in some exceptional cases) use send_gdb, it creates races wrt > syncing on end of the commands. Use gdb_test or gdb_test_no_output. > > The testcase even does not run for me with send_gdb when I use the "read1" > reproducer catching such racy testcases behavior from: > reproducer for races of expect incomplete reads > http://sourceware.org/bugzilla/show_bug.cgi?id=12649 Ok. > > >> + >> + set bp_location [gdb_get_line_number "set breakpoint 1 here"] >> + >> + gdb_breakpoint ${srcfile}:${bp_location} temporary no-message > > I already explained in detail why no-message is inappropriate here. Ok. > > >> + >> + gdb_run_cmd { ${binlibfiledirrun} } > > main() no longer uses argv[1] so you can remove this parameter here. Ok. > > >> + gdb_test "" "set breakpoint 1 here.*" "" > > But all these commands here, specifically these: > > set bp_location [gdb_get_line_number "set breakpoint 1 here"] > gdb_breakpoint ${srcfile}:${bp_location} temporary no-message > gdb_run_cmd { ${binlibfiledirrun} } > gdb_test "" "set breakpoint 1 here.*" "" > > seem overcomplicated to me, it is enough to use: > > if ![runto "${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]"] { > return > } Ok, thanks. > > >> + send_gdb "sharedlibrary\n" >> + gdb_test "" "" "" > > Again never use send_gdb. Ok. > > >> + >> + set nocrlf "\[^\r\n\]*" >> + set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" >> + set expected_line "${symsloaded}${nocrlf}${solibfile}" >> + >> + gdb_test "info sharedlibrary ${solibfile}" \ >> + "${expected_header}\r\n.*${expected_line}.*" \ >> + "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" > > Those .* around ${expected_line} destroy the whole purpose of ${nocrlf} as > they can match anything. To make it really single-line one can use for > example: I was aiming at matching ${symsloaded} and ${solibfile} on _the_same_ line, but ignore if there are extra lines. I believe this guards against e.g. ............. Yes ....... SomeOtherLibraryNotSureWhyMatchedTheRegexp ............. No ......... ${solibfile} In this case, if 'Yes' is expected, it would not match. > > set footer_line {\(\*\): Shared library is missing debugging information\.} > + > "${expected_header}\r\n${nocrlf}${expected_line}${nocrlf}(?:\r\n$footer_line)?" \ > > >> + return 0 > > The return value (0) is not used by any caller. And also just "return" at and > of proc is redundant, remove it. Actually, I was going to use it to communicate failures within the function - changed accordingly. If something goes wrong in one run of solib_matching_test, it will print UNTESTED and continue, I believe this would aid diagnostics of the issues. > > ... >> + >> + >> + > > It is a nitpick but you leave in almost all files trailing empty lines. Ok. I think I removed them. I didn't think they were evil :-) Thanks, Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-16 17:25 ` Aleksandar Ristovski @ 2013-04-18 5:37 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 5:37 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:15:04 +0200, Aleksandar Ristovski wrote: > On 13-04-14 10:18 AM, Jan Kratochvil wrote: > >On Tue, 09 Apr 2013 17:27:45 +0200, Aleksandar Ristovski wrote: > >>+ set nocrlf "\[^\r\n\]*" > >>+ set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" > >>+ set expected_line "${symsloaded}${nocrlf}${solibfile}" > >>+ > >>+ gdb_test "info sharedlibrary ${solibfile}" \ > >>+ "${expected_header}\r\n.*${expected_line}.*" \ > >>+ "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" > > > >Those .* around ${expected_line} destroy the whole purpose of ${nocrlf} as > >they can match anything. To make it really single-line one can use for > >example: > > I was aiming at matching ${symsloaded} and ${solibfile} on > _the_same_ line, but ignore if there are extra lines. I believe this > guards against e.g. > > ............. Yes ....... SomeOtherLibraryNotSureWhyMatchedTheRegexp > ............. No ......... ${solibfile} > > In this case, if 'Yes' is expected, it would not match. That was the purpose, it would FAIL as such case is unexpected and user should investigate/bugreport why it happened. (It would be absolutely correct to rather report UNRESOLVED rather than FILE in the unexpected multi-line case.) But if it was intentional how you wrote it I do not mind either way. > > set footer_line {\(\*\): Shared library is missing debugging information\.} > >+ > > "${expected_header}\r\n${nocrlf}${expected_line}${nocrlf}(?:\r\n$footer_line)?" \ > > > > > >>+ return 0 > > > >The return value (0) is not used by any caller. And also just "return" at and > >of proc is redundant, remove it. > > Actually, I was going to use it to communicate failures within the > function - changed accordingly. If something goes wrong in one run > of solib_matching_test, it will print UNTESTED and continue, I > believe this would aid diagnostics of the issues. OK, I found now the caller has been updated. Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 7/8] Validate symbol file using build-id. 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (6 preceding siblings ...) 2013-04-09 17:37 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski @ 2013-04-09 17:50 ` Aleksandar Ristovski 2013-04-10 22:35 ` Aleksandar Ristovski 2013-04-15 14:58 ` Jan Kratochvil 2013-04-09 17:53 ` [PATCH 0/8] v2 - validate binary before use Jan Kratochvil 2013-04-16 18:03 ` Aleksandar Ristovski 9 siblings, 2 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 17:50 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Notable changes: gear for fetching build-id from target memory that was in the previous patcset in svr4_relocate_section_addresses is moved back to svr4_validate. This code path is taken only if build-id was not fetched via TARGET_OBJECT_LIBRARIES_SVR4, but build-id exists in the so. * solib-darwin.c (_initialize_darwin_solib): Assign validate value. * solib-dsbt.c (_initialize_dsbt_solib): Ditto. * solib-frv.c (_initialize_frv_solib): Ditto. * solib-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto. * solib-irix.c (_initialize_irix_solib): Ditto. * solib-osf.c (_initialize_osf_solib): Ditto. * solib-pa64.c (_initialize_pa64_solib): Ditto. * solib-som.c (_initialize_som_solib): Ditto. * solib-spu.c (set_spu_solib_ops): Ditto. * solib-sunos.c (_initialize_sunos_solib): Ditto. * solib-svr4.c (NOTE_GNU_BUILD_ID_NAME): New define. (svr4_validate): New function. (library_list_start_library): Parse 'build-id' attribute. (svr4_library_attributes): Add 'build-id' attribute. (_initialize_svr4_solib): Assign validate value. * solib-target.c (solib.h): Include. (_initialize_solib_target): Assign validate value. * solib.c (solib_map_sections): Use ops->validate. (free_so): Free build_id. (solib_validate): New function. * solib.h (solib_validate): New declaration. * solist.h (so_list): New fields 'build_idsz' and 'build_id'. (target_so_ops): New field 'validate'. --- gdb/solib-darwin.c | 1 + gdb/solib-dsbt.c | 1 + gdb/solib-frv.c | 1 + gdb/solib-ia64-hpux.c | 1 + gdb/solib-irix.c | 1 + gdb/solib-osf.c | 1 + gdb/solib-pa64.c | 1 + gdb/solib-som.c | 1 + gdb/solib-spu.c | 1 + gdb/solib-sunos.c | 1 + gdb/solib-svr4.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ gdb/solib-target.c | 2 + gdb/solib.c | 20 ++++++++ gdb/solib.h | 4 ++ gdb/solist.h | 14 ++++++ 15 files changed, 180 insertions(+) diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index b9a4be1..ff57016 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -647,4 +647,5 @@ _initialize_darwin_solib (void) darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol; darwin_so_ops.bfd_open = darwin_bfd_open; + darwin_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index ea2acd1..9728470 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -1182,6 +1182,7 @@ _initialize_dsbt_solib (void) dsbt_so_ops.open_symbol_file_object = open_symbol_file_object; dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code; dsbt_so_ops.bfd_open = solib_bfd_open; + dsbt_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance, diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index 57e418f..5621b2a 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -1182,6 +1182,7 @@ _initialize_frv_solib (void) frv_so_ops.open_symbol_file_object = open_symbol_file_object; frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code; frv_so_ops.bfd_open = solib_bfd_open; + frv_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-frv", class_maintenance, diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c index 67085d7..6fb146c 100644 --- a/gdb/solib-ia64-hpux.c +++ b/gdb/solib-ia64-hpux.c @@ -686,6 +686,7 @@ ia64_hpux_target_so_ops (void) ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; ops->bfd_open = solib_bfd_open; + ops->validate = default_solib_validate; return ops; } diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c index af3e7d6..871fb19 100644 --- a/gdb/solib-irix.c +++ b/gdb/solib-irix.c @@ -652,4 +652,5 @@ _initialize_irix_solib (void) irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; irix_so_ops.bfd_open = solib_bfd_open; + irix_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c index d05c5c1..5b1cd0b 100644 --- a/gdb/solib-osf.c +++ b/gdb/solib-osf.c @@ -633,6 +633,7 @@ _initialize_osf_solib (void) osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object; osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code; osf_so_ops.bfd_open = solib_bfd_open; + osf_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &osf_so_ops; diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c index f646cfb..795bcda 100644 --- a/gdb/solib-pa64.c +++ b/gdb/solib-pa64.c @@ -621,6 +621,7 @@ _initialize_pa64_solib (void) pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; pa64_so_ops.bfd_open = solib_bfd_open; + pa64_so_ops.validate = default_solib_validate; memset (&dld_cache, 0, sizeof (dld_cache)); } diff --git a/gdb/solib-som.c b/gdb/solib-som.c index ff7fbaa..cc2d344 100644 --- a/gdb/solib-som.c +++ b/gdb/solib-som.c @@ -811,6 +811,7 @@ _initialize_som_solib (void) som_so_ops.open_symbol_file_object = som_open_symbol_file_object; som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; som_so_ops.bfd_open = solib_bfd_open; + som_so_ops.validate = default_solib_validate; } void diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index 7be5232..4cc343b 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch) spu_so_ops.current_sos = spu_current_sos; spu_so_ops.bfd_open = spu_bfd_open; spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol; + spu_so_ops.validate = default_solib_validate; } set_solib_ops (gdbarch, &spu_so_ops); diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c index 5863fc2..71c8ee3 100644 --- a/gdb/solib-sunos.c +++ b/gdb/solib-sunos.c @@ -738,6 +738,7 @@ _initialize_sunos_solib (void) sunos_so_ops.open_symbol_file_object = open_symbol_file_object; sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code; sunos_so_ops.bfd_open = solib_bfd_open; + sunos_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &sunos_so_ops; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index bb2a4e9..90e421b 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -47,6 +47,8 @@ #include "exceptions.h" #include "gdb_bfd.h" +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id" + static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); static void svr4_relocate_main_executable (void); @@ -871,6 +873,109 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) return (name_lm >= vaddr && name_lm < vaddr + size); } +/* Validate SO by comparing build-id from the associated bfd and + corresponding build-id from target memory. */ + +static int +svr4_validate (const struct so_list *const so) +{ + gdb_byte *build_id; + size_t build_idsz; + + gdb_assert (so != NULL); + + if (so->abfd == NULL) + return 1; + + if (!bfd_check_format (so->abfd, bfd_object) + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour + || elf_tdata (so->abfd)->build_id == NULL) + return 1; + + build_id = so->build_id; + build_idsz = so->build_idsz; + + if (build_id == NULL) + { + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. + This is a fallback mechanism for targets that do not + implement TARGET_OBJECT_SOLIB_SVR4. */ + + const asection *const asec + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); + ULONGEST bfd_sect_size; + + if (asec == NULL) + return 1; + + bfd_sect_size = bfd_get_section_size (asec); + + if ((asec->flags & SEC_LOAD) == SEC_LOAD + && bfd_sect_size != 0 + && strcmp (bfd_section_name (asec->bfd, asec), + NOTE_GNU_BUILD_ID_NAME) == 0) + { + const enum bfd_endian byte_order + = gdbarch_byte_order (target_gdbarch ()); + Elf_External_Note *const note = xmalloc (bfd_sect_size); + gdb_byte *const note_raw = (void *) note; + struct cleanup *cleanups = make_cleanup (xfree, note); + + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) + + lm_addr_check (so, so->abfd), + note_raw, bfd_sect_size) == 0) + { + build_idsz + = extract_unsigned_integer ((gdb_byte *) note->descsz, + sizeof (note->descsz), + byte_order); + + if (build_idsz == elf_tdata (so->abfd)->build_id->size) + { + const char gnu[4] = "GNU\0"; + + if (memcmp (note->name, gnu, 4) == 0) + { + ULONGEST namesz + = extract_unsigned_integer ((gdb_byte *) note->namesz, + sizeof (note->namesz), + byte_order); + CORE_ADDR build_id_offs; + + /* Rounded to next sizeof (ElfXX_Word). */ + namesz = ((namesz + (sizeof (note->namesz) - 1)) + & ~((ULONGEST) (sizeof (note->namesz) - 1))); + build_id_offs = (sizeof (note->namesz) + + sizeof (note->descsz) + + sizeof (note->type) + namesz); + build_id = xmalloc (build_idsz); + memcpy (build_id, note_raw + build_id_offs, build_idsz); + } + } + else + warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); + + } + do_cleanups (cleanups); + } + } + + if (build_id != NULL) + { + const int match + = elf_tdata (so->abfd)->build_id->size == build_idsz + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, + elf_tdata (so->abfd)->build_id->size) == 0; + + if (build_id != so->build_id) + xfree (build_id); + + return match; + } + + return 1; +} + /* Implement the "open_symbol_file_object" target_so_ops method. If no open symbol file, attempt to locate and open the main symbol @@ -999,6 +1104,9 @@ library_list_start_library (struct gdb_xml_parser *parser, ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; + const struct gdb_xml_value *const att_build_id + = xml_find_attribute (attributes, "build-id"); + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; struct so_list *new_elem; new_elem = XZALLOC (struct so_list); @@ -1010,6 +1118,26 @@ library_list_start_library (struct gdb_xml_parser *parser, strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; strcpy (new_elem->so_original_name, new_elem->so_name); + if (hex_build_id != NULL) + { + const size_t hex_build_id_len = strlen (hex_build_id); + + if (hex_build_id_len > 0) + { + new_elem->build_id = xmalloc (hex_build_id_len / 2); + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, + hex_build_id_len); + if (new_elem->build_idsz != (hex_build_id_len / 2)) + { + warning (_("Gdbserver returned invalid hex encoded build_id '%s'" + "(%zu/%zu)\n"), + hex_build_id, hex_build_id_len, new_elem->build_idsz); + xfree (new_elem->build_id); + new_elem->build_id = NULL; + new_elem->build_idsz = 0; + } + } + } *list->tailp = new_elem; list->tailp = &new_elem->next; @@ -1044,6 +1172,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; @@ -2458,4 +2587,5 @@ _initialize_svr4_solib (void) svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; svr4_so_ops.same = svr4_same; svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; + svr4_so_ops.validate = svr4_validate; } diff --git a/gdb/solib-target.c b/gdb/solib-target.c index d897bc0..ed82218 100644 --- a/gdb/solib-target.c +++ b/gdb/solib-target.c @@ -25,6 +25,7 @@ #include "target.h" #include "vec.h" #include "solib-target.h" +#include "solib.h" #include "gdb_string.h" @@ -500,6 +501,7 @@ _initialize_solib_target (void) solib_target_so_ops.in_dynsym_resolve_code = solib_target_in_dynsym_resolve_code; solib_target_so_ops.bfd_open = solib_bfd_open; + solib_target_so_ops.validate = default_solib_validate; /* Set current_target_so_ops to solib_target_so_ops if not already set. */ diff --git a/gdb/solib.c b/gdb/solib.c index 8129c0f..20c709e 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -471,6 +471,17 @@ solib_map_sections (struct so_list *so) error (_("Shared library file name is too long.")); strcpy (so->so_name, bfd_get_filename (abfd)); + gdb_assert (ops->validate != NULL); + + if (!ops->validate (so)) + { + warning (_("Shared object \"%s\" could not be validated " + "and will be ignored."), so->so_name); + gdb_bfd_unref (so->abfd); + so->abfd = NULL; + return 0; + } + if (build_section_table (abfd, &so->sections, &so->sections_end)) { error (_("Can't find the file sections in `%s': %s"), @@ -551,6 +562,7 @@ free_so (struct so_list *so) { struct target_so_ops *ops = solib_ops (target_gdbarch ()); + xfree (so->build_id); free_so_symbols (so); ops->free_so (so); @@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, return symaddr; } +/* Default implementation does not perform any validation. */ + +int +default_solib_validate (const struct so_list *const so) +{ + return 1; /* No validation. */ +} + extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ void diff --git a/gdb/solib.h b/gdb/solib.h index b811866..670949a 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, void *), void *data); +/* Default validation always returns 1. */ + +extern int default_solib_validate (const struct so_list *so); + #endif /* SOLIB_H */ diff --git a/gdb/solist.h b/gdb/solist.h index f784fc3..72e003d 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -75,6 +75,16 @@ struct so_list There may not be just one (e.g. if two segments are relocated differently); but this is only used for "info sharedlibrary". */ CORE_ADDR addr_low, addr_high; + + /* Build id in raw format, contains verbatim contents of + .note.gnu.build-id including note header. This is actual + BUILD_ID which comes either from the remote target via qXfer + packet or via reading target memory. Therefore, it may differ + from the build-id of the associated bfd. In a normal + scenario, this so would soon lose its abfd due to failed + validation. */ + size_t build_idsz; + gdb_byte *build_id; }; struct target_so_ops @@ -148,6 +158,10 @@ struct target_so_ops core file (in particular, for readonly sections). */ int (*keep_data_in_core) (CORE_ADDR vaddr, unsigned long size); + + /* Return 0 if SO does not match target SO it is supposed to + represent. Return 1 otherwise. */ + int (*validate) (const struct so_list *so); }; /* Free the memory associated with a (so_list *). */ -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-09 17:50 ` [PATCH 7/8] Validate " Aleksandar Ristovski @ 2013-04-10 22:35 ` Aleksandar Ristovski 2013-04-10 19:58 ` Aleksandar Ristovski 2013-04-11 1:26 ` Jan Kratochvil 2013-04-15 14:58 ` Jan Kratochvil 1 sibling, 2 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-10 22:35 UTC (permalink / raw) To: gdb-patches; +Cc: gdb-patches, jan.kratochvil Minor but important change in svr4_validate: if target memory read succeeded, but the note read doesn't look like build-id note, this means the file does not match. Current patch would say it matches. Also, the warning emitted in this case is misleading (thus removed). I can repost the patch, but the diff is this: @@ -952,8 +952,16 @@ svr4_validate (const struct so_list *const so) memcpy (build_id, note_raw + build_id_offs, build_idsz); } } - else - warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); + + if (build_id == NULL) + { + /* If we are here, it means target memory read succeeded + but note was not where it was expected according to the + abfd. Allow the logic below to perform the check + with an impossible build-id and fail validation. */ + build_idsz = 0; + build_id = xstrdup (""); + } } do_cleanups (cleanups); On 13-04-09 11:27 AM, Aleksandar Ristovski wrote: > Notable changes: gear for fetching build-id from target memory that > was in the previous patcset in svr4_relocate_section_addresses is moved > back to svr4_validate. This code path is taken only if build-id was > not fetched via TARGET_OBJECT_LIBRARIES_SVR4, but build-id exists > in the so. > > * solib-darwin.c (_initialize_darwin_solib): Assign validate value. > * solib-dsbt.c (_initialize_dsbt_solib): Ditto. > * solib-frv.c (_initialize_frv_solib): Ditto. > * solib-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto. > * solib-irix.c (_initialize_irix_solib): Ditto. > * solib-osf.c (_initialize_osf_solib): Ditto. > * solib-pa64.c (_initialize_pa64_solib): Ditto. > * solib-som.c (_initialize_som_solib): Ditto. > * solib-spu.c (set_spu_solib_ops): Ditto. > * solib-sunos.c (_initialize_sunos_solib): Ditto. > * solib-svr4.c (NOTE_GNU_BUILD_ID_NAME): New define. > (svr4_validate): New function. > (library_list_start_library): Parse 'build-id' attribute. > (svr4_library_attributes): Add 'build-id' attribute. > (_initialize_svr4_solib): Assign validate value. > * solib-target.c (solib.h): Include. > (_initialize_solib_target): Assign validate value. > * solib.c (solib_map_sections): Use ops->validate. > (free_so): Free build_id. > (solib_validate): New function. > * solib.h (solib_validate): New declaration. > * solist.h (so_list): New fields 'build_idsz' and 'build_id'. > (target_so_ops): New field 'validate'. > --- > gdb/solib-darwin.c | 1 + > gdb/solib-dsbt.c | 1 + > gdb/solib-frv.c | 1 + > gdb/solib-ia64-hpux.c | 1 + > gdb/solib-irix.c | 1 + > gdb/solib-osf.c | 1 + > gdb/solib-pa64.c | 1 + > gdb/solib-som.c | 1 + > gdb/solib-spu.c | 1 + > gdb/solib-sunos.c | 1 + > gdb/solib-svr4.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ > gdb/solib-target.c | 2 + > gdb/solib.c | 20 ++++++++ > gdb/solib.h | 4 ++ > gdb/solist.h | 14 ++++++ > 15 files changed, 180 insertions(+) > > diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c > index b9a4be1..ff57016 100644 > --- a/gdb/solib-darwin.c > +++ b/gdb/solib-darwin.c > @@ -647,4 +647,5 @@ _initialize_darwin_solib (void) > darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; > darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol; > darwin_so_ops.bfd_open = darwin_bfd_open; > + darwin_so_ops.validate = default_solib_validate; > } > diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c > index ea2acd1..9728470 100644 > --- a/gdb/solib-dsbt.c > +++ b/gdb/solib-dsbt.c > @@ -1182,6 +1182,7 @@ _initialize_dsbt_solib (void) > dsbt_so_ops.open_symbol_file_object = open_symbol_file_object; > dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code; > dsbt_so_ops.bfd_open = solib_bfd_open; > + dsbt_so_ops.validate = default_solib_validate; > > /* Debug this file's internals. */ > add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance, > diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c > index 57e418f..5621b2a 100644 > --- a/gdb/solib-frv.c > +++ b/gdb/solib-frv.c > @@ -1182,6 +1182,7 @@ _initialize_frv_solib (void) > frv_so_ops.open_symbol_file_object = open_symbol_file_object; > frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code; > frv_so_ops.bfd_open = solib_bfd_open; > + frv_so_ops.validate = default_solib_validate; > > /* Debug this file's internals. */ > add_setshow_zuinteger_cmd ("solib-frv", class_maintenance, > diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c > index 67085d7..6fb146c 100644 > --- a/gdb/solib-ia64-hpux.c > +++ b/gdb/solib-ia64-hpux.c > @@ -686,6 +686,7 @@ ia64_hpux_target_so_ops (void) > ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; > ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; > ops->bfd_open = solib_bfd_open; > + ops->validate = default_solib_validate; > > return ops; > } > diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c > index af3e7d6..871fb19 100644 > --- a/gdb/solib-irix.c > +++ b/gdb/solib-irix.c > @@ -652,4 +652,5 @@ _initialize_irix_solib (void) > irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; > irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; > irix_so_ops.bfd_open = solib_bfd_open; > + irix_so_ops.validate = default_solib_validate; > } > diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c > index d05c5c1..5b1cd0b 100644 > --- a/gdb/solib-osf.c > +++ b/gdb/solib-osf.c > @@ -633,6 +633,7 @@ _initialize_osf_solib (void) > osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object; > osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code; > osf_so_ops.bfd_open = solib_bfd_open; > + osf_so_ops.validate = default_solib_validate; > > /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ > current_target_so_ops = &osf_so_ops; > diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c > index f646cfb..795bcda 100644 > --- a/gdb/solib-pa64.c > +++ b/gdb/solib-pa64.c > @@ -621,6 +621,7 @@ _initialize_pa64_solib (void) > pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; > pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; > pa64_so_ops.bfd_open = solib_bfd_open; > + pa64_so_ops.validate = default_solib_validate; > > memset (&dld_cache, 0, sizeof (dld_cache)); > } > diff --git a/gdb/solib-som.c b/gdb/solib-som.c > index ff7fbaa..cc2d344 100644 > --- a/gdb/solib-som.c > +++ b/gdb/solib-som.c > @@ -811,6 +811,7 @@ _initialize_som_solib (void) > som_so_ops.open_symbol_file_object = som_open_symbol_file_object; > som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; > som_so_ops.bfd_open = solib_bfd_open; > + som_so_ops.validate = default_solib_validate; > } > > void > diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c > index 7be5232..4cc343b 100644 > --- a/gdb/solib-spu.c > +++ b/gdb/solib-spu.c > @@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch) > spu_so_ops.current_sos = spu_current_sos; > spu_so_ops.bfd_open = spu_bfd_open; > spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol; > + spu_so_ops.validate = default_solib_validate; > } > > set_solib_ops (gdbarch, &spu_so_ops); > diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c > index 5863fc2..71c8ee3 100644 > --- a/gdb/solib-sunos.c > +++ b/gdb/solib-sunos.c > @@ -738,6 +738,7 @@ _initialize_sunos_solib (void) > sunos_so_ops.open_symbol_file_object = open_symbol_file_object; > sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code; > sunos_so_ops.bfd_open = solib_bfd_open; > + sunos_so_ops.validate = default_solib_validate; > > /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ > current_target_so_ops = &sunos_so_ops; > diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c > index bb2a4e9..90e421b 100644 > --- a/gdb/solib-svr4.c > +++ b/gdb/solib-svr4.c > @@ -47,6 +47,8 @@ > #include "exceptions.h" > #include "gdb_bfd.h" > > +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id" > + > static struct link_map_offsets *svr4_fetch_link_map_offsets (void); > static int svr4_have_link_map_offsets (void); > static void svr4_relocate_main_executable (void); > @@ -871,6 +873,109 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) > return (name_lm >= vaddr && name_lm < vaddr + size); > } > > +/* Validate SO by comparing build-id from the associated bfd and > + corresponding build-id from target memory. */ > + > +static int > +svr4_validate (const struct so_list *const so) > +{ > + gdb_byte *build_id; > + size_t build_idsz; > + > + gdb_assert (so != NULL); > + > + if (so->abfd == NULL) > + return 1; > + > + if (!bfd_check_format (so->abfd, bfd_object) > + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour > + || elf_tdata (so->abfd)->build_id == NULL) > + return 1; > + > + build_id = so->build_id; > + build_idsz = so->build_idsz; > + > + if (build_id == NULL) > + { > + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. > + This is a fallback mechanism for targets that do not > + implement TARGET_OBJECT_SOLIB_SVR4. */ > + > + const asection *const asec > + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); > + ULONGEST bfd_sect_size; > + > + if (asec == NULL) > + return 1; > + > + bfd_sect_size = bfd_get_section_size (asec); > + > + if ((asec->flags & SEC_LOAD) == SEC_LOAD > + && bfd_sect_size != 0 > + && strcmp (bfd_section_name (asec->bfd, asec), > + NOTE_GNU_BUILD_ID_NAME) == 0) > + { > + const enum bfd_endian byte_order > + = gdbarch_byte_order (target_gdbarch ()); > + Elf_External_Note *const note = xmalloc (bfd_sect_size); > + gdb_byte *const note_raw = (void *) note; > + struct cleanup *cleanups = make_cleanup (xfree, note); > + > + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) > + + lm_addr_check (so, so->abfd), > + note_raw, bfd_sect_size) == 0) > + { > + build_idsz > + = extract_unsigned_integer ((gdb_byte *) note->descsz, > + sizeof (note->descsz), > + byte_order); > + > + if (build_idsz == elf_tdata (so->abfd)->build_id->size) > + { > + const char gnu[4] = "GNU\0"; > + > + if (memcmp (note->name, gnu, 4) == 0) > + { > + ULONGEST namesz > + = extract_unsigned_integer ((gdb_byte *) note->namesz, > + sizeof (note->namesz), > + byte_order); > + CORE_ADDR build_id_offs; > + > + /* Rounded to next sizeof (ElfXX_Word). */ > + namesz = ((namesz + (sizeof (note->namesz) - 1)) > + & ~((ULONGEST) (sizeof (note->namesz) - 1))); > + build_id_offs = (sizeof (note->namesz) > + + sizeof (note->descsz) > + + sizeof (note->type) + namesz); > + build_id = xmalloc (build_idsz); > + memcpy (build_id, note_raw + build_id_offs, build_idsz); > + } > + } > + else > + warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); > + > + } > + do_cleanups (cleanups); > + } > + } > + > + if (build_id != NULL) > + { > + const int match > + = elf_tdata (so->abfd)->build_id->size == build_idsz > + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, > + elf_tdata (so->abfd)->build_id->size) == 0; > + > + if (build_id != so->build_id) > + xfree (build_id); > + > + return match; > + } > + > + return 1; > +} > + > /* Implement the "open_symbol_file_object" target_so_ops method. > > If no open symbol file, attempt to locate and open the main symbol > @@ -999,6 +1104,9 @@ library_list_start_library (struct gdb_xml_parser *parser, > ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; > ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; > ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; > + const struct gdb_xml_value *const att_build_id > + = xml_find_attribute (attributes, "build-id"); > + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; > struct so_list *new_elem; > > new_elem = XZALLOC (struct so_list); > @@ -1010,6 +1118,26 @@ library_list_start_library (struct gdb_xml_parser *parser, > strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); > new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; > strcpy (new_elem->so_original_name, new_elem->so_name); > + if (hex_build_id != NULL) > + { > + const size_t hex_build_id_len = strlen (hex_build_id); > + > + if (hex_build_id_len > 0) > + { > + new_elem->build_id = xmalloc (hex_build_id_len / 2); > + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, > + hex_build_id_len); > + if (new_elem->build_idsz != (hex_build_id_len / 2)) > + { > + warning (_("Gdbserver returned invalid hex encoded build_id '%s'" > + "(%zu/%zu)\n"), > + hex_build_id, hex_build_id_len, new_elem->build_idsz); > + xfree (new_elem->build_id); > + new_elem->build_id = NULL; > + new_elem->build_idsz = 0; > + } > + } > + } > > *list->tailp = new_elem; > list->tailp = &new_elem->next; > @@ -1044,6 +1172,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = > { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, > { NULL, GDB_XML_AF_NONE, NULL, NULL } > }; > > @@ -2458,4 +2587,5 @@ _initialize_svr4_solib (void) > svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; > svr4_so_ops.same = svr4_same; > svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; > + svr4_so_ops.validate = svr4_validate; > } > diff --git a/gdb/solib-target.c b/gdb/solib-target.c > index d897bc0..ed82218 100644 > --- a/gdb/solib-target.c > +++ b/gdb/solib-target.c > @@ -25,6 +25,7 @@ > #include "target.h" > #include "vec.h" > #include "solib-target.h" > +#include "solib.h" > > #include "gdb_string.h" > > @@ -500,6 +501,7 @@ _initialize_solib_target (void) > solib_target_so_ops.in_dynsym_resolve_code > = solib_target_in_dynsym_resolve_code; > solib_target_so_ops.bfd_open = solib_bfd_open; > + solib_target_so_ops.validate = default_solib_validate; > > /* Set current_target_so_ops to solib_target_so_ops if not already > set. */ > diff --git a/gdb/solib.c b/gdb/solib.c > index 8129c0f..20c709e 100644 > --- a/gdb/solib.c > +++ b/gdb/solib.c > @@ -471,6 +471,17 @@ solib_map_sections (struct so_list *so) > error (_("Shared library file name is too long.")); > strcpy (so->so_name, bfd_get_filename (abfd)); > > + gdb_assert (ops->validate != NULL); > + > + if (!ops->validate (so)) > + { > + warning (_("Shared object \"%s\" could not be validated " > + "and will be ignored."), so->so_name); > + gdb_bfd_unref (so->abfd); > + so->abfd = NULL; > + return 0; > + } > + > if (build_section_table (abfd, &so->sections, &so->sections_end)) > { > error (_("Can't find the file sections in `%s': %s"), > @@ -551,6 +562,7 @@ free_so (struct so_list *so) > { > struct target_so_ops *ops = solib_ops (target_gdbarch ()); > > + xfree (so->build_id); > free_so_symbols (so); > ops->free_so (so); > > @@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, > return symaddr; > } > > +/* Default implementation does not perform any validation. */ > + > +int > +default_solib_validate (const struct so_list *const so) > +{ > + return 1; /* No validation. */ > +} > + > extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ > > void > diff --git a/gdb/solib.h b/gdb/solib.h > index b811866..670949a 100644 > --- a/gdb/solib.h > +++ b/gdb/solib.h > @@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, > void *), > void *data); > > +/* Default validation always returns 1. */ > + > +extern int default_solib_validate (const struct so_list *so); > + > #endif /* SOLIB_H */ > diff --git a/gdb/solist.h b/gdb/solist.h > index f784fc3..72e003d 100644 > --- a/gdb/solist.h > +++ b/gdb/solist.h > @@ -75,6 +75,16 @@ struct so_list > There may not be just one (e.g. if two segments are relocated > differently); but this is only used for "info sharedlibrary". */ > CORE_ADDR addr_low, addr_high; > + > + /* Build id in raw format, contains verbatim contents of > + .note.gnu.build-id including note header. This is actual > + BUILD_ID which comes either from the remote target via qXfer > + packet or via reading target memory. Therefore, it may differ > + from the build-id of the associated bfd. In a normal > + scenario, this so would soon lose its abfd due to failed > + validation. */ > + size_t build_idsz; > + gdb_byte *build_id; > }; > > struct target_so_ops > @@ -148,6 +158,10 @@ struct target_so_ops > core file (in particular, for readonly sections). */ > int (*keep_data_in_core) (CORE_ADDR vaddr, > unsigned long size); > + > + /* Return 0 if SO does not match target SO it is supposed to > + represent. Return 1 otherwise. */ > + int (*validate) (const struct so_list *so); > }; > > /* Free the memory associated with a (so_list *). */ > ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-10 22:35 ` Aleksandar Ristovski @ 2013-04-10 19:58 ` Aleksandar Ristovski 2013-04-11 1:26 ` Jan Kratochvil 1 sibling, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-10 19:58 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches, jan.kratochvil Minor but important change in svr4_validate: if target memory read succeeded, but the note read doesn't look like build-id note, this means the file does not match. Current patch would say it matches. Also, the warning emitted in this case is misleading (thus removed). I can repost the patch, but the diff is this: @@ -952,8 +952,16 @@ svr4_validate (const struct so_list *const so) memcpy (build_id, note_raw + build_id_offs, build_idsz); } } - else - warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); + + if (build_id == NULL) + { + /* If we are here, it means target memory read succeeded + but note was not where it was expected according to the + abfd. Allow the logic below to perform the check + with an impossible build-id and fail validation. */ + build_idsz = 0; + build_id = xstrdup (""); + } } do_cleanups (cleanups); On 13-04-09 11:27 AM, Aleksandar Ristovski wrote: > Notable changes: gear for fetching build-id from target memory that > was in the previous patcset in svr4_relocate_section_addresses is moved > back to svr4_validate. This code path is taken only if build-id was > not fetched via TARGET_OBJECT_LIBRARIES_SVR4, but build-id exists > in the so. > > * solib-darwin.c (_initialize_darwin_solib): Assign validate value. > * solib-dsbt.c (_initialize_dsbt_solib): Ditto. > * solib-frv.c (_initialize_frv_solib): Ditto. > * solib-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto. > * solib-irix.c (_initialize_irix_solib): Ditto. > * solib-osf.c (_initialize_osf_solib): Ditto. > * solib-pa64.c (_initialize_pa64_solib): Ditto. > * solib-som.c (_initialize_som_solib): Ditto. > * solib-spu.c (set_spu_solib_ops): Ditto. > * solib-sunos.c (_initialize_sunos_solib): Ditto. > * solib-svr4.c (NOTE_GNU_BUILD_ID_NAME): New define. > (svr4_validate): New function. > (library_list_start_library): Parse 'build-id' attribute. > (svr4_library_attributes): Add 'build-id' attribute. > (_initialize_svr4_solib): Assign validate value. > * solib-target.c (solib.h): Include. > (_initialize_solib_target): Assign validate value. > * solib.c (solib_map_sections): Use ops->validate. > (free_so): Free build_id. > (solib_validate): New function. > * solib.h (solib_validate): New declaration. > * solist.h (so_list): New fields 'build_idsz' and 'build_id'. > (target_so_ops): New field 'validate'. > --- > gdb/solib-darwin.c | 1 + > gdb/solib-dsbt.c | 1 + > gdb/solib-frv.c | 1 + > gdb/solib-ia64-hpux.c | 1 + > gdb/solib-irix.c | 1 + > gdb/solib-osf.c | 1 + > gdb/solib-pa64.c | 1 + > gdb/solib-som.c | 1 + > gdb/solib-spu.c | 1 + > gdb/solib-sunos.c | 1 + > gdb/solib-svr4.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ > gdb/solib-target.c | 2 + > gdb/solib.c | 20 ++++++++ > gdb/solib.h | 4 ++ > gdb/solist.h | 14 ++++++ > 15 files changed, 180 insertions(+) > > diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c > index b9a4be1..ff57016 100644 > --- a/gdb/solib-darwin.c > +++ b/gdb/solib-darwin.c > @@ -647,4 +647,5 @@ _initialize_darwin_solib (void) > darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; > darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol; > darwin_so_ops.bfd_open = darwin_bfd_open; > + darwin_so_ops.validate = default_solib_validate; > } > diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c > index ea2acd1..9728470 100644 > --- a/gdb/solib-dsbt.c > +++ b/gdb/solib-dsbt.c > @@ -1182,6 +1182,7 @@ _initialize_dsbt_solib (void) > dsbt_so_ops.open_symbol_file_object = open_symbol_file_object; > dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code; > dsbt_so_ops.bfd_open = solib_bfd_open; > + dsbt_so_ops.validate = default_solib_validate; > > /* Debug this file's internals. */ > add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance, > diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c > index 57e418f..5621b2a 100644 > --- a/gdb/solib-frv.c > +++ b/gdb/solib-frv.c > @@ -1182,6 +1182,7 @@ _initialize_frv_solib (void) > frv_so_ops.open_symbol_file_object = open_symbol_file_object; > frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code; > frv_so_ops.bfd_open = solib_bfd_open; > + frv_so_ops.validate = default_solib_validate; > > /* Debug this file's internals. */ > add_setshow_zuinteger_cmd ("solib-frv", class_maintenance, > diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c > index 67085d7..6fb146c 100644 > --- a/gdb/solib-ia64-hpux.c > +++ b/gdb/solib-ia64-hpux.c > @@ -686,6 +686,7 @@ ia64_hpux_target_so_ops (void) > ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; > ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; > ops->bfd_open = solib_bfd_open; > + ops->validate = default_solib_validate; > > return ops; > } > diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c > index af3e7d6..871fb19 100644 > --- a/gdb/solib-irix.c > +++ b/gdb/solib-irix.c > @@ -652,4 +652,5 @@ _initialize_irix_solib (void) > irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; > irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; > irix_so_ops.bfd_open = solib_bfd_open; > + irix_so_ops.validate = default_solib_validate; > } > diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c > index d05c5c1..5b1cd0b 100644 > --- a/gdb/solib-osf.c > +++ b/gdb/solib-osf.c > @@ -633,6 +633,7 @@ _initialize_osf_solib (void) > osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object; > osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code; > osf_so_ops.bfd_open = solib_bfd_open; > + osf_so_ops.validate = default_solib_validate; > > /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ > current_target_so_ops = &osf_so_ops; > diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c > index f646cfb..795bcda 100644 > --- a/gdb/solib-pa64.c > +++ b/gdb/solib-pa64.c > @@ -621,6 +621,7 @@ _initialize_pa64_solib (void) > pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; > pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; > pa64_so_ops.bfd_open = solib_bfd_open; > + pa64_so_ops.validate = default_solib_validate; > > memset (&dld_cache, 0, sizeof (dld_cache)); > } > diff --git a/gdb/solib-som.c b/gdb/solib-som.c > index ff7fbaa..cc2d344 100644 > --- a/gdb/solib-som.c > +++ b/gdb/solib-som.c > @@ -811,6 +811,7 @@ _initialize_som_solib (void) > som_so_ops.open_symbol_file_object = som_open_symbol_file_object; > som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; > som_so_ops.bfd_open = solib_bfd_open; > + som_so_ops.validate = default_solib_validate; > } > > void > diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c > index 7be5232..4cc343b 100644 > --- a/gdb/solib-spu.c > +++ b/gdb/solib-spu.c > @@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch) > spu_so_ops.current_sos = spu_current_sos; > spu_so_ops.bfd_open = spu_bfd_open; > spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol; > + spu_so_ops.validate = default_solib_validate; > } > > set_solib_ops (gdbarch, &spu_so_ops); > diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c > index 5863fc2..71c8ee3 100644 > --- a/gdb/solib-sunos.c > +++ b/gdb/solib-sunos.c > @@ -738,6 +738,7 @@ _initialize_sunos_solib (void) > sunos_so_ops.open_symbol_file_object = open_symbol_file_object; > sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code; > sunos_so_ops.bfd_open = solib_bfd_open; > + sunos_so_ops.validate = default_solib_validate; > > /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ > current_target_so_ops = &sunos_so_ops; > diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c > index bb2a4e9..90e421b 100644 > --- a/gdb/solib-svr4.c > +++ b/gdb/solib-svr4.c > @@ -47,6 +47,8 @@ > #include "exceptions.h" > #include "gdb_bfd.h" > > +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id" > + > static struct link_map_offsets *svr4_fetch_link_map_offsets (void); > static int svr4_have_link_map_offsets (void); > static void svr4_relocate_main_executable (void); > @@ -871,6 +873,109 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) > return (name_lm >= vaddr && name_lm < vaddr + size); > } > > +/* Validate SO by comparing build-id from the associated bfd and > + corresponding build-id from target memory. */ > + > +static int > +svr4_validate (const struct so_list *const so) > +{ > + gdb_byte *build_id; > + size_t build_idsz; > + > + gdb_assert (so != NULL); > + > + if (so->abfd == NULL) > + return 1; > + > + if (!bfd_check_format (so->abfd, bfd_object) > + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour > + || elf_tdata (so->abfd)->build_id == NULL) > + return 1; > + > + build_id = so->build_id; > + build_idsz = so->build_idsz; > + > + if (build_id == NULL) > + { > + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. > + This is a fallback mechanism for targets that do not > + implement TARGET_OBJECT_SOLIB_SVR4. */ > + > + const asection *const asec > + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); > + ULONGEST bfd_sect_size; > + > + if (asec == NULL) > + return 1; > + > + bfd_sect_size = bfd_get_section_size (asec); > + > + if ((asec->flags & SEC_LOAD) == SEC_LOAD > + && bfd_sect_size != 0 > + && strcmp (bfd_section_name (asec->bfd, asec), > + NOTE_GNU_BUILD_ID_NAME) == 0) > + { > + const enum bfd_endian byte_order > + = gdbarch_byte_order (target_gdbarch ()); > + Elf_External_Note *const note = xmalloc (bfd_sect_size); > + gdb_byte *const note_raw = (void *) note; > + struct cleanup *cleanups = make_cleanup (xfree, note); > + > + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) > + + lm_addr_check (so, so->abfd), > + note_raw, bfd_sect_size) == 0) > + { > + build_idsz > + = extract_unsigned_integer ((gdb_byte *) note->descsz, > + sizeof (note->descsz), > + byte_order); > + > + if (build_idsz == elf_tdata (so->abfd)->build_id->size) > + { > + const char gnu[4] = "GNU\0"; > + > + if (memcmp (note->name, gnu, 4) == 0) > + { > + ULONGEST namesz > + = extract_unsigned_integer ((gdb_byte *) note->namesz, > + sizeof (note->namesz), > + byte_order); > + CORE_ADDR build_id_offs; > + > + /* Rounded to next sizeof (ElfXX_Word). */ > + namesz = ((namesz + (sizeof (note->namesz) - 1)) > + & ~((ULONGEST) (sizeof (note->namesz) - 1))); > + build_id_offs = (sizeof (note->namesz) > + + sizeof (note->descsz) > + + sizeof (note->type) + namesz); > + build_id = xmalloc (build_idsz); > + memcpy (build_id, note_raw + build_id_offs, build_idsz); > + } > + } > + else > + warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); > + > + } > + do_cleanups (cleanups); > + } > + } > + > + if (build_id != NULL) > + { > + const int match > + = elf_tdata (so->abfd)->build_id->size == build_idsz > + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, > + elf_tdata (so->abfd)->build_id->size) == 0; > + > + if (build_id != so->build_id) > + xfree (build_id); > + > + return match; > + } > + > + return 1; > +} > + > /* Implement the "open_symbol_file_object" target_so_ops method. > > If no open symbol file, attempt to locate and open the main symbol > @@ -999,6 +1104,9 @@ library_list_start_library (struct gdb_xml_parser *parser, > ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; > ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; > ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; > + const struct gdb_xml_value *const att_build_id > + = xml_find_attribute (attributes, "build-id"); > + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; > struct so_list *new_elem; > > new_elem = XZALLOC (struct so_list); > @@ -1010,6 +1118,26 @@ library_list_start_library (struct gdb_xml_parser *parser, > strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); > new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; > strcpy (new_elem->so_original_name, new_elem->so_name); > + if (hex_build_id != NULL) > + { > + const size_t hex_build_id_len = strlen (hex_build_id); > + > + if (hex_build_id_len > 0) > + { > + new_elem->build_id = xmalloc (hex_build_id_len / 2); > + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, > + hex_build_id_len); > + if (new_elem->build_idsz != (hex_build_id_len / 2)) > + { > + warning (_("Gdbserver returned invalid hex encoded build_id '%s'" > + "(%zu/%zu)\n"), > + hex_build_id, hex_build_id_len, new_elem->build_idsz); > + xfree (new_elem->build_id); > + new_elem->build_id = NULL; > + new_elem->build_idsz = 0; > + } > + } > + } > > *list->tailp = new_elem; > list->tailp = &new_elem->next; > @@ -1044,6 +1172,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = > { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, > { NULL, GDB_XML_AF_NONE, NULL, NULL } > }; > > @@ -2458,4 +2587,5 @@ _initialize_svr4_solib (void) > svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; > svr4_so_ops.same = svr4_same; > svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; > + svr4_so_ops.validate = svr4_validate; > } > diff --git a/gdb/solib-target.c b/gdb/solib-target.c > index d897bc0..ed82218 100644 > --- a/gdb/solib-target.c > +++ b/gdb/solib-target.c > @@ -25,6 +25,7 @@ > #include "target.h" > #include "vec.h" > #include "solib-target.h" > +#include "solib.h" > > #include "gdb_string.h" > > @@ -500,6 +501,7 @@ _initialize_solib_target (void) > solib_target_so_ops.in_dynsym_resolve_code > = solib_target_in_dynsym_resolve_code; > solib_target_so_ops.bfd_open = solib_bfd_open; > + solib_target_so_ops.validate = default_solib_validate; > > /* Set current_target_so_ops to solib_target_so_ops if not already > set. */ > diff --git a/gdb/solib.c b/gdb/solib.c > index 8129c0f..20c709e 100644 > --- a/gdb/solib.c > +++ b/gdb/solib.c > @@ -471,6 +471,17 @@ solib_map_sections (struct so_list *so) > error (_("Shared library file name is too long.")); > strcpy (so->so_name, bfd_get_filename (abfd)); > > + gdb_assert (ops->validate != NULL); > + > + if (!ops->validate (so)) > + { > + warning (_("Shared object \"%s\" could not be validated " > + "and will be ignored."), so->so_name); > + gdb_bfd_unref (so->abfd); > + so->abfd = NULL; > + return 0; > + } > + > if (build_section_table (abfd, &so->sections, &so->sections_end)) > { > error (_("Can't find the file sections in `%s': %s"), > @@ -551,6 +562,7 @@ free_so (struct so_list *so) > { > struct target_so_ops *ops = solib_ops (target_gdbarch ()); > > + xfree (so->build_id); > free_so_symbols (so); > ops->free_so (so); > > @@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, > return symaddr; > } > > +/* Default implementation does not perform any validation. */ > + > +int > +default_solib_validate (const struct so_list *const so) > +{ > + return 1; /* No validation. */ > +} > + > extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ > > void > diff --git a/gdb/solib.h b/gdb/solib.h > index b811866..670949a 100644 > --- a/gdb/solib.h > +++ b/gdb/solib.h > @@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, > void *), > void *data); > > +/* Default validation always returns 1. */ > + > +extern int default_solib_validate (const struct so_list *so); > + > #endif /* SOLIB_H */ > diff --git a/gdb/solist.h b/gdb/solist.h > index f784fc3..72e003d 100644 > --- a/gdb/solist.h > +++ b/gdb/solist.h > @@ -75,6 +75,16 @@ struct so_list > There may not be just one (e.g. if two segments are relocated > differently); but this is only used for "info sharedlibrary". */ > CORE_ADDR addr_low, addr_high; > + > + /* Build id in raw format, contains verbatim contents of > + .note.gnu.build-id including note header. This is actual > + BUILD_ID which comes either from the remote target via qXfer > + packet or via reading target memory. Therefore, it may differ > + from the build-id of the associated bfd. In a normal > + scenario, this so would soon lose its abfd due to failed > + validation. */ > + size_t build_idsz; > + gdb_byte *build_id; > }; > > struct target_so_ops > @@ -148,6 +158,10 @@ struct target_so_ops > core file (in particular, for readonly sections). */ > int (*keep_data_in_core) (CORE_ADDR vaddr, > unsigned long size); > + > + /* Return 0 if SO does not match target SO it is supposed to > + represent. Return 1 otherwise. */ > + int (*validate) (const struct so_list *so); > }; > > /* Free the memory associated with a (so_list *). */ > ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-10 22:35 ` Aleksandar Ristovski 2013-04-10 19:58 ` Aleksandar Ristovski @ 2013-04-11 1:26 ` Jan Kratochvil 2013-04-11 2:43 ` Aleksandar Ristovski 1 sibling, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-11 1:26 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Wed, 10 Apr 2013 17:00:59 +0200, Aleksandar Ristovski wrote: > I can repost the patch, but the diff is this: Yes, repost the patch, please. It is not applicable as is. Also it is convenient for everyone to (also) keep the patches in some GIT branch, not requiring it. Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 7/8] Validate symbol file using build-id. 2013-04-11 1:26 ` Jan Kratochvil @ 2013-04-11 2:43 ` Aleksandar Ristovski 0 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-11 2:43 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski Full patch. I also created new branch in the archer: aristovski/validate-binary-before-use Thanks, Aleksandar * solib-darwin.c (_initialize_darwin_solib): Assign validate value. * solib-dsbt.c (_initialize_dsbt_solib): Ditto. * solib-frv.c (_initialize_frv_solib): Ditto. * solib-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto. * solib-irix.c (_initialize_irix_solib): Ditto. * solib-osf.c (_initialize_osf_solib): Ditto. * solib-pa64.c (_initialize_pa64_solib): Ditto. * solib-som.c (_initialize_som_solib): Ditto. * solib-spu.c (set_spu_solib_ops): Ditto. * solib-sunos.c (_initialize_sunos_solib): Ditto. * solib-svr4.c (NOTE_GNU_BUILD_ID_NAME): New define. (svr4_validate): New function. (library_list_start_library): Parse 'build-id' attribute. (svr4_library_attributes): Add 'build-id' attribute. (_initialize_svr4_solib): Assign validate value. * solib-target.c (solib.h): Include. (_initialize_solib_target): Assign validate value. * solib.c (solib_map_sections): Use ops->validate. (free_so): Free build_id. (solib_validate): New function. * solib.h (solib_validate): New declaration. * solist.h (so_list): New fields 'build_idsz' and 'build_id'. (target_so_ops): New field 'validate'. --- gdb/solib-darwin.c | 1 + gdb/solib-dsbt.c | 1 + gdb/solib-frv.c | 1 + gdb/solib-ia64-hpux.c | 1 + gdb/solib-irix.c | 1 + gdb/solib-osf.c | 1 + gdb/solib-pa64.c | 1 + gdb/solib-som.c | 1 + gdb/solib-spu.c | 1 + gdb/solib-sunos.c | 1 + gdb/solib-svr4.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ gdb/solib-target.c | 2 + gdb/solib.c | 20 ++++++++ gdb/solib.h | 4 ++ gdb/solist.h | 14 +++++ 15 files changed, 185 insertions(+) diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index b9a4be1..ff57016 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -647,4 +647,5 @@ _initialize_darwin_solib (void) darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol; darwin_so_ops.bfd_open = darwin_bfd_open; + darwin_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index e2822c1..6cadf82 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -1182,6 +1182,7 @@ _initialize_dsbt_solib (void) dsbt_so_ops.open_symbol_file_object = open_symbol_file_object; dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code; dsbt_so_ops.bfd_open = solib_bfd_open; + dsbt_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance, diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index 52588bc..741ede5 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -1182,6 +1182,7 @@ _initialize_frv_solib (void) frv_so_ops.open_symbol_file_object = open_symbol_file_object; frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code; frv_so_ops.bfd_open = solib_bfd_open; + frv_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-frv", class_maintenance, diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c index 67085d7..6fb146c 100644 --- a/gdb/solib-ia64-hpux.c +++ b/gdb/solib-ia64-hpux.c @@ -686,6 +686,7 @@ ia64_hpux_target_so_ops (void) ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; ops->bfd_open = solib_bfd_open; + ops->validate = default_solib_validate; return ops; } diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c index af3e7d6..871fb19 100644 --- a/gdb/solib-irix.c +++ b/gdb/solib-irix.c @@ -652,4 +652,5 @@ _initialize_irix_solib (void) irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; irix_so_ops.bfd_open = solib_bfd_open; + irix_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c index d05c5c1..5b1cd0b 100644 --- a/gdb/solib-osf.c +++ b/gdb/solib-osf.c @@ -633,6 +633,7 @@ _initialize_osf_solib (void) osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object; osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code; osf_so_ops.bfd_open = solib_bfd_open; + osf_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &osf_so_ops; diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c index f646cfb..795bcda 100644 --- a/gdb/solib-pa64.c +++ b/gdb/solib-pa64.c @@ -621,6 +621,7 @@ _initialize_pa64_solib (void) pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; pa64_so_ops.bfd_open = solib_bfd_open; + pa64_so_ops.validate = default_solib_validate; memset (&dld_cache, 0, sizeof (dld_cache)); } diff --git a/gdb/solib-som.c b/gdb/solib-som.c index 650e3df..2fbf0a2 100644 --- a/gdb/solib-som.c +++ b/gdb/solib-som.c @@ -811,6 +811,7 @@ _initialize_som_solib (void) som_so_ops.open_symbol_file_object = som_open_symbol_file_object; som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; som_so_ops.bfd_open = solib_bfd_open; + som_so_ops.validate = default_solib_validate; } void diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index 7be5232..4cc343b 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -519,6 +519,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch) spu_so_ops.current_sos = spu_current_sos; spu_so_ops.bfd_open = spu_bfd_open; spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol; + spu_so_ops.validate = default_solib_validate; } set_solib_ops (gdbarch, &spu_so_ops); diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c index 5863fc2..71c8ee3 100644 --- a/gdb/solib-sunos.c +++ b/gdb/solib-sunos.c @@ -738,6 +738,7 @@ _initialize_sunos_solib (void) sunos_so_ops.open_symbol_file_object = open_symbol_file_object; sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code; sunos_so_ops.bfd_open = solib_bfd_open; + sunos_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &sunos_so_ops; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index bb2a4e9..54a7e6f 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -47,6 +47,8 @@ #include "exceptions.h" #include "gdb_bfd.h" +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id" + static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); static void svr4_relocate_main_executable (void); @@ -871,6 +873,117 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) return (name_lm >= vaddr && name_lm < vaddr + size); } +/* Validate SO by comparing build-id from the associated bfd and + corresponding build-id from target memory. */ + +static int +svr4_validate (const struct so_list *const so) +{ + gdb_byte *build_id; + size_t build_idsz; + + gdb_assert (so != NULL); + + if (so->abfd == NULL) + return 1; + + if (!bfd_check_format (so->abfd, bfd_object) + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour + || elf_tdata (so->abfd)->build_id == NULL) + return 1; + + build_id = so->build_id; + build_idsz = so->build_idsz; + + if (build_id == NULL) + { + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. + This is a fallback mechanism for targets that do not + implement TARGET_OBJECT_SOLIB_SVR4. */ + + const asection *const asec + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); + ULONGEST bfd_sect_size; + + if (asec == NULL) + return 1; + + bfd_sect_size = bfd_get_section_size (asec); + + if ((asec->flags & SEC_LOAD) == SEC_LOAD + && bfd_sect_size != 0 + && strcmp (bfd_section_name (asec->bfd, asec), + NOTE_GNU_BUILD_ID_NAME) == 0) + { + const enum bfd_endian byte_order + = gdbarch_byte_order (target_gdbarch ()); + Elf_External_Note *const note = xmalloc (bfd_sect_size); + gdb_byte *const note_raw = (void *) note; + struct cleanup *cleanups = make_cleanup (xfree, note); + + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) + + lm_addr_check (so, so->abfd), + note_raw, bfd_sect_size) == 0) + { + build_idsz + = extract_unsigned_integer ((gdb_byte *) note->descsz, + sizeof (note->descsz), + byte_order); + + if (build_idsz == elf_tdata (so->abfd)->build_id->size) + { + const char gnu[4] = "GNU\0"; + + if (memcmp (note->name, gnu, 4) == 0) + { + ULONGEST namesz + = extract_unsigned_integer ((gdb_byte *) note->namesz, + sizeof (note->namesz), + byte_order); + CORE_ADDR build_id_offs; + + /* Rounded to next sizeof (ElfXX_Word). */ + namesz = ((namesz + (sizeof (note->namesz) - 1)) + & ~((ULONGEST) (sizeof (note->namesz) - 1))); + build_id_offs = (sizeof (note->namesz) + + sizeof (note->descsz) + + sizeof (note->type) + namesz); + build_id = xmalloc (build_idsz); + memcpy (build_id, note_raw + build_id_offs, build_idsz); + } + } + + if (build_id == NULL) + { + /* If we are here, it means target memory read succeeded + but note was not where it was expected according to the + abfd. Allow the logic below to perform the check + with an impossible build-id and fail validation. */ + build_idsz = 0; + build_id = xstrdup (""); + } + + } + do_cleanups (cleanups); + } + } + + if (build_id != NULL) + { + const int match + = elf_tdata (so->abfd)->build_id->size == build_idsz + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, + elf_tdata (so->abfd)->build_id->size) == 0; + + if (build_id != so->build_id) + xfree (build_id); + + return match; + } + + return 1; +} + /* Implement the "open_symbol_file_object" target_so_ops method. If no open symbol file, attempt to locate and open the main symbol @@ -999,6 +1112,9 @@ library_list_start_library (struct gdb_xml_parser *parser, ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; + const struct gdb_xml_value *const att_build_id + = xml_find_attribute (attributes, "build-id"); + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; struct so_list *new_elem; new_elem = XZALLOC (struct so_list); @@ -1010,6 +1126,23 @@ library_list_start_library (struct gdb_xml_parser *parser, strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; strcpy (new_elem->so_original_name, new_elem->so_name); + if (hex_build_id != NULL) + { + const size_t hex_build_id_len = strlen (hex_build_id); + + if (hex_build_id_len > 0) + { + new_elem->build_id = xmalloc (hex_build_id_len / 2); + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, + hex_build_id_len); + if (new_elem->build_idsz != (hex_build_id_len / 2)) + { + xfree (new_elem->build_id); + new_elem->build_id = NULL; + new_elem->build_idsz = 0; + } + } + } *list->tailp = new_elem; list->tailp = &new_elem->next; @@ -1044,6 +1177,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; @@ -2458,4 +2592,5 @@ _initialize_svr4_solib (void) svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; svr4_so_ops.same = svr4_same; svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; + svr4_so_ops.validate = svr4_validate; } diff --git a/gdb/solib-target.c b/gdb/solib-target.c index 0ad29ba..b67509f 100644 --- a/gdb/solib-target.c +++ b/gdb/solib-target.c @@ -25,6 +25,7 @@ #include "target.h" #include "vec.h" #include "solib-target.h" +#include "solib.h" #include "gdb_string.h" @@ -501,6 +502,7 @@ _initialize_solib_target (void) solib_target_so_ops.in_dynsym_resolve_code = solib_target_in_dynsym_resolve_code; solib_target_so_ops.bfd_open = solib_bfd_open; + solib_target_so_ops.validate = default_solib_validate; /* Set current_target_so_ops to solib_target_so_ops if not already set. */ diff --git a/gdb/solib.c b/gdb/solib.c index 8129c0f..20c709e 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -471,6 +471,17 @@ solib_map_sections (struct so_list *so) error (_("Shared library file name is too long.")); strcpy (so->so_name, bfd_get_filename (abfd)); + gdb_assert (ops->validate != NULL); + + if (!ops->validate (so)) + { + warning (_("Shared object \"%s\" could not be validated " + "and will be ignored."), so->so_name); + gdb_bfd_unref (so->abfd); + so->abfd = NULL; + return 0; + } + if (build_section_table (abfd, &so->sections, &so->sections_end)) { error (_("Can't find the file sections in `%s': %s"), @@ -551,6 +562,7 @@ free_so (struct so_list *so) { struct target_so_ops *ops = solib_ops (target_gdbarch ()); + xfree (so->build_id); free_so_symbols (so); ops->free_so (so); @@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, return symaddr; } +/* Default implementation does not perform any validation. */ + +int +default_solib_validate (const struct so_list *const so) +{ + return 1; /* No validation. */ +} + extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ void diff --git a/gdb/solib.h b/gdb/solib.h index b811866..670949a 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, void *), void *data); +/* Default validation always returns 1. */ + +extern int default_solib_validate (const struct so_list *so); + #endif /* SOLIB_H */ diff --git a/gdb/solist.h b/gdb/solist.h index f784fc3..72e003d 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -75,6 +75,16 @@ struct so_list There may not be just one (e.g. if two segments are relocated differently); but this is only used for "info sharedlibrary". */ CORE_ADDR addr_low, addr_high; + + /* Build id in raw format, contains verbatim contents of + .note.gnu.build-id including note header. This is actual + BUILD_ID which comes either from the remote target via qXfer + packet or via reading target memory. Therefore, it may differ + from the build-id of the associated bfd. In a normal + scenario, this so would soon lose its abfd due to failed + validation. */ + size_t build_idsz; + gdb_byte *build_id; }; struct target_so_ops @@ -148,6 +158,10 @@ struct target_so_ops core file (in particular, for readonly sections). */ int (*keep_data_in_core) (CORE_ADDR vaddr, unsigned long size); + + /* Return 0 if SO does not match target SO it is supposed to + represent. Return 1 otherwise. */ + int (*validate) (const struct so_list *so); }; /* Free the memory associated with a (so_list *). */ -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-09 17:50 ` [PATCH 7/8] Validate " Aleksandar Ristovski 2013-04-10 22:35 ` Aleksandar Ristovski @ 2013-04-15 14:58 ` Jan Kratochvil 2013-04-16 19:14 ` Aleksandar Ristovski 1 sibling, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-15 14:58 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:44 +0200, Aleksandar Ristovski wrote: [...] > --- a/gdb/solib-svr4.c > +++ b/gdb/solib-svr4.c [...] > @@ -871,6 +873,109 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) > return (name_lm >= vaddr && name_lm < vaddr + size); > } > > +/* Validate SO by comparing build-id from the associated bfd and > + corresponding build-id from target memory. */ > + > +static int > +svr4_validate (const struct so_list *const so) > +{ > + gdb_byte *build_id; > + size_t build_idsz; > + > + gdb_assert (so != NULL); > + > + if (so->abfd == NULL) > + return 1; > + > + if (!bfd_check_format (so->abfd, bfd_object) > + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour > + || elf_tdata (so->abfd)->build_id == NULL) > + return 1; > + > + build_id = so->build_id; > + build_idsz = so->build_idsz; > + > + if (build_id == NULL) > + { > + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. > + This is a fallback mechanism for targets that do not > + implement TARGET_OBJECT_SOLIB_SVR4. */ > + > + const asection *const asec > + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); > + ULONGEST bfd_sect_size; > + > + if (asec == NULL) > + return 1; > + > + bfd_sect_size = bfd_get_section_size (asec); > + > + if ((asec->flags & SEC_LOAD) == SEC_LOAD > + && bfd_sect_size != 0 > + && strcmp (bfd_section_name (asec->bfd, asec), > + NOTE_GNU_BUILD_ID_NAME) == 0) > + { > + const enum bfd_endian byte_order > + = gdbarch_byte_order (target_gdbarch ()); > + Elf_External_Note *const note = xmalloc (bfd_sect_size); > + gdb_byte *const note_raw = (void *) note; > + struct cleanup *cleanups = make_cleanup (xfree, note); > + > + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) > + + lm_addr_check (so, so->abfd), I see it is the most easy one how to get the target VMA of the options we were discussing. > + note_raw, bfd_sect_size) == 0) > + { > + build_idsz > + = extract_unsigned_integer ((gdb_byte *) note->descsz, > + sizeof (note->descsz), > + byte_order); > + > + if (build_idsz == elf_tdata (so->abfd)->build_id->size) > + { > + const char gnu[4] = "GNU\0"; > + > + if (memcmp (note->name, gnu, 4) == 0) > + { > + ULONGEST namesz > + = extract_unsigned_integer ((gdb_byte *) note->namesz, > + sizeof (note->namesz), > + byte_order); > + CORE_ADDR build_id_offs; > + > + /* Rounded to next sizeof (ElfXX_Word). */ > + namesz = ((namesz + (sizeof (note->namesz) - 1)) > + & ~((ULONGEST) (sizeof (note->namesz) - 1))); Like in the previous patch the rounding should be 4 bytes according to the standard. Not a sizeof of anything. > + build_id_offs = (sizeof (note->namesz) > + + sizeof (note->descsz) > + + sizeof (note->type) + namesz); I find more simple/clear to use offsetof (which is even more correct due to possible alignments) but I do not mind either way. > + build_id = xmalloc (build_idsz); I would say that build_id should be protected by cleanups but there is currently no risky function called between here and BUILD_ID comparison below so I do not mind. > + memcpy (build_id, note_raw + build_id_offs, build_idsz); > + } > + } > + else > + warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); Again some better identification, vaddr, in fact also PID should be printed in all these cases. > + > + } > + do_cleanups (cleanups); > + } > + } > + > + if (build_id != NULL) > + { > + const int match > + = elf_tdata (so->abfd)->build_id->size == build_idsz > + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, > + elf_tdata (so->abfd)->build_id->size) == 0; GNU Coding Standards require parentheses on multiple-line expressions: const int match = (elf_tdata (so->abfd)->build_id->size == build_idsz && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, elf_tdata (so->abfd)->build_id->size) == 0); Also it would be apropriate to use a temporary variable struct elf_build_id *somename = elf_tdata (so->abfd)->build_id; than to repeat the long expression again and again. Also such variable should be at the top of this function as there is already accessed 'elf_tdata (so->abfd)->build_id' at the top of this function. > + > + if (build_id != so->build_id) > + xfree (build_id); > + > + return match; > + } > + > + return 1; > +} > + > /* Implement the "open_symbol_file_object" target_so_ops method. > > If no open symbol file, attempt to locate and open the main symbol > @@ -999,6 +1104,9 @@ library_list_start_library (struct gdb_xml_parser *parser, > ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; > ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; > ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; > + const struct gdb_xml_value *const att_build_id > + = xml_find_attribute (attributes, "build-id"); > + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; > struct so_list *new_elem; > > new_elem = XZALLOC (struct so_list); > @@ -1010,6 +1118,26 @@ library_list_start_library (struct gdb_xml_parser *parser, > strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); > new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; > strcpy (new_elem->so_original_name, new_elem->so_name); > + if (hex_build_id != NULL) > + { > + const size_t hex_build_id_len = strlen (hex_build_id); > + > + if (hex_build_id_len > 0) > + { > + new_elem->build_id = xmalloc (hex_build_id_len / 2); > + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, > + hex_build_id_len); The hex2bin COUNT parameter is in bytes, not hex characters (divide it by 2). > + if (new_elem->build_idsz != (hex_build_id_len / 2)) Already written before: Check it the opposite way: if (2 * new_elem->build_idsz != hex_build_id_len) as otherwise odd length of the "build-id" attribute string will not be caught as invalid. > + { > + warning (_("Gdbserver returned invalid hex encoded build_id '%s'" Use "gdbserver", not capitalized. > + "(%zu/%zu)\n"), Already written before: I would omit this (%zu/%zu) part. Primarily currently %z is not allowed as it is not compatible with some OSes, there is a plan to import %z printf support in gdb/gnulib/ but so far there wasn't a need for it. Besides that you should describe what the two numbers mean otherwise they are mostly useless. And after all when you already print the XML string the numbers do not add any more info to it. > + hex_build_id, hex_build_id_len, new_elem->build_idsz); > + xfree (new_elem->build_id); > + new_elem->build_id = NULL; > + new_elem->build_idsz = 0; Already written before: I am not completely sure warning cannot throw, better to do these cleanups before the warning call (moreover when %zu/%zu will no longer be printed). > + } > + } > + } > > *list->tailp = new_elem; > list->tailp = &new_elem->next; > @@ -1044,6 +1172,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = > { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, > { NULL, GDB_XML_AF_NONE, NULL, NULL } > }; > > @@ -2458,4 +2587,5 @@ _initialize_svr4_solib (void) > svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; > svr4_so_ops.same = svr4_same; > svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; > + svr4_so_ops.validate = svr4_validate; > } > diff --git a/gdb/solib-target.c b/gdb/solib-target.c > index d897bc0..ed82218 100644 > --- a/gdb/solib-target.c > +++ b/gdb/solib-target.c > @@ -25,6 +25,7 @@ > #include "target.h" > #include "vec.h" > #include "solib-target.h" > +#include "solib.h" > > #include "gdb_string.h" > > @@ -500,6 +501,7 @@ _initialize_solib_target (void) > solib_target_so_ops.in_dynsym_resolve_code > = solib_target_in_dynsym_resolve_code; > solib_target_so_ops.bfd_open = solib_bfd_open; > + solib_target_so_ops.validate = default_solib_validate; > > /* Set current_target_so_ops to solib_target_so_ops if not already > set. */ > diff --git a/gdb/solib.c b/gdb/solib.c > index 8129c0f..20c709e 100644 > --- a/gdb/solib.c > +++ b/gdb/solib.c > @@ -471,6 +471,17 @@ solib_map_sections (struct so_list *so) > error (_("Shared library file name is too long.")); > strcpy (so->so_name, bfd_get_filename (abfd)); > > + gdb_assert (ops->validate != NULL); > + > + if (!ops->validate (so)) > + { > + warning (_("Shared object \"%s\" could not be validated " > + "and will be ignored."), so->so_name); Maybe the warning should by printed by svr4_validate stating the build-id does not match (even possibly printing the both build-ids). And then sure one can remove the warning here. > + gdb_bfd_unref (so->abfd); > + so->abfd = NULL; > + return 0; > + } > + > if (build_section_table (abfd, &so->sections, &so->sections_end)) > { > error (_("Can't find the file sections in `%s': %s"), > @@ -551,6 +562,7 @@ free_so (struct so_list *so) > { > struct target_so_ops *ops = solib_ops (target_gdbarch ()); > > + xfree (so->build_id); > free_so_symbols (so); > ops->free_so (so); > I already wrote: The problem is there is: xfree (so->build_id); in free_so() but it should be in free_so_symbols instead. free_so_symbols is called also from reload_shared_libraries_1 where so_list->abfd can change. Then obviously one should also set so->build_id = NULL there. I was thinking making the BUILD_ID data private so solib-svr4.c but that is currently not possible, lm_info is private for solib-svr4.c but that has lifetime of so_list, not the lifetime of so_list->abfd. > @@ -1448,6 +1460,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, > return symaddr; > } > > +/* Default implementation does not perform any validation. */ > + > +int > +default_solib_validate (const struct so_list *const so) > +{ > + return 1; /* No validation. */ > +} > + > extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ > > void [...] Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-15 14:58 ` Jan Kratochvil @ 2013-04-16 19:14 ` Aleksandar Ristovski 2013-04-18 10:23 ` Jan Kratochvil 0 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 19:14 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-14 10:17 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:44 +0200, Aleksandar Ristovski wrote: > [...] >> --- a/gdb/solib-svr4.c >> +++ b/gdb/solib-svr4.c > [...] >> @@ -871,6 +873,109 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) >> return (name_lm >= vaddr && name_lm < vaddr + size); >> } >> >> +/* Validate SO by comparing build-id from the associated bfd and >> + corresponding build-id from target memory. */ >> + >> +static int >> +svr4_validate (const struct so_list *const so) >> +{ >> + gdb_byte *build_id; >> + size_t build_idsz; >> + >> + gdb_assert (so != NULL); >> + >> + if (so->abfd == NULL) >> + return 1; >> + >> + if (!bfd_check_format (so->abfd, bfd_object) >> + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour >> + || elf_tdata (so->abfd)->build_id == NULL) >> + return 1; >> + >> + build_id = so->build_id; >> + build_idsz = so->build_idsz; >> + >> + if (build_id == NULL) >> + { >> + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. >> + This is a fallback mechanism for targets that do not >> + implement TARGET_OBJECT_SOLIB_SVR4. */ >> + >> + const asection *const asec >> + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); >> + ULONGEST bfd_sect_size; >> + >> + if (asec == NULL) >> + return 1; >> + >> + bfd_sect_size = bfd_get_section_size (asec); >> + >> + if ((asec->flags & SEC_LOAD) == SEC_LOAD >> + && bfd_sect_size != 0 >> + && strcmp (bfd_section_name (asec->bfd, asec), >> + NOTE_GNU_BUILD_ID_NAME) == 0) >> + { >> + const enum bfd_endian byte_order >> + = gdbarch_byte_order (target_gdbarch ()); >> + Elf_External_Note *const note = xmalloc (bfd_sect_size); >> + gdb_byte *const note_raw = (void *) note; >> + struct cleanup *cleanups = make_cleanup (xfree, note); >> + >> + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) >> + + lm_addr_check (so, so->abfd), > > I see it is the most easy one how to get the target VMA of the options we were > discussing. I do not parse this unambiguously... did you mean this is the easiest way of getting target VMA? If so, I agree. > > >> + note_raw, bfd_sect_size) == 0) >> + { >> + build_idsz >> + = extract_unsigned_integer ((gdb_byte *) note->descsz, >> + sizeof (note->descsz), >> + byte_order); >> + >> + if (build_idsz == elf_tdata (so->abfd)->build_id->size) >> + { >> + const char gnu[4] = "GNU\0"; >> + >> + if (memcmp (note->name, gnu, 4) == 0) >> + { >> + ULONGEST namesz >> + = extract_unsigned_integer ((gdb_byte *) note->namesz, >> + sizeof (note->namesz), >> + byte_order); >> + CORE_ADDR build_id_offs; >> + >> + /* Rounded to next sizeof (ElfXX_Word). */ >> + namesz = ((namesz + (sizeof (note->namesz) - 1)) >> + & ~((ULONGEST) (sizeof (note->namesz) - 1))); > > Like in the previous patch the rounding should be 4 bytes according to the > standard. Not a sizeof of anything. Yes, I re-read it, you are right: it is 4 byte aligned. Somehow I remembered it as Word aligned. > > >> + build_id_offs = (sizeof (note->namesz) >> + + sizeof (note->descsz) >> + + sizeof (note->type) + namesz); > > I find more simple/clear to use offsetof (which is even more correct due to > possible alignments) but I do not mind either way. Ok, offsetof looks good. > > >> + build_id = xmalloc (build_idsz); > > I would say that build_id should be protected by cleanups but there is > currently no risky function called between here and BUILD_ID comparison below > so I do not mind. Ok, and yes, this is why I did not put any cleanups (explicit xfree looked straight forward). > > >> + memcpy (build_id, note_raw + build_id_offs, build_idsz); >> + } >> + } >> + else >> + warning (_("Malformed %s note\n"), NOTE_GNU_BUILD_ID_NAME); > > Again some better identification, vaddr, in fact also PID should be printed in > all these cases. I think you missed updated patch: http://sourceware.org/ml/gdb-patches/2013-04/msg00271.html > > >> + >> + } >> + do_cleanups (cleanups); >> + } >> + } >> + >> + if (build_id != NULL) >> + { >> + const int match >> + = elf_tdata (so->abfd)->build_id->size == build_idsz >> + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, >> + elf_tdata (so->abfd)->build_id->size) == 0; > > GNU Coding Standards require parentheses on multiple-line expressions: > const int match > = (elf_tdata (so->abfd)->build_id->size == build_idsz > && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, > elf_tdata (so->abfd)->build_id->size) == 0); Ok. > > Also it would be apropriate to use a temporary variable > struct elf_build_id *somename = elf_tdata (so->abfd)->build_id; > than to repeat the long expression again and again. > Also such variable should be at the top of this function as there is already > accessed 'elf_tdata (so->abfd)->build_id' at the top of this function. Ok. > > >> + >> + if (build_id != so->build_id) >> + xfree (build_id); >> + >> + return match; >> + } >> + >> + return 1; >> +} >> + >> /* Implement the "open_symbol_file_object" target_so_ops method. >> >> If no open symbol file, attempt to locate and open the main symbol >> @@ -999,6 +1104,9 @@ library_list_start_library (struct gdb_xml_parser *parser, >> ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; >> ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; >> ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; >> + const struct gdb_xml_value *const att_build_id >> + = xml_find_attribute (attributes, "build-id"); >> + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; >> struct so_list *new_elem; >> >> new_elem = XZALLOC (struct so_list); >> @@ -1010,6 +1118,26 @@ library_list_start_library (struct gdb_xml_parser *parser, >> strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); >> new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; >> strcpy (new_elem->so_original_name, new_elem->so_name); >> + if (hex_build_id != NULL) >> + { >> + const size_t hex_build_id_len = strlen (hex_build_id); >> + >> + if (hex_build_id_len > 0) >> + { >> + new_elem->build_id = xmalloc (hex_build_id_len / 2); >> + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, >> + hex_build_id_len); > > The hex2bin COUNT parameter is in bytes, not hex characters (divide it by 2). Ok, thanks. > > >> + if (new_elem->build_idsz != (hex_build_id_len / 2)) > > Already written before: > > Check it the opposite way: > if (2 * new_elem->build_idsz != hex_build_id_len) > > as otherwise odd length of the "build-id" attribute string will not be caught > as invalid. Ok, re-arranged so we only try to convert if hex_build_id_len is even number. > > >> + { >> + warning (_("Gdbserver returned invalid hex encoded build_id '%s'" > > Use "gdbserver", not capitalized. > > >> + "(%zu/%zu)\n"), > > Already written before: > > I would omit this (%zu/%zu) part. Primarily currently %z is not allowed as it > is not compatible with some OSes, there is a plan to import %z printf support > in gdb/gnulib/ but so far there wasn't a need for it. > > Besides that you should describe what the two numbers mean otherwise they are > mostly useless. And after all when you already print the XML string the > numbers do not add any more info to it. THis warning was removed in the updated patch: http://sourceware.org/ml/gdb-patches/2013-04/msg00271.html > > >> + hex_build_id, hex_build_id_len, new_elem->build_idsz); >> + xfree (new_elem->build_id); >> + new_elem->build_id = NULL; >> + new_elem->build_idsz = 0; > > Already written before: > I am not completely sure warning cannot throw, better to do these cleanups > before the warning call (moreover when %zu/%zu will no longer be printed). Not applicable to the updated patch: http://sourceware.org/ml/gdb-patches/2013-04/msg00271.html > > ... >> + warning (_("Shared object \"%s\" could not be validated " >> + "and will be ignored."), so->so_name); > > Maybe the warning should by printed by svr4_validate stating the build-id does > not match (even possibly printing the both build-ids). And then sure one can > remove the warning here. I was thinking about that, but then decided that svr4_validate should simply provide an answer, not print warnings. User of the function should warn if appropriate (as is done in the patch). This is along the lines of (see below) using build-id for e.g. finding separate debug info etc... > > >> + gdb_bfd_unref (so->abfd); >> + so->abfd = NULL; >> + return 0; >> + } >> + >> if (build_section_table (abfd, &so->sections, &so->sections_end)) >> { >> error (_("Can't find the file sections in `%s': %s"), >> @@ -551,6 +562,7 @@ free_so (struct so_list *so) >> { >> struct target_so_ops *ops = solib_ops (target_gdbarch ()); >> >> + xfree (so->build_id); >> free_so_symbols (so); >> ops->free_so (so); >> > > I already wrote: > > The problem is there is: > xfree (so->build_id); > in free_so() but it should be in free_so_symbols instead. free_so_symbols is > called also from reload_shared_libraries_1 where so_list->abfd can change. > Then obviously one should also set so->build_id = NULL there. I'm not sure I follow this. In cases where so->build_id is determined it is good for the lifetime of the 'so', not symbols. It can not change for the given 'so'. > > I was thinking making the BUILD_ID data private so solib-svr4.c but that is > currently not possible, lm_info is private for solib-svr4.c but that has > lifetime of so_list, not the lifetime of so_list->abfd. I was thinking slightly differently: build-id should be generalized to represent "an ID". For svr4, it is build-id, for some other system it might be something else, but if present, should represent the connection between target binary, binary at hand and associated optional separate debug info. Thanks, --- Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 7/8] Validate symbol file using build-id. 2013-04-16 19:14 ` Aleksandar Ristovski @ 2013-04-18 10:23 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 10:23 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:15:00 +0200, Aleksandar Ristovski wrote: > On 13-04-14 10:17 AM, Jan Kratochvil wrote: > >On Tue, 09 Apr 2013 17:27:44 +0200, Aleksandar Ristovski wrote: > >[...] > >>--- a/gdb/solib-svr4.c > >>+++ b/gdb/solib-svr4.c > >[...] [...] > >>+ if (target_read_memory (bfd_get_section_vma (so->abfd, asec) > >>+ + lm_addr_check (so, so->abfd), > > > >I see it is the most easy one how to get the target VMA of the options we were > >discussing. > > I do not parse this unambiguously... did you mean this is the > easiest way of getting target VMA? If so, I agree. Yes. > >>+ { > >>+ build_idsz > >>+ = extract_unsigned_integer ((gdb_byte *) note->descsz, > >>+ sizeof (note->descsz), > >>+ byte_order); > >>+ > >>+ if (build_idsz == elf_tdata (so->abfd)->build_id->size) > >>+ { > >>+ const char gnu[4] = "GNU\0"; > >>+ > >>+ if (memcmp (note->name, gnu, 4) == 0) > >>+ { > >>+ ULONGEST namesz > >>+ = extract_unsigned_integer ((gdb_byte *) note->namesz, > >>+ sizeof (note->namesz), > >>+ byte_order); > >>+ CORE_ADDR build_id_offs; > >>+ > >>+ /* Rounded to next sizeof (ElfXX_Word). */ > >>+ namesz = ((namesz + (sizeof (note->namesz) - 1)) > >>+ & ~((ULONGEST) (sizeof (note->namesz) - 1))); > > > >Like in the previous patch the rounding should be 4 bytes according to the > >standard. Not a sizeof of anything. > > Yes, I re-read it, you are right: it is 4 byte aligned. Somehow I > remembered it as Word aligned. But I do not see it fixed (to use literal constant 4) in solib-svr4.c. (Checking your GIT branch, not your posted patch, I hope they match.) > >>+ warning (_("Shared object \"%s\" could not be validated " > >>+ "and will be ignored."), so->so_name); > > > >Maybe the warning should by printed by svr4_validate stating the build-id does > >not match (even possibly printing the both build-ids). And then sure one can > >remove the warning here. > > I was thinking about that, but then decided that svr4_validate > should simply provide an answer, not print warnings. User of the > function should warn if appropriate (as is done in the patch). The problem is what end-user will do with a situation GDB prints Shared object \"%s\" could not be validated and will be ignored. and the symbols are missing? The user has to start investigating target and local shared library, it would be easier if GDB already printed both local and remote build-ids which it already knows. It may be easier for user to check it then. Or why don't you find useful to print both build-ids? Not a blocker, one can easily change the message in the future depending on how it will be useful in practice. > This is along the lines of (see below) using build-id for e.g. > finding separate debug info etc... When there are problems finding separate debug info it is already difficult to troubleshoot, I commonly use strace on gdb, that could be also improved (that is sure very unrelated to your current patchset). > >>@@ -551,6 +562,7 @@ free_so (struct so_list *so) > >> { > >> struct target_so_ops *ops = solib_ops (target_gdbarch ()); > >> > >>+ xfree (so->build_id); > >> free_so_symbols (so); > >> ops->free_so (so); > >> > > > >I already wrote: > > > >The problem is there is: > > xfree (so->build_id); > >in free_so() but it should be in free_so_symbols instead. free_so_symbols is > >called also from reload_shared_libraries_1 where so_list->abfd can change. > >Then obviously one should also set so->build_id = NULL there. > > > I'm not sure I follow this. In cases where so->build_id is > determined it is good for the lifetime of the 'so', not symbols. It > can not change for the given 'so'. OK, I take my comment back. You are right current svr4_validate() never stores the linux-nat-mode fetched build-id into so_list. so_list->build_id contains only build-id from gdbserver which is always right. Therefore I agree xfree in free_so is OK. > >I was thinking making the BUILD_ID data private so solib-svr4.c but that is > >currently not possible, lm_info is private for solib-svr4.c but that has > >lifetime of so_list, not the lifetime of so_list->abfd. > > > I was thinking slightly differently: build-id should be generalized > to represent "an ID". For svr4, it is build-id, for some other > system it might be something else, but if present, should represent > the connection between target binary, binary at hand and associated > optional separate debug info. Not comment "what if" but currently there is no solib-backend-specific subpart of so_list which is not trashed during reread_symbols (like so_list->lm_info is) so there isn't where else to place the gdbserver build_id field now. Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 0/8] v2 - validate binary before use 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (7 preceding siblings ...) 2013-04-09 17:50 ` [PATCH 7/8] Validate " Aleksandar Ristovski @ 2013-04-09 17:53 ` Jan Kratochvil 2013-04-09 18:09 ` Aleksandar Ristovski 2013-04-16 18:03 ` Aleksandar Ristovski 9 siblings, 1 reply; 42+ messages in thread From: Jan Kratochvil @ 2013-04-09 17:53 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 09 Apr 2013 17:27:37 +0200, Aleksandar Ristovski wrote: > Core support: > - core will use second method. Note, however, that due to (at least > on ubuntu) not dumping page containing buid-id in the core, the > validation can not be performed (it will always default to valid). > This is misfortunate but outside the scope of this patch. FYI it is bit 4 in /proc/self/coredump_filter, Fedora has the default 0x33. It is configured for Linux kernel by: linux-2.6/fs/Kconfig.binfmt CORE_DUMP_DEFAULT_ELF_HEADERS One can simulate it if not pre-configured: echo 0x33 >/proc/self/coredump_filter Regards, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 0/8] v2 - validate binary before use 2013-04-09 17:53 ` [PATCH 0/8] v2 - validate binary before use Jan Kratochvil @ 2013-04-09 18:09 ` Aleksandar Ristovski 0 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-09 18:09 UTC (permalink / raw) To: Jan Kratochvil; +Cc: gdb-patches On 13-04-09 11:36 AM, Jan Kratochvil wrote: > On Tue, 09 Apr 2013 17:27:37 +0200, Aleksandar Ristovski wrote: >> Core support: >> - core will use second method. Note, however, that due to (at least >> on ubuntu) not dumping page containing buid-id in the core, the >> validation can not be performed (it will always default to valid). >> This is misfortunate but outside the scope of this patch. > > FYI it is bit 4 in /proc/self/coredump_filter, Fedora has the default 0x33. > > It is configured for Linux kernel by: > linux-2.6/fs/Kconfig.binfmt CORE_DUMP_DEFAULT_ELF_HEADERS > > One can simulate it if not pre-configured: > echo 0x33 >/proc/self/coredump_filter > Good to know. Thanks. In that case, it will be picked up by normal target_read_memory (second method). --- Aleksandar ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 0/8] v2 - validate binary before use 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski ` (8 preceding siblings ...) 2013-04-09 17:53 ` [PATCH 0/8] v2 - validate binary before use Jan Kratochvil @ 2013-04-16 18:03 ` Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski ` (7 more replies) 9 siblings, 8 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:03 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski This is a respin, addressed Jan's comments from: http://sourceware.org/ml/gdb-patches/2013-04/msg00400.html http://sourceware.org/ml/gdb-patches/2013-04/msg00401.html http://sourceware.org/ml/gdb-patches/2013-04/msg00402.html http://sourceware.org/ml/gdb-patches/2013-04/msg00403.html http://sourceware.org/ml/gdb-patches/2013-04/msg00404.html Thanks, Aleksandar Ristovski QNX Software Systems ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 2/8] Merge multiple hex conversions 2013-04-16 18:03 ` Aleksandar Ristovski @ 2013-04-16 18:30 ` Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 7/8] Validate symbol file using build-id Aleksandar Ristovski ` (6 subsequent siblings) 7 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:30 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * common/common-utils.c (fromhex): Make externally linkable. Change error message. (tohex): Make externally linkable. * common/common-utils.h (fromhex, tohex): New declaration. * gdbserver/gdbreplay.c (tohex): Rename to 'fromhex'. (logchar): Use fromhex. * gdbserver/remote-utils.c (fromhex, unhexify): Remove. (tohex, hexify): Remove. (look_up_one_symbol, monitor_output): Use bin2hex instead of hexify. * gdbserver/server.c (handle_query): Use bin2hex instead of hexify. (handle_v_run): Ditto. * gdbserver/server.h (unhexify, hexify): Remove declarations. * gdbserver/tracepoint.c (cmd_qtdpsrc, cmd_qtdv): Use hex2bin instead of unhexify. (cmd_qtstatus): Use bin2hex instead of hexify. (cmd_qtnotes): Use hex2bin instead of unhexify. * monitor.c (fromhex): Remove definition. * remote.c (tohex, fromhex): Remove fwd declarations, remove definitions. --- gdb/common/common-utils.c | 6 ++-- gdb/common/common-utils.h | 4 +++ gdb/gdbserver/gdbreplay.c | 6 ++-- gdb/gdbserver/remote-utils.c | 67 ++---------------------------------------- gdb/gdbserver/server.c | 5 ++-- gdb/gdbserver/server.h | 2 -- gdb/gdbserver/tracepoint.c | 16 +++++----- gdb/monitor.c | 15 ---------- gdb/remote.c | 30 ------------------- 9 files changed, 24 insertions(+), 127 deletions(-) diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c index 5e96692..c123ed7 100644 --- a/gdb/common/common-utils.c +++ b/gdb/common/common-utils.c @@ -264,7 +264,7 @@ strtoulst (const char *num, const char **trailer, int base) /* Convert hex digit A to a number. */ -static int +int fromhex (int a) { if (a >= '0' && a <= '9') @@ -274,7 +274,7 @@ fromhex (int a) else if (a >= 'A' && a <= 'F') return a - 'A' + 10; else - error (_("Reply contains invalid hex digit %d"), a); + error (_("Invalid hex digit %d"), a); } int @@ -298,7 +298,7 @@ hex2bin (const char *hex, gdb_byte *bin, int count) /* Convert number NIB to a hex digit. */ -static int +int tohex (int nib) { if (nib < 10) diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h index ee7870e..2c95d34 100644 --- a/gdb/common/common-utils.h +++ b/gdb/common/common-utils.h @@ -74,6 +74,10 @@ char *savestring (const char *ptr, size_t len); ULONGEST strtoulst (const char *num, const char **trailer, int base); +extern int fromhex (int a); + +extern int tohex (int nib); + extern int hex2bin (const char *hex, gdb_byte *bin, int count); extern int bin2hex (const gdb_byte *bin, char *hex, int count); diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c index 0aa52d8..d0ff8c4 100644 --- a/gdb/gdbserver/gdbreplay.c +++ b/gdb/gdbserver/gdbreplay.c @@ -273,7 +273,7 @@ remote_open (char *name) } static int -tohex (int ch) +fromhex (int ch) { if (ch >= '0' && ch <= '9') { @@ -336,11 +336,11 @@ logchar (FILE *fp) ch2 = fgetc (fp); fputc (ch2, stdout); fflush (stdout); - ch = tohex (ch2) << 4; + ch = fromhex (ch2) << 4; ch2 = fgetc (fp); fputc (ch2, stdout); fflush (stdout); - ch |= tohex (ch2); + ch |= fromhex (ch2); break; default: /* Treat any other char as just itself */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 42c6a54..6ff491e 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -416,20 +416,6 @@ remote_close (void) reset_readchar (); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else - error ("Reply contains invalid hex digit"); - return 0; -} - #endif static const char hexchars[] = "0123456789abcdef"; @@ -457,25 +443,6 @@ ishex (int ch, int *val) #ifndef IN_PROCESS_AGENT -int -unhexify (char *bin, const char *hex, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - if (hex[0] == 0 || hex[1] == 0) - { - /* Hex string is short, or of uneven length. - Return the count that has been converted so far. */ - return i; - } - *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - return i; -} - void decode_address (CORE_ADDR *addrp, const char *start, int len) { @@ -511,37 +478,8 @@ decode_address_to_semicolon (CORE_ADDR *addrp, const char *start) #endif -/* Convert number NIB to a hex digit. */ - -static int -tohex (int nib) -{ - if (nib < 10) - return '0' + nib; - else - return 'a' + nib - 10; -} - #ifndef IN_PROCESS_AGENT -int -hexify (char *hex, const char *bin, int count) -{ - int i; - - /* May use a length, or a nul-terminated string as input. */ - if (count == 0) - count = strlen (bin); - - for (i = 0; i < count; i++) - { - *hex++ = tohex ((*bin >> 4) & 0xf); - *hex++ = tohex (*bin++ & 0xf); - } - *hex = 0; - return i; -} - /* Convert BUFFER, binary data at least LEN bytes long, into escaped binary data in OUT_BUF. Set *OUT_LEN to the length of the data encoded in OUT_BUF, and return the number of bytes in OUT_BUF @@ -1608,7 +1546,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) /* Send the request. */ strcpy (own_buf, "qSymbol:"); - hexify (own_buf + strlen ("qSymbol:"), name, strlen (name)); + bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"), + strlen (name)); if (putpkt (own_buf) < 0) return -1; @@ -1770,7 +1709,7 @@ monitor_output (const char *msg) char *buf = xmalloc (strlen (msg) * 2 + 2); buf[0] = 'O'; - hexify (buf + 1, msg, 0); + bin2hex ((const gdb_byte *) msg, buf + 1, 0); putpkt (buf); free (buf); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 6bb36d8..8b586dd 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1920,7 +1920,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } - if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2) + if ((len % 2) != 0 + || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2) { write_enn (own_buf); free (mon); @@ -2214,7 +2215,7 @@ handle_v_run (char *own_buf) { /* FIXME: Fail request if out of memory instead of dying. */ new_argv[i] = xmalloc (1 + (next_p - p) / 2); - unhexify (new_argv[i], p, (next_p - p) / 2); + hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2); new_argv[i][(next_p - p) / 2] = '\0'; } diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 139cd49..5e16088 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -322,8 +322,6 @@ int decode_search_memory_packet (const char *buf, int packet_len, gdb_byte *pattern, unsigned int *pattern_lenp); -int unhexify (char *bin, const char *hex, int count); -int hexify (char *hex, const char *bin, int count); int remote_escape_output (const gdb_byte *buffer, int len, gdb_byte *out_buf, int *out_len, int out_maxlen); diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 419765b..f48e3b6 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -2679,7 +2679,7 @@ cmd_qtdpsrc (char *own_buf) packet = unpack_varlen_hex (packet, &slen); ++packet; /* skip a colon */ src = xmalloc (slen + 1); - nbytes = unhexify (src, packet, strlen (packet) / 2); + nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2); src[nbytes] = '\0'; newlast = xmalloc (sizeof (struct source_string)); @@ -2721,7 +2721,7 @@ cmd_qtdv (char *own_buf) nbytes = strlen (packet) / 2; varname = xmalloc (nbytes + 1); - nbytes = unhexify (varname, packet, nbytes); + nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes); varname[nbytes] = '\0'; tsv = create_trace_state_variable (num, 1); @@ -3594,17 +3594,17 @@ cmd_qtstatus (char *packet) str = (tracing_user_name ? tracing_user_name : ""); slen = strlen (str); buf1 = (char *) alloca (slen * 2 + 1); - hexify (buf1, str, slen); + bin2hex ((const gdb_byte *) str, buf1, slen); str = (tracing_notes ? tracing_notes : ""); slen = strlen (str); buf2 = (char *) alloca (slen * 2 + 1); - hexify (buf2, str, slen); + bin2hex ((const gdb_byte *) str, buf2, slen); str = (tracing_stop_note ? tracing_stop_note : ""); slen = strlen (str); buf3 = (char *) alloca (slen * 2 + 1); - hexify (buf3, str, slen); + bin2hex ((const gdb_byte *) str, buf3, slen); trace_debug ("Returning trace status as %d, stop reason %s", tracing, tracing_stop_reason); @@ -4078,7 +4078,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; user = xmalloc (nbytes + 1); - nbytes = unhexify (user, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) user, nbytes); user[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("User is '%s'", user); @@ -4092,7 +4092,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; notes = xmalloc (nbytes + 1); - nbytes = unhexify (notes, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes); notes[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("Notes is '%s'", notes); @@ -4106,7 +4106,7 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; stopnote = xmalloc (nbytes + 1); - nbytes = unhexify (stopnote, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes); stopnote[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("tstop note is '%s'", stopnote); diff --git a/gdb/monitor.c b/gdb/monitor.c index 0337075..c3c623b 100644 --- a/gdb/monitor.c +++ b/gdb/monitor.c @@ -226,21 +226,6 @@ monitor_error (char *function, char *message, message, safe_string); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error (_("Invalid hex digit %d"), a); -} - /* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses This function exists to get around the problem that many host platforms diff --git a/gdb/remote.c b/gdb/remote.c index 8f74b55..64a79e3 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -126,8 +126,6 @@ static void remote_serial_write (const char *str, int len); static void remote_kill (struct target_ops *ops); -static int tohex (int nib); - static int remote_can_async_p (void); static int remote_is_async_p (void); @@ -184,8 +182,6 @@ static void remote_find_new_threads (void); static void record_currthread (ptid_t currthread); -static int fromhex (int a); - static int putpkt_binary (char *buf, int cnt); static void check_binary_download (CORE_ADDR addr); @@ -4554,32 +4550,6 @@ extended_remote_attach (struct target_ops *ops, char *args, int from_tty) extended_remote_attach_1 (ops, args, from_tty); } -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error (_("Reply contains invalid hex digit %d"), a); -} - -/* Convert number NIB to a hex digit. */ - -static int -tohex (int nib) -{ - if (nib < 10) - return '0' + nib; - else - return 'a' + nib - 10; -} - \f /* Check for the availability of vCont. This function should also check the response. */ -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 7/8] Validate symbol file using build-id. 2013-04-16 18:03 ` Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski @ 2013-04-16 18:30 ` Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski ` (5 subsequent siblings) 7 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:30 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * solib-darwin.c (_initialize_darwin_solib): Assign validate value. * solib-dsbt.c (_initialize_dsbt_solib): Ditto. * solib-frv.c (_initialize_frv_solib): Ditto. * solib-ia64-hpux.c (ia64_hpux_target_so_ops): Ditto. * solib-irix.c (_initialize_irix_solib): Ditto. * solib-osf.c (_initialize_osf_solib): Ditto. * solib-pa64.c (_initialize_pa64_solib): Ditto. * solib-som.c (_initialize_som_solib): Ditto. * solib-spu.c (set_spu_solib_ops): Ditto. * solib-sunos.c (_initialize_sunos_solib): Ditto. * solib-svr4.c (NOTE_GNU_BUILD_ID_NAME): New define. (svr4_validate): New function. (library_list_start_library): Parse 'build-id' attribute. (svr4_library_attributes): Add 'build-id' attribute. (_initialize_svr4_solib): Assign validate value. * solib-target.c (solib.h): Include. (_initialize_solib_target): Assign validate value. * solib.c (solib_map_sections): Use ops->validate. (free_so): Free build_id. (solib_validate): New function. * solib.h (solib_validate): New declaration. * solist.h (so_list): New fields 'build_idsz' and 'build_id'. (target_so_ops): New field 'validate'. --- gdb/solib-darwin.c | 1 + gdb/solib-dsbt.c | 1 + gdb/solib-frv.c | 1 + gdb/solib-ia64-hpux.c | 1 + gdb/solib-irix.c | 1 + gdb/solib-osf.c | 1 + gdb/solib-pa64.c | 1 + gdb/solib-som.c | 1 + gdb/solib-spu.c | 1 + gdb/solib-sunos.c | 1 + gdb/solib-svr4.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ gdb/solib-target.c | 2 + gdb/solib.c | 20 +++++++ gdb/solib.h | 4 ++ gdb/solist.h | 14 +++++ 15 files changed, 188 insertions(+) diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index b9a4be1..ff57016 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -647,4 +647,5 @@ _initialize_darwin_solib (void) darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code; darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol; darwin_so_ops.bfd_open = darwin_bfd_open; + darwin_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index e2822c1..6cadf82 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -1182,6 +1182,7 @@ _initialize_dsbt_solib (void) dsbt_so_ops.open_symbol_file_object = open_symbol_file_object; dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code; dsbt_so_ops.bfd_open = solib_bfd_open; + dsbt_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance, diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index 52588bc..741ede5 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -1182,6 +1182,7 @@ _initialize_frv_solib (void) frv_so_ops.open_symbol_file_object = open_symbol_file_object; frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code; frv_so_ops.bfd_open = solib_bfd_open; + frv_so_ops.validate = default_solib_validate; /* Debug this file's internals. */ add_setshow_zuinteger_cmd ("solib-frv", class_maintenance, diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c index 67085d7..6fb146c 100644 --- a/gdb/solib-ia64-hpux.c +++ b/gdb/solib-ia64-hpux.c @@ -686,6 +686,7 @@ ia64_hpux_target_so_ops (void) ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; ops->bfd_open = solib_bfd_open; + ops->validate = default_solib_validate; return ops; } diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c index af3e7d6..871fb19 100644 --- a/gdb/solib-irix.c +++ b/gdb/solib-irix.c @@ -652,4 +652,5 @@ _initialize_irix_solib (void) irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object; irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code; irix_so_ops.bfd_open = solib_bfd_open; + irix_so_ops.validate = default_solib_validate; } diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c index d05c5c1..5b1cd0b 100644 --- a/gdb/solib-osf.c +++ b/gdb/solib-osf.c @@ -633,6 +633,7 @@ _initialize_osf_solib (void) osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object; osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code; osf_so_ops.bfd_open = solib_bfd_open; + osf_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &osf_so_ops; diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c index f646cfb..795bcda 100644 --- a/gdb/solib-pa64.c +++ b/gdb/solib-pa64.c @@ -621,6 +621,7 @@ _initialize_pa64_solib (void) pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; pa64_so_ops.bfd_open = solib_bfd_open; + pa64_so_ops.validate = default_solib_validate; memset (&dld_cache, 0, sizeof (dld_cache)); } diff --git a/gdb/solib-som.c b/gdb/solib-som.c index 650e3df..2fbf0a2 100644 --- a/gdb/solib-som.c +++ b/gdb/solib-som.c @@ -811,6 +811,7 @@ _initialize_som_solib (void) som_so_ops.open_symbol_file_object = som_open_symbol_file_object; som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; som_so_ops.bfd_open = solib_bfd_open; + som_so_ops.validate = default_solib_validate; } void diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index fc9dcda..27d6fa6 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -521,6 +521,7 @@ set_spu_solib_ops (struct gdbarch *gdbarch) spu_so_ops.current_sos = spu_current_sos; spu_so_ops.bfd_open = spu_bfd_open; spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol; + spu_so_ops.validate = default_solib_validate; } set_solib_ops (gdbarch, &spu_so_ops); diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c index 5863fc2..71c8ee3 100644 --- a/gdb/solib-sunos.c +++ b/gdb/solib-sunos.c @@ -738,6 +738,7 @@ _initialize_sunos_solib (void) sunos_so_ops.open_symbol_file_object = open_symbol_file_object; sunos_so_ops.in_dynsym_resolve_code = sunos_in_dynsym_resolve_code; sunos_so_ops.bfd_open = solib_bfd_open; + sunos_so_ops.validate = default_solib_validate; /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ current_target_so_ops = &sunos_so_ops; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index bb2a4e9..d576245 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -47,6 +47,8 @@ #include "exceptions.h" #include "gdb_bfd.h" +#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id" + static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); static void svr4_relocate_main_executable (void); @@ -871,6 +873,118 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) return (name_lm >= vaddr && name_lm < vaddr + size); } +/* Validate SO by comparing build-id from the associated bfd and + corresponding build-id from target memory. */ + +static int +svr4_validate (const struct so_list *const so) +{ + gdb_byte *build_id; + size_t build_idsz; + size_t abfd_build_idsz; + + gdb_assert (so != NULL); + + if (so->abfd == NULL) + return 1; + + if (!bfd_check_format (so->abfd, bfd_object) + || bfd_get_flavour (so->abfd) != bfd_target_elf_flavour + || elf_tdata (so->abfd)->build_id == NULL) + return 1; + + build_id = so->build_id; + build_idsz = so->build_idsz; + abfd_build_idsz = elf_tdata (so->abfd)->build_id->size; + + if (build_id == NULL) + { + /* Get build_id from NOTE_GNU_BUILD_ID_NAME section. + This is a fallback mechanism for targets that do not + implement TARGET_OBJECT_SOLIB_SVR4. */ + + const asection *const asec + = bfd_get_section_by_name (so->abfd, NOTE_GNU_BUILD_ID_NAME); + ULONGEST bfd_sect_size; + + if (asec == NULL) + return 1; + + bfd_sect_size = bfd_get_section_size (asec); + + if ((asec->flags & SEC_LOAD) == SEC_LOAD + && bfd_sect_size != 0 + && strcmp (bfd_section_name (asec->bfd, asec), + NOTE_GNU_BUILD_ID_NAME) == 0) + { + const enum bfd_endian byte_order + = gdbarch_byte_order (target_gdbarch ()); + Elf_External_Note *const note = xmalloc (bfd_sect_size); + gdb_byte *const note_raw = (void *) note; + struct cleanup *cleanups = make_cleanup (xfree, note); + + if (target_read_memory (bfd_get_section_vma (so->abfd, asec) + + lm_addr_check (so, so->abfd), + note_raw, bfd_sect_size) == 0) + { + build_idsz + = extract_unsigned_integer ((gdb_byte *) note->descsz, + sizeof (note->descsz), + byte_order); + + if (build_idsz == abfd_build_idsz) + { + const char gnu[4] = "GNU\0"; + + if (memcmp (note->name, gnu, 4) == 0) + { + ULONGEST namesz + = extract_unsigned_integer ((gdb_byte *) note->namesz, + sizeof (note->namesz), + byte_order); + CORE_ADDR build_id_offs; + + /* Rounded to next sizeof (ElfXX_Word). */ + namesz = ((namesz + (sizeof (note->namesz) - 1)) + & ~((ULONGEST) (sizeof (note->namesz) - 1))); + build_id_offs = (offsetof (Elf_External_Note, name) + + namesz); + build_id = xmalloc (build_idsz); + memcpy (build_id, note_raw + build_id_offs, build_idsz); + } + } + + if (build_id == NULL) + { + /* If we are here, it means target memory read succeeded + but note was not where it was expected according to the + abfd. Allow the logic below to perform the check + with an impossible build-id and fail validation. */ + build_idsz = 0; + build_id = xstrdup (""); + } + + } + do_cleanups (cleanups); + } + } + + if (build_id != NULL) + { + const int match + = (abfd_build_idsz == build_idsz + && memcmp (build_id, elf_tdata (so->abfd)->build_id->data, + build_idsz) == 0); + + if (build_id != so->build_id) + xfree (build_id); + + return match; + } + + return 1; +} + /* Implement the "open_symbol_file_object" target_so_ops method. If no open symbol file, attempt to locate and open the main symbol @@ -999,6 +1113,9 @@ library_list_start_library (struct gdb_xml_parser *parser, ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; + const struct gdb_xml_value *const att_build_id + = xml_find_attribute (attributes, "build-id"); + const char *const hex_build_id = att_build_id ? att_build_id->value : NULL; struct so_list *new_elem; new_elem = XZALLOC (struct so_list); @@ -1010,6 +1127,25 @@ library_list_start_library (struct gdb_xml_parser *parser, strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; strcpy (new_elem->so_original_name, new_elem->so_name); + if (hex_build_id != NULL) + { + const size_t hex_build_id_len = strlen (hex_build_id); + + if (hex_build_id_len > 0 && (hex_build_id_len & 1U) == 0) + { + const size_t build_idsz = hex_build_id_len / 2; + + new_elem->build_id = xmalloc (build_idsz); + new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id, + build_idsz); + if (new_elem->build_idsz != build_idsz) + { + xfree (new_elem->build_id); + new_elem->build_id = NULL; + new_elem->build_idsz = 0; + } + } + } *list->tailp = new_elem; list->tailp = &new_elem->next; @@ -1044,6 +1180,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] = { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; @@ -2458,4 +2595,5 @@ _initialize_svr4_solib (void) svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; svr4_so_ops.same = svr4_same; svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; + svr4_so_ops.validate = svr4_validate; } diff --git a/gdb/solib-target.c b/gdb/solib-target.c index 0ad29ba..b67509f 100644 --- a/gdb/solib-target.c +++ b/gdb/solib-target.c @@ -25,6 +25,7 @@ #include "target.h" #include "vec.h" #include "solib-target.h" +#include "solib.h" #include "gdb_string.h" @@ -501,6 +502,7 @@ _initialize_solib_target (void) solib_target_so_ops.in_dynsym_resolve_code = solib_target_in_dynsym_resolve_code; solib_target_so_ops.bfd_open = solib_bfd_open; + solib_target_so_ops.validate = default_solib_validate; /* Set current_target_so_ops to solib_target_so_ops if not already set. */ diff --git a/gdb/solib.c b/gdb/solib.c index 6978677..9950338 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -465,6 +465,17 @@ solib_map_sections (struct so_list *so) /* Leave bfd open, core_xfer_memory and "info files" need it. */ so->abfd = abfd; + gdb_assert (ops->validate != NULL); + + if (!ops->validate (so)) + { + warning (_("Shared object \"%s\" could not be validated " + "and will be ignored."), so->so_name); + gdb_bfd_unref (so->abfd); + so->abfd = NULL; + return 0; + } + if (build_section_table (abfd, &so->sections, &so->sections_end)) { error (_("Can't find the file sections in `%s': %s"), @@ -545,6 +556,7 @@ free_so (struct so_list *so) { struct target_so_ops *ops = solib_ops (target_gdbarch ()); + xfree (so->build_id); free_so_symbols (so); ops->free_so (so); @@ -1442,6 +1454,14 @@ gdb_bfd_lookup_symbol (bfd *abfd, return symaddr; } +/* Default implementation does not perform any validation. */ + +int +default_solib_validate (const struct so_list *const so) +{ + return 1; /* No validation. */ +} + extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */ void diff --git a/gdb/solib.h b/gdb/solib.h index b811866..670949a 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -90,4 +90,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, void *), void *data); +/* Default validation always returns 1. */ + +extern int default_solib_validate (const struct so_list *so); + #endif /* SOLIB_H */ diff --git a/gdb/solist.h b/gdb/solist.h index f784fc3..72e003d 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -75,6 +75,16 @@ struct so_list There may not be just one (e.g. if two segments are relocated differently); but this is only used for "info sharedlibrary". */ CORE_ADDR addr_low, addr_high; + + /* Build id in raw format, contains verbatim contents of + .note.gnu.build-id including note header. This is actual + BUILD_ID which comes either from the remote target via qXfer + packet or via reading target memory. Therefore, it may differ + from the build-id of the associated bfd. In a normal + scenario, this so would soon lose its abfd due to failed + validation. */ + size_t build_idsz; + gdb_byte *build_id; }; struct target_so_ops @@ -148,6 +158,10 @@ struct target_so_ops core file (in particular, for readonly sections). */ int (*keep_data_in_core) (CORE_ADDR vaddr, unsigned long size); + + /* Return 0 if SO does not match target SO it is supposed to + represent. Return 1 otherwise. */ + int (*validate) (const struct so_list *so); }; /* Free the memory associated with a (so_list *). */ -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move 2013-04-16 18:03 ` Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 7/8] Validate symbol file using build-id Aleksandar Ristovski @ 2013-04-16 18:31 ` Aleksandar Ristovski 2013-04-18 8:58 ` Jan Kratochvil 2013-04-16 18:31 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski ` (4 subsequent siblings) 7 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:31 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * linux-tdep.c (linux_find_memory_region_ftype): Comment. (linux_find_memory_regions_full): Change signature and prepare for moving to linux-maps. (linux_find_memory_regions_data): Rename field 'obfd' to 'data'. (linux_find_memory_regions_thunk): New. (linux_find_memory_regions_thunk): Use 'data' field instead of 'obfd'. (linux_find_memory_regions_gdb): New. (linux_find_memory_regions): Rename argument 'obfd' to 'func_data'. (linux_make_mappings_corefile_notes): Use linux_find_memory_regions_gdb. * target.c (read_alloc_pread_ftype): New typedef. (target_fileio_read_alloc_1_pread): New function. (read_alloc): Refactor from target_fileio_read_alloc_1. (read_stralloc_func_ftype): New typedef. (target_fileio_read_alloc_1): New implementation. Use read_alloc. (read_stralloc): Refactored from target_fileio_read_stralloc. (target_fileio_read_stralloc): New implementation, use read_stralloc. --- gdb/linux-tdep.c | 98 +++++++++++++++++++++++++++++++++++--------------- gdb/target.c | 106 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 146 insertions(+), 58 deletions(-) diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 9def108..77c98d2 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -661,6 +661,10 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args, error (_("unable to handle request")); } +/* Callback function for linux_find_memory_regions_full. If it returns + non-zero linux_find_memory_regions_full returns immediately with that + value. */ + typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, ULONGEST offset, ULONGEST inode, int read, int write, @@ -668,34 +672,41 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, const char *filename, void *data); -/* List memory regions in the inferior for a corefile. */ +/* List memory regions in the inferior PID for a corefile. Call FUNC + with FUNC_DATA for each such region. Return immediately with the + value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should + be registered to be freed automatically if called FUNC throws an + exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is + not used. Return -1 if error occurs, 0 if all memory regions have + been processed or return the value from FUNC if FUNC returns + non-zero. */ static int -linux_find_memory_regions_full (struct gdbarch *gdbarch, - linux_find_memory_region_ftype *func, - void *obfd) +linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr) { char mapsfilename[100]; - gdb_byte *data; - - /* We need to know the real target PID to access /proc. */ - if (current_inferior ()->fake_pid_p) - return 1; + char *data; - xsnprintf (mapsfilename, sizeof mapsfilename, - "/proc/%d/smaps", current_inferior ()->pid); + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); data = target_fileio_read_stralloc (mapsfilename); if (data == NULL) { /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, - "/proc/%d/maps", current_inferior ()->pid); + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", + (int) pid); data = target_fileio_read_stralloc (mapsfilename); } if (data) { - struct cleanup *cleanup = make_cleanup (xfree, data); char *line; + int retval = 0; + + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = data; + } line = strtok (data, "\n"); while (line) @@ -752,15 +763,22 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch, modified = 1; /* Invoke the callback function to create the corefile segment. */ - func (addr, endaddr - addr, offset, inode, - read, write, exec, modified, filename, obfd); + retval = func (addr, endaddr - addr, offset, inode, + read, write, exec, modified, filename, func_data); + if (retval != 0) + break; } - do_cleanups (cleanup); - return 0; + if (memory_to_free_ptr != NULL) + { + gdb_assert (data == *memory_to_free_ptr); + *memory_to_free_ptr = NULL; + } + xfree (data); + return retval; } - return 1; + return -1; } /* A structure for passing information through @@ -774,9 +792,11 @@ struct linux_find_memory_regions_data /* The original datum. */ - void *obfd; + void *data; }; +static linux_find_memory_region_ftype linux_find_memory_regions_thunk; + /* A callback for linux_find_memory_regions that converts between the "full"-style callback and find_memory_region_ftype. */ @@ -788,7 +808,30 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size, { struct linux_find_memory_regions_data *data = arg; - return data->func (vaddr, size, read, write, exec, modified, data->obfd); + return data->func (vaddr, size, read, write, exec, modified, data->data); +} + +/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */ + +static int +linux_find_memory_regions_gdb (struct gdbarch *gdbarch, + linux_find_memory_region_ftype *func, + void *func_data) +{ + void *memory_to_free = NULL; + struct cleanup *cleanup; + int retval; + + /* We need to know the real target PID so + linux_find_memory_regions_full can access /proc. */ + if (current_inferior ()->fake_pid_p) + return 1; + + cleanup = make_cleanup (free_current_contents, &memory_to_free); + retval = linux_find_memory_regions_full (current_inferior ()->pid, + func, func_data, &memory_to_free); + do_cleanups (cleanup); + return retval; } /* A variant of linux_find_memory_regions_full that is suitable as the @@ -796,16 +839,15 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size, static int linux_find_memory_regions (struct gdbarch *gdbarch, - find_memory_region_ftype func, void *obfd) + find_memory_region_ftype func, void *func_data) { struct linux_find_memory_regions_data data; data.func = func; - data.obfd = obfd; + data.data = func_data; - return linux_find_memory_regions_full (gdbarch, - linux_find_memory_regions_thunk, - &data); + return linux_find_memory_regions_gdb (gdbarch, + linux_find_memory_regions_thunk, &data); } /* Determine which signal stopped execution. */ @@ -987,8 +1029,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, pack_long (buf, long_type, 1); obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type)); - linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback, - &mapping_data); + linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback, + &mapping_data); if (mapping_data.file_count != 0) { diff --git a/gdb/target.c b/gdb/target.c index 8f8e46a..33afe2b 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -3476,6 +3476,22 @@ target_fileio_close_cleanup (void *opaque) target_fileio_close (fd, &target_errno); } +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno); + +static read_alloc_pread_ftype target_fileio_read_alloc_1_pread; + +/* Helper for target_fileio_read_alloc_1 to make it interruptible. */ + +static int +target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno) +{ + QUIT; + + return target_fileio_pread (handle, read_buf, len, offset, target_errno); +} + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. PADDING additional bytes are available in *BUF_P. This is a helper function for @@ -3483,48 +3499,46 @@ target_fileio_close_cleanup (void *opaque) information. */ static LONGEST -target_fileio_read_alloc_1 (const char *filename, - gdb_byte **buf_p, int padding) +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, + int padding, void **memory_to_free_ptr) { - struct cleanup *close_cleanup; size_t buf_alloc, buf_pos; gdb_byte *buf; LONGEST n; - int fd; int target_errno; - fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); - if (fd == -1) - return -1; - - close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); - /* 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); + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = buf; + } buf_pos = 0; while (1) { - n = target_fileio_pread (fd, &buf[buf_pos], - buf_alloc - buf_pos - padding, buf_pos, - &target_errno); - if (n < 0) + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, + buf_pos, &target_errno); + if (n <= 0) { - /* An error occurred. */ - do_cleanups (close_cleanup); - xfree (buf); - return -1; - } - else if (n == 0) - { - /* Read all there was. */ - do_cleanups (close_cleanup); - if (buf_pos == 0) + if (n < 0 || (n == 0 && buf_pos == 0)) xfree (buf); else *buf_p = buf; - return buf_pos; + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = NULL; + if (n < 0) + { + /* An error occurred. */ + return -1; + } + else + { + /* Read all there was. */ + return buf_pos; + } } buf_pos += n; @@ -3534,12 +3548,39 @@ target_fileio_read_alloc_1 (const char *filename, { buf_alloc *= 2; buf = xrealloc (buf, buf_alloc); + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = buf; } - - QUIT; } } +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); + +static read_stralloc_func_ftype target_fileio_read_alloc_1; + +static LONGEST +target_fileio_read_alloc_1 (const char *filename, + gdb_byte **buf_p, int padding) +{ + struct cleanup *close_cleanup; + int fd, target_errno; + void *memory_to_free = NULL; + LONGEST retval; + + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); + if (fd == -1) + return -1; + + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); + + make_cleanup (free_current_contents, &memory_to_free); + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding, + &memory_to_free); + do_cleanups (close_cleanup); + return retval; +} + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. See the declaration in "target.h" function for more information about the return value. */ @@ -3556,14 +3597,14 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) are returned as allocated but empty strings. A warning is issued if the result contains any embedded NUL bytes. */ -char * -target_fileio_read_stralloc (const char *filename) +static char * +read_stralloc (const char *filename, read_stralloc_func_ftype *func) { gdb_byte *buffer; char *bufstr; LONGEST i, transferred; - transferred = target_fileio_read_alloc_1 (filename, &buffer, 1); + transferred = func (filename, &buffer, 1); bufstr = (char *) buffer; if (transferred < 0) @@ -3587,6 +3628,11 @@ target_fileio_read_stralloc (const char *filename) return bufstr; } +char * +target_fileio_read_stralloc (const char *filename) +{ + return read_stralloc (filename, target_fileio_read_alloc_1); +} static int default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move 2013-04-16 18:31 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski @ 2013-04-18 8:58 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 8:58 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:44:52 +0200, Aleksandar Ristovski wrote: [...] > --- a/gdb/target.c > +++ b/gdb/target.c > @@ -3476,6 +3476,22 @@ target_fileio_close_cleanup (void *opaque) > target_fileio_close (fd, &target_errno); > } > > +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, > + ULONGEST offset, int *target_errno); This typedef is in the end duplicate both in target.c and in common/common-target.h. It should remain only in common/common-target.h. > + > +static read_alloc_pread_ftype target_fileio_read_alloc_1_pread; > + > +/* Helper for target_fileio_read_alloc_1 to make it interruptible. */ > + > +static int > +target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, > + ULONGEST offset, int *target_errno) > +{ > + QUIT; > + > + return target_fileio_pread (handle, read_buf, len, offset, target_errno); > +} > + > /* Read target file FILENAME. Store the result in *BUF_P and > return the size of the transferred data. PADDING additional bytes are > available in *BUF_P. This is a helper function for [...] > @@ -3534,12 +3548,39 @@ target_fileio_read_alloc_1 (const char *filename, > { > buf_alloc *= 2; > buf = xrealloc (buf, buf_alloc); > + if (memory_to_free_ptr != NULL) > + *memory_to_free_ptr = buf; > } > - > - QUIT; > } > } > > +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, > + gdb_byte **buf_p, int padding); This typedef is in the end duplicate both in target.c and in common/common-target.h. It should remain only in common/common-target.h. > + > +static read_stralloc_func_ftype target_fileio_read_alloc_1; > + > +static LONGEST > +target_fileio_read_alloc_1 (const char *filename, > + gdb_byte **buf_p, int padding) > +{ > + struct cleanup *close_cleanup; > + int fd, target_errno; > + void *memory_to_free = NULL; > + LONGEST retval; > + > + fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); > + if (fd == -1) > + return -1; > + > + close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); > + > + make_cleanup (free_current_contents, &memory_to_free); > + retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding, > + &memory_to_free); > + do_cleanups (close_cleanup); > + return retval; > +} > + > /* Read target file FILENAME. Store the result in *BUF_P and return > the size of the transferred data. See the declaration in "target.h" > function for more information about the return value. */ [...] Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 1/8] Move utility functions to common/ 2013-04-16 18:03 ` Aleksandar Ristovski ` (2 preceding siblings ...) 2013-04-16 18:31 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski @ 2013-04-16 18:31 ` Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski ` (3 subsequent siblings) 7 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:31 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * cli/cli-utils.c (skip_spaces, skip_spaces_const): Move defs to common/common-utils.c. * cli/cli-utils.h (skip_spaces, skip_spaces_const): Move decls to common/common-utils.h. * common/common-utils.c (ctype.h): Include. (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move from utils.c. (fromhex): Copy from remote.c. (hex2bin): Move from remote.c. (tohex): Copy from remote.c. (bin2hex): Move from remote.c. (skip_spaces, skip_spaces_const): Move from cli/cli-utils.c. * common/common-utils.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Moved from defs.h. (strtoulst): Move decl from utils.h. (hex2bin, bin2hex): Move decls from remote.h. (skip_spaces, skip_spaces_const): Move decls from cli/cli-utils.h. * defs.h (TARGET_CHAR_BIT, HOST_CHAR_BIT): Move to common/common-utils.h * remote.c (hex2bin, bin2hex): Moved defs to common/common-utils.c. * remote.h (hex2bin, bin2hex): Moved decls to common/common-utils.h. * utils.c (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int, strtoulst): Move to common/common-utils.c. * utils.h (strtoulst): Moved decl to common/common-utils.h. --- gdb/cli/cli-utils.c | 24 ------ gdb/cli/cli-utils.h | 9 --- gdb/common/common-utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++ gdb/common/common-utils.h | 34 +++++++++ gdb/defs.h | 19 ----- gdb/remote.c | 36 --------- gdb/remote.h | 4 - gdb/utils.c | 99 ------------------------ gdb/utils.h | 2 - 9 files changed, 221 insertions(+), 193 deletions(-) diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c index f74e6b1..60f7553 100644 --- a/gdb/cli/cli-utils.c +++ b/gdb/cli/cli-utils.c @@ -213,30 +213,6 @@ number_is_in_list (char *list, int number) /* See documentation in cli-utils.h. */ -char * -skip_spaces (char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* A const-correct version of the above. */ - -const char * -skip_spaces_const (const char *chp) -{ - if (chp == NULL) - return NULL; - while (*chp && isspace (*chp)) - chp++; - return chp; -} - -/* See documentation in cli-utils.h. */ - const char * skip_to_space_const (const char *chp) { diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h index 152fb89..2a8850d 100644 --- a/gdb/cli/cli-utils.h +++ b/gdb/cli/cli-utils.h @@ -89,15 +89,6 @@ extern int get_number_or_range (struct get_number_or_range_state *state); extern int number_is_in_list (char *list, int number); -/* Skip leading whitespace characters in INP, returning an updated - pointer. If INP is NULL, return NULL. */ - -extern char *skip_spaces (char *inp); - -/* A const-correct version of the above. */ - -extern const char *skip_spaces_const (const char *inp); - /* Skip leading non-whitespace characters in INP, returning an updated pointer. If INP is NULL, return NULL. */ diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c index 4204abf..5e96692 100644 --- a/gdb/common/common-utils.c +++ b/gdb/common/common-utils.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <stdio.h> +#include <ctype.h> /* The xmalloc() (libiberty.h) family of memory management routines. @@ -161,3 +162,189 @@ savestring (const char *ptr, size_t len) p[len] = 0; return p; } + +/* The bit offset of the highest byte in a ULONGEST, for overflow + checking. */ + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 36. */ + +static int +is_digit_in_base (unsigned char digit, int base) +{ + if (!isalnum (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (unsigned char c) +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ + +ULONGEST +strtoulst (const char *num, const char **trailer, int base) +{ + unsigned int high_part; + ULONGEST result; + int minus = 0; + int i = 0; + + /* Skip leading whitespace. */ + while (isspace (num[i])) + i++; + + /* Handle prefixes. */ + if (num[i] == '+') + i++; + else if (num[i] == '-') + { + minus = 1; + i++; + } + + if (base == 0 || base == 16) + { + if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) + { + i += 2; + if (base == 0) + base = 16; + } + } + + if (base == 0 && num[i] == '0') + base = 8; + + if (base == 0) + base = 10; + + if (base < 2 || base > 36) + { + errno = EINVAL; + return 0; + } + + result = high_part = 0; + for (; is_digit_in_base (num[i], base); i += 1) + { + result = result * base + digit_to_int (num[i]); + high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = ~ (ULONGEST) 0; + high_part = 0; + minus = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); + if (minus) + return -result; + else + return result; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else + error (_("Reply contains invalid hex digit %d"), a); +} + +int +hex2bin (const char *hex, gdb_byte *bin, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + if (hex[0] == 0 || hex[1] == 0) + { + /* Hex string is short, or of uneven length. + Return the count that has been converted so far. */ + return i; + } + *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); + hex += 2; + } + return i; +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +int +bin2hex (const gdb_byte *bin, char *hex, int count) +{ + int i; + + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen ((char *) bin); + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +/* See documentation in cli-utils.h. */ + +char * +skip_spaces (char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} + +/* A const-correct version of the above. */ + +const char * +skip_spaces_const (const char *chp) +{ + if (chp == NULL) + return NULL; + while (*chp && isspace (*chp)) + chp++; + return chp; +} diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h index 9b659d8..ee7870e 100644 --- a/gdb/common/common-utils.h +++ b/gdb/common/common-utils.h @@ -25,6 +25,25 @@ #include <stddef.h> #include <stdarg.h> +/* Static target-system-dependent parameters for GDB. */ + +/* Number of bits in a char or unsigned char for the target machine. + Just like CHAR_BIT in <limits.h> but describes the target machine. */ +#if !defined (TARGET_CHAR_BIT) +#define TARGET_CHAR_BIT 8 +#endif + +/* If we picked up a copy of CHAR_BIT from a configuration file + (which may get it by including <limits.h>) then use it to set + the number of bits in a host char. If not, use the same size + as the target. */ + +#if defined (CHAR_BIT) +#define HOST_CHAR_BIT CHAR_BIT +#else +#define HOST_CHAR_BIT TARGET_CHAR_BIT +#endif + extern void malloc_failure (long size) ATTRIBUTE_NORETURN; extern void internal_error (const char *file, int line, const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 4); @@ -53,4 +72,19 @@ int xsnprintf (char *str, size_t size, const char *format, ...) char *savestring (const char *ptr, size_t len); +ULONGEST strtoulst (const char *num, const char **trailer, int base); + +extern int hex2bin (const char *hex, gdb_byte *bin, int count); + +extern int bin2hex (const gdb_byte *bin, char *hex, int count); + +/* Skip leading whitespace characters in INP, returning an updated + pointer. If INP is NULL, return NULL. */ + +extern char *skip_spaces (char *inp); + +/* A const-correct version of the above. */ + +extern const char *skip_spaces_const (const char *inp); + #endif diff --git a/gdb/defs.h b/gdb/defs.h index d8a1adb..ec7e4f3 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -648,25 +648,6 @@ extern void *alloca (); enum { MAX_REGISTER_SIZE = 64 }; -/* Static target-system-dependent parameters for GDB. */ - -/* Number of bits in a char or unsigned char for the target machine. - Just like CHAR_BIT in <limits.h> but describes the target machine. */ -#if !defined (TARGET_CHAR_BIT) -#define TARGET_CHAR_BIT 8 -#endif - -/* If we picked up a copy of CHAR_BIT from a configuration file - (which may get it by including <limits.h>) then use it to set - the number of bits in a host char. If not, use the same size - as the target. */ - -#if defined (CHAR_BIT) -#define HOST_CHAR_BIT CHAR_BIT -#else -#define HOST_CHAR_BIT TARGET_CHAR_BIT -#endif - /* In findvar.c. */ extern LONGEST extract_signed_integer (const gdb_byte *, int, diff --git a/gdb/remote.c b/gdb/remote.c index 96abc5d..8f74b55 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -4569,25 +4569,6 @@ fromhex (int a) error (_("Reply contains invalid hex digit %d"), a); } -int -hex2bin (const char *hex, gdb_byte *bin, int count) -{ - int i; - - for (i = 0; i < count; i++) - { - if (hex[0] == 0 || hex[1] == 0) - { - /* Hex string is short, or of uneven length. - Return the count that has been converted so far. */ - return i; - } - *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]); - hex += 2; - } - return i; -} - /* Convert number NIB to a hex digit. */ static int @@ -4599,23 +4580,6 @@ tohex (int nib) return 'a' + nib - 10; } -int -bin2hex (const gdb_byte *bin, char *hex, int count) -{ - int i; - - /* May use a length, or a nul-terminated string as input. */ - if (count == 0) - count = strlen ((char *) bin); - - for (i = 0; i < count; i++) - { - *hex++ = tohex ((*bin >> 4) & 0xf); - *hex++ = tohex (*bin++ & 0xf); - } - *hex = 0; - return i; -} \f /* Check for the availability of vCont. This function should also check the response. */ diff --git a/gdb/remote.h b/gdb/remote.h index b95370c..d49b427 100644 --- a/gdb/remote.h +++ b/gdb/remote.h @@ -39,10 +39,6 @@ extern void getpkt (char **buf, long *sizeof_buf, int forever); extern int putpkt (char *buf); -extern int hex2bin (const char *hex, gdb_byte *bin, int count); - -extern int bin2hex (const gdb_byte *bin, char *hex, int count); - extern char *unpack_varlen_hex (char *buff, ULONGEST *result); extern void async_remote_interrupt_twice (void *arg); diff --git a/gdb/utils.c b/gdb/utils.c index 218faed..2b90315 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -3257,105 +3257,6 @@ dummy_obstack_deallocate (void *object, void *data) return; } -/* The bit offset of the highest byte in a ULONGEST, for overflow - checking. */ - -#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) - -/* True (non-zero) iff DIGIT is a valid digit in radix BASE, - where 2 <= BASE <= 36. */ - -static int -is_digit_in_base (unsigned char digit, int base) -{ - if (!isalnum (digit)) - return 0; - if (base <= 10) - return (isdigit (digit) && digit < base + '0'); - else - return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); -} - -static int -digit_to_int (unsigned char c) -{ - if (isdigit (c)) - return c - '0'; - else - return tolower (c) - 'a' + 10; -} - -/* As for strtoul, but for ULONGEST results. */ - -ULONGEST -strtoulst (const char *num, const char **trailer, int base) -{ - unsigned int high_part; - ULONGEST result; - int minus = 0; - int i = 0; - - /* Skip leading whitespace. */ - while (isspace (num[i])) - i++; - - /* Handle prefixes. */ - if (num[i] == '+') - i++; - else if (num[i] == '-') - { - minus = 1; - i++; - } - - if (base == 0 || base == 16) - { - if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X')) - { - i += 2; - if (base == 0) - base = 16; - } - } - - if (base == 0 && num[i] == '0') - base = 8; - - if (base == 0) - base = 10; - - if (base < 2 || base > 36) - { - errno = EINVAL; - return 0; - } - - result = high_part = 0; - for (; is_digit_in_base (num[i], base); i += 1) - { - result = result * base + digit_to_int (num[i]); - high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN); - result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; - if (high_part > 0xff) - { - errno = ERANGE; - result = ~ (ULONGEST) 0; - high_part = 0; - minus = 0; - break; - } - } - - if (trailer != NULL) - *trailer = &num[i]; - - result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN); - if (minus) - return -result; - else - return result; -} - /* Simple, portable version of dirname that does not modify its argument. */ diff --git a/gdb/utils.h b/gdb/utils.h index ad5bea4..e3b6fbf 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -39,8 +39,6 @@ extern int streq (const char *, const char *); extern int subset_compare (char *, char *); -ULONGEST strtoulst (const char *num, const char **trailer, int base); - int compare_positive_ints (const void *ap, const void *bp); int compare_strings (const void *ap, const void *bp); -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 6/8] gdbserver build-id attribute generator 2013-04-16 18:03 ` Aleksandar Ristovski ` (3 preceding siblings ...) 2013-04-16 18:31 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski @ 2013-04-16 18:31 ` Aleksandar Ristovski 2013-04-18 7:40 ` Jan Kratochvil 2013-04-16 18:31 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski ` (2 subsequent siblings) 7 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:31 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * doc/gdb.texinfo (Library List Format for SVR4 Targets): Add 'build-id' in description, example, new attribute in dtd. * features/library-list-svr4.dtd (library-list-svr4): New 'build-id' attribute. * linux-low.c (linux-maps.h, search.h): Include. (ElfXX_Ehdr, ElfXX_Phdr, ElfXX_Nhdr): New. (ELFXX_FLD, ELFXX_SIZEOF, ELFXX_ROUNDUP, BUILD_ID_INVALID): New. (find_phdr): New. (get_dynamic): Use find_pdhr to traverse program headers. (struct mapping_entry): New structure. (mapping_entry_s): New typedef, new vector type def. (free_mapping_entry, compare_mapping_entry, compare_mapping_entry_range, compare_mapping_entry_inode): New. (struct find_memory_region_callback_data): New. (find_memory_region_callback): New fwd. declaration. (read_build_id, find_memory_region_callback, get_hex_build_id): New. (linux_qxfer_libraries_svr4): Add optional build-id attribute to reply XML document. --- gdb/doc/gdb.texinfo | 17 +- gdb/features/library-list-svr4.dtd | 13 +- gdb/gdbserver/linux-low.c | 388 ++++++++++++++++++++++++++++++++---- 3 files changed, 369 insertions(+), 49 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 337837e..cc9e846 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40435,6 +40435,8 @@ memory address. It is a displacement of absolute memory address against address the file was prelinked to during the library load. @item @code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment +@item +@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if it exists. @end itemize Additionally the single @code{main-lm} attribute specifies address of @@ -40452,7 +40454,7 @@ looks like this: <library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000" l_ld="0xe4eefc"/> <library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000" - l_ld="0x152350"/> + l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/> </library-list-svr> @end smallexample @@ -40461,13 +40463,14 @@ The format of an SVR4 library list is described by this DTD: @smallexample <!-- library-list-svr4: Root element with versioning --> <!ELEMENT library-list-svr4 (library)*> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> <!ELEMENT library EMPTY> -<!ATTLIST library name CDATA #REQUIRED> -<!ATTLIST library lm CDATA #REQUIRED> -<!ATTLIST library l_addr CDATA #REQUIRED> -<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library name CDATA #REQUIRED> +<!ATTLIST library lm CDATA #REQUIRED> +<!ATTLIST library l_addr CDATA #REQUIRED> +<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library build-id CDATA #IMPLIED> @end smallexample @node Memory Map Format diff --git a/gdb/features/library-list-svr4.dtd b/gdb/features/library-list-svr4.dtd index cae7fd8..fdd6ec0 100644 --- a/gdb/features/library-list-svr4.dtd +++ b/gdb/features/library-list-svr4.dtd @@ -6,11 +6,12 @@ <!-- library-list-svr4: Root element with versioning --> <!ELEMENT library-list-svr4 (library)*> -<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> -<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> +<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0"> +<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED> <!ELEMENT library EMPTY> -<!ATTLIST library name CDATA #REQUIRED> -<!ATTLIST library lm CDATA #REQUIRED> -<!ATTLIST library l_addr CDATA #REQUIRED> -<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library name CDATA #REQUIRED> +<!ATTLIST library lm CDATA #REQUIRED> +<!ATTLIST library l_addr CDATA #REQUIRED> +<!ATTLIST library l_ld CDATA #REQUIRED> +<!ATTLIST library build-id CDATA #IMPLIED> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 72c51e0..eac5318 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -20,6 +20,7 @@ #include "linux-low.h" #include "linux-osdata.h" #include "agent.h" +#include "linux-maps.h" #include "gdb_wait.h" #include <stdio.h> @@ -43,6 +44,7 @@ #include "gdb_stat.h" #include <sys/vfs.h> #include <sys/uio.h> +#include <search.h> #ifndef ELFMAG0 /* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h then ELFMAG0 will have been defined. If it didn't get included by @@ -118,6 +120,34 @@ typedef struct } Elf64_auxv_t; #endif +typedef union ElfXX_Ehdr +{ + Elf32_Ehdr _32; + Elf64_Ehdr _64; +} ElfXX_Ehdr; + +typedef union ElfXX_Phdr +{ + Elf32_Phdr _32; + Elf64_Phdr _64; +} ElfXX_Phdr; + +typedef union ElfXX_Nhdr +{ + Elf32_Nhdr _32; + Elf64_Nhdr _64; +} ElfXX_Nhdr; + +#define ELFXX_FLD(elf64, hdr, fld) ((elf64) ? (hdr)._64.fld : (hdr)._32.fld) +#define ELFXX_SIZEOF(elf64, hdr) ((elf64) ? sizeof ((hdr)._64) \ + : sizeof ((hdr)._32)) +/* Round up to next 4 byte boundary. */ +#define ELFXX_ROUNDUP_4(elf64, what) ((elf64) ? (((what) + 3) \ + & ~((Elf64_Word)3U)) \ + : (((what) + 3) \ + & ~((Elf32_Word) 3U))) +#define BUILD_ID_INVALID "?" + /* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol representation of the thread ID. @@ -5432,15 +5462,38 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, return 0; } +/* Linearly traverse pheaders and look for P_TYPE pheader. */ + +static const void * +find_phdr (const int is_elf64, const void *const phdr_begin, + const void *const phdr_end, const ULONGEST p_type) +{ +#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \ + ELFXX_SIZEOF (is_elf64, *hdrp))) + + const ElfXX_Phdr *phdr = phdr_begin; + + while (PHDR_NEXT (phdr) <= phdr_end) + { + if (ELFXX_FLD (is_elf64, *phdr, p_type) == p_type) + return phdr; + phdr = PHDR_NEXT (phdr); + } + + return NULL; +#undef PHDR_NEXT +} + /* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ static CORE_ADDR get_dynamic (const int pid, const int is_elf64) { CORE_ADDR phdr_memaddr, relocation; - int num_phdr, i; + int num_phdr; unsigned char *phdr_buf; - const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + const ElfXX_Phdr *phdr; + const int phdr_size = ELFXX_SIZEOF (is_elf64, *phdr); if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) return 0; @@ -5454,22 +5507,10 @@ get_dynamic (const int pid, const int is_elf64) /* Compute relocation: it is expected to be 0 for "regular" executables, non-zero for PIE ones. */ relocation = -1; - for (i = 0; relocation == -1 && i < num_phdr; i++) - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_PHDR) - relocation = phdr_memaddr - p->p_vaddr; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_PHDR) - relocation = phdr_memaddr - p->p_vaddr; - } - + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + PT_PHDR); + if (phdr != NULL) + relocation = phdr_memaddr - ELFXX_FLD (is_elf64, *phdr, p_vaddr); if (relocation == -1) { /* PT_PHDR is optional, but necessary for PIE in general. Fortunately @@ -5485,23 +5526,11 @@ get_dynamic (const int pid, const int is_elf64) return 0; } - for (i = 0; i < num_phdr; i++) - { - if (is_elf64) - { - Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size, + PT_DYNAMIC); - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; - } - else - { - Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); - - if (p->p_type == PT_DYNAMIC) - return p->p_vaddr + relocation; - } - } + if (phdr != NULL) + return ELFXX_FLD (is_elf64, *phdr, p_vaddr) + relocation; return 0; } @@ -5641,6 +5670,275 @@ struct link_map_offsets int l_prev_offset; }; + +/* Structure for holding a mapping. Only mapping + containing l_ld can have hex_build_id set. */ + +struct mapping_entry +{ + /* Fields are populated from linux_find_memory_region parameters. */ + + ULONGEST vaddr; + ULONGEST size; + ULONGEST offset; + ULONGEST inode; + + /* Hex encoded string allocated using xmalloc, and + needs to be freed. It can be NULL. */ + + char *hex_build_id; +}; + +typedef struct mapping_entry mapping_entry_s; + +DEF_VEC_O(mapping_entry_s); + +/* Free vector of mapping_entry_s objects. */ + +static void +free_mapping_entry_vec (VEC (mapping_entry_s) *lst) +{ + int ix; + mapping_entry_s *p; + + for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix) + xfree (p->hex_build_id); + + VEC_free (mapping_entry_s, lst); +} + +/* Used for finding a mapping containing the given + l_ld passed in K. */ + +static int +compare_mapping_entry_range (const void *const k, const void *const b) +{ + const ULONGEST key = *(CORE_ADDR *) k; + const mapping_entry_s *const p = b; + + if (key < p->vaddr) + return -1; + + if (key < p->vaddr + p->size) + return 0; + + return 1; +} + +struct find_memory_region_callback_data +{ + unsigned is_elf64; + + /* Return. Must be freed with free_mapping_entry_vec. */ + VEC (mapping_entry_s) *list; +}; + +/* Read build-id from PT_NOTE. + Argument LOAD_ADDR pepresents run time virtual address corresponding to + the beginning of the first loadable segment. L_ADDR is displacement + as supplied by the dynamic linker. */ + +static void +read_build_id (struct find_memory_region_callback_data *const p, + mapping_entry_s *const bil, const CORE_ADDR load_addr, + const CORE_ADDR l_addr) +{ + const int is_elf64 = p->is_elf64; + ElfXX_Ehdr ehdr; + + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, + ELFXX_SIZEOF (is_elf64, ehdr)) == 0 + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG0]) == ELFMAG0 + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG1]) == ELFMAG1 + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG2]) == ELFMAG2 + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG3]) == ELFMAG3) + { + const ElfXX_Phdr *phdr; + void *phdr_buf; + const unsigned e_phentsize = ELFXX_FLD (is_elf64, ehdr, e_phentsize); + + if (ELFXX_FLD (is_elf64, ehdr, e_phnum) >= 100 + || e_phentsize != ELFXX_SIZEOF (is_elf64, *phdr)) + { + /* Basic sanity check failed. */ + warning ("Could not read program header."); + return; + } + + phdr_buf = alloca (ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize); + + if (linux_read_memory (load_addr + ELFXX_FLD (is_elf64, ehdr, e_phoff), + phdr_buf, + ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize) + != 0) + { + warning ("Could not read program header."); + return; + } + + phdr = phdr_buf; + + for (;;) + { + gdb_byte *pt_note; + const gdb_byte *pt_end; + const ElfXX_Nhdr *nhdr; + CORE_ADDR note_addr; + + phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf + + ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize, + PT_NOTE); + if (phdr == NULL) + break; + pt_note = xmalloc (ELFXX_FLD (is_elf64, *phdr, p_memsz)); + note_addr = ELFXX_FLD (is_elf64, *phdr, p_vaddr) + l_addr; + if (linux_read_memory (note_addr, pt_note, + ELFXX_FLD (is_elf64, *phdr, p_memsz)) != 0) + { + xfree (pt_note); + warning ("Could not read note at address 0x%s", + paddress (note_addr)); + break; + } + + pt_end = pt_note + ELFXX_FLD (is_elf64, *phdr, p_memsz); + nhdr = (void *) pt_note; + while ((gdb_byte *) nhdr < pt_end) + { + const size_t namesz + = ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr, + n_namesz)); + const size_t descsz + = ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr, + n_descsz)); + const size_t note_sz = ELFXX_SIZEOF (is_elf64, *nhdr) + namesz + + descsz; + + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 + || descsz == 0) + { + warning ("Malformed PT_NOTE at address 0x%s\n", + paddress ((CORE_ADDR) nhdr)); + break; + } + if (ELFXX_FLD (is_elf64, *nhdr, n_type) == NT_GNU_BUILD_ID + && ELFXX_FLD (is_elf64, *nhdr, n_namesz) == 4) + { + const char gnu[4] = "GNU\0"; + const char *const pname + = (char *) nhdr + ELFXX_SIZEOF (is_elf64, *nhdr); + + if (memcmp (pname, gnu, 4) == 0) + { + const size_t n_descsz = ELFXX_FLD (is_elf64, *nhdr, + n_descsz); + + bil->hex_build_id = xmalloc (n_descsz * 2 + 1); + bin2hex ((const gdb_byte *) pname + namesz, + bil->hex_build_id, n_descsz); + xfree (pt_note); + return; + } + } + nhdr = (void *) ((gdb_byte *) nhdr + note_sz); + } + xfree (pt_note); + } + } +} + +static linux_find_memory_region_ftype find_memory_region_callback; + +/* Add mapping_entry. See linux_find_memory_ftype for the parameters + description. */ + +static int +find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset, + ULONGEST inode, int read, int write, int exec, + int modified, const char *filename, void *data) +{ + if (inode != 0) + { + struct find_memory_region_callback_data *const p = data; + mapping_entry_s bil; + + bil.vaddr = vaddr; + bil.size = size; + bil.offset = offset; + bil.inode = inode; + bil.hex_build_id = NULL; + + VEC_safe_push (mapping_entry_s, p->list, &bil); + } + + /* Continue the traversal. */ + return 0; +} + +/* Linear reverse find starting from RBEGIN towards REND looking for + the lowest vaddr mapping of the same inode and zero offset. */ + +static mapping_entry_s * +lrfind_mapping_entry (mapping_entry_s *const rbegin, + const mapping_entry_s *const rend) +{ + mapping_entry_s *p; + + for (p = rbegin - 1; p >= rend; --p) + if (p->offset == 0 && p->inode == rbegin->inode) + return p; + + return NULL; +} + +/* Get build-id for the given L_LD, where L_LD corresponds to + link_map.l_ld as specified by the dynamic linker. + DATA must point to already filled list of mapping_entry elements. + + If build-id had not been read, read it and cache in corresponding + list element. + + Return build_id as stored in the list element corresponding + to L_LD. + + NULL may be returned if build-id could not be fetched. + + Returned string must not be freed explicitly. */ + +static const char * +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, + struct find_memory_region_callback_data *const data) +{ + mapping_entry_s *bil; + + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list), + VEC_length (mapping_entry_s, data->list), + sizeof (mapping_entry_s), compare_mapping_entry_range); + + if (bil == NULL) + return NULL; + + if (bil->hex_build_id == NULL) + { + mapping_entry_s *bil_min; + + bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s, + data->list)); + if (bil_min != NULL) + read_build_id (data, bil, bil_min->vaddr, l_addr); + else + { + /* Do not try to find hex_build_id again. */ + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); + warning ("Could not determine load address; mapping entry with" + " offset 0 corresponding to l_ld=0x%s could not be found; " + "build-id can not be used.", paddress (l_ld)); + } + } + + return bil->hex_build_id; +} + /* Construct qXfer:libraries-svr4:read reply. */ static int @@ -5653,6 +5951,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, struct process_info_private *const priv = current_process ()->private; char filename[PATH_MAX]; int pid, is_elf64; + struct find_memory_region_callback_data data; static const struct link_map_offsets lmo_32bit_offsets = { @@ -5688,6 +5987,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, is_elf64 = elf_64_file_p (filename, &machine); lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + data.is_elf64 = is_elf64; + data.list = NULL; + VEC_reserve (mapping_entry_s, data.list, 16); + if (linux_find_memory_regions_full (pid, find_memory_region_callback, &data, + NULL) < 0) + warning ("Finding memory regions failed"); + if (priv->r_debug == 0) priv->r_debug = get_r_debug (pid, is_elf64); @@ -5762,6 +6068,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, /* 6x the size for xml_escape_text below. */ size_t len = 6 * strlen ((char *) libname); char *name; + const char *hex_enc_build_id = NULL; if (!header_done) { @@ -5770,7 +6077,11 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, header_done = 1; } - while (allocated < p - document + len + 200) + hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data); + + while (allocated < (p - document + len + 200 + + (hex_enc_build_id != NULL + ? strlen (hex_enc_build_id) : 0))) { /* Expand to guarantee sufficient storage. */ uintptr_t document_len = p - document; @@ -5782,9 +6093,13 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, name = xml_escape_text ((char *) libname); p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" " - "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>", + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"", name, (unsigned long) lm_addr, (unsigned long) l_addr, (unsigned long) l_ld); + if (hex_enc_build_id != NULL + && strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0) + p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id); + p += sprintf (p, "/>"); free (name); } else if (lm_prev == 0) @@ -5819,6 +6134,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, memcpy (readbuf, document + offset, len); xfree (document); + free_mapping_entry_vec (data.list); return len; } -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 6/8] gdbserver build-id attribute generator 2013-04-16 18:31 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski @ 2013-04-18 7:40 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 7:40 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:44:54 +0200, Aleksandar Ristovski wrote: [...] > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c [...] > +#define ELFXX_FLD(elf64, hdr, fld) ((elf64) ? (hdr)._64.fld : (hdr)._32.fld) > +#define ELFXX_SIZEOF(elf64, hdr) ((elf64) ? sizeof ((hdr)._64) \ > + : sizeof ((hdr)._32)) > +/* Round up to next 4 byte boundary. */ > +#define ELFXX_ROUNDUP_4(elf64, what) ((elf64) ? (((what) + 3) \ > + & ~((Elf64_Word)3U)) \ GNU Coding Standards: & ~((Elf64_Word) 3U)) \ > + : (((what) + 3) \ > + & ~((Elf32_Word) 3U))) This is still overcomplicated, why the ELF64 parameter at all? There should not be any. And all the casts there with Elf64_Word and Elf32_Word: * both Elf64_Word and Elf32_Word are the same, they are 32-bit. * despite all the casts the macro is not safe for 64-bit WHAT as the mask will be just 0xffffffff. Put there just: #define ELFXX_ROUNDUP_4(what) (((what) + 3) & ~(ULONGEST) 3) > +#define BUILD_ID_INVALID "?" > + > /* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol > representation of the thread ID. > [...] > +/* Used for finding a mapping containing the given > + l_ld passed in K. */ > + > +static int > +compare_mapping_entry_range (const void *const k, const void *const b) > +{ > + const ULONGEST key = *(CORE_ADDR *) k; More commented in another mail. I already wrote when k is const * there should be (const CORE_ADDR *). It is here even unrelated to the const values unusual in GDB. 'k' is pointing to const data so it is incorrect to cast it to non-const-target pointer. In such case 'k' should be void * and not const void *. > + const mapping_entry_s *const p = b; > + > + if (key < p->vaddr) > + return -1; > + > + if (key < p->vaddr + p->size) > + return 0; > + > + return 1; > +} [...] > +/* Read build-id from PT_NOTE. > + Argument LOAD_ADDR pepresents run time virtual address corresponding to > + the beginning of the first loadable segment. L_ADDR is displacement > + as supplied by the dynamic linker. */ > + > +static void > +read_build_id (struct find_memory_region_callback_data *const p, > + mapping_entry_s *const bil, const CORE_ADDR load_addr, > + const CORE_ADDR l_addr) > +{ > + const int is_elf64 = p->is_elf64; > + ElfXX_Ehdr ehdr; > + > + if (linux_read_memory (load_addr, (unsigned char *) &ehdr, > + ELFXX_SIZEOF (is_elf64, ehdr)) == 0 > + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG0]) == ELFMAG0 > + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG1]) == ELFMAG1 > + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG2]) == ELFMAG2 > + && ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG3]) == ELFMAG3) > + { > + const ElfXX_Phdr *phdr; > + void *phdr_buf; > + const unsigned e_phentsize = ELFXX_FLD (is_elf64, ehdr, e_phentsize); > + > + if (ELFXX_FLD (is_elf64, ehdr, e_phnum) >= 100 > + || e_phentsize != ELFXX_SIZEOF (is_elf64, *phdr)) > + { > + /* Basic sanity check failed. */ > + warning ("Could not read program header."); Print LOAD_ADDR, otherwise one has to start debugging gdbserver to find out why the message was printed. The message could be different than the message for failed linux_read_memory below. > + return; > + } > + > + phdr_buf = alloca (ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize); > + > + if (linux_read_memory (load_addr + ELFXX_FLD (is_elf64, ehdr, e_phoff), > + phdr_buf, > + ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize) > + != 0) > + { > + warning ("Could not read program header."); Print LOAD_ADDR, otherwise one has to start debugging gdbserver to find out why the message was printed. > + return; > + } > + > + phdr = phdr_buf; > + > + for (;;) > + { > + gdb_byte *pt_note; > + const gdb_byte *pt_end; > + const ElfXX_Nhdr *nhdr; > + CORE_ADDR note_addr; > + > + phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf > + + ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize, > + PT_NOTE); > + if (phdr == NULL) > + break; > + pt_note = xmalloc (ELFXX_FLD (is_elf64, *phdr, p_memsz)); > + note_addr = ELFXX_FLD (is_elf64, *phdr, p_vaddr) + l_addr; > + if (linux_read_memory (note_addr, pt_note, > + ELFXX_FLD (is_elf64, *phdr, p_memsz)) != 0) > + { > + xfree (pt_note); > + warning ("Could not read note at address 0x%s", > + paddress (note_addr)); > + break; > + } > + > + pt_end = pt_note + ELFXX_FLD (is_elf64, *phdr, p_memsz); > + nhdr = (void *) pt_note; > + while ((gdb_byte *) nhdr < pt_end) This should be (const gdb_byte *) as nhdr is const-target pointer. > + { > + const size_t namesz > + = ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr, > + n_namesz)); > + const size_t descsz > + = ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr, > + n_descsz)); > + const size_t note_sz = ELFXX_SIZEOF (is_elf64, *nhdr) + namesz > + + descsz; GNU Coding Standards: const size_t note_sz = (ELFXX_SIZEOF (is_elf64, *nhdr) + namesz + descsz); > + > + if (((gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0 This should be (const gdb_byte *) as nhdr is const-target pointer. > + || descsz == 0) > + { > + warning ("Malformed PT_NOTE at address 0x%s\n", > + paddress ((CORE_ADDR) nhdr)); NHDR is in gdbserver's memory, that has no useful value for the user. You should print: paddress (note_addr + nhdr - pt_note)); > + break; > + } [...] > +/* Get build-id for the given L_LD, where L_LD corresponds to > + link_map.l_ld as specified by the dynamic linker. > + DATA must point to already filled list of mapping_entry elements. > + > + If build-id had not been read, read it and cache in corresponding > + list element. > + > + Return build_id as stored in the list element corresponding > + to L_LD. > + > + NULL may be returned if build-id could not be fetched. > + > + Returned string must not be freed explicitly. */ > + > +static const char * > +get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld, > + struct find_memory_region_callback_data *const data) > +{ > + mapping_entry_s *bil; > + > + bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list), > + VEC_length (mapping_entry_s, data->list), > + sizeof (mapping_entry_s), compare_mapping_entry_range); > + > + if (bil == NULL) > + return NULL; > + > + if (bil->hex_build_id == NULL) > + { > + mapping_entry_s *bil_min; > + > + bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s, > + data->list)); > + if (bil_min != NULL) > + read_build_id (data, bil, bil_min->vaddr, l_addr); > + else > + { > + /* Do not try to find hex_build_id again. */ > + bil->hex_build_id = xstrdup (BUILD_ID_INVALID); > + warning ("Could not determine load address; mapping entry with" > + " offset 0 corresponding to l_ld=0x%s could not be found; " > + "build-id can not be used.", paddress (l_ld)); GNU Coding Standards s/=/ = / - IMO it applies also to the output. Also GDB uses continuation space at the end of previous line. There should be localization. warning (_("Could not determine load address; mapping entry with " "offset 0 corresponding to l_ld = 0x%s could not be " "found; build-id can not be used."), paddress (l_ld)); > + } > + } > + > + return bil->hex_build_id; > +} > + > /* Construct qXfer:libraries-svr4:read reply. */ > > static int [...] Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 5/8] Move linux_find_memory_regions_full & co. 2013-04-16 18:03 ` Aleksandar Ristovski ` (4 preceding siblings ...) 2013-04-16 18:31 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski @ 2013-04-16 18:31 ` Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski 2013-04-16 20:24 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski 7 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:31 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * common/common-target.c (gdb_assert.h, gdb_string.h): Include. (read_alloc, read_stralloc): Move definitions from target.c. * common/common-target.h (read_alloc_pread_ftype): New typedef. (read_alloc): New declaration. (read_stralloc_func_ftype): New typedef. (read_stralloc): New declaration. * common/linux-maps.c (fcntl.h, unistd.h, target.h, gdb_assert.h, ctype.h, string.h, common-target.h): Include. (read_mapping): Move from linux-tdep.c. (linux_find_memory_read_stralloc_1_pread): New function. (linux_find_memory_read_stralloc_1): New function. (linux_find_memory_read_stralloc): New function. * common/linux-maps.h (read_mapping): New declaration. (linux_find_memory_region_ftype): Moved typedef from linux-tdep.c. (linux_find_memory_regions_full): New declaration. * linux-tdep.c (linux-maps.h): Include. (read_mapping): Moved to common/linux-maps.c. (linux_find_memory_region_ftype): Moved typedef to common/linux-maps.h. (linux_find_memory_regions_full): Moved definition to common/linux-maps.c. * target.c (common-target.h): Include. (read_alloc_pread_ftype): Moved typedef to common/common-target.h. (read_alloc, read_stralloc): Moved definitions to common/common-target.c. --- gdb/common/common-target.c | 88 ++++++++++++++++++++ gdb/common/common-target.h | 12 ++- gdb/common/linux-maps.c | 197 ++++++++++++++++++++++++++++++++++++++++++++ gdb/common/linux-maps.h | 25 ++++++ gdb/linux-tdep.c | 159 +---------------------------------- gdb/target.c | 98 ++-------------------- 6 files changed, 328 insertions(+), 251 deletions(-) diff --git a/gdb/common/common-target.c b/gdb/common/common-target.c index a24953e..907f95c 100644 --- a/gdb/common/common-target.c +++ b/gdb/common/common-target.c @@ -24,4 +24,92 @@ #endif #include "common-target.h" +#include "gdb_assert.h" +#include "gdb_string.h" +LONGEST +read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, + int padding, void **memory_to_free_ptr) +{ + size_t buf_alloc, buf_pos; + gdb_byte *buf; + LONGEST n; + int target_errno; + + /* 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); + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = buf; + } + buf_pos = 0; + while (1) + { + n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, + buf_pos, &target_errno); + if (n <= 0) + { + if (n < 0 || (n == 0 && buf_pos == 0)) + xfree (buf); + else + *buf_p = buf; + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = NULL; + if (n < 0) + { + /* An error occurred. */ + return -1; + } + else + { + /* Read all there was. */ + 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); + if (memory_to_free_ptr != NULL) + *memory_to_free_ptr = buf; + } + } +} + +char * +read_stralloc (const char *filename, read_stralloc_func_ftype *func) +{ + gdb_byte *buffer; + char *bufstr; + LONGEST i, transferred; + + transferred = func (filename, &buffer, 1); + bufstr = (char *) buffer; + + if (transferred < 0) + return NULL; + + if (transferred == 0) + return xstrdup (""); + + bufstr[transferred] = 0; + + /* Check for embedded NUL bytes; but allow trailing NULs. */ + for (i = strlen (bufstr); i < transferred; i++) + if (bufstr[i] != 0) + { + warning (_("target file %s " + "contained unexpected null characters"), + filename); + break; + } + + return bufstr; +} diff --git a/gdb/common/common-target.h b/gdb/common/common-target.h index f56cb72..b252c00 100644 --- a/gdb/common/common-target.h +++ b/gdb/common/common-target.h @@ -20,5 +20,15 @@ #ifndef COMMON_COMMON_TARGET_H #define COMMON_COMMON_TARGET_H -#endif /* COMMON_COMMON_TARGET_H */ +typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len, + ULONGEST offset, int *target_errno); +extern LONGEST read_alloc (gdb_byte **buf_p, int handle, + read_alloc_pread_ftype *pread_func, int padding, + void **memory_to_free_ptr); + +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); +extern char *read_stralloc (const char *filename, + read_stralloc_func_ftype *func); +#endif /* COMMON_COMMON_TARGET_H */ diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c index efb0875..6432b8f 100644 --- a/gdb/common/linux-maps.c +++ b/gdb/common/linux-maps.c @@ -18,8 +18,205 @@ #ifdef GDBSERVER #include "server.h" +#include <fcntl.h> +#include <unistd.h> #else #include "defs.h" +#include "target.h" #endif #include "linux-maps.h" +#include "gdb_assert.h" +#include <ctype.h> +#include <string.h> +#include "common-target.h" + +/* Service function for corefiles and info proc. */ + +void +read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename) +{ + const char *p = line; + + *addr = strtoulst (p, &p, 16); + if (*p == '-') + p++; + *endaddr = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *permissions = p; + while (*p && !isspace (*p)) + p++; + *permissions_len = p - *permissions; + + *offset = strtoulst (p, &p, 16); + + p = skip_spaces_const (p); + *device = p; + while (*p && !isspace (*p)) + p++; + *device_len = p - *device; + + *inode = strtoulst (p, &p, 10); + + p = skip_spaces_const (p); + *filename = p; +} + +#ifdef GDBSERVER + +static int +linux_find_memory_read_stralloc_1_pread (int handle, gdb_byte *read_buf, + int len, ULONGEST offset, + int *target_errno) +{ + int retval = pread (handle, read_buf, len, offset); + + *target_errno = errno; + return retval; +} + +static LONGEST +linux_find_memory_read_stralloc_1 (const char *filename, gdb_byte **buf_p, + int padding) +{ + int fd; + LONGEST retval; + + fd = open (filename, O_RDONLY); + if (fd == -1) + return -1; + + retval = read_alloc (buf_p, fd, linux_find_memory_read_stralloc_1_pread, + padding, NULL); + + close (fd); + + return retval; +} + +#endif /* GDBSERVER */ + +static char * +linux_find_memory_read_stralloc (const char *filename) +{ +#ifndef GDBSERVER + return target_fileio_read_stralloc (filename); +#else /* GDBSERVER */ + return read_stralloc (filename, linux_find_memory_read_stralloc_1); +#endif /* GDBSERVER */ +} + +/* List memory regions in the inferior PID for a corefile. Call FUNC + with FUNC_DATA for each such region. Return immediately with the + value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should + be registered to be freed automatically if called FUNC throws an + exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is + not used. Return -1 if error occurs, 0 if all memory regions have + been processed or return the value from FUNC if FUNC returns + non-zero. */ + +int +linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr) +{ + char mapsfilename[100]; + char *data; + + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); + data = linux_find_memory_read_stralloc (mapsfilename); + if (data == NULL) + { + /* Older Linux kernels did not support /proc/PID/smaps. */ + xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", (int) pid); + data = linux_find_memory_read_stralloc (mapsfilename); + } + if (data) + { + char *line; + int retval = 0; + + if (memory_to_free_ptr != NULL) + { + gdb_assert (*memory_to_free_ptr == NULL); + *memory_to_free_ptr = data; + } + + line = strtok (data, "\n"); + while (line) + { + ULONGEST addr, endaddr, offset, inode; + const char *permissions, *device, *filename; + size_t permissions_len, device_len; + int read, write, exec; + int modified = 0, has_anonymous = 0; + + read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, + &offset, &device, &device_len, &inode, &filename); + + /* Decode permissions. */ + read = (memchr (permissions, 'r', permissions_len) != 0); + write = (memchr (permissions, 'w', permissions_len) != 0); + exec = (memchr (permissions, 'x', permissions_len) != 0); + + /* Try to detect if region was modified by parsing smaps counters. */ + for (line = strtok (NULL, "\n"); + line && line[0] >= 'A' && line[0] <= 'Z'; + line = strtok (NULL, "\n")) + { + char keyword[64 + 1]; + + if (sscanf (line, "%64s", keyword) != 1) + { + warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); + break; + } + if (strcmp (keyword, "Anonymous:") == 0) + has_anonymous = 1; + if (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0) + { + unsigned long number; + + if (sscanf (line, "%*s%lu", &number) != 1) + { + warning (_("Error parsing {s,}maps file '%s' number"), + mapsfilename); + break; + } + if (number != 0) + modified = 1; + } + } + + /* Older Linux kernels did not support the "Anonymous:" counter. + If it is missing, we can't be sure - dump all the pages. */ + if (!has_anonymous) + modified = 1; + + /* Invoke the callback function to create the corefile segment. */ + retval = func (addr, endaddr - addr, offset, inode, + read, write, exec, modified, filename, func_data); + if (retval != 0) + break; + } + + if (memory_to_free_ptr != NULL) + { + gdb_assert (data == *memory_to_free_ptr); + *memory_to_free_ptr = NULL; + } + xfree (data); + return retval; + } + + return -1; +} diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h index da426e5..e989376 100644 --- a/gdb/common/linux-maps.h +++ b/gdb/common/linux-maps.h @@ -19,4 +19,29 @@ #ifndef COMMON_LINUX_MAPS_H #define COMMON_LINUX_MAPS_H +extern void + read_mapping (const char *line, + ULONGEST *addr, ULONGEST *endaddr, + const char **permissions, size_t *permissions_len, + ULONGEST *offset, + const char **device, size_t *device_len, + ULONGEST *inode, + const char **filename); + +/* Callback function for linux_find_memory_regions_full. If it returns + non-zero linux_find_memory_regions_full returns immediately with that + value. */ + +typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, + ULONGEST offset, ULONGEST inode, + int read, int write, + int exec, int modified, + const char *filename, + void *data); + +extern int + linux_find_memory_regions_full (pid_t pid, + linux_find_memory_region_ftype *func, + void *func_data, void **memory_to_free_ptr); + #endif /* COMMON_LINUX_MAPS_H */ diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 77c98d2..4544e5f 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -33,6 +33,7 @@ #include "arch-utils.h" #include "gdb_obstack.h" #include "cli/cli-utils.h" +#include "linux-maps.h" #include <ctype.h> @@ -207,44 +208,6 @@ linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) return normal_pid_to_str (ptid); } -/* Service function for corefiles and info proc. */ - -static void -read_mapping (const char *line, - ULONGEST *addr, ULONGEST *endaddr, - const char **permissions, size_t *permissions_len, - ULONGEST *offset, - const char **device, size_t *device_len, - ULONGEST *inode, - const char **filename) -{ - const char *p = line; - - *addr = strtoulst (p, &p, 16); - if (*p == '-') - p++; - *endaddr = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *permissions = p; - while (*p && !isspace (*p)) - p++; - *permissions_len = p - *permissions; - - *offset = strtoulst (p, &p, 16); - - p = skip_spaces_const (p); - *device = p; - while (*p && !isspace (*p)) - p++; - *device_len = p - *device; - - *inode = strtoulst (p, &p, 10); - - p = skip_spaces_const (p); - *filename = p; -} - /* Implement the "info proc" command. */ static void @@ -661,126 +624,6 @@ linux_core_info_proc (struct gdbarch *gdbarch, char *args, error (_("unable to handle request")); } -/* Callback function for linux_find_memory_regions_full. If it returns - non-zero linux_find_memory_regions_full returns immediately with that - value. */ - -typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, - ULONGEST offset, ULONGEST inode, - int read, int write, - int exec, int modified, - const char *filename, - void *data); - -/* List memory regions in the inferior PID for a corefile. Call FUNC - with FUNC_DATA for each such region. Return immediately with the - value returned by FUNC if it is non-zero. *MEMORY_TO_FREE_PTR should - be registered to be freed automatically if called FUNC throws an - exception. MEMORY_TO_FREE_PTR can be also passed as NULL if it is - not used. Return -1 if error occurs, 0 if all memory regions have - been processed or return the value from FUNC if FUNC returns - non-zero. */ - -static int -linux_find_memory_regions_full (pid_t pid, linux_find_memory_region_ftype *func, - void *func_data, void **memory_to_free_ptr) -{ - char mapsfilename[100]; - char *data; - - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - if (data == NULL) - { - /* Older Linux kernels did not support /proc/PID/smaps. */ - xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", - (int) pid); - data = target_fileio_read_stralloc (mapsfilename); - } - if (data) - { - char *line; - int retval = 0; - - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = data; - } - - line = strtok (data, "\n"); - while (line) - { - ULONGEST addr, endaddr, offset, inode; - const char *permissions, *device, *filename; - size_t permissions_len, device_len; - int read, write, exec; - int modified = 0, has_anonymous = 0; - - read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, - &offset, &device, &device_len, &inode, &filename); - - /* Decode permissions. */ - read = (memchr (permissions, 'r', permissions_len) != 0); - write = (memchr (permissions, 'w', permissions_len) != 0); - exec = (memchr (permissions, 'x', permissions_len) != 0); - - /* Try to detect if region was modified by parsing smaps counters. */ - for (line = strtok (NULL, "\n"); - line && line[0] >= 'A' && line[0] <= 'Z'; - line = strtok (NULL, "\n")) - { - char keyword[64 + 1]; - - if (sscanf (line, "%64s", keyword) != 1) - { - warning (_("Error parsing {s,}maps file '%s'"), mapsfilename); - break; - } - if (strcmp (keyword, "Anonymous:") == 0) - has_anonymous = 1; - if (strcmp (keyword, "Shared_Dirty:") == 0 - || strcmp (keyword, "Private_Dirty:") == 0 - || strcmp (keyword, "Swap:") == 0 - || strcmp (keyword, "Anonymous:") == 0) - { - unsigned long number; - - if (sscanf (line, "%*s%lu", &number) != 1) - { - warning (_("Error parsing {s,}maps file '%s' number"), - mapsfilename); - break; - } - if (number != 0) - modified = 1; - } - } - - /* Older Linux kernels did not support the "Anonymous:" counter. - If it is missing, we can't be sure - dump all the pages. */ - if (!has_anonymous) - modified = 1; - - /* Invoke the callback function to create the corefile segment. */ - retval = func (addr, endaddr - addr, offset, inode, - read, write, exec, modified, filename, func_data); - if (retval != 0) - break; - } - - if (memory_to_free_ptr != NULL) - { - gdb_assert (data == *memory_to_free_ptr); - *memory_to_free_ptr = NULL; - } - xfree (data); - return retval; - } - - return -1; -} - /* A structure for passing information through linux_find_memory_regions_full. */ diff --git a/gdb/target.c b/gdb/target.c index 33afe2b..db06389 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -43,6 +43,7 @@ #include "tracepoint.h" #include "gdb/fileio.h" #include "agent.h" +#include "common-target.h" static void target_info (char *, int); @@ -3492,6 +3493,11 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, return target_fileio_pread (handle, read_buf, len, offset, target_errno); } +typedef LONGEST (read_stralloc_func_ftype) (const char *filename, + gdb_byte **buf_p, int padding); + +static read_stralloc_func_ftype target_fileio_read_alloc_1; + /* Read target file FILENAME. Store the result in *BUF_P and return the size of the transferred data. PADDING additional bytes are available in *BUF_P. This is a helper function for @@ -3499,67 +3505,6 @@ target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len, information. */ static LONGEST -read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func, - int padding, void **memory_to_free_ptr) -{ - size_t buf_alloc, buf_pos; - gdb_byte *buf; - LONGEST n; - int target_errno; - - /* 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); - if (memory_to_free_ptr != NULL) - { - gdb_assert (*memory_to_free_ptr == NULL); - *memory_to_free_ptr = buf; - } - buf_pos = 0; - while (1) - { - n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding, - buf_pos, &target_errno); - if (n <= 0) - { - if (n < 0 || (n == 0 && buf_pos == 0)) - xfree (buf); - else - *buf_p = buf; - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = NULL; - if (n < 0) - { - /* An error occurred. */ - return -1; - } - else - { - /* Read all there was. */ - 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); - if (memory_to_free_ptr != NULL) - *memory_to_free_ptr = buf; - } - } -} - -typedef LONGEST (read_stralloc_func_ftype) (const char *filename, - gdb_byte **buf_p, int padding); - -static read_stralloc_func_ftype target_fileio_read_alloc_1; - -static LONGEST target_fileio_read_alloc_1 (const char *filename, gdb_byte **buf_p, int padding) { @@ -3597,37 +3542,6 @@ target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) are returned as allocated but empty strings. A warning is issued if the result contains any embedded NUL bytes. */ -static char * -read_stralloc (const char *filename, read_stralloc_func_ftype *func) -{ - gdb_byte *buffer; - char *bufstr; - LONGEST i, transferred; - - transferred = func (filename, &buffer, 1); - bufstr = (char *) buffer; - - if (transferred < 0) - return NULL; - - if (transferred == 0) - return xstrdup (""); - - bufstr[transferred] = 0; - - /* Check for embedded NUL bytes; but allow trailing NULs. */ - for (i = strlen (bufstr); i < transferred; i++) - if (bufstr[i] != 0) - { - warning (_("target file %s " - "contained unexpected null characters"), - filename); - break; - } - - return bufstr; -} - char * target_fileio_read_stralloc (const char *filename) { -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-16 18:03 ` Aleksandar Ristovski ` (5 preceding siblings ...) 2013-04-16 18:31 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski @ 2013-04-16 18:31 ` Aleksandar Ristovski 2013-04-18 10:15 ` Jan Kratochvil 2013-04-16 20:24 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski 7 siblings, 1 reply; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 18:31 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * gdb.base/solib-mismatch-lib.c: New file. * gdb.base/solib-mismatch-libmod.c: New file. * gdb.base/solib-mismatch.c: New file. * gdb.base/solib-mismatch.exp: New file. --- gdb/testsuite/gdb.base/solib-mismatch-lib.c | 29 +++++ gdb/testsuite/gdb.base/solib-mismatch-libmod.c | 29 +++++ gdb/testsuite/gdb.base/solib-mismatch.c | 56 +++++++++ gdb/testsuite/gdb.base/solib-mismatch.exp | 150 ++++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-lib.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch-libmod.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.c create mode 100644 gdb/testsuite/gdb.base/solib-mismatch.exp diff --git a/gdb/testsuite/gdb.base/solib-mismatch-lib.c b/gdb/testsuite/gdb.base/solib-mismatch-lib.c new file mode 100644 index 0000000..19f1545 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch-lib.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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/>. */ + + +int _bar = 42; + +int bar(void) +{ + return _bar + 21; +} + +int foo(void) +{ + return _bar; +} diff --git a/gdb/testsuite/gdb.base/solib-mismatch-libmod.c b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c new file mode 100644 index 0000000..3b025a8 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch-libmod.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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/>. */ + + +int _bar = 21; + +int bar(void) +{ + return 42 - _bar; +} + +int foo(void) +{ + return 24 + bar(); +} diff --git a/gdb/testsuite/gdb.base/solib-mismatch.c b/gdb/testsuite/gdb.base/solib-mismatch.c new file mode 100644 index 0000000..7a5d960 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch.c @@ -0,0 +1,56 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + 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 <dlfcn.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> + +/* The following defines must correspond to solib-mismatch.exp */ + +/* DIRNAME must be defined at compile time. */ +#ifndef DIRNAME +#error DIRNAME not defined +#endif +#ifndef LIB +#error LIB not defined +#endif + +int main (int argc, char *argv[]) +{ + void *h; + int (*foo) (void); + + if (chdir (DIRNAME) != 0) + { + printf ("ERROR - Could not cd to %s\n", DIRNAME); + return 1; + } + + h = dlopen (LIB, RTLD_NOW); + + if (h == NULL) + { + printf ("ERROR - could not open lib %s\n", LIB); + return 1; + } + foo = dlsym (h, "foo"); /* set breakpoint 1 here */ + dlclose (h); + return 0; +} diff --git a/gdb/testsuite/gdb.base/solib-mismatch.exp b/gdb/testsuite/gdb.base/solib-mismatch.exp new file mode 100644 index 0000000..4504bc3 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-mismatch.exp @@ -0,0 +1,150 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# 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/>. */ + +standard_testfile +set executable $testfile + +# Test overview: +# generate two shared objects. One that will be used by the process +# and another, modified, that will be found by gdb. Gdb should +# detect the mismatch and refuse to use mismatched shared object. + +if { [get_compiler_info] } { + untested "get_compiler_info failed." + return -1 +} + +# First version of the object, to be loaded by ld. +set srclibfilerun ${testfile}-lib.c + +# Modified version of the object to be loaded by gdb +# Code in -libmod.c is tuned so it gives a mismatch but +# leaves .dynamic at the same point. +set srclibfilegdb ${testfile}-libmod.c + +# So file name: +set binlibfilebase lib${testfile}.so + +# Setup run directory (where program is run from) +# It contains executable and '-lib' version of the library. +set binlibfiledirrun [standard_output_file ${testfile}_wd] +set binlibfilerun ${binlibfiledirrun}/${binlibfilebase} + +# Second solib version is in current directory, '-libmod' version. +set binlibfiledirgdb [standard_output_file ""] +set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase} + +# Executable +set srcfile ${testfile}.c +set executable ${testfile} + +file delete -force -- "${binlibfiledirrun}" +file mkdir "${binlibfiledirrun}" + +set exec_opts {} + +if { ![istarget "*-*-nto-*"] } { + lappend exec_opts "shlib_load" +} + +lappend exec_opts "additional_flags=-DDIRNAME\=\"${binlibfiledirrun}\" -DLIB\=\"./${binlibfilebase}\"" +lappend exec_opts "debug" + +if { [build_executable $testfile.exp $executable $srcfile $exec_opts] != 0 } { + return -1 +} + +if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,--build-id]] != "" + || [gdb_gnu_strip_debug "${binlibfilerun}"] + || [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,--build-id]] != "" } { + untested "gdb_compile_shlib failed." + return -1 +} + +proc solib_matching_test { solibfile symsloaded msg } { + global gdb_prompt + global testfile + global executable + global srcdir + global subdir + global binlibfiledirrun + global binlibfiledirgdb + global srcfile + + clean_restart ${binlibfiledirrun}/${executable} + + gdb_test_no_output "set solib-search-path \"${binlibfiledirgdb}\"" "" + if { [gdb_test "cd ${binlibfiledirgdb}" "" ""] != 0 } { + untested "cd ${binlibfiledirgdb}" + return -1 + } + + # Do not auto load shared libraries, the test needs to have control + # over when the relevant output gets printed. + gdb_test_no_output "set auto-solib-add off" "" + + if ![runto "${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]"] { + return -1 + } + + gdb_test "sharedlibrary" "" "" + + set nocrlf "\[^\r\n\]*" + set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" + set expected_line "${symsloaded}${nocrlf}${solibfile}" + + gdb_test "info sharedlibrary ${solibfile}" \ + "${expected_header}\r\n.*${expected_line}.*" \ + "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" + + return 0 +} + +# Copy binary to working dir so it pulls in the library from that dir +# (by the virtue of $ORIGIN). +file copy -force "${binlibfiledirgdb}/${executable}" \ + "${binlibfiledirrun}/${executable}" + +# Test unstripped, .dynamic matching +if { [solib_matching_test "${binlibfilebase}" "No" \ + "test unstripped, .dynamic matching"] != 0 } { + untested "test unstripped, .dynamic matching" +} + +# Keep original so for debugging purposes +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig" +set objcopy_program [transform objcopy] +set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"] +if {$result != 0} { + untested "test --only-keep-debug (objcopy)" +} + +# Test --only-keep-debug, .dynamic matching so +if { [solib_matching_test "${binlibfilebase}" "No" \ + "test --only-keep-debug"] != 0 } { + untested "test --only-keep-debug" +} + +# Keep previous so for debugging puroses +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1" + +# Copy loaded so over the one gdb will find +file copy -force "${binlibfilerun}" "${binlibfilegdb}" + +# Now test it does not mis-invalidate matching libraries +if { [solib_matching_test "${binlibfilebase}" "Yes" \ + "test matching libraries"] } { + untested "test matching libraries" +} -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 8/8] Tests for validate symbol file using build-id. 2013-04-16 18:31 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski @ 2013-04-18 10:15 ` Jan Kratochvil 0 siblings, 0 replies; 42+ messages in thread From: Jan Kratochvil @ 2013-04-18 10:15 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches On Tue, 16 Apr 2013 17:44:56 +0200, Aleksandar Ristovski wrote: [...] > +proc solib_matching_test { solibfile symsloaded msg } { > + global gdb_prompt > + global testfile > + global executable > + global srcdir > + global subdir > + global binlibfiledirrun > + global binlibfiledirgdb > + global srcfile > + > + clean_restart ${binlibfiledirrun}/${executable} > + > + gdb_test_no_output "set solib-search-path \"${binlibfiledirgdb}\"" "" > + if { [gdb_test "cd ${binlibfiledirgdb}" "" ""] != 0 } { > + untested "cd ${binlibfiledirgdb}" > + return -1 > + } > + > + # Do not auto load shared libraries, the test needs to have control > + # over when the relevant output gets printed. > + gdb_test_no_output "set auto-solib-add off" "" > + > + if ![runto "${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]"] { > + return -1 > + } > + > + gdb_test "sharedlibrary" "" "" > + > + set nocrlf "\[^\r\n\]*" > + set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}" > + set expected_line "${symsloaded}${nocrlf}${solibfile}" > + > + gdb_test "info sharedlibrary ${solibfile}" \ > + "${expected_header}\r\n.*${expected_line}.*" \ > + "${msg} - Symbols for ${solibfile} loaded: expected '${symsloaded}'" > + > + return 0 > +} > + > +# Copy binary to working dir so it pulls in the library from that dir > +# (by the virtue of $ORIGIN). > +file copy -force "${binlibfiledirgdb}/${executable}" \ > + "${binlibfiledirrun}/${executable}" > + > +# Test unstripped, .dynamic matching > +if { [solib_matching_test "${binlibfilebase}" "No" \ > + "test unstripped, .dynamic matching"] != 0 } { > + untested "test unstripped, .dynamic matching" I do not understand this message. "untested" means some tests were skipped. But here no tests are skipped. And the callee in one case already prints "untested" itself (cd ${binlibfiledirgdb}) and in other case it just prints FAIL without any "untested" output (runto). In the first case there will be two "untested" messages. When you are so corrected with "untested" messages make sure it is printed even in the failed "runto" case and also that "untested" is printed only once. > +} > + > +# Keep original so for debugging purposes > +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig" > +set objcopy_program [transform objcopy] > +set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"] > +if {$result != 0} { > + untested "test --only-keep-debug (objcopy)" "untested" is inappropriate here because no tests are skipped. Either put also "return -1" here or remove the "untested" message. Maybe you meant "xfail" here, that something failed in the supporting system environment. > +} > + > +# Test --only-keep-debug, .dynamic matching so > +if { [solib_matching_test "${binlibfilebase}" "No" \ > + "test --only-keep-debug"] != 0 } { > + untested "test --only-keep-debug" Likewise probably "xfail". > +} > + > +# Keep previous so for debugging puroses > +file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1" > + > +# Copy loaded so over the one gdb will find > +file copy -force "${binlibfilerun}" "${binlibfilegdb}" > + > +# Now test it does not mis-invalidate matching libraries > +if { [solib_matching_test "${binlibfilebase}" "Yes" \ > + "test matching libraries"] } { > + untested "test matching libraries" Likewise duplicate "untested" message. > +} > -- > 1.7.10.4 Thanks, Jan ^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] 2013-04-16 18:03 ` Aleksandar Ristovski ` (6 preceding siblings ...) 2013-04-16 18:31 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski @ 2013-04-16 20:24 ` Aleksandar Ristovski 7 siblings, 0 replies; 42+ messages in thread From: Aleksandar Ristovski @ 2013-04-16 20:24 UTC (permalink / raw) To: gdb-patches; +Cc: jan.kratochvil, Aleksandar Ristovski * Makefile.in (HFILES_NO_SRCDIR); Add common/linux-maps.h, common/common-target.h. (COMMON_OBS): Add common-target.o. (linux-maps.o, common-target.o): New. * common/common-target.c: New file. * common/common-target.h: New file. * common/linux-maps.c: New file. * common/linux-maps.h: New file. * config/i386/linux.mh (NATDEPFILES): Add linux-maps.o. * config/i386/linux64.mh (NATDEPFILES): Ditto. * gdbserver/Makefile.in (OBS): Add common-taret.o. (linux-maps.o, common-target.o): New. * gdbserver/configure.srv (srv_tgtobj): Add linux-maps.o. --- gdb/Makefile.in | 15 ++++++-- gdb/common/common-target.c | 27 +++++++++++++++ gdb/common/common-target.h | 24 +++++++++++++ gdb/common/linux-maps.c | 25 ++++++++++++++ gdb/common/linux-maps.h | 22 ++++++++++++ gdb/config/i386/linux.mh | 2 +- gdb/config/i386/linux64.mh | 2 +- gdb/gdbserver/Makefile.in | 8 ++++- gdb/gdbserver/configure.srv | 79 ++++++++++++++++++++++++++++++++----------- 9 files changed, 180 insertions(+), 24 deletions(-) create mode 100644 gdb/common/common-target.c create mode 100644 gdb/common/common-target.h create mode 100644 gdb/common/linux-maps.c create mode 100644 gdb/common/linux-maps.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index dd874ce..d4158f4 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -779,7 +779,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c HFILES_NO_SRCDIR = \ common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \ -common/i386-xstate.h common/linux-ptrace.h \ +common/i386-xstate.h common/linux-maps.h common/linux-ptrace.h \ proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \ ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \ exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \ @@ -845,7 +845,9 @@ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \ common/format.h common/host-defs.h utils.h common/queue.h common/gdb_string.h \ common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \ gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \ -ctf.h +ctf.h \ +common/common-target.h + # Header files that already have srcdir in them, or which are in objdir. @@ -938,6 +940,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \ gdb_vecs.o jit.o progspace.o skip.o probe.o \ common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \ + common-target.o \ format.o registry.o btrace.o record-btrace.o TSOBS = inflow.o @@ -1973,6 +1976,10 @@ format.o: ${srcdir}/common/format.c $(COMPILE) $(srcdir)/common/format.c $(POSTCOMPILE) +linux-maps.o: ${srcdir}/common/linux-maps.c + $(COMPILE) $(srcdir)/common/linux-maps.c + $(POSTCOMPILE) + linux-osdata.o: ${srcdir}/common/linux-osdata.c $(COMPILE) $(srcdir)/common/linux-osdata.c $(POSTCOMPILE) @@ -1989,6 +1996,10 @@ common-agent.o: $(srcdir)/common/agent.c $(COMPILE) $(srcdir)/common/agent.c $(POSTCOMPILE) +common-target.o: ${srcdir}/common/common-target.c + $(COMPILE) $(srcdir)/common/common-target.c + $(POSTCOMPILE) + vec.o: ${srcdir}/common/vec.c $(COMPILE) $(srcdir)/common/vec.c $(POSTCOMPILE) diff --git a/gdb/common/common-target.c b/gdb/common/common-target.c new file mode 100644 index 0000000..a24953e --- /dev/null +++ b/gdb/common/common-target.c @@ -0,0 +1,27 @@ +/* Utility target functions for GDB, and GDBserver. + + Copyright (C) 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "common-target.h" + diff --git a/gdb/common/common-target.h b/gdb/common/common-target.h new file mode 100644 index 0000000..f56cb72 --- /dev/null +++ b/gdb/common/common-target.h @@ -0,0 +1,24 @@ +/* Utility target functions for GDB, and GDBserver. + + Copyright (C) 2013 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/>. */ + +#ifndef COMMON_COMMON_TARGET_H +#define COMMON_COMMON_TARGET_H + +#endif /* COMMON_COMMON_TARGET_H */ + diff --git a/gdb/common/linux-maps.c b/gdb/common/linux-maps.c new file mode 100644 index 0000000..efb0875 --- /dev/null +++ b/gdb/common/linux-maps.c @@ -0,0 +1,25 @@ +/* Linux-specific memory maps manipulation routines. + Copyright (C) 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "linux-maps.h" diff --git a/gdb/common/linux-maps.h b/gdb/common/linux-maps.h new file mode 100644 index 0000000..da426e5 --- /dev/null +++ b/gdb/common/linux-maps.h @@ -0,0 +1,22 @@ +/* Linux-specific memory maps manipulation routines. + Copyright (C) 2013 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/>. */ + +#ifndef COMMON_LINUX_MAPS_H +#define COMMON_LINUX_MAPS_H + +#endif /* COMMON_LINUX_MAPS_H */ diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh index 7c64e83..e34f1dc 100644 --- a/gdb/config/i386/linux.mh +++ b/gdb/config/i386/linux.mh @@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o i386-linux-nat.o \ - proc-service.o linux-thread-db.o \ + proc-service.o linux-thread-db.o linux-maps.o \ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ linux-btrace.o NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh index 8d782c1..78ecf30 100644 --- a/gdb/config/i386/linux64.mh +++ b/gdb/config/i386/linux64.mh @@ -1,7 +1,7 @@ # Host: GNU/Linux x86-64 NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o amd64-nat.o amd64-linux-nat.o \ - linux-nat.o linux-osdata.o \ + linux-maps.o linux-nat.o linux-osdata.o \ proc-service.o linux-thread-db.o linux-fork.o \ linux-procfs.o linux-ptrace.o linux-btrace.o NAT_FILE= config/nm-linux.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 6c3d7bd..b08d401 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -167,7 +167,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o target.o \ utils.o version.o vec.o gdb_vecs.o \ mem-break.o hostio.o event-loop.o tracepoint.o \ - xml-utils.o common-utils.o ptid.o buffer.o format.o \ + xml-utils.o common-target.o common-utils.o ptid.o buffer.o format.o \ dll.o notif.o \ $(XML_BUILTIN) \ $(DEPFILES) $(LIBOBJS) @@ -510,12 +510,18 @@ ax.o: ax.c signals.o: ../common/signals.c $(COMPILE) $< $(POSTCOMPILE) +linux-maps.o: ../common/linux-maps.c + $(COMPILE) $< + $(POSTCOMPILE) linux-procfs.o: ../common/linux-procfs.c $(COMPILE) $< $(POSTCOMPILE) linux-ptrace.o: ../common/linux-ptrace.c $(COMPILE) $< $(POSTCOMPILE) +common-target.o: ../common/common-target.c + $(COMPILE) $< + $(POSTCOMPILE) common-utils.o: ../common/common-utils.c $(COMPILE) $< $(POSTCOMPILE) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 271a0fe..f3669d6 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -46,6 +46,7 @@ case "${target}" in srv_regobj="aarch64.o aarch64-without-fpu.o" srv_tgtobj="linux-aarch64-low.o" srv_tgtobj="${srv_tgtobj} linux-low.o" + srv_tgtobj="${srv_tgtobj} linux-maps.o" srv_tgtobj="${srv_tgtobj} linux-osdata.o" srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" @@ -61,7 +62,9 @@ case "${target}" in srv_regobj="${srv_regobj} arm-with-vfpv2.o" srv_regobj="${srv_regobj} arm-with-vfpv3.o" srv_regobj="${srv_regobj} arm-with-neon.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-arm-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="arm-with-iwmmxt.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml" @@ -84,19 +87,25 @@ case "${target}" in srv_mingwce=yes ;; bfin-*-*linux*) srv_regobj=reg-bfin.o - srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-bfin-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes ;; crisv32-*-linux*) srv_regobj=reg-crisv32.o - srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-crisv32-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes ;; cris-*-linux*) srv_regobj=reg-cris.o - srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-cris-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes @@ -111,7 +120,10 @@ case "${target}" in srv_regobj="$srv_regobj $srv_amd64_linux_regobj" srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles" fi - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-x86-low.o" + srv_tgtobj="${srv_tgtobj} i386-low.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -147,12 +159,16 @@ case "${target}" in srv_qnx="yes" ;; ia64-*-linux*) srv_regobj=reg-ia64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-ia64-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes ;; m32r*-*-linux*) srv_regobj=reg-m32r.o - srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m32r-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_thread_db=yes @@ -162,7 +178,9 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m68k-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -173,7 +191,9 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-m68k-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes @@ -183,7 +203,10 @@ case "${target}" in srv_regobj="${srv_regobj} mips-dsp-linux.o" srv_regobj="${srv_regobj} mips64-linux.o" srv_regobj="${srv_regobj} mips64-dsp-linux.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o" + srv_tgtobj="${srv_tgtobj} linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-mips-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="mips-linux.xml" srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" @@ -216,7 +239,9 @@ case "${target}" in srv_regobj="${srv_regobj} powerpc-isa205-64l.o" srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o" srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-ppc-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="rs6000/powerpc-32l.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml" @@ -262,7 +287,9 @@ case "${target}" in srv_regobj="${srv_regobj} s390x-linux64.o" srv_regobj="${srv_regobj} s390x-linux64v1.o" srv_regobj="${srv_regobj} s390x-linux64v2.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-s390-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_xmlfiles="s390-linux32.xml" srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml" @@ -283,14 +310,18 @@ case "${target}" in srv_linux_thread_db=yes ;; sh*-*-linux*) srv_regobj=reg-sh.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-sh-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes ;; sparc*-*-linux*) srv_regobj=reg-sparc64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-sparc-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes @@ -307,15 +338,20 @@ case "${target}" in srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml" - srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-tic6x-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_usrregs=yes srv_linux_thread_db=yes ;; x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj" - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-x86-low.o i386-low.o" + srv_tgtobj="${srv_tgtobj} i387-fp.o linux-procfs.o" + srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="${srv_tgtobj} linux-btrace.o" srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles" srv_linux_usrregs=yes # This is for i386 progs. srv_linux_regsets=yes @@ -334,13 +370,18 @@ case "${target}" in ;; xtensa*-*-linux*) srv_regobj=reg-xtensa.o - srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-xtensa-low.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes ;; tilegx-*-linux*) srv_regobj=reg-tilegx.o srv_regobj="${srv_regobj} reg-tilegx32.o" - srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o" + srv_tgtobj="linux-low.o linux-maps.o" + srv_tgtobj="${srv_tgtobj} linux-tile-low.o" + srv_tgtobj="${srv_tgtobj} linux-osdata.o" + srv_tgtobj="${srv_tgtobj} linux-procfs.o" srv_tgtobj="${srv_tgtobj} linux-ptrace.o" srv_linux_regsets=yes srv_linux_thread_db=yes -- 1.7.10.4 ^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2013-04-17 20:54 UTC | newest] Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-04-09 16:15 [PATCH 0/8] v2 - validate binary before use Aleksandar Ristovski 2013-04-09 15:53 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski 2013-04-09 16:01 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski 2013-04-09 16:03 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski 2013-04-15 13:34 ` Jan Kratochvil 2013-04-09 16:39 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski 2013-04-15 13:36 ` Jan Kratochvil 2013-04-16 17:19 ` Aleksandar Ristovski 2013-04-09 16:48 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski 2013-04-15 13:52 ` Jan Kratochvil 2013-04-16 15:46 ` Aleksandar Ristovski 2013-04-09 16:55 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski 2013-04-09 18:52 ` Eli Zaretskii 2013-04-15 14:23 ` Jan Kratochvil 2013-04-16 16:40 ` Aleksandar Ristovski 2013-04-18 10:08 ` Jan Kratochvil 2013-04-09 17:37 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski 2013-04-15 15:12 ` Jan Kratochvil 2013-04-16 17:25 ` Aleksandar Ristovski 2013-04-18 5:37 ` Jan Kratochvil 2013-04-09 17:50 ` [PATCH 7/8] Validate " Aleksandar Ristovski 2013-04-10 22:35 ` Aleksandar Ristovski 2013-04-10 19:58 ` Aleksandar Ristovski 2013-04-11 1:26 ` Jan Kratochvil 2013-04-11 2:43 ` Aleksandar Ristovski 2013-04-15 14:58 ` Jan Kratochvil 2013-04-16 19:14 ` Aleksandar Ristovski 2013-04-18 10:23 ` Jan Kratochvil 2013-04-09 17:53 ` [PATCH 0/8] v2 - validate binary before use Jan Kratochvil 2013-04-09 18:09 ` Aleksandar Ristovski 2013-04-16 18:03 ` Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 2/8] Merge multiple hex conversions Aleksandar Ristovski 2013-04-16 18:30 ` [PATCH 7/8] Validate symbol file using build-id Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 4/8] Prepare linux_find_memory_regions_full & co. for move Aleksandar Ristovski 2013-04-18 8:58 ` Jan Kratochvil 2013-04-16 18:31 ` [PATCH 1/8] Move utility functions to common/ Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 6/8] gdbserver build-id attribute generator Aleksandar Ristovski 2013-04-18 7:40 ` Jan Kratochvil 2013-04-16 18:31 ` [PATCH 5/8] Move linux_find_memory_regions_full & co Aleksandar Ristovski 2013-04-16 18:31 ` [PATCH 8/8] Tests for validate symbol file using build-id Aleksandar Ristovski 2013-04-18 10:15 ` Jan Kratochvil 2013-04-16 20:24 ` [PATCH 3/8] Create empty common/linux-maps.[ch] and common/common-target.[ch] Aleksandar Ristovski
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox