diff options
author | Jim Blandy <jimb@codesourcery.com> | 2002-05-13 18:13:07 +0000 |
---|---|---|
committer | Jim Blandy <jimb@codesourcery.com> | 2002-05-13 18:13:07 +0000 |
commit | ec2bcbe7540d6ffda2119ad95ba0b9326e497b28 (patch) | |
tree | a16c0ccc63b7ca477d2695cc5131e9d54c3f61f8 /gdb | |
parent | 6d53172289ad02b0ca255c6b85d79c2d9be43b4f (diff) | |
download | gdb-ec2bcbe7540d6ffda2119ad95ba0b9326e497b28.zip gdb-ec2bcbe7540d6ffda2119ad95ba0b9326e497b28.tar.gz gdb-ec2bcbe7540d6ffda2119ad95ba0b9326e497b28.tar.bz2 |
Add first preprocessor macro-expansion files.
* macroexp.c, macroexp.h, macrotab.c, macrotab.h: New files.
* Makefile.in (SFILES): Add macrotab.c, macroexp.c.
(splay_tree_h, macroexp_h, macrotab_h): New variable.
(HFILES_NO_SRCDIR): Add macrotab.h, macroexp.h.
(COMMON_OBS): Add macrotab.o, macroexp.o.
(macroexp.o, macrotab.o): New rules.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/Makefile.in | 11 | ||||
-rw-r--r-- | gdb/macroexp.c | 1169 | ||||
-rw-r--r-- | gdb/macroexp.h | 90 | ||||
-rw-r--r-- | gdb/macrotab.c | 862 | ||||
-rw-r--r-- | gdb/macrotab.h | 295 |
6 files changed, 2437 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 79d5dd6..b884162 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2002-05-13 Jim Blandy <jimb@redhat.com> + + Add first preprocessor macro-expansion files. + * macroexp.c, macroexp.h, macrotab.c, macrotab.h: New files. + * Makefile.in (SFILES): Add macrotab.c, macroexp.c. + (splay_tree_h, macroexp_h, macrotab_h): New variable. + (HFILES_NO_SRCDIR): Add macrotab.h, macroexp.h. + (COMMON_OBS): Add macrotab.o, macroexp.o. + (macroexp.o, macrotab.o): New rules. + 2002-05-13 Andrew Cagney <ac131313@redhat.com> * config/m88k/tm-m88k.h: Update copyright. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 143e548..36fb4ac 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -539,6 +539,7 @@ SFILES = ax-general.c ax-gdb.c bcache.c blockframe.c breakpoint.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \ memattr.c mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c \ p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c \ + macrotab.c macroexp.c \ printcmd.c remote.c remote-nrom.c scm-exp.c scm-lang.c \ scm-valprint.c source.c stabsread.c stack.c symfile.c \ symmisc.c symtab.c linespec.c target.c thread.c top.c tracepoint.c \ @@ -571,6 +572,7 @@ dis_asm_h = $(INCLUDE_DIR)/dis-asm.h remote-sim_h = $(INCLUDE_DIR)/remote-sim.h demangle_h = $(INCLUDE_DIR)/demangle.h obstack_h = $(INCLUDE_DIR)/obstack.h +splay_tree_h = $(INCLUDE_DIR)/splay-tree.h readline_headers = \ $(READLINE_SRC)/chardefs.h \ @@ -634,6 +636,8 @@ inf_loop_h = inf-loop.h inferior_h = inferior.h $(breakpoint_h) language_h = language.h linespec_h = linespec.h +macroexp_h = macroexp.h +macrotab_h = macrotab.h $(obstack_h) $(bcache_h) memattr_h = memattr.h monitor_h = monitor.h objfiles_h = objfiles.h @@ -672,6 +676,7 @@ HFILES_NO_SRCDIR = bcache.h buildsym.h call-cmds.h coff-solib.h defs.h \ gdb-stabs.h $(inferior_h) language.h minimon.h monitor.h \ objfiles.h parser-defs.h serial.h solib.h \ symfile.h stabsread.h target.h terminal.h typeprint.h xcoffsolib.h \ + macrotab.h macroexp.h \ c-lang.h ch-lang.h f-lang.h \ jv-lang.h \ m2-lang.h p-lang.h \ @@ -714,6 +719,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \ symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \ expprint.o environ.o stack.o thread.o \ + macrotab.o macroexp.o \ event-loop.o event-top.o inf-loop.o completer.o \ gdbarch.o arch-utils.o gdbtypes.o copying.o $(DEPFILES) \ memattr.o mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \ @@ -2124,6 +2130,11 @@ linespec.o: linespec.c $(linespec_h) $(defs_h) $(frame_h) $(value_h) \ $(objfiles_h) $(symfile_h) $(completer_h) $(symtab_h) \ $(demangle_h) $(command_h) $(cp_abi_h) +macroexp.o: macroexp.c $(defs_h) $(macrotab_h) + +macrotab.o: macrotab.c $(defs_h) $(obstack_h) $(objfiles_h) $(symtab_h) \ + $(macrotab_h) $(splay_tree_h) gdb_assert.h $(bcache_h) + target.o: target.c $(bfd_h) $(defs_h) $(gdbcmd_h) $(inferior_h) \ $(objfiles_h) $(symfile_h) $(target_h) $(gdb_string_h) $(regcache_h) diff --git a/gdb/macroexp.c b/gdb/macroexp.c new file mode 100644 index 0000000..cb97f42 --- /dev/null +++ b/gdb/macroexp.c @@ -0,0 +1,1169 @@ +/* C preprocessor macro expansion for GDB. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Red Hat, 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bcache.h" +#include "macrotab.h" +#include "macroexp.h" +#include "gdb_assert.h" + + + +/* A resizeable, substringable string type. */ + + +/* A string type that we can resize, quickly append to, and use to + refer to substrings of other strings. */ +struct macro_buffer +{ + /* An array of characters. The first LEN bytes are the real text, + but there are SIZE bytes allocated to the array. If SIZE is + zero, then this doesn't point to a malloc'ed block. If SHARED is + non-zero, then this buffer is actually a pointer into some larger + string, and we shouldn't append characters to it, etc. Because + of sharing, we can't assume in general that the text is + null-terminated. */ + char *text; + + /* The number of characters in the string. */ + int len; + + /* The number of characters allocated to the string. If SHARED is + non-zero, this is meaningless; in this case, we set it to zero so + that any "do we have room to append something?" tests will fail, + so we don't always have to check SHARED before using this field. */ + int size; + + /* Zero if TEXT can be safely realloc'ed (i.e., it's its own malloc + block). Non-zero if TEXT is actually pointing into the middle of + some other block, and we shouldn't reallocate it. */ + int shared; + + /* For detecting token splicing. + + This is the index in TEXT of the first character of the token + that abuts the end of TEXT. If TEXT contains no tokens, then we + set this equal to LEN. If TEXT ends in whitespace, then there is + no token abutting the end of TEXT (it's just whitespace), and + again, we set this equal to LEN. We set this to -1 if we don't + know the nature of TEXT. */ + int last_token; + + /* If this buffer is holding the result from get_token, then this + is non-zero if it is an identifier token, zero otherwise. */ + int is_identifier; +}; + + +/* Set the macro buffer *B to the empty string, guessing that its + final contents will fit in N bytes. (It'll get resized if it + doesn't, so the guess doesn't have to be right.) Allocate the + initial storage with xmalloc. */ +static void +init_buffer (struct macro_buffer *b, int n) +{ + /* Small value for initial testing. */ + n = 1; + + b->size = n; + if (n > 0) + b->text = (char *) xmalloc (n); + else + b->text = 0; + b->len = 0; + b->shared = 0; + b->last_token = -1; +} + + +/* Set the macro buffer *BUF to refer to the LEN bytes at ADDR, as a + shared substring. */ +static void +init_shared_buffer (struct macro_buffer *buf, char *addr, int len) +{ + buf->text = addr; + buf->len = len; + buf->shared = 1; + buf->size = 0; + buf->last_token = -1; +} + + +/* Free the text of the buffer B. Raise an error if B is shared. */ +static void +free_buffer (struct macro_buffer *b) +{ + gdb_assert (! b->shared); + if (b->size) + xfree (b->text); +} + + +/* A cleanup function for macro buffers. */ +static void +cleanup_macro_buffer (void *untyped_buf) +{ + free_buffer ((struct macro_buffer *) untyped_buf); +} + + +/* Resize the buffer B to be at least N bytes long. Raise an error if + B shouldn't be resized. */ +static void +resize_buffer (struct macro_buffer *b, int n) +{ + /* We shouldn't be trying to resize shared strings. */ + gdb_assert (! b->shared); + + if (b->size == 0) + b->size = n; + else + while (b->size <= n) + b->size *= 2; + + b->text = xrealloc (b->text, b->size); +} + + +/* Append the character C to the buffer B. */ +static inline void +appendc (struct macro_buffer *b, int c) +{ + int new_len = b->len + 1; + + if (new_len > b->size) + resize_buffer (b, new_len); + + b->text[b->len] = c; + b->len = new_len; +} + + +/* Append the LEN bytes at ADDR to the buffer B. */ +static inline void +appendmem (struct macro_buffer *b, char *addr, int len) +{ + int new_len = b->len + len; + + if (new_len > b->size) + resize_buffer (b, new_len); + + memcpy (b->text + b->len, addr, len); + b->len = new_len; +} + + + +/* Recognizing preprocessor tokens. */ + + +static int +is_whitespace (int c) +{ + return (c == ' ' + || c == '\t' + || c == '\n' + || c == '\v' + || c == '\f'); +} + + +static int +is_digit (int c) +{ + return ('0' <= c && c <= '9'); +} + + +static int +is_identifier_nondigit (int c) +{ + return (c == '_' + || ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z')); +} + + +static void +set_token (struct macro_buffer *tok, char *start, char *end) +{ + init_shared_buffer (tok, start, end - start); + tok->last_token = 0; + + /* Presumed; get_identifier may overwrite this. */ + tok->is_identifier = 0; +} + + +static int +get_comment (struct macro_buffer *tok, char *p, char *end) +{ + if (p + 2 > end) + return 0; + else if (p[0] == '/' + && p[1] == '*') + { + char *tok_start = p; + + p += 2; + + for (; p < end; p++) + if (p + 2 <= end + && p[0] == '*' + && p[1] == '/') + { + p += 2; + set_token (tok, tok_start, p); + return 1; + } + + error ("Unterminated comment in macro expansion."); + } + else if (p[0] == '/' + && p[1] == '/') + { + char *tok_start = p; + + p += 2; + for (; p < end; p++) + if (*p == '\n') + break; + + set_token (tok, tok_start, p); + return 1; + } + else + return 0; +} + + +static int +get_identifier (struct macro_buffer *tok, char *p, char *end) +{ + if (p < end + && is_identifier_nondigit (*p)) + { + char *tok_start = p; + + while (p < end + && (is_identifier_nondigit (*p) + || is_digit (*p))) + p++; + + set_token (tok, tok_start, p); + tok->is_identifier = 1; + return 1; + } + else + return 0; +} + + +static int +get_pp_number (struct macro_buffer *tok, char *p, char *end) +{ + if (p < end + && (is_digit (*p) + || *p == '.')) + { + char *tok_start = p; + + while (p < end) + { + if (is_digit (*p) + || is_identifier_nondigit (*p) + || *p == '.') + p++; + else if (p + 2 <= end + && strchr ("eEpP.", *p) + && (p[1] == '+' || p[1] == '-')) + p += 2; + else + break; + } + + set_token (tok, tok_start, p); + return 1; + } + else + return 0; +} + + + +/* If the text starting at P going up to (but not including) END + starts with a character constant, set *TOK to point to that + character constant, and return 1. Otherwise, return zero. + Signal an error if it contains a malformed or incomplete character + constant. */ +static int +get_character_constant (struct macro_buffer *tok, char *p, char *end) +{ + /* ISO/IEC 9899:1999 (E) Section 6.4.4.4 paragraph 1 + But of course, what really matters is that we handle it the same + way GDB's C/C++ lexer does. So we call parse_escape in utils.c + to handle escape sequences. */ + if ((p + 1 <= end && *p == '\'') + || (p + 2 <= end && p[0] == 'L' && p[1] == '\'')) + { + char *tok_start = p; + char *body_start; + + if (*p == '\'') + p++; + else if (*p == 'L') + p += 2; + else + gdb_assert (0); + + body_start = p; + for (;;) + { + if (p >= end) + error ("Unmatched single quote."); + else if (*p == '\'') + { + if (p == body_start) + error ("A character constant must contain at least one " + "character."); + p++; + break; + } + else if (*p == '\\') + { + p++; + parse_escape (&p); + } + else + p++; + } + + set_token (tok, tok_start, p); + return 1; + } + else + return 0; +} + + +/* If the text starting at P going up to (but not including) END + starts with a string literal, set *TOK to point to that string + literal, and return 1. Otherwise, return zero. Signal an error if + it contains a malformed or incomplete string literal. */ +static int +get_string_literal (struct macro_buffer *tok, char *p, char *end) +{ + if ((p + 1 <= end + && *p == '\"') + || (p + 2 <= end + && p[0] == 'L' + && p[1] == '\"')) + { + char *tok_start = p; + + if (*p == '\"') + p++; + else if (*p == 'L') + p += 2; + else + gdb_assert (0); + + for (;;) + { + if (p >= end) + error ("Unterminated string in expression."); + else if (*p == '\"') + { + p++; + break; + } + else if (*p == '\n') + error ("Newline characters may not appear in string " + "constants."); + else if (*p == '\\') + { + p++; + parse_escape (&p); + } + else + p++; + } + + set_token (tok, tok_start, p); + return 1; + } + else + return 0; +} + + +static int +get_punctuator (struct macro_buffer *tok, char *p, char *end) +{ + /* Here, speed is much less important than correctness and clarity. */ + + /* ISO/IEC 9899:1999 (E) Section 6.4.6 Paragraph 1 */ + static const char * const punctuators[] = { + "[", "]", "(", ")", "{", "}", ".", "->", + "++", "--", "&", "*", "+", "-", "~", "!", + "/", "%", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", + "^", "|", "&&", "||", + "?", ":", ";", "...", + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=", + ",", "#", "##", + "<:", ":>", "<%", "%>", "%:", "%:%:", + 0 + }; + + int i; + + if (p + 1 <= end) + { + for (i = 0; punctuators[i]; i++) + { + const char *punctuator = punctuators[i]; + + if (p[0] == punctuator[0]) + { + int len = strlen (punctuator); + + if (p + len <= end + && ! memcmp (p, punctuator, len)) + { + set_token (tok, p, p + len); + return 1; + } + } + } + } + + return 0; +} + + +/* Peel the next preprocessor token off of SRC, and put it in TOK. + Mutate TOK to refer to the first token in SRC, and mutate SRC to + refer to the text after that token. SRC must be a shared buffer; + the resulting TOK will be shared, pointing into the same string SRC + does. Initialize TOK's last_token field. Return non-zero if we + succeed, or 0 if we didn't find any more tokens in SRC. */ +static int +get_token (struct macro_buffer *tok, + struct macro_buffer *src) +{ + char *p = src->text; + char *end = p + src->len; + + gdb_assert (src->shared); + + /* From the ISO C standard, ISO/IEC 9899:1999 (E), section 6.4: + + preprocessing-token: + header-name + identifier + pp-number + character-constant + string-literal + punctuator + each non-white-space character that cannot be one of the above + + We don't have to deal with header-name tokens, since those can + only occur after a #include, which we will never see. */ + + while (p < end) + if (is_whitespace (*p)) + p++; + else if (get_comment (tok, p, end)) + p += tok->len; + else if (get_pp_number (tok, p, end) + || get_character_constant (tok, p, end) + || get_string_literal (tok, p, end) + /* Note: the grammar in the standard seems to be + ambiguous: L'x' can be either a wide character + constant, or an identifier followed by a normal + character constant. By trying `get_identifier' after + we try get_character_constant and get_string_literal, + we give the wide character syntax precedence. Now, + since GDB doesn't handle wide character constants + anyway, is this the right thing to do? */ + || get_identifier (tok, p, end) + || get_punctuator (tok, p, end)) + { + /* How many characters did we consume, including whitespace? */ + int consumed = p - src->text + tok->len; + src->text += consumed; + src->len -= consumed; + return 1; + } + else + { + /* We have found a "non-whitespace character that cannot be + one of the above." Make a token out of it. */ + int consumed; + + set_token (tok, p, p + 1); + consumed = p - src->text + tok->len; + src->text += consumed; + src->len -= consumed; + return 1; + } + + return 0; +} + + + +/* Appending token strings, with and without splicing */ + + +/* Append the macro buffer SRC to the end of DEST, and ensure that + doing so doesn't splice the token at the end of SRC with the token + at the beginning of DEST. SRC and DEST must have their last_token + fields set. Upon return, DEST's last_token field is set correctly. + + For example: + + If DEST is "(" and SRC is "y", then we can return with + DEST set to "(y" --- we've simply appended the two buffers. + + However, if DEST is "x" and SRC is "y", then we must not return + with DEST set to "xy" --- that would splice the two tokens "x" and + "y" together to make a single token "xy". However, it would be + fine to return with DEST set to "x y". Similarly, "<" and "<" must + yield "< <", not "<<", etc. */ +static void +append_tokens_without_splicing (struct macro_buffer *dest, + struct macro_buffer *src) +{ + int original_dest_len = dest->len; + struct macro_buffer dest_tail, new_token; + + gdb_assert (src->last_token != -1); + gdb_assert (dest->last_token != -1); + + /* First, just try appending the two, and call get_token to see if + we got a splice. */ + appendmem (dest, src->text, src->len); + + /* If DEST originally had no token abutting its end, then we can't + have spliced anything, so we're done. */ + if (dest->last_token == original_dest_len) + { + dest->last_token = original_dest_len + src->last_token; + return; + } + + /* Set DEST_TAIL to point to the last token in DEST, followed by + all the stuff we just appended. */ + init_shared_buffer (&dest_tail, + dest->text + dest->last_token, + dest->len - dest->last_token); + + /* Re-parse DEST's last token. We know that DEST used to contain + at least one token, so if it doesn't contain any after the + append, then we must have spliced "/" and "*" or "/" and "/" to + make a comment start. (Just for the record, I got this right + the first time. This is not a bug fix.) */ + if (get_token (&new_token, &dest_tail) + && (new_token.text + new_token.len + == dest->text + original_dest_len)) + { + /* No splice, so we're done. */ + dest->last_token = original_dest_len + src->last_token; + return; + } + + /* Okay, a simple append caused a splice. Let's chop dest back to + its original length and try again, but separate the texts with a + space. */ + dest->len = original_dest_len; + appendc (dest, ' '); + appendmem (dest, src->text, src->len); + + init_shared_buffer (&dest_tail, + dest->text + dest->last_token, + dest->len - dest->last_token); + + /* Try to re-parse DEST's last token, as above. */ + if (get_token (&new_token, &dest_tail) + && (new_token.text + new_token.len + == dest->text + original_dest_len)) + { + /* No splice, so we're done. */ + dest->last_token = original_dest_len + 1 + src->last_token; + return; + } + + /* As far as I know, there's no case where inserting a space isn't + enough to prevent a splice. */ + internal_error (__FILE__, __LINE__, + "unable to avoid splicing tokens during macro expansion"); +} + + + +/* Expanding macros! */ + + +/* A singly-linked list of the names of the macros we are currently + expanding --- for detecting expansion loops. */ +struct macro_name_list { + const char *name; + struct macro_name_list *next; +}; + + +/* Return non-zero if we are currently expanding the macro named NAME, + according to LIST; otherwise, return zero. + + You know, it would be possible to get rid of all the NO_LOOP + arguments to these functions by simply generating a new lookup + function and baton which refuses to find the definition for a + particular macro, and otherwise delegates the decision to another + function/baton pair. But that makes the linked list of excluded + macros chained through untyped baton pointers, which will make it + harder to debug. :( */ +static int +currently_rescanning (struct macro_name_list *list, const char *name) +{ + for (; list; list = list->next) + if (! strcmp (name, list->name)) + return 1; + + return 0; +} + + +/* Gather the arguments to a macro expansion. + + NAME is the name of the macro being invoked. (It's only used for + printing error messages.) + + Assume that SRC is the text of the macro invocation immediately + following the macro name. For example, if we're processing the + text foo(bar, baz), then NAME would be foo and SRC will be (bar, + baz). + + If SRC doesn't start with an open paren ( token at all, return + zero, leave SRC unchanged, and don't set *ARGC_P to anything. + + If SRC doesn't contain a properly terminated argument list, then + raise an error. + + Otherwise, return a pointer to the first element of an array of + macro buffers referring to the argument texts, and set *ARGC_P to + the number of arguments we found --- the number of elements in the + array. The macro buffers share their text with SRC, and their + last_token fields are initialized. The array is allocated with + xmalloc, and the caller is responsible for freeing it. + + NOTE WELL: if SRC starts with a open paren ( token followed + immediately by a close paren ) token (e.g., the invocation looks + like "foo()"), we treat that as one argument, which happens to be + the empty list of tokens. The caller should keep in mind that such + a sequence of tokens is a valid way to invoke one-parameter + function-like macros, but also a valid way to invoke zero-parameter + function-like macros. Eeew. + + Consume the tokens from SRC; after this call, SRC contains the text + following the invocation. */ + +static struct macro_buffer * +gather_arguments (const char *name, struct macro_buffer *src, int *argc_p) +{ + struct macro_buffer tok; + int args_len, args_size; + struct macro_buffer *args = 0; + struct cleanup *back_to = make_cleanup (free_current_contents, &args); + + /* Does SRC start with an opening paren token? Read from a copy of + SRC, so SRC itself is unaffected if we don't find an opening + paren. */ + { + struct macro_buffer temp; + init_shared_buffer (&temp, src->text, src->len); + + if (! get_token (&tok, &temp) + || tok.len != 1 + || tok.text[0] != '(') + { + discard_cleanups (back_to); + return 0; + } + } + + /* Consume SRC's opening paren. */ + get_token (&tok, src); + + args_len = 0; + args_size = 1; /* small for initial testing */ + args = (struct macro_buffer *) xmalloc (sizeof (*args) * args_size); + + for (;;) + { + struct macro_buffer *arg; + int depth; + + /* Make sure we have room for the next argument. */ + if (args_len >= args_size) + { + args_size *= 2; + args = xrealloc (args, sizeof (*args) * args_size); + } + + /* Initialize the next argument. */ + arg = &args[args_len++]; + set_token (arg, src->text, src->text); + + /* Gather the argument's tokens. */ + depth = 0; + for (;;) + { + char *start = src->text; + + if (! get_token (&tok, src)) + error ("Malformed argument list for macro `%s'.", name); + + /* Is tok an opening paren? */ + if (tok.len == 1 && tok.text[0] == '(') + depth++; + + /* Is tok is a closing paren? */ + else if (tok.len == 1 && tok.text[0] == ')') + { + /* If it's a closing paren at the top level, then that's + the end of the argument list. */ + if (depth == 0) + { + discard_cleanups (back_to); + *argc_p = args_len; + return args; + } + + depth--; + } + + /* If tok is a comma at top level, then that's the end of + the current argument. */ + else if (tok.len == 1 && tok.text[0] == ',' && depth == 0) + break; + + /* Extend the current argument to enclose this token. If + this is the current argument's first token, leave out any + leading whitespace, just for aesthetics. */ + if (arg->len == 0) + { + arg->text = tok.text; + arg->len = tok.len; + arg->last_token = 0; + } + else + { + arg->len = (tok.text + tok.len) - arg->text; + arg->last_token = tok.text - arg->text; + } + } + } +} + + +/* The `expand' and `substitute_args' functions both invoke `scan' + recursively, so we need a forward declaration somewhere. */ +static void scan (struct macro_buffer *dest, + struct macro_buffer *src, + struct macro_name_list *no_loop, + macro_lookup_ftype *lookup_func, + void *lookup_baton); + + +/* Given the macro definition DEF, being invoked with the actual + arguments given by ARGC and ARGV, substitute the arguments into the + replacement list, and store the result in DEST. + + If it is necessary to expand macro invocations in one of the + arguments, use LOOKUP_FUNC and LOOKUP_BATON to find the macro + definitions, and don't expand invocations of the macros listed in + NO_LOOP. */ +static void +substitute_args (struct macro_buffer *dest, + struct macro_definition *def, + int argc, struct macro_buffer *argv, + struct macro_name_list *no_loop, + macro_lookup_ftype *lookup_func, + void *lookup_baton) +{ + /* A macro buffer for the macro's replacement list. */ + struct macro_buffer replacement_list; + + init_shared_buffer (&replacement_list, (char *) def->replacement, + strlen (def->replacement)); + + gdb_assert (dest->len == 0); + dest->last_token = 0; + + for (;;) + { + struct macro_buffer tok; + char *original_rl_start = replacement_list.text; + int substituted = 0; + + /* Find the next token in the replacement list. */ + if (! get_token (&tok, &replacement_list)) + break; + + /* Just for aesthetics. If we skipped some whitespace, copy + that to DEST. */ + if (tok.text > original_rl_start) + { + appendmem (dest, original_rl_start, tok.text - original_rl_start); + dest->last_token = dest->len; + } + + /* Is this token the stringification operator? */ + if (tok.len == 1 + && tok.text[0] == '#') + error ("Stringification is not implemented yet."); + + /* Is this token the splicing operator? */ + if (tok.len == 2 + && tok.text[0] == '#' + && tok.text[1] == '#') + error ("Token splicing is not implemented yet."); + + /* Is this token an identifier? */ + if (tok.is_identifier) + { + int i; + + /* Is it the magic varargs parameter? */ + if (tok.len == 11 + && ! memcmp (tok.text, "__VA_ARGS__", 11)) + error ("Variable-arity macros not implemented yet."); + + /* Is it one of the parameters? */ + for (i = 0; i < def->argc; i++) + if (tok.len == strlen (def->argv[i]) + && ! memcmp (tok.text, def->argv[i], tok.len)) + { + struct macro_buffer arg_src; + + /* Expand any macro invocations in the argument text, + and append the result to dest. Remember that scan + mutates its source, so we need to scan a new buffer + referring to the argument's text, not the argument + itself. */ + init_shared_buffer (&arg_src, argv[i].text, argv[i].len); + scan (dest, &arg_src, no_loop, lookup_func, lookup_baton); + substituted = 1; + break; + } + } + + /* If it wasn't a parameter, then just copy it across. */ + if (! substituted) + append_tokens_without_splicing (dest, &tok); + } +} + + +/* Expand a call to a macro named ID, whose definition is DEF. Append + its expansion to DEST. SRC is the input text following the ID + token. We are currently rescanning the expansions of the macros + named in NO_LOOP; don't re-expand them. Use LOOKUP_FUNC and + LOOKUP_BATON to find definitions for any nested macro references. + + Return 1 if we decided to expand it, zero otherwise. (If it's a + function-like macro name that isn't followed by an argument list, + we don't expand it.) If we return zero, leave SRC unchanged. */ +static int +expand (const char *id, + struct macro_definition *def, + struct macro_buffer *dest, + struct macro_buffer *src, + struct macro_name_list *no_loop, + macro_lookup_ftype *lookup_func, + void *lookup_baton) +{ + struct macro_name_list new_no_loop; + + /* Create a new node to be added to the front of the no-expand list. + This list is appropriate for re-scanning replacement lists, but + it is *not* appropriate for scanning macro arguments; invocations + of the macro whose arguments we are gathering *do* get expanded + there. */ + new_no_loop.name = id; + new_no_loop.next = no_loop; + + /* What kind of macro are we expanding? */ + if (def->kind == macro_object_like) + { + struct macro_buffer replacement_list; + + init_shared_buffer (&replacement_list, (char *) def->replacement, + strlen (def->replacement)); + + scan (dest, &replacement_list, &new_no_loop, lookup_func, lookup_baton); + return 1; + } + else if (def->kind == macro_function_like) + { + struct cleanup *back_to = make_cleanup (null_cleanup, 0); + int argc; + struct macro_buffer *argv = 0; + struct macro_buffer substituted; + struct macro_buffer substituted_src; + + if (def->argc >= 1 + && ! strcmp (def->argv[def->argc - 1], "...")) + error ("Varargs macros not implemented yet."); + + make_cleanup (free_current_contents, &argv); + argv = gather_arguments (id, src, &argc); + + /* If we couldn't find any argument list, then we don't expand + this macro. */ + if (! argv) + { + do_cleanups (back_to); + return 0; + } + + /* Check that we're passing an acceptable number of arguments for + this macro. */ + if (argc != def->argc) + { + /* Remember that a sequence of tokens like "foo()" is a + valid invocation of a macro expecting either zero or one + arguments. */ + if (! (argc == 1 + && argv[0].len == 0 + && def->argc == 0)) + error ("Wrong number of arguments to macro `%s' " + "(expected %d, got %d).", + id, def->argc, argc); + } + + /* Note that we don't expand macro invocations in the arguments + yet --- we let subst_args take care of that. Parameters that + appear as operands of the stringifying operator "#" or the + splicing operator "##" don't get macro references expanded, + so we can't really tell whether it's appropriate to macro- + expand an argument until we see how it's being used. */ + init_buffer (&substituted, 0); + make_cleanup (cleanup_macro_buffer, &substituted); + substitute_args (&substituted, def, argc, argv, no_loop, + lookup_func, lookup_baton); + + /* Now `substituted' is the macro's replacement list, with all + argument values substituted into it properly. Re-scan it for + macro references, but don't expand invocations of this macro. + + We create a new buffer, `substituted_src', which points into + `substituted', and scan that. We can't scan `substituted' + itself, since the tokenization process moves the buffer's + text pointer around, and we still need to be able to find + `substituted's original text buffer after scanning it so we + can free it. */ + init_shared_buffer (&substituted_src, substituted.text, substituted.len); + scan (dest, &substituted_src, &new_no_loop, lookup_func, lookup_baton); + + do_cleanups (back_to); + + return 1; + } + else + internal_error (__FILE__, __LINE__, "bad macro definition kind"); +} + + +/* If the single token in SRC_FIRST followed by the tokens in SRC_REST + constitute a macro invokation not forbidden in NO_LOOP, append its + expansion to DEST and return non-zero. Otherwise, return zero, and + leave DEST unchanged. + + SRC_FIRST and SRC_REST must be shared buffers; DEST must not be one. + SRC_FIRST must be a string built by get_token. */ +static int +maybe_expand (struct macro_buffer *dest, + struct macro_buffer *src_first, + struct macro_buffer *src_rest, + struct macro_name_list *no_loop, + macro_lookup_ftype *lookup_func, + void *lookup_baton) +{ + gdb_assert (src_first->shared); + gdb_assert (src_rest->shared); + gdb_assert (! dest->shared); + + /* Is this token an identifier? */ + if (src_first->is_identifier) + { + /* Make a null-terminated copy of it, since that's what our + lookup function expects. */ + char *id = xmalloc (src_first->len + 1); + struct cleanup *back_to = make_cleanup (xfree, id); + memcpy (id, src_first->text, src_first->len); + id[src_first->len] = 0; + + /* If we're currently re-scanning the result of expanding + this macro, don't expand it again. */ + if (! currently_rescanning (no_loop, id)) + { + /* Does this identifier have a macro definition in scope? */ + struct macro_definition *def = lookup_func (id, lookup_baton); + + if (def && expand (id, def, dest, src_rest, no_loop, + lookup_func, lookup_baton)) + { + do_cleanups (back_to); + return 1; + } + } + + do_cleanups (back_to); + } + + return 0; +} + + +/* Expand macro references in SRC, appending the results to DEST. + Assume we are re-scanning the result of expanding the macros named + in NO_LOOP, and don't try to re-expand references to them. + + SRC must be a shared buffer; DEST must not be one. */ +static void +scan (struct macro_buffer *dest, + struct macro_buffer *src, + struct macro_name_list *no_loop, + macro_lookup_ftype *lookup_func, + void *lookup_baton) +{ + gdb_assert (src->shared); + gdb_assert (! dest->shared); + + for (;;) + { + struct macro_buffer tok; + char *original_src_start = src->text; + + /* Find the next token in SRC. */ + if (! get_token (&tok, src)) + break; + + /* Just for aesthetics. If we skipped some whitespace, copy + that to DEST. */ + if (tok.text > original_src_start) + { + appendmem (dest, original_src_start, tok.text - original_src_start); + dest->last_token = dest->len; + } + + if (! maybe_expand (dest, &tok, src, no_loop, lookup_func, lookup_baton)) + /* We didn't end up expanding tok as a macro reference, so + simply append it to dest. */ + append_tokens_without_splicing (dest, &tok); + } + + /* Just for aesthetics. If there was any trailing whitespace in + src, copy it to dest. */ + if (src->len) + { + appendmem (dest, src->text, src->len); + dest->last_token = dest->len; + } +} + + +char * +macro_expand (const char *source, + macro_lookup_ftype *lookup_func, + void *lookup_func_baton) +{ + struct macro_buffer src, dest; + struct cleanup *back_to; + + init_shared_buffer (&src, (char *) source, strlen (source)); + + init_buffer (&dest, 0); + dest.last_token = 0; + back_to = make_cleanup (cleanup_macro_buffer, &dest); + + scan (&dest, &src, 0, lookup_func, lookup_func_baton); + + appendc (&dest, '\0'); + + discard_cleanups (back_to); + return dest.text; +} + + +char * +macro_expand_once (const char *source, + macro_lookup_ftype *lookup_func, + void *lookup_func_baton) +{ + error ("Expand-once not implemented yet."); +} + + +char * +macro_expand_next (char **lexptr, + macro_lookup_ftype *lookup_func, + void *lookup_baton) +{ + struct macro_buffer src, dest, tok; + struct cleanup *back_to; + + /* Set up SRC to refer to the input text, pointed to by *lexptr. */ + init_shared_buffer (&src, *lexptr, strlen (*lexptr)); + + /* Set up DEST to receive the expansion, if there is one. */ + init_buffer (&dest, 0); + dest.last_token = 0; + back_to = make_cleanup (cleanup_macro_buffer, &dest); + + /* Get the text's first preprocessing token. */ + if (! get_token (&tok, &src)) + { + do_cleanups (back_to); + return 0; + } + + /* If it's a macro invocation, expand it. */ + if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton)) + { + /* It was a macro invocation! Package up the expansion as a + null-terminated string and return it. Set *lexptr to the + start of the next token in the input. */ + appendc (&dest, '\0'); + discard_cleanups (back_to); + *lexptr = src.text; + return dest.text; + } + else + { + /* It wasn't a macro invocation. */ + do_cleanups (back_to); + return 0; + } +} diff --git a/gdb/macroexp.h b/gdb/macroexp.h new file mode 100644 index 0000000..57269fa --- /dev/null +++ b/gdb/macroexp.h @@ -0,0 +1,90 @@ +/* Interface to C preprocessor macro expansion for GDB. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Red Hat, 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +#ifndef MACROEXP_H +#define MACROEXP_H + +/* A function for looking up preprocessor macro definitions. Return + the preprocessor definition of NAME in scope according to BATON, or + zero if NAME is not defined as a preprocessor macro. + + The caller must not free or modify the definition returned. It is + probably unwise for the caller to hold pointers to it for very + long; it probably lives in some objfile's obstacks. */ +typedef struct macro_definition *(macro_lookup_ftype) (const char *name, + void *baton); + + +/* Expand any preprocessor macros in SOURCE, and return the expanded + text. Use LOOKUP_FUNC and LOOKUP_FUNC_BATON to find identifiers' + preprocessor definitions. SOURCE is a null-terminated string. The + result is a null-terminated string, allocated using xmalloc; it is + the caller's responsibility to free it. */ +char *macro_expand (const char *source, + macro_lookup_ftype *lookup_func, + void *lookup_func_baton); + + +/* Expand all preprocessor macro references that appear explicitly in + SOURCE, but do not expand any new macro references introduced by + that first level of expansion. Use LOOKUP_FUNC and + LOOKUP_FUNC_BATON to find identifiers' preprocessor definitions. + SOURCE is a null-terminated string. The result is a + null-terminated string, allocated using xmalloc; it is the caller's + responsibility to free it. */ +char *macro_expand_once (const char *source, + macro_lookup_ftype *lookup_func, + void *lookup_func_baton); + + +/* If the null-terminated string pointed to by *LEXPTR begins with a + macro invocation, return the result of expanding that invocation as + a null-terminated string, and set *LEXPTR to the next character + after the invocation. The result is completely expanded; it + contains no further macro invocations. + + Otherwise, if *LEXPTR does not start with a macro invocation, + return zero, and leave *LEXPTR unchanged. + + Use LOOKUP_FUNC and LOOKUP_BATON to find macro definitions. + + If this function returns a string, the caller is responsible for + freeing it, using xfree. + + We need this expand-one-token-at-a-time interface in order to + accomodate GDB's C expression parser, which may not consume the + entire string. When the user enters a command like + + (gdb) break *func+20 if x == 5 + + the parser is expected to consume `func+20', and then stop when it + sees the "if". But of course, "if" appearing in a character string + or as part of a larger identifier doesn't count. So you pretty + much have to do tokenization to find the end of the string that + needs to be macro-expanded. Our C/C++ tokenizer isn't really + designed to be called by anything but the yacc parser engine. */ +char *macro_expand_next (char **lexptr, + macro_lookup_ftype *lookup_func, + void *lookup_baton); + + +#endif /* MACROEXP_H */ diff --git a/gdb/macrotab.c b/gdb/macrotab.c new file mode 100644 index 0000000..d73ec9e --- /dev/null +++ b/gdb/macrotab.c @@ -0,0 +1,862 @@ +/* C preprocessor macro tables for GDB. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Red Hat, 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "splay-tree.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "macrotab.h" +#include "gdb_assert.h" +#include "bcache.h" +#include "complaints.h" + + +/* The macro table structure. */ + +struct macro_table +{ + /* The obstack this table's data should be allocated in, or zero if + we should use xmalloc. */ + struct obstack *obstack; + + /* The bcache we should use to hold macro names, argument names, and + definitions, or zero if we should use xmalloc. */ + struct bcache *bcache; + + /* The main source file for this compilation unit --- the one whose + name was given to the compiler. This is the root of the + #inclusion tree; everything else is #included from here. */ + struct macro_source_file *main_source; + + /* The table of macro definitions. This is a splay tree (an ordered + binary tree that stays balanced, effectively), sorted by macro + name. Where a macro gets defined more than once (presumably with + an #undefinition in between), we sort the definitions by the + order they would appear in the preprocessor's output. That is, + if `a.c' #includes `m.h' and then #includes `n.h', and both + header files #define X (with an #undef somewhere in between), + then the definition from `m.h' appears in our splay tree before + the one from `n.h'. + + The splay tree's keys are `struct macro_key' pointers; + the values are `struct macro_definition' pointers. + + The splay tree, its nodes, and the keys and values are allocated + in obstack, if it's non-zero, or with xmalloc otherwise. The + macro names, argument names, argument name arrays, and definition + strings are all allocated in bcache, if non-zero, or with xmalloc + otherwise. */ + splay_tree definitions; +}; + + + +/* Allocation and freeing functions. */ + +/* Allocate SIZE bytes of memory appropriately for the macro table T. + This just checks whether T has an obstack, or whether its pieces + should be allocated with xmalloc. */ +static void * +macro_alloc (int size, struct macro_table *t) +{ + if (t->obstack) + return obstack_alloc (t->obstack, size); + else + return xmalloc (size); +} + + +static void +macro_free (void *object, struct macro_table *t) +{ + gdb_assert (! t->obstack); + xfree (object); +} + + +/* If the macro table T has a bcache, then cache the LEN bytes at ADDR + there, and return the cached copy. Otherwise, just xmalloc a copy + of the bytes, and return a pointer to that. */ +static const void * +macro_bcache (struct macro_table *t, const void *addr, int len) +{ + if (t->bcache) + return bcache (addr, len, t->bcache); + else + { + void *copy = xmalloc (len); + memcpy (copy, addr, len); + return copy; + } +} + + +/* If the macro table T has a bcache, cache the null-terminated string + S there, and return a pointer to the cached copy. Otherwise, + xmalloc a copy and return that. */ +static const char * +macro_bcache_str (struct macro_table *t, const char *s) +{ + return (char *) macro_bcache (t, s, strlen (s) + 1); +} + + +/* Free a possibly bcached object OBJ. That is, if the macro table T + has a bcache, it's an error; otherwise, xfree OBJ. */ +void +macro_bcache_free (struct macro_table *t, void *obj) +{ + gdb_assert (! t->bcache); + xfree (obj); +} + + + +/* Macro tree keys, w/their comparison, allocation, and freeing functions. */ + +/* A key in the splay tree. */ +struct macro_key +{ + /* The table we're in. We only need this in order to free it, since + the splay tree library's key and value freeing functions require + that the key or value contain all the information needed to free + themselves. */ + struct macro_table *table; + + /* The name of the macro. This is in the table's bcache, if it has + one. */ + const char *name; + + /* The source file and line number where the definition's scope + begins. This is also the line of the definition itself. */ + struct macro_source_file *start_file; + int start_line; + + /* The first source file and line after the definition's scope. + (That is, the scope does not include this endpoint.) If end_file + is zero, then the definition extends to the end of the + compilation unit. */ + struct macro_source_file *end_file; + int end_line; +}; + + +/* Return the #inclusion depth of the source file FILE. This is the + number of #inclusions it took to reach this file. For the main + source file, the #inclusion depth is zero; for a file it #includes + directly, the depth would be one; and so on. */ +static int +inclusion_depth (struct macro_source_file *file) +{ + int depth; + + for (depth = 0; file->included_by; depth++) + file = file->included_by; + + return depth; +} + + +/* Compare two source locations (from the same compilation unit). + This is part of the comparison function for the tree of + definitions. + + LINE1 and LINE2 are line numbers in the source files FILE1 and + FILE2. Return a value: + - less than zero if {LINE,FILE}1 comes before {LINE,FILE}2, + - greater than zero if {LINE,FILE}1 comes after {LINE,FILE}2, or + - zero if they are equal. + + When the two locations are in different source files --- perhaps + one is in a header, while another is in the main source file --- we + order them by where they would appear in the fully pre-processed + sources, where all the #included files have been substituted into + their places. */ +static int +compare_locations (struct macro_source_file *file1, int line1, + struct macro_source_file *file2, int line2) +{ + /* We want to treat positions in an #included file as coming *after* + the line containing the #include, but *before* the line after the + include. As we walk up the #inclusion tree toward the main + source file, we update fileX and lineX as we go; includedX + indicates whether the original position was from the #included + file. */ + int included1 = 0; + int included2 = 0; + + /* If a file is zero, that means "end of compilation unit." Handle + that specially. */ + if (! file1) + { + if (! file2) + return 0; + else + return 1; + } + else if (! file2) + return -1; + + /* If the two files are not the same, find their common ancestor in + the #inclusion tree. */ + if (file1 != file2) + { + /* If one file is deeper than the other, walk up the #inclusion + chain until the two files are at least at the same *depth*. + Then, walk up both files in synchrony until they're the same + file. That file is the common ancestor. */ + int depth1 = inclusion_depth (file1); + int depth2 = inclusion_depth (file2); + + /* Only one of these while loops will ever execute in any given + case. */ + while (depth1 > depth2) + { + line1 = file1->included_at_line; + file1 = file1->included_by; + included1 = 1; + depth1--; + } + while (depth2 > depth1) + { + line2 = file2->included_at_line; + file2 = file2->included_by; + included2 = 1; + depth2--; + } + + /* Now both file1 and file2 are at the same depth. Walk toward + the root of the tree until we find where the branches meet. */ + while (file1 != file2) + { + line1 = file1->included_at_line; + file1 = file1->included_by; + /* At this point, we know that the case the includedX flags + are trying to deal with won't come up, but we'll just + maintain them anyway. */ + included1 = 1; + + line2 = file2->included_at_line; + file2 = file2->included_by; + included2 = 1; + + /* Sanity check. If file1 and file2 are really from the + same compilation unit, then they should both be part of + the same tree, and this shouldn't happen. */ + gdb_assert (file1 && file2); + } + } + + /* Now we've got two line numbers in the same file. */ + if (line1 == line2) + { + /* They can't both be from #included files. Then we shouldn't + have walked up this far. */ + gdb_assert (! included1 || ! included2); + + /* Any #included position comes after a non-#included position + with the same line number in the #including file. */ + if (included1) + return 1; + else if (included2) + return -1; + else + return 0; + } + else + return line1 - line2; +} + + +/* Compare a macro key KEY against NAME, the source file FILE, and + line number LINE. + + Sort definitions by name; for two definitions with the same name, + place the one whose definition comes earlier before the one whose + definition comes later. + + Return -1, 0, or 1 if key comes before, is identical to, or comes + after NAME, FILE, and LINE. */ +static int +key_compare (struct macro_key *key, + const char *name, struct macro_source_file *file, int line) +{ + int names = strcmp (key->name, name); + if (names) + return names; + + return compare_locations (key->start_file, key->start_line, + file, line); +} + + +/* The macro tree comparison function, typed for the splay tree + library's happiness. */ +static int +macro_tree_compare (splay_tree_key untyped_key1, + splay_tree_key untyped_key2) +{ + struct macro_key *key1 = (struct macro_key *) untyped_key1; + struct macro_key *key2 = (struct macro_key *) untyped_key2; + + return key_compare (key1, key2->name, key2->start_file, key2->start_line); +} + + +/* Construct a new macro key node for a macro in table T whose name is + NAME, and whose scope starts at LINE in FILE; register the name in + the bcache. */ +static struct macro_key * +new_macro_key (struct macro_table *t, + const char *name, + struct macro_source_file *file, + int line) +{ + struct macro_key *k = macro_alloc (sizeof (*k), t); + + memset (k, 0, sizeof (*k)); + k->table = t; + k->name = macro_bcache_str (t, name); + k->start_file = file; + k->start_line = line; + k->end_file = 0; + + return k; +} + + +static void +macro_tree_delete_key (void *untyped_key) +{ + struct macro_key *key = (struct macro_key *) untyped_key; + + macro_bcache_free (key->table, (char *) key->name); + macro_free (key, key->table); +} + + + +/* Building and querying the tree of #included files. */ + + +/* Allocate and initialize a new source file structure. */ +static struct macro_source_file * +new_source_file (struct macro_table *t, + const char *filename) +{ + /* Get space for the source file structure itself. */ + struct macro_source_file *f = macro_alloc (sizeof (*f), t); + + memset (f, 0, sizeof (*f)); + f->table = t; + f->filename = macro_bcache_str (t, filename); + f->includes = 0; + + return f; +} + + +/* Free a source file, and all the source files it #included. */ +static void +free_macro_source_file (struct macro_source_file *src) +{ + struct macro_source_file *child, *next_child; + + /* Free this file's children. */ + for (child = src->includes; child; child = next_child) + { + next_child = child->next_included; + free_macro_source_file (child); + } + + macro_bcache_free (src->table, (char *) src->filename); + macro_free (src, src->table); +} + + +struct macro_source_file * +macro_set_main (struct macro_table *t, + const char *filename) +{ + /* You can't change a table's main source file. What would that do + to the tree? */ + gdb_assert (! t->main_source); + + t->main_source = new_source_file (t, filename); + + return t->main_source; +} + + +struct macro_source_file * +macro_main (struct macro_table *t) +{ + gdb_assert (t->main_source); + + return t->main_source; +} + + +struct macro_source_file * +macro_include (struct macro_source_file *source, + int line, + const char *included) +{ + struct macro_source_file *new; + struct macro_source_file **link; + + /* Find the right position in SOURCE's `includes' list for the new + file. Scan until we find the first file we shouldn't follow --- + which is therefore the file we should directly precede --- or + reach the end of the list. */ + for (link = &source->includes; + *link && line < (*link)->included_at_line; + link = &(*link)->next_included) + ; + + /* Did we find another file already #included at the same line as + the new one? */ + if (*link && line == (*link)->included_at_line) + { + /* This means the compiler is emitting bogus debug info. (GCC + circa March 2002 did this.) It also means that the splay + tree ordering function, macro_tree_compare, will abort, + because it can't tell which #inclusion came first. But GDB + should tolerate bad debug info. So: + + First, squawk. */ + static struct complaint bogus_inclusion_line = { + "both `%s' and `%s' allegedly #included at %s:%d", 0, 0 + }; + + complain (&bogus_inclusion_line, + included, (*link)->filename, source->filename, line); + + /* Now, choose a new, unoccupied line number for this + #inclusion, after the alleged #inclusion line. */ + while (*link && line == (*link)->included_at_line) + { + /* This line number is taken, so try the next line. */ + line++; + link = &(*link)->next_included; + } + } + + /* At this point, we know that LINE is an unused line number, and + *LINK points to the entry an #inclusion at that line should + precede. */ + new = new_source_file (source->table, included); + new->included_by = source; + new->included_at_line = line; + new->next_included = *link; + *link = new; + + return new; +} + + +struct macro_source_file * +macro_lookup_inclusion (struct macro_source_file *source, const char *name) +{ + /* Is SOURCE itself named NAME? */ + if (! strcmp (name, source->filename)) + return source; + + /* The filename in the source structure is probably a full path, but + NAME could be just the final component of the name. */ + { + int name_len = strlen (name); + int src_name_len = strlen (source->filename); + + /* We do mean < here, and not <=; if the lengths are the same, + then the strcmp above should have triggered, and we need to + check for a slash here. */ + if (name_len < src_name_len + && source->filename[src_name_len - name_len - 1] == '/' + && ! strcmp (name, source->filename + src_name_len - name_len)) + return source; + } + + /* It's not us. Try all our children, and return the lowest. */ + { + struct macro_source_file *child; + struct macro_source_file *best = 0; + int best_depth; + + for (child = source->includes; child; child = child->next_included) + { + struct macro_source_file *result + = macro_lookup_inclusion (child, name); + + if (result) + { + int result_depth = inclusion_depth (result); + + if (! best || result_depth < best_depth) + { + best = result; + best_depth = result_depth; + } + } + } + + return best; + } +} + + + +/* Registering and looking up macro definitions. */ + + +/* Construct a definition for a macro in table T. Cache all strings, + and the macro_definition structure itself, in T's bcache. */ +static struct macro_definition * +new_macro_definition (struct macro_table *t, + enum macro_kind kind, + int argc, const char **argv, + const char *replacement) +{ + struct macro_definition *d = macro_alloc (sizeof (*d), t); + + memset (d, 0, sizeof (*d)); + d->table = t; + d->kind = kind; + d->replacement = macro_bcache_str (t, replacement); + + if (kind == macro_function_like) + { + int i; + const char **cached_argv; + int cached_argv_size = argc * sizeof (*cached_argv); + + /* Bcache all the arguments. */ + cached_argv = alloca (cached_argv_size); + for (i = 0; i < argc; i++) + cached_argv[i] = macro_bcache_str (t, argv[i]); + + /* Now bcache the array of argument pointers itself. */ + d->argv = macro_bcache (t, cached_argv, cached_argv_size); + d->argc = argc; + } + + /* We don't bcache the entire definition structure because it's got + a pointer to the macro table in it; since each compilation unit + has its own macro table, you'd only get bcache hits for identical + definitions within a compilation unit, which seems unlikely. + + "So, why do macro definitions have pointers to their macro tables + at all?" Well, when the splay tree library wants to free a + node's value, it calls the value freeing function with nothing + but the value itself. It makes the (apparently reasonable) + assumption that the value carries enough information to free + itself. But not all macro tables have bcaches, so not all macro + definitions would be bcached. There's no way to tell whether a + given definition is bcached without knowing which table the + definition belongs to. ... blah. The thing's only sixteen + bytes anyway, and we can still bcache the name, args, and + definition, so we just don't bother bcaching the definition + structure itself. */ + return d; +} + + +/* Free a macro definition. */ +static void +macro_tree_delete_value (void *untyped_definition) +{ + struct macro_definition *d = (struct macro_definition *) untyped_definition; + struct macro_table *t = d->table; + + if (d->kind == macro_function_like) + { + int i; + + for (i = 0; i < d->argc; i++) + macro_bcache_free (t, (char *) d->argv[i]); + macro_bcache_free (t, (char **) d->argv); + } + + macro_bcache_free (t, (char *) d->replacement); + macro_free (d, t); +} + + +/* Find the splay tree node for the definition of NAME at LINE in + SOURCE, or zero if there is none. */ +static splay_tree_node +find_definition (const char *name, + struct macro_source_file *file, + int line) +{ + struct macro_table *t = file->table; + splay_tree_node n; + + /* Construct a macro_key object, just for the query. */ + struct macro_key query; + + query.name = name; + query.start_file = file; + query.start_line = line; + query.end_file = 0; + + n = splay_tree_lookup (t->definitions, (splay_tree_key) &query); + if (! n) + { + /* It's okay for us to do two queries like this: the real work + of the searching is done when we splay, and splaying the tree + a second time at the same key is a constant time operation. + If this still bugs you, you could always just extend the + splay tree library with a predecessor-or-equal operation, and + use that. */ + splay_tree_node pred = splay_tree_predecessor (t->definitions, + (splay_tree_key) &query); + + if (pred) + { + /* Make sure this predecessor actually has the right name. + We just want to search within a given name's definitions. */ + struct macro_key *found = (struct macro_key *) pred->key; + + if (! strcmp (found->name, name)) + n = pred; + } + } + + if (n) + { + struct macro_key *found = (struct macro_key *) n->key; + + /* Okay, so this definition has the right name, and its scope + begins before the given source location. But does its scope + end after the given source location? */ + if (compare_locations (file, line, found->end_file, found->end_line) < 0) + return n; + else + return 0; + } + else + return 0; +} + + +/* If NAME already has a definition in scope at LINE in FILE, and + return the key. Otherwise, return zero. */ +static struct macro_key * +check_for_redefinition (struct macro_source_file *source, int line, + const char *name) +{ + splay_tree_node n = find_definition (name, source, line); + + /* This isn't really right. There's nothing wrong with redefining a + macro if the new replacement list is the same as the old one. */ + if (n) + { + struct macro_key *found_key = (struct macro_key *) n->key; + static struct complaint macro_redefined = { + "macro `%s' redefined at %s:%d;" + "original definition at %s:%d", 0, 0 + }; + complain (¯o_redefined, name, + source->filename, line, + found_key->start_file->filename, + found_key->start_line); + return found_key; + } + else + return 0; +} + + +void +macro_define_object (struct macro_source_file *source, int line, + const char *name, const char *replacement) +{ + struct macro_table *t = source->table; + struct macro_key *k; + struct macro_definition *d; + + k = check_for_redefinition (source, line, name); + + /* If we're redefining a symbol, and the existing key would be + identical to our new key, then the splay_tree_insert function + will try to delete the old definition. When the definition is + living on an obstack, this isn't a happy thing. + + Since this only happens in the presence of questionable debug + info, we just ignore all definitions after the first. The only + case I know of where this arises is in GCC's output for + predefined macros, and all the definitions are the same in that + case. */ + if (k && ! key_compare (k, name, source, line)) + return; + + k = new_macro_key (t, name, source, line); + d = new_macro_definition (t, macro_object_like, 0, 0, replacement); + splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d); +} + + +void +macro_define_function (struct macro_source_file *source, int line, + const char *name, int argc, const char **argv, + const char *replacement) +{ + struct macro_table *t = source->table; + struct macro_key *k; + struct macro_definition *d; + + k = check_for_redefinition (source, line, name); + + /* See comments about duplicate keys in macro_define_object. */ + if (k && ! key_compare (k, name, source, line)) + return; + + /* We should also check here that all the argument names in ARGV are + distinct. */ + + k = new_macro_key (t, name, source, line); + d = new_macro_definition (t, macro_function_like, argc, argv, replacement); + splay_tree_insert (t->definitions, (splay_tree_key) k, (splay_tree_value) d); +} + + +void +macro_undef (struct macro_source_file *source, int line, + const char *name) +{ + splay_tree_node n = find_definition (name, source, line); + + if (n) + { + /* This function is the only place a macro's end-of-scope + location gets set to anything other than "end of the + compilation unit" (i.e., end_file is zero). So if this macro + already has its end-of-scope set, then we're probably seeing + a second #undefinition for the same #definition. */ + struct macro_key *key = (struct macro_key *) n->key; + + if (key->end_file) + { + static struct complaint double_undef = { + "macro '%s' is #undefined twice, at %s:%d and %s:%d", + 0, 0 + }; + complain (&double_undef, name, source->filename, line, + key->end_file->filename, key->end_line); + } + + /* Whatever the case, wipe out the old ending point, and + make this the ending point. */ + key->end_file = source; + key->end_line = line; + } + else + { + /* According to the ISO C standard, an #undef for a symbol that + has no macro definition in scope is ignored. So we should + ignore it too. */ +#if 0 + static struct complaint no_macro_to_undefine = { + "no definition for macro `%s' in scope to #undef at %s:%d", + 0, 0 + }; + complain (&no_macro_to_undefine, name, source->filename, line); +#endif + } +} + + +struct macro_definition * +macro_lookup_definition (struct macro_source_file *source, + int line, const char *name) +{ + splay_tree_node n = find_definition (name, source, line); + + if (n) + return (struct macro_definition *) n->value; + else + return 0; +} + + +struct macro_source_file * +macro_definition_location (struct macro_source_file *source, + int line, + const char *name, + int *definition_line) +{ + splay_tree_node n = find_definition (name, source, line); + + if (n) + { + struct macro_key *key = (struct macro_key *) n->key; + *definition_line = key->start_line; + return key->start_file; + } + else + return 0; +} + + + +/* Creating and freeing macro tables. */ + + +struct macro_table * +new_macro_table (struct obstack *obstack, + struct bcache *b) +{ + struct macro_table *t; + + /* First, get storage for the `struct macro_table' itself. */ + if (obstack) + t = obstack_alloc (obstack, sizeof (*t)); + else + t = xmalloc (sizeof (*t)); + + memset (t, 0, sizeof (*t)); + t->obstack = obstack; + t->bcache = b; + t->main_source = 0; + t->definitions = (splay_tree_new_with_allocator + (macro_tree_compare, + ((splay_tree_delete_key_fn) macro_tree_delete_key), + ((splay_tree_delete_value_fn) macro_tree_delete_value), + ((splay_tree_allocate_fn) macro_alloc), + ((splay_tree_deallocate_fn) macro_free), + t)); + + return t; +} + + +void +free_macro_table (struct macro_table *table) +{ + /* Free the source file tree. */ + free_macro_source_file (table->main_source); + + /* Free the table of macro definitions. */ + splay_tree_delete (table->definitions); +} diff --git a/gdb/macrotab.h b/gdb/macrotab.h new file mode 100644 index 0000000..cbc6d1b --- /dev/null +++ b/gdb/macrotab.h @@ -0,0 +1,295 @@ +/* Interface to C preprocessor macro tables for GDB. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Red Hat, 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef MACROTAB_H +#define MACROTAB_H + +#include "obstack.h" +#include "bcache.h" + +/* How do we represent a source location? I mean, how should we + represent them within GDB; the user wants to use all sorts of + ambiguous abbreviations, like "break 32" and "break foo.c:32" + ("foo.c" may have been #included into several compilation units), + but what do we disambiguate those things to? + + - Answer 1: "Filename and line number." (Or column number, if + you're picky.) That's not quite good enough. For example, the + same source file can be #included into several different + compilation units --- which #inclusion do you mean? + + - Answer 2: "Compilation unit, filename, and line number." This is + a pretty good answer; GDB's `struct symtab_and_line' basically + embodies this representation. But it's still ambiguous; what if a + given compilation unit #includes the same file twice --- how can I + set a breakpoint on line 12 of the fifth #inclusion of "foo.c"? + + - Answer 3: "Compilation unit, chain of #inclusions, and line + number." This is analogous to the way GCC reports errors in + #include files: + + $ gcc -c base.c + In file included from header2.h:8, + from header1.h:3, + from base.c:5: + header3.h:1: parse error before ')' token + $ + + GCC tells you exactly what path of #inclusions led you to the + problem. It gives you complete information, in a way that the + following would not: + + $ gcc -c base.c + header3.h:1: parse error before ')' token + $ + + Converting all of GDB to use this is a big task, and I'm not really + suggesting it should be a priority. But this module's whole + purpose is to maintain structures describing the macro expansion + process, so I think it's appropriate for us to take a little care + to do that in a complete fashion. + + In this interface, the first line of a file is numbered 1, not 0. + This is the same convention the rest of GDB uses. */ + + +/* A table of all the macro definitions for a given compilation unit. */ +struct macro_table; + + +/* A source file that participated in a compilation unit --- either a + main file, or an #included file. If a file is #included more than + once, the presence of the `included_from' and `included_at_line' + members means that we need to make one instance of this structure + for each #inclusion. Taken as a group, these structures form a + tree mapping the #inclusions that contributed to the compilation + unit, with the main source file as its root. + + It's worth noting that libcpp has a simpler way of representing all + this, which we should consider switching to. It might even be + suitable for ordinary non-macro line number info. + + Suppose you take your main source file, and after each line + containing an #include directive you insert the text of the + #included file. The result is a big file that pretty much + corresponds to the full text the compiler's going to see. There's + a one-to-one correspondence between lines in the big file and + per-inclusion lines in the source files. (Obviously, #include + directives that are #if'd out don't count. And you'll need to + append a newline to any file that doesn't end in one, to avoid + splicing the last #included line with the next line of the + #including file.) + + Libcpp calls line numbers in this big imaginary file "logical line + numbers", and has a data structure called a "line map" that can map + logical line numbers onto actual source filenames and line numbers, + and also tell you the chain of #inclusions responsible for any + particular logical line number. Basically, this means you can pass + around a single line number and some kind of "compilation unit" + object and you get nice, unambiguous source code locations that + distinguish between multiple #inclusions of the same file, etc. + + Pretty neat, huh? */ + +struct macro_source_file +{ + + /* The macro table for the compilation unit this source location is + a part of. */ + struct macro_table *table; + + /* A source file --- possibly a header file. */ + const char *filename; + + /* The location we were #included from, or zero if we are the + compilation unit's main source file. */ + struct macro_source_file *included_by; + + /* If `included_from' is non-zero, the line number in that source + file at which we were included. */ + int included_at_line; + + /* Head of a linked list of the source files #included by this file; + our children in the #inclusion tree. This list is sorted by its + elements' `included_at_line' values, which are unique. (The + macro splay tree's ordering function needs this property.) */ + struct macro_source_file *includes; + + /* The next file #included by our `included_from' file; our sibling + in the #inclusion tree. */ + struct macro_source_file *next_included; +}; + + +/* Create a new, empty macro table. Allocate it in OBSTACK, or use + xmalloc if OBSTACK is zero. Use BCACHE to store all macro names, + arguments, definitions, and anything else that might be the same + amongst compilation units in an executable file; if BCACHE is zero, + don't cache these things. + + Note that, if either OBSTACK or BCACHE are non-zero, then you + should only ever add information the macro table --- you should + never remove things from it. You'll get an error if you try. At + the moment, since we only provide obstacks and bcaches for macro + tables for symtabs, this restriction makes a nice sanity check. + Obstacks and bcaches are pretty much grow-only structures anyway. + However, if we find that it's occasionally useful to delete things + even from the symtab's tables, and the storage leak isn't a + problem, this restriction could be lifted. */ +struct macro_table *new_macro_table (struct obstack *obstack, + struct bcache *bcache); + + +/* Free TABLE, and any macro definitions, source file structures, + etc. it owns. This will raise an internal error if TABLE was + allocated on an obstack, or if it uses a bcache. */ +void free_macro_table (struct macro_table *table); + + +/* Set FILENAME as the main source file of TABLE. Return a source + file structure describing that file; if we record the #definition + of macros, or the #inclusion of other files into FILENAME, we'll + use that source file structure to indicate the context. + + The "main source file" is the one that was given to the compiler; + all other source files that contributed to the compilation unit are + #included, directly or indirectly, from this one. + + The macro table makes its own copy of FILENAME; the caller is + responsible for freeing FILENAME when it is no longer needed. */ +struct macro_source_file *macro_set_main (struct macro_table *table, + const char *filename); + + +/* Return the main source file of the macro table TABLE. */ +struct macro_source_file *macro_main (struct macro_table *table); + + +/* Record a #inclusion. + Record in SOURCE's macro table that, at line number LINE in SOURCE, + we #included the file INCLUDED. Return a source file structure we + can use for symbols #defined or files #included into that. If we've + already created a source file structure for this #inclusion, return + the same structure we created last time. + + The first line of the source file has a line number of 1, not 0. + + The macro table makes its own copy of INCLUDED; the caller is + responsible for freeing INCLUDED when it is no longer needed. */ +struct macro_source_file *macro_include (struct macro_source_file *source, + int line, + const char *included); + + +/* Find any source file structure for a file named NAME, either + included into SOURCE, or SOURCE itself. Return zero if we have + none. NAME is only the final portion of the filename, not the full + path. e.g., `stdio.h', not `/usr/include/stdio.h'. If NAME + appears more than once in the inclusion tree, return the + least-nested inclusion --- the one closest to the main source file. */ +struct macro_source_file *(macro_lookup_inclusion + (struct macro_source_file *source, + const char *name)); + + +/* Record an object-like #definition (i.e., one with no parameter list). + Record in SOURCE's macro table that, at line number LINE in SOURCE, + we #defined a preprocessor symbol named NAME, whose replacement + string is REPLACEMENT. This function makes copies of NAME and + REPLACEMENT; the caller is responsible for freeing them. */ +void macro_define_object (struct macro_source_file *source, int line, + const char *name, const char *replacement); + + +/* Record an function-like #definition (i.e., one with a parameter list). + + Record in SOURCE's macro table that, at line number LINE in SOURCE, + we #defined a preprocessor symbol named NAME, with ARGC arguments + whose names are given in ARGV, whose replacement string is REPLACEMENT. If + the macro takes a variable number of arguments, then ARGC should be + one greater than the number of named arguments, and ARGV[ARGC-1] + should be the string "...". This function makes its own copies of + NAME, ARGV, and REPLACEMENT; the caller is responsible for freeing + them. */ +void macro_define_function (struct macro_source_file *source, int line, + const char *name, int argc, const char **argv, + const char *replacement); + + +/* Record an #undefinition. + Record in SOURCE's macro table that, at line number LINE in SOURCE, + we removed the definition for the preprocessor symbol named NAME. */ +void macro_undef (struct macro_source_file *source, int line, + const char *name); + + +/* Different kinds of macro definitions. */ +enum macro_kind +{ + macro_object_like, + macro_function_like +}; + + +/* A preprocessor symbol definition. */ +struct macro_definition +{ + /* The table this definition lives in. */ + struct macro_table *table; + + /* What kind of macro it is. */ + enum macro_kind kind; + + /* If `kind' is `macro_function_like', the number of arguments it + takes, and their names. The names, and the array of pointers to + them, are in the table's bcache, if it has one. */ + int argc; + const char * const *argv; + + /* The replacement string (body) of the macro. This is in the + table's bcache, if it has one. */ + const char *replacement; +}; + + +/* Return a pointer to the macro definition for NAME in scope at line + number LINE of SOURCE. If LINE is -1, return the definition in + effect at the end of the file. The macro table owns the structure; + the caller need not free it. Return zero if NAME is not #defined + at that point. */ +struct macro_definition *(macro_lookup_definition + (struct macro_source_file *source, + int line, const char *name)); + + +/* Return the source location of the definition for NAME in scope at + line number LINE of SOURCE. Set *DEFINITION_LINE to the line + number of the definition, and return a source file structure for + the file. Return zero if NAME has no definition in scope at that + point, and leave *DEFINITION_LINE unchanged. */ +struct macro_source_file *(macro_definition_location + (struct macro_source_file *source, + int line, + const char *name, + int *definition_line)); + + +#endif /* MACROTAB_H */ |