This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
RFC: preprocessor macro support (should actually work now)
- From: Jim Blandy <jimb at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Thu, 28 Mar 2002 02:05:04 -0500 (EST)
- Subject: RFC: preprocessor macro support (should actually work now)
This is a revised version of the preprocessor macro support patch I
posted before, tested against the current GCC sources. I've fixed a
bunch of bugs, and made it tolerant of the GCC bugs that came up.
So please try it out; compile with the -gdwarf-2 -g3 flags.
Breakpoint 3, value_primitive_field (arg1=0x88dc578, offset=0, fieldno=1,
arg_type=0x89f3f70)
at /home/jimb/cygnus/src/sourceware/gdb/main/src/gdb/values.c:937
(top-top-gdb) print TYPE_FIELD_BITPOS (arg_type, fieldno)
$1 = 32
(top-top-gdb) macro expand TYPE_FIELD_BITPOS (arg_type, fieldno)
expands to: (((arg_type)->fields[fieldno]).loc.bitpos)
(top-top-gdb) show macro TYPE_FIELD_BITPOS
Defined at /home/jimb/cygnus/src/sourceware/gdb/main/src/gdb/gdbtypes.h:811
included at /home/jimb/cygnus/src/sourceware/gdb/main/src/gdb/values.c:26
included at /home/jimb/cygnus/src/sourceware/gdb/main/src/gdb/values.c:0
#define TYPE_FIELD_BITPOS(thistype, n) FIELD_BITPOS(TYPE_FIELD(thistype,n))
(top-top-gdb)
I'll start breaking it into individual patches and submitting it soon.
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.166
diff -c -r1.166 Makefile.in
*** gdb/Makefile.in 2002/03/27 05:10:38 1.166
--- gdb/Makefile.in 2002/03/28 06:50:31
***************
*** 533,538 ****
--- 533,539 ----
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 macrocmd.c macroscope.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 \
***************
*** 564,569 ****
--- 565,571 ----
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 \
***************
*** 589,595 ****
bcache_h = bcache.h
breakpoint_h = breakpoint.h $(frame_h) $(value_h)
buildsym_h = buildsym.h
! c_lang_h = c-lang.h $(value_h)
call_cmds_h = call-cmds.h
cli_cmds_h = $(srcdir)/cli/cli-cmds.h
cli_decode_h = $(srcdir)/cli/cli-decode.h $(command_h)
--- 591,597 ----
bcache_h = bcache.h
breakpoint_h = breakpoint.h $(frame_h) $(value_h)
buildsym_h = buildsym.h
! c_lang_h = c-lang.h $(value_h) $(macroexp_h)
call_cmds_h = call-cmds.h
cli_cmds_h = $(srcdir)/cli/cli-cmds.h
cli_decode_h = $(srcdir)/cli/cli-decode.h $(command_h)
***************
*** 622,627 ****
--- 624,632 ----
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)
+ macroscope_h = macroscope.h $(macrotab_h) $(symtab_h)
memattr_h = memattr.h
monitor_h = monitor.h
objfiles_h = objfiles.h
***************
*** 660,665 ****
--- 665,671 ----
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 macroscope.h \
c-lang.h ch-lang.h f-lang.h \
jv-lang.h \
m2-lang.h p-lang.h \
***************
*** 702,707 ****
--- 708,714 ----
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 macrocmd.o macroexp.o macroscope.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 \
***************
*** 1268,1277 ****
$(completer_h) $(gdb_h)
buildsym.o: buildsym.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
! $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h)
c-lang.o: c-lang.c $(c_lang_h) $(defs_h) $(expression_h) $(gdbtypes_h) \
! $(language_h) $(parser_defs_h) $(symtab_h)
c-typeprint.o: c-typeprint.c $(c_lang_h) $(defs_h) $(expression_h) \
$(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) $(language_h) $(symtab_h) \
--- 1275,1286 ----
$(completer_h) $(gdb_h)
buildsym.o: buildsym.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
! $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h) \
! $(macrotab.h)
c-lang.o: c-lang.c $(c_lang_h) $(defs_h) $(expression_h) $(gdbtypes_h) \
! $(language_h) $(parser_defs_h) $(symtab_h) $(macroscope_h) \
! gdb_assert.h
c-typeprint.o: c-typeprint.c $(c_lang_h) $(defs_h) $(expression_h) \
$(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) $(language_h) $(symtab_h) \
***************
*** 1376,1382 ****
dwarf2read.o: dwarf2read.c $(bfd_h) $(buildsym_h) $(defs_h) \
$(expression_h) $(gdbtypes_h) $(language_h) $(objfiles_h) \
! $(symfile_h) $(symtab_h) $(gdb_string_h)
elfread.o: elfread.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
$(gdb_stabs_h) $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h) \
--- 1385,1391 ----
dwarf2read.o: dwarf2read.c $(bfd_h) $(buildsym_h) $(defs_h) \
$(expression_h) $(gdbtypes_h) $(language_h) $(objfiles_h) \
! $(symfile_h) $(symtab_h) $(gdb_string_h) $(macrotab_h)
elfread.o: elfread.c $(bfd_h) $(buildsym_h) $(complaints_h) $(defs_h) \
$(gdb_stabs_h) $(objfiles_h) $(symfile_h) $(symtab_h) $(gdb_string_h) \
***************
*** 2089,2094 ****
--- 2098,2110 ----
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)
+
+ macroscope.o: macroscope.c $(defs_h) $(macroscope_h)
target.o: target.c $(bfd_h) $(defs_h) $(gdbcmd_h) $(inferior_h) \
$(objfiles_h) $(symfile_h) $(target_h) $(gdb_string_h) $(regcache_h)
Index: gdb/blockframe.c
===================================================================
RCS file: /cvs/src/src/gdb/blockframe.c,v
retrieving revision 1.21
diff -c -r1.21 blockframe.c
*** gdb/blockframe.c 2002/02/27 20:04:29 1.21
--- gdb/blockframe.c 2002/03/28 06:50:32
***************
*** 507,513 ****
in a specified stack frame. The frame address is assumed valid. */
struct block *
! get_frame_block (struct frame_info *frame)
{
CORE_ADDR pc;
--- 507,513 ----
in a specified stack frame. The frame address is assumed valid. */
struct block *
! get_frame_block (struct frame_info *frame, CORE_ADDR *pc_in_block)
{
CORE_ADDR pc;
***************
*** 520,532 ****
after the call insn, we probably want to make frame->pc point after
the call insn anyway. */
--pc;
return block_for_pc (pc);
}
struct block *
! get_current_block (void)
{
! return block_for_pc (read_pc ());
}
CORE_ADDR
--- 520,541 ----
after the call insn, we probably want to make frame->pc point after
the call insn anyway. */
--pc;
+
+ if (pc_in_block)
+ *pc_in_block = pc;
+
return block_for_pc (pc);
}
struct block *
! get_current_block (CORE_ADDR *pc_in_block)
{
! CORE_ADDR pc = read_pc ();
!
! if (pc_in_block)
! *pc_in_block = pc;
!
! return block_for_pc (pc);
}
CORE_ADDR
***************
*** 559,565 ****
struct symbol *
get_frame_function (struct frame_info *frame)
{
! register struct block *bl = get_frame_block (frame);
if (bl == 0)
return 0;
return block_function (bl);
--- 568,574 ----
struct symbol *
get_frame_function (struct frame_info *frame)
{
! register struct block *bl = get_frame_block (frame, 0);
if (bl == 0)
return 0;
return block_function (bl);
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.67
diff -c -r1.67 breakpoint.c
*** gdb/breakpoint.c 2002/03/06 06:28:33 1.67
--- gdb/breakpoint.c 2002/03/28 06:50:36
***************
*** 5621,5627 ****
but it's better than a core dump. */
if (selected_frame == NULL)
error ("No selected frame.");
! block = get_frame_block (selected_frame);
pc = selected_frame->pc;
sals.nelts = 0;
--- 5621,5627 ----
but it's better than a core dump. */
if (selected_frame == NULL)
error ("No selected frame.");
! block = get_frame_block (selected_frame, 0);
pc = selected_frame->pc;
sals.nelts = 0;
Index: gdb/buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.14
diff -c -r1.14 buildsym.c
*** gdb/buildsym.c 2002/01/20 19:42:04 1.14
--- gdb/buildsym.c 2002/03/28 06:50:36
***************
*** 39,44 ****
--- 39,45 ----
#include "language.h" /* For "longest_local_hex_string_custom" */
#include "bcache.h"
#include "filenames.h" /* For DOSish file names */
+ #include "macrotab.h"
/* Ask buildsym.h to define the vars it normally declares `extern'. */
#define EXTERN
/**/
***************
*** 192,197 ****
--- 193,201 ----
xfree ((void *) next);
}
global_symbols = NULL;
+
+ if (pending_macros)
+ free_macro_table (pending_macros);
}
/* This function is called to discard any pending blocks. */
***************
*** 883,889 ****
if (pending_blocks == NULL
&& file_symbols == NULL
&& global_symbols == NULL
! && have_line_numbers == 0)
{
/* Ignore symtabs that have no functions with real debugging
info. */
--- 887,894 ----
if (pending_blocks == NULL
&& file_symbols == NULL
&& global_symbols == NULL
! && have_line_numbers == 0
! && pending_macros == NULL)
{
/* Ignore symtabs that have no functions with real debugging
info. */
***************
*** 944,949 ****
--- 949,955 ----
/* Fill in its components. */
symtab->blockvector = blockvector;
+ symtab->macro_table = pending_macros;
if (subfile->line_vector)
{
/* Reallocate the line table on the symbol obstack */
***************
*** 1022,1027 ****
--- 1028,1034 ----
last_source_file = NULL;
current_subfile = NULL;
+ pending_macros = NULL;
return symtab;
}
***************
*** 1112,1117 ****
--- 1119,1125 ----
file_symbols = NULL;
global_symbols = NULL;
pending_blocks = NULL;
+ pending_macros = NULL;
}
/* Initialize anything that needs initializing when a completely new
Index: gdb/buildsym.h
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.h,v
retrieving revision 1.3
diff -c -r1.3 buildsym.h
*** gdb/buildsym.h 2001/03/06 08:21:06 1.3
--- gdb/buildsym.h 2002/03/28 06:50:37
***************
*** 296,301 ****
--- 296,305 ----
extern void merge_symbol_lists (struct pending **srclist,
struct pending **targetlist);
+ /* The macro table for the compilation unit whose symbols we're
+ currently reading. All the symtabs for this CU will point to this. */
+ EXTERN struct macro_table *pending_macros;
+
#undef EXTERN
#endif /* defined (BUILDSYM_H) */
Index: gdb/c-exp.y
===================================================================
RCS file: /cvs/src/src/gdb/c-exp.y,v
retrieving revision 1.7
diff -c -r1.7 c-exp.y
*** gdb/c-exp.y 2001/11/15 01:55:59 1.7
--- gdb/c-exp.y 2002/03/28 06:50:37
***************
*** 1218,1223 ****
--- 1218,1234 ----
retry:
+ /* Check if this is a macro invocation that we need to expand. */
+ if (! scanning_macro_expansion ())
+ {
+ char *expanded = macro_expand_next (&lexptr,
+ expression_macro_lookup_func,
+ expression_macro_lookup_baton);
+
+ if (expanded)
+ scan_macro_expansion (expanded);
+ }
+
unquoted_expr = 1;
tokstart = lexptr;
***************
*** 1242,1248 ****
switch (c = *tokstart)
{
case 0:
! return 0;
case ' ':
case '\t':
--- 1253,1269 ----
switch (c = *tokstart)
{
case 0:
! /* If we were just scanning the result of a macro expansion,
! then we need to resume scanning the original text.
! Otherwise, we were already scanning the original text, and
! we're really done. */
! if (scanning_macro_expansion ())
! {
! finished_macro_expansion ();
! goto retry;
! }
! else
! return 0;
case ' ':
case '\t':
***************
*** 1295,1301 ****
return c;
case ',':
! if (comma_terminates && paren_depth == 0)
return 0;
lexptr++;
return c;
--- 1316,1324 ----
return c;
case ',':
! if (comma_terminates
! && paren_depth == 0
! && ! scanning_macro_expansion ())
return 0;
lexptr++;
return c;
***************
*** 1474,1482 ****
c = tokstart[++namelen];
}
! /* The token "if" terminates the expression and is NOT
! removed from the input stream. */
! if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
{
return 0;
}
--- 1497,1509 ----
c = tokstart[++namelen];
}
! /* The token "if" terminates the expression and is NOT removed from
! the input stream. It doesn't count if it appears in the
! expansion of a macro. */
! if (namelen == 2
! && tokstart[0] == 'i'
! && tokstart[1] == 'f'
! && ! scanning_macro_expansion ())
{
return 0;
}
Index: gdb/c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.11
diff -c -r1.11 c-lang.c
*** gdb/c-lang.c 2002/03/21 00:53:44 1.11
--- gdb/c-lang.c 2002/03/28 06:50:38
***************
*** 27,32 ****
--- 27,34 ----
#include "language.h"
#include "c-lang.h"
#include "valprint.h"
+ #include "macroscope.h"
+ #include "gdb_assert.h"
extern void _initialize_c_language (void);
static void c_emit_char (int c, struct ui_file * stream, int quoter);
***************
*** 371,377 ****
--- 373,484 ----
return (type);
}
+ /* Preprocessing and parsing C and C++ expressions. */
+
+ /* When we find that lexptr (the global var defined in parse.c) is
+ pointing at a macro invocation, we expand the invocation, and call
+ scan_macro_expansion to save the old lexptr here and point lexptr
+ into the expanded text. When we reach the end of that, we call
+ end_macro_expansion to pop back to the value we saved here. The
+ macro expansion code promises to return only fully-expanded text,
+ so we don't need to "push" more than one level.
+
+ This is disgusting, of course. It would be cleaner to do all macro
+ expansion beforehand, and then hand that to lexptr. But we don't
+ really know where the expression ends. Remember, in a command like
+
+ (gdb) break *ADDRESS if CONDITION
+
+ we evaluate ADDRESS in the scope of the current frame, but we
+ evaluate CONDITION in the scope of the breakpoint's location. So
+ it's simply wrong to try to macro-expand the whole thing at once. */
+ static char *macro_original_text;
+ static char *macro_expanded_text;
+
+
+ void
+ scan_macro_expansion (char *expansion)
+ {
+ /* We'd better not be trying to push the stack twice. */
+ gdb_assert (! macro_original_text);
+ gdb_assert (! macro_expanded_text);
+
+ /* Save the old lexptr value, so we can return to it when we're done
+ parsing the expanded text. */
+ macro_original_text = lexptr;
+ lexptr = expansion;
+
+ /* Save the expanded text, so we can free it when we're finished. */
+ macro_expanded_text = expansion;
+ }
+
+
+ int
+ scanning_macro_expansion ()
+ {
+ return macro_original_text != 0;
+ }
+
+
+ void
+ finished_macro_expansion ()
+ {
+ /* There'd better be something to pop back to, and we better have
+ saved a pointer to the start of the expanded text. */
+ gdb_assert (macro_original_text);
+ gdb_assert (macro_expanded_text);
+
+ /* Pop back to the original text. */
+ lexptr = macro_original_text;
+ macro_original_text = 0;
+
+ /* Free the expanded text. */
+ xfree (macro_expanded_text);
+ macro_expanded_text = 0;
+ }
+
+
+ static void
+ scan_macro_cleanup (void *dummy)
+ {
+ if (macro_original_text)
+ finished_macro_expansion ();
+ }
+
+
+ /* We set these global variables before calling c_parse, to tell it
+ how it to find macro definitions for the expression at hand. */
+ macro_lookup_ftype *expression_macro_lookup_func;
+ void *expression_macro_lookup_baton;
+
+ static int
+ c_preprocess_and_parse ()
+ {
+ /* Set up a lookup function for the macro expander. */
+ struct macro_scope *scope = 0;
+ struct cleanup *back_to = make_cleanup (free_current_contents, &scope);
+
+ if (expression_context_block)
+ scope = sal_macro_scope (find_pc_line (expression_context_pc, 0));
+ else
+ scope = default_macro_scope ();
+
+ expression_macro_lookup_func = standard_macro_lookup;
+ expression_macro_lookup_baton = (void *) scope;
+
+ gdb_assert (! macro_original_text);
+ make_cleanup (scan_macro_cleanup, 0);
+
+ {
+ int result = c_parse ();
+ do_cleanups (back_to);
+ return result;
+ }
+ }
+
+
+
/* Table mapping opcodes into strings for printing operators
and precedences of the operators. */
***************
*** 439,445 ****
range_check_off,
type_check_off,
case_sensitive_on,
! c_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
--- 546,552 ----
range_check_off,
type_check_off,
case_sensitive_on,
! c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
***************
*** 491,497 ****
range_check_off,
type_check_off,
case_sensitive_on,
! c_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
--- 598,604 ----
range_check_off,
type_check_off,
case_sensitive_on,
! c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
***************
*** 520,526 ****
range_check_off,
type_check_off,
case_sensitive_on,
! c_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
--- 627,633 ----
range_check_off,
type_check_off,
case_sensitive_on,
! c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
Index: gdb/c-lang.h
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.h,v
retrieving revision 1.4
diff -c -r1.4 c-lang.h
*** gdb/c-lang.h 2002/02/13 18:49:29 1.4
--- gdb/c-lang.h 2002/03/28 06:50:38
***************
*** 24,29 ****
--- 24,30 ----
#define C_LANG_H 1
#include "value.h"
+ #include "macroexp.h"
extern int c_parse (void); /* Defined in c-exp.y */
***************
*** 48,53 ****
--- 49,61 ----
extern void c_printstr (struct ui_file * stream, char *string,
unsigned int length, int width,
int force_ellipses);
+
+ extern void scan_macro_expansion (char *expansion);
+ extern int scanning_macro_expansion (void);
+ extern void finished_macro_expansion (void);
+
+ extern macro_lookup_ftype *expression_macro_lookup_func;
+ extern void *expression_macro_lookup_baton;
extern struct type *c_create_fundamental_type (struct objfile *, int);
Index: gdb/configure.in
===================================================================
RCS file: /cvs/src/src/gdb/configure.in,v
retrieving revision 1.84
diff -c -r1.84 configure.in
*** gdb/configure.in 2002/03/15 00:44:49 1.84
--- gdb/configure.in 2002/03/28 06:50:39
***************
*** 130,135 ****
--- 130,136 ----
AC_HEADER_STAT
AC_C_CONST
+ AC_C_INLINE
AC_CHECK_FUNCS(bcopy btowc bzero canonicalize_file_name isascii poll \
realpath sbrk setpgid setpgrp sigaction sigprocmask sigsetmask )
Index: gdb/dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.51
diff -c -r1.51 dwarf2read.c
*** gdb/dwarf2read.c 2002/03/21 00:53:44 1.51
--- gdb/dwarf2read.c 2002/03/28 06:50:41
***************
*** 37,42 ****
--- 37,43 ----
#include "demangle.h"
#include "expression.h"
#include "filenames.h" /* for DOSish file names */
+ #include "macrotab.h"
#include "language.h"
#include "complaints.h"
***************
*** 175,193 ****
4 or 12 */
};
! /* The data in the .debug_line statement prologue looks like this. */
! struct line_head
{
! unsigned int total_length;
! unsigned short version;
! unsigned int prologue_length;
! unsigned char minimum_instruction_length;
! unsigned char default_is_stmt;
! int line_base;
! unsigned char line_range;
! unsigned char opcode_base;
! unsigned char *standard_opcode_lengths;
! };
/* When we construct a partial symbol table entry we only
need this much information. */
--- 176,225 ----
4 or 12 */
};
! /* The line number information for a compilation unit (found in the
! .debug_line section) begins with a "statement program prologue",
! which contains the following information. */
! struct line_prologue
! {
! unsigned int total_length;
! unsigned short version;
! unsigned int prologue_length;
! unsigned char minimum_instruction_length;
! unsigned char default_is_stmt;
! int line_base;
! unsigned char line_range;
! unsigned char opcode_base;
!
! /* standard_opcode_lengths[i] is the number of operands for the
! standard opcode whose value is i. This means that
! standard_opcode_lengths[0] is unused, and the last meaningful
! element is standard_opcode_lengths[opcode_base - 1]. */
! unsigned char *standard_opcode_lengths;
!
! /* The include_directories table. NOTE! These strings are not
! allocated with xmalloc; instead, they are pointers into
! debug_line_buffer. If you try to free them, `free' will get
! indigestion. */
! unsigned int num_include_dirs, include_dirs_size;
! char **include_dirs;
!
! /* The file_names table. NOTE! These strings are not allocated
! with xmalloc; instead, they are pointers into debug_line_buffer.
! Don't try to free them directly. */
! unsigned int num_file_names, file_names_size;
! struct file_entry
{
! char *name;
! unsigned int dir_index;
! unsigned int mod_time;
! unsigned int length;
! } *file_names;
!
! /* The start and end of the statement program following this
! prologue. These point into dwarf_line_buffer. */
! char *statement_program_start, *statement_program_end;
! };
!
/* When we construct a partial symbol table entry we only
need this much information. */
***************
*** 310,315 ****
--- 342,348 ----
static char *dwarf_abbrev_buffer;
static char *dwarf_line_buffer;
static char *dwarf_str_buffer;
+ static char *dwarf_macinfo_buffer;
/* A zeroed version of a partial die for initialization purposes. */
static struct partial_die_info zeroed_partial_die;
***************
*** 399,404 ****
--- 432,446 ----
/* Size of dwarf string section for the objfile. */
unsigned int dwarf_str_size;
+
+ /* Pointer to start of dwarf macro buffer for the objfile. */
+
+ char *dwarf_macinfo_buffer;
+
+ /* Size of dwarf macinfo section for the objfile. */
+
+ unsigned int dwarf_macinfo_size;
+
};
#define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
***************
*** 409,414 ****
--- 451,458 ----
#define DWARF_LINE_BUFFER(p) (PST_PRIVATE(p)->dwarf_line_buffer)
#define DWARF_STR_BUFFER(p) (PST_PRIVATE(p)->dwarf_str_buffer)
#define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size)
+ #define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
+ #define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size)
/* Maintain an array of referenced fundamental types for the current
compilation unit being read. For DWARF version 1, we have to construct
***************
*** 492,497 ****
--- 536,545 ----
{
"missing .debug_line section", 0, 0
};
+ static struct complaint dwarf2_statement_list_fits_in_line_number_section =
+ {
+ "statement list doesn't fit in .debug_line section", 0, 0
+ };
static struct complaint dwarf2_mangled_line_number_section =
{
"mangled .debug_line section", 0, 0
***************
*** 560,565 ****
--- 608,645 ----
{
"unsupported const value attribute form: '%s'", 0, 0
};
+ static struct complaint dwarf2_line_prologue_too_long =
+ {
+ "line number info prologue doesn't fit in `.debug_line' section", 0, 0
+ };
+ static struct complaint dwarf2_missing_macinfo_section =
+ {
+ "missing .debug_macinfo section", 0, 0
+ };
+ static struct complaint dwarf2_macros_too_long =
+ {
+ "macro info runs off end of `.debug_macinfo' section", 0, 0
+ };
+ static struct complaint dwarf2_macros_not_terminated =
+ {
+ "no terminating 0-type entry for macros in `.debug_macinfo' section", 0, 0
+ };
+ static struct complaint dwarf2_macro_outside_file =
+ {
+ "debug info gives macro %s outside of any file: %s", 0, 0
+ };
+ static struct complaint dwarf2_macro_unmatched_end_file =
+ {
+ "macro debug info has an unmatched `close_file' directive", 0, 0
+ };
+ static struct complaint dwarf2_macro_malformed_definition =
+ {
+ "macro debug info contains a malformed macro definition:\n`%s'", 0, 0
+ };
+ static struct complaint dwarf2_macro_spaces_in_definition =
+ {
+ "macro definition contains spaces in formal argument list:\n`%s'", 0, 0
+ };
/* local function prototypes */
***************
*** 639,645 ****
static int die_is_declaration (struct die_info *);
! static void dwarf_decode_lines (unsigned int, char *, bfd *,
const struct comp_unit_head *);
static void dwarf2_start_subfile (char *, char *);
--- 719,732 ----
static int die_is_declaration (struct die_info *);
! static void free_line_prologue (struct line_prologue *lp);
!
! static struct line_prologue *(dwarf_decode_line_prologue
! (unsigned int offset,
! bfd *abfd,
! const struct comp_unit_head *cu_header));
!
! static void dwarf_decode_lines (struct line_prologue *, char *, bfd *,
const struct comp_unit_head *);
static void dwarf2_start_subfile (char *, char *);
***************
*** 794,808 ****
static struct die_info *dwarf_alloc_die (void);
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
int
dwarf2_has_info (bfd *abfd)
{
! dwarf_info_offset = dwarf_abbrev_offset = dwarf_line_offset = 0;
dwarf_str_offset = 0;
! dwarf_frame_offset = dwarf_eh_frame_offset = 0;
bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
if (dwarf_info_offset && dwarf_abbrev_offset)
{
--- 881,903 ----
static struct die_info *dwarf_alloc_die (void);
+ static void dwarf_decode_macros (struct line_prologue *, unsigned int,
+ char *, bfd *, const struct comp_unit_head *,
+ struct objfile *);
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
int
dwarf2_has_info (bfd *abfd)
{
! dwarf_info_offset = 0;
! dwarf_abbrev_offset = 0;
! dwarf_line_offset = 0;
dwarf_str_offset = 0;
! dwarf_macinfo_offset = 0;
! dwarf_frame_offset = 0;
! dwarf_eh_frame_offset = 0;
bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
if (dwarf_info_offset && dwarf_abbrev_offset)
{
***************
*** 890,902 ****
dwarf_line_buffer = dwarf2_read_section (objfile,
dwarf_line_offset,
dwarf_line_size);
-
if (dwarf_str_offset)
dwarf_str_buffer = dwarf2_read_section (objfile,
dwarf_str_offset,
dwarf_str_size);
else
dwarf_str_buffer = NULL;
if (mainline
|| (objfile->global_psymbols.size == 0
--- 985,1002 ----
dwarf_line_buffer = dwarf2_read_section (objfile,
dwarf_line_offset,
dwarf_line_size);
if (dwarf_str_offset)
dwarf_str_buffer = dwarf2_read_section (objfile,
dwarf_str_offset,
dwarf_str_size);
else
dwarf_str_buffer = NULL;
+ if (dwarf_macinfo_offset)
+ dwarf_macinfo_buffer = dwarf2_read_section (objfile,
+ dwarf_macinfo_offset,
+ dwarf_macinfo_size);
+ else
+ dwarf_macinfo_buffer = NULL;
if (mainline
|| (objfile->global_psymbols.size == 0
***************
*** 1105,1110 ****
--- 1205,1212 ----
DWARF_LINE_BUFFER (pst) = dwarf_line_buffer;
DWARF_STR_BUFFER (pst) = dwarf_str_buffer;
DWARF_STR_SIZE (pst) = dwarf_str_size;
+ DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
+ DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
/* Store the function that reads in the rest of the symbol table */
***************
*** 1406,1411 ****
--- 1508,1515 ----
dwarf_line_buffer = DWARF_LINE_BUFFER (pst);
dwarf_str_buffer = DWARF_STR_BUFFER (pst);
dwarf_str_size = DWARF_STR_SIZE (pst);
+ dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
+ dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
cu_header_offset = offset;
info_ptr = dwarf_info_buffer + offset;
***************
*** 1541,1551 ****
}
}
static void
read_file_scope (struct die_info *die, struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
- unsigned int line_offset = 0;
CORE_ADDR lowpc = ((CORE_ADDR) -1);
CORE_ADDR highpc = ((CORE_ADDR) 0);
struct attribute *attr;
--- 1645,1655 ----
}
}
+
static void
read_file_scope (struct die_info *die, struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
CORE_ADDR lowpc = ((CORE_ADDR) -1);
CORE_ADDR highpc = ((CORE_ADDR) 0);
struct attribute *attr;
***************
*** 1553,1558 ****
--- 1657,1663 ----
char *comp_dir = NULL;
struct die_info *child_die;
bfd *abfd = objfile->obfd;
+ struct line_prologue *line_prologue = 0;
if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile))
{
***************
*** 1637,1646 ****
attr = dwarf_attr (die, DW_AT_stmt_list);
if (attr)
{
! line_offset = DW_UNSND (attr);
! dwarf_decode_lines (line_offset, comp_dir, abfd, cu_header);
}
/* Process all dies in compilation unit. */
if (die->has_children)
{
--- 1742,1778 ----
attr = dwarf_attr (die, DW_AT_stmt_list);
if (attr)
{
! unsigned int line_offset = DW_UNSND (attr);
! line_prologue = dwarf_decode_line_prologue (line_offset,
! abfd, cu_header);
! if (line_prologue)
! {
! make_cleanup ((make_cleanup_ftype *) free_line_prologue,
! (void *) line_prologue);
! dwarf_decode_lines (line_prologue, comp_dir, abfd, cu_header);
! }
}
+
+ /* Decode macro information, if present. Dwarf 2 macro information
+ refers to information in the line number info statement program
+ prologue, so we can only read it if we've read the prologue
+ successfully. */
+ #if 1
+ attr = dwarf_attr (die, DW_AT_macro_info);
+ if (attr)
+ {
+ unsigned int macro_offset = DW_UNSND (attr);
+ dwarf_decode_macros (line_prologue, macro_offset,
+ comp_dir, abfd, cu_header, objfile);
+ }
+ #else
+ /* A hack for testing. */
+ if (dwarf_macinfo_buffer
+ && dwarf_macinfo_size > 0)
+ dwarf_decode_macros (line_prologue, 0, comp_dir, abfd, cu_header, objfile);
+ #endif
+
/* Process all dies in compilation unit. */
if (die->has_children)
{
***************
*** 3885,3971 ****
&& ! dwarf_attr (die, DW_AT_specification));
}
! /* Decode the line number information for the compilation unit whose
! line number info is at OFFSET in the .debug_line section.
! The compilation directory of the file is passed in COMP_DIR. */
! struct filenames
{
! unsigned int num_files;
! struct fileinfo
{
! char *name;
! unsigned int dir;
! unsigned int time;
! unsigned int size;
}
! *files;
! };
! struct directories
! {
! unsigned int num_dirs;
! char **dirs;
! };
static void
! dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
! const struct comp_unit_head *cu_header)
{
! char *line_ptr;
! char *line_end;
! struct line_head lh;
! struct cleanup *back_to;
! unsigned int i, bytes_read;
! char *cur_file, *cur_dir;
! unsigned char op_code, extended_op, adj_opcode;
! #define FILE_ALLOC_CHUNK 5
! #define DIR_ALLOC_CHUNK 5
! struct filenames files;
! struct directories dirs;
if (dwarf_line_buffer == NULL)
{
complain (&dwarf2_missing_line_number_section);
! return;
}
! files.num_files = 0;
! files.files = NULL;
! dirs.num_dirs = 0;
! dirs.dirs = NULL;
line_ptr = dwarf_line_buffer + offset;
/* read in the prologue */
! lh.total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
line_ptr += bytes_read;
! line_end = line_ptr + lh.total_length;
! lh.version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
! lh.prologue_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
line_ptr += bytes_read;
! lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lh.default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lh.line_base = read_1_signed_byte (abfd, line_ptr);
line_ptr += 1;
! lh.line_range = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lh.opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lh.standard_opcode_lengths = (unsigned char *)
! xmalloc (lh.opcode_base * sizeof (unsigned char));
! back_to = make_cleanup (free_current_contents, &lh.standard_opcode_lengths);
! lh.standard_opcode_lengths[0] = 1;
! for (i = 1; i < lh.opcode_base; ++i)
{
! lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
--- 4017,4169 ----
&& ! dwarf_attr (die, DW_AT_specification));
}
!
! /* Free the line_prologue structure *LP, and any arrays and strings it
! refers to. */
! static void
! free_line_prologue (struct line_prologue *lp)
! {
! if (lp->standard_opcode_lengths)
! free (lp->standard_opcode_lengths);
! /* Remember that all the lp->file_names[i].name pointers are
! pointers into debug_line_buffer, and don't need to be freed. */
! if (lp->file_names)
! free (lp->file_names);
!
! /* Similarly for the include directory names. */
! if (lp->include_dirs)
! free (lp->include_dirs);
!
! free (lp);
! }
!
!
! /* Add an entry to LP's include directory table. */
! static void
! add_include_dir (struct line_prologue *lp, char *include_dir)
{
! /* Grow the array if necessary. */
! if (lp->include_dirs_size == 0)
{
! lp->include_dirs_size = 1; /* for testing */
! lp->include_dirs = xmalloc (lp->include_dirs_size
! * sizeof (*lp->include_dirs));
}
! else if (lp->num_include_dirs >= lp->include_dirs_size)
! {
! lp->include_dirs_size *= 2;
! lp->include_dirs = xrealloc (lp->include_dirs,
! (lp->include_dirs_size
! * sizeof (*lp->include_dirs)));
! }
! lp->include_dirs[lp->num_include_dirs++] = include_dir;
! }
!
+ /* Add an entry to LP's file name table. */
static void
! add_file_name (struct line_prologue *lp,
! char *name,
! unsigned int dir_index,
! unsigned int mod_time,
! unsigned int length)
{
! struct file_entry *fe;
!
! /* Grow the array if necessary. */
! if (lp->file_names_size == 0)
! {
! lp->file_names_size = 1; /* for testing */
! lp->file_names = xmalloc (lp->file_names_size
! * sizeof (*lp->file_names));
! }
! else if (lp->num_file_names >= lp->file_names_size)
! {
! lp->file_names_size *= 2;
! lp->file_names = xrealloc (lp->file_names,
! (lp->file_names_size
! * sizeof (*lp->file_names)));
! }
! fe = &lp->file_names[lp->num_file_names++];
! fe->name = name;
! fe->dir_index = dir_index;
! fe->mod_time = mod_time;
! fe->length = length;
! }
!
! /* Read the statement program prologue starting at OFFSET in
! dwarf_line_buffer, according to the endianness of ABFD. Return a
! pointer to a struct line_prologue, allocated using xmalloc.
!
! NOTE: the strings in the include directory and file name tables of
! the returned object point into debug_line_buffer, and must not be
! freed. */
! static struct line_prologue *
! dwarf_decode_line_prologue (unsigned int offset, bfd *abfd,
! const struct comp_unit_head *cu_header)
! {
! struct cleanup *back_to;
! struct line_prologue *lp;
! char *line_ptr;
! int bytes_read;
! int i;
! char *cur_dir, *cur_file;
if (dwarf_line_buffer == NULL)
{
complain (&dwarf2_missing_line_number_section);
! return 0;
}
! /* Make sure that at least there's room for the total_length field. That
! could be 12 bytes long, but we're just going to fudge that. */
! if (offset + 4 >= dwarf_line_size)
! {
! complain (&dwarf2_statement_list_fits_in_line_number_section);
! return 0;
! }
! lp = xmalloc (sizeof (*lp));
! memset (lp, 0, sizeof (*lp));
! back_to = make_cleanup ((make_cleanup_ftype *) free_line_prologue,
! (void *) lp);
line_ptr = dwarf_line_buffer + offset;
/* read in the prologue */
! lp->total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
line_ptr += bytes_read;
! if (line_ptr + lp->total_length > dwarf_line_buffer + dwarf_line_size)
! {
! complain (&dwarf2_statement_list_fits_in_line_number_section);
! return 0;
! }
! lp->statement_program_end = line_ptr + lp->total_length;
! lp->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
! lp->prologue_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
line_ptr += bytes_read;
! lp->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lp->default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lp->line_base = read_1_signed_byte (abfd, line_ptr);
line_ptr += 1;
! lp->line_range = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lp->opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! lp->standard_opcode_lengths
! = (unsigned char *) xmalloc (lp->opcode_base * sizeof (unsigned char));
! lp->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
! for (i = 1; i < lp->opcode_base; ++i)
{
! lp->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
***************
*** 3973,4017 ****
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
! if ((dirs.num_dirs % DIR_ALLOC_CHUNK) == 0)
! {
! dirs.dirs = (char **)
! xrealloc (dirs.dirs,
! (dirs.num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
! if (dirs.num_dirs == 0)
! make_cleanup (free_current_contents, &dirs.dirs);
! }
! dirs.dirs[dirs.num_dirs++] = cur_dir;
}
line_ptr += bytes_read;
/* Read file name table */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
! if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
! {
! files.files = (struct fileinfo *)
! xrealloc (files.files,
! (files.num_files + FILE_ALLOC_CHUNK)
! * sizeof (struct fileinfo));
! if (files.num_files == 0)
! make_cleanup (free_current_contents, &files.files);
! }
! files.files[files.num_files].name = cur_file;
! files.files[files.num_files].dir =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
! files.files[files.num_files].time =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
! files.files[files.num_files].size =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
! files.num_files++;
}
line_ptr += bytes_read;
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
{
--- 4171,4223 ----
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
! add_include_dir (lp, cur_dir);
}
line_ptr += bytes_read;
/* Read file name table */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
+ unsigned int dir_index, mod_time, length;
+
line_ptr += bytes_read;
! dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
! mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
! length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
!
! add_file_name (lp, cur_file, dir_index, mod_time, length);
}
line_ptr += bytes_read;
+ lp->statement_program_start = line_ptr;
+ if (line_ptr > dwarf_line_buffer + dwarf_line_size)
+ complain (&dwarf2_line_prologue_too_long);
+
+ discard_cleanups (back_to);
+ return lp;
+ }
+
+
+ /* Decode the line number information for the compilation unit whose
+ line number info is at OFFSET in the .debug_line section.
+ The compilation directory of the file is passed in COMP_DIR. */
+
+ static void
+ dwarf_decode_lines (struct line_prologue *lp, char *comp_dir, bfd *abfd,
+ const struct comp_unit_head *cu_header)
+ {
+ char *line_ptr;
+ char *line_end;
+ unsigned int i, bytes_read;
+ char *cur_dir;
+ unsigned char op_code, extended_op, adj_opcode;
+
+ line_ptr = lp->statement_program_start;
+ line_end = lp->statement_program_end;
+
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
{
***************
*** 4020,4038 ****
unsigned int file = 1;
unsigned int line = 1;
unsigned int column = 0;
! int is_stmt = lh.default_is_stmt;
int basic_block = 0;
int end_sequence = 0;
/* Start a subfile for the current file of the state machine. */
! if (files.num_files >= file)
{
! /* The file and directory tables are 0 based, the references
! are 1 based. */
! dwarf2_start_subfile (files.files[file - 1].name,
! (files.files[file - 1].dir
! ? dirs.dirs[files.files[file - 1].dir - 1]
! : comp_dir));
}
/* Decode the table. */
--- 4226,4248 ----
unsigned int file = 1;
unsigned int line = 1;
unsigned int column = 0;
! int is_stmt = lp->default_is_stmt;
int basic_block = 0;
int end_sequence = 0;
/* Start a subfile for the current file of the state machine. */
! if (lp->num_file_names >= file)
{
! /* lp->include_dirs and lp->file_names are 0-based, but the
! directory and file name numbers in the statement program
! are 1-based. */
! struct file_entry *fe = &lp->file_names[file - 1];
! char *dir;
! if (fe->dir_index)
! dir = lp->include_dirs[fe->dir_index - 1];
! else
! dir = comp_dir;
! dwarf2_start_subfile (fe->name, dir);
}
/* Decode the table. */
***************
*** 4041,4052 ****
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! if (op_code >= lh.opcode_base)
{ /* Special operand. */
! adj_opcode = op_code - lh.opcode_base;
! address += (adj_opcode / lh.line_range)
! * lh.minimum_instruction_length;
! line += lh.line_base + (adj_opcode % lh.line_range);
/* append row to matrix using current values */
record_line (current_subfile, line, address);
basic_block = 1;
--- 4251,4262 ----
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
! if (op_code >= lp->opcode_base)
{ /* Special operand. */
! adj_opcode = op_code - lp->opcode_base;
! address += (adj_opcode / lp->line_range)
! * lp->minimum_instruction_length;
! line += lp->line_base + (adj_opcode % lp->line_range);
/* append row to matrix using current values */
record_line (current_subfile, line, address);
basic_block = 1;
***************
*** 4074,4105 ****
address += baseaddr;
break;
case DW_LNE_define_file:
! cur_file = read_string (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
! {
! files.files = (struct fileinfo *)
! xrealloc (files.files,
! (files.num_files + FILE_ALLOC_CHUNK)
! * sizeof (struct fileinfo));
! if (files.num_files == 0)
! make_cleanup (free_current_contents, &files.files);
! }
! files.files[files.num_files].name = cur_file;
! files.files[files.num_files].dir =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! files.files[files.num_files].time =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! files.files[files.num_files].size =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! files.num_files++;
break;
default:
complain (&dwarf2_mangled_line_number_section);
! goto done;
}
break;
case DW_LNS_copy:
--- 4284,4310 ----
address += baseaddr;
break;
case DW_LNE_define_file:
! {
! char *cur_file;
! unsigned int dir_index, mod_time, length;
!
! cur_file = read_string (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! dir_index =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! mod_time =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! length =
! read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! add_file_name (lp, cur_file, dir_index, mod_time, length);
! }
break;
default:
complain (&dwarf2_mangled_line_number_section);
! return;
}
break;
case DW_LNS_copy:
***************
*** 4107,4113 ****
basic_block = 0;
break;
case DW_LNS_advance_pc:
! address += lh.minimum_instruction_length
* read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
--- 4312,4318 ----
basic_block = 0;
break;
case DW_LNS_advance_pc:
! address += lp->minimum_instruction_length
* read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
***************
*** 4116,4130 ****
line_ptr += bytes_read;
break;
case DW_LNS_set_file:
! /* The file and directory tables are 0 based, the references
! are 1 based. */
! file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! dwarf2_start_subfile
! (files.files[file - 1].name,
! (files.files[file - 1].dir
! ? dirs.dirs[files.files[file - 1].dir - 1]
! : comp_dir));
break;
case DW_LNS_set_column:
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
--- 4321,4341 ----
line_ptr += bytes_read;
break;
case DW_LNS_set_file:
! {
! /* lp->include_dirs and lp->file_names are 0-based,
! but the directory and file name numbers in the
! statement program are 1-based. */
! struct file_entry *fe;
! char *dir;
! file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
! line_ptr += bytes_read;
! fe = &lp->file_names[file - 1];
! if (fe->dir_index)
! dir = lp->include_dirs[fe->dir_index - 1];
! else
! dir = comp_dir;
! dwarf2_start_subfile (fe->name, dir);
! }
break;
case DW_LNS_set_column:
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
***************
*** 4142,4149 ****
length since special opcode 255 would have scaled the
the increment. */
case DW_LNS_const_add_pc:
! address += (lh.minimum_instruction_length
! * ((255 - lh.opcode_base) / lh.line_range));
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (abfd, line_ptr);
--- 4353,4360 ----
length since special opcode 255 would have scaled the
the increment. */
case DW_LNS_const_add_pc:
! address += (lp->minimum_instruction_length
! * ((255 - lp->opcode_base) / lp->line_range));
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (abfd, line_ptr);
***************
*** 4152,4158 ****
default:
{ /* Unknown standard opcode, ignore it. */
int i;
! for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
{
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
--- 4363,4369 ----
default:
{ /* Unknown standard opcode, ignore it. */
int i;
! for (i = 0; i < lp->standard_opcode_lengths[op_code]; i++)
{
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
***************
*** 4161,4170 ****
}
}
}
- done:
- do_cleanups (back_to);
}
/* Start a subfile for DWARF. FILENAME is the name of the file and
DIRNAME the name of the source directory which contains FILENAME
or NULL if not known.
--- 4372,4380 ----
}
}
}
}
+
/* Start a subfile for DWARF. FILENAME is the name of the file and
DIRNAME the name of the source directory which contains FILENAME
or NULL if not known.
***************
*** 6126,6129 ****
--- 6336,6710 ----
die = (struct die_info *) xmalloc (sizeof (struct die_info));
memset (die, 0, sizeof (struct die_info));
return (die);
+ }
+
+
+ /* Macro support. */
+
+
+ /* Return the full name of file number I in *LP's file name table.
+ Use COMP_DIR as the name of the current directory of the
+ compilation. The result is allocated using xmalloc; the caller is
+ responsible for freeing it. */
+ static char *
+ file_full_name (int file, struct line_prologue *lp, const char *comp_dir)
+ {
+ struct file_entry *fe = &lp->file_names[file - 1];
+
+ if (IS_ABSOLUTE_PATH (fe->name))
+ return xstrdup (fe->name);
+ else
+ {
+ const char *dir;
+ int dir_len;
+ char *full_name;
+
+ if (fe->dir_index)
+ dir = lp->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+
+ if (dir)
+ {
+ dir_len = strlen (dir);
+ full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1);
+ strcpy (full_name, dir);
+ full_name[dir_len] = '/';
+ strcpy (full_name + dir_len + 1, fe->name);
+ return full_name;
+ }
+ else
+ return xstrdup (fe->name);
+ }
+ }
+
+
+ static struct macro_source_file *
+ macro_start_file (int file, int line,
+ struct macro_source_file *current_file,
+ const char *comp_dir,
+ struct line_prologue *lp, struct objfile *objfile)
+ {
+ /* The full name of this source file. */
+ char *full_name = file_full_name (file, lp, comp_dir);
+
+ /* We don't create a macro table for this compilation unit
+ at all until we actually get a filename. */
+ if (! pending_macros)
+ pending_macros = new_macro_table (&objfile->symbol_obstack,
+ &objfile->macro_cache);
+
+ if (! current_file)
+ /* If we have no current file, then this must be the start_file
+ directive for the compilation unit's main source file. */
+ current_file = macro_set_main (pending_macros, full_name);
+ else
+ current_file = macro_include (current_file, line, full_name);
+
+ xfree (full_name);
+
+ return current_file;
+ }
+
+
+ /* Copy the LEN characters at BUF to a xmalloc'ed block of memory,
+ followed by a null byte. */
+ static char *
+ copy_string (const char *buf, int len)
+ {
+ char *s = xmalloc (len + 1);
+ memcpy (s, buf, len);
+ s[len] = '\0';
+
+ return s;
+ }
+
+
+ static void
+ consume_improper_spaces (const char **p, const char *body)
+ {
+ if (**p == ' ')
+ {
+ complain (&dwarf2_macro_spaces_in_definition, body);
+
+ while (**p == ' ')
+ (*p)++;
+ }
+ }
+
+
+ static void
+ parse_macro_definition (struct macro_source_file *file, int line,
+ const char *body)
+ {
+ const char *p;
+
+ /* The body string takes one of two forms. For object-like macro
+ definitions, it should be:
+
+ <macro name> " " <definition>
+
+ For function-like macro definitions, it should be:
+
+ <macro name> "() " <definition>
+ or
+ <macro name> "(" <arg name> ( "," <arg name> ) * ") " <definition>
+
+ Spaces may appear only where explicitly indicated, and in the
+ <definition>.
+
+ The Dwarf 2 spec says that an object-like macro's name is always
+ followed by a space, but versions of GCC around March 2002 omit
+ the space when the macro's definition is the empty string.
+
+ The Dwarf 2 spec says that there should be no spaces between the
+ formal arguments in a function-like macro's formal argument list,
+ but versions of GCC around March 2002 include spaces after the
+ commas. */
+
+
+ /* Find the extent of the macro name. The macro name is terminated
+ by either a space or null character (for an object-like macro) or
+ an opening paren (for a function-like macro). */
+ for (p = body; *p; p++)
+ if (*p == ' ' || *p == '(')
+ break;
+
+ if (*p == ' ' || *p == '\0')
+ {
+ /* It's an object-like macro. */
+ int name_len = p - body;
+ char *name = copy_string (body, name_len);
+ const char *replacement;
+
+ if (*p == ' ')
+ replacement = body + name_len + 1;
+ else
+ {
+ complain (&dwarf2_macro_malformed_definition, body);
+ replacement = body + name_len;
+ }
+
+ macro_define_object (file, line, name, replacement);
+
+ xfree (name);
+ }
+ else if (*p == '(')
+ {
+ /* It's a function-like macro. */
+ char *name = copy_string (body, p - body);
+ int argc = 0;
+ int argv_size = 1;
+ char **argv = xmalloc (argv_size * sizeof (*argv));
+
+ p++;
+
+ consume_improper_spaces (&p, body);
+
+ /* Parse the formal argument list. */
+ while (*p && *p != ')')
+ {
+ /* Find the extent of the current argument name. */
+ const char *arg_start = p;
+
+ while (*p && *p != ',' && *p != ')' && *p != ' ')
+ p++;
+
+ if (! *p || p == arg_start)
+ complain (&dwarf2_macro_malformed_definition,
+ body);
+ else
+ {
+ /* Make sure argv has room for the new argument. */
+ if (argc >= argv_size)
+ {
+ argv_size *= 2;
+ argv = xrealloc (argv, argv_size * sizeof (*argv));
+ }
+
+ argv[argc++] = copy_string (arg_start, p - arg_start);
+ }
+
+ consume_improper_spaces (&p, body);
+
+ /* Consume the comma, if present. */
+ if (*p == ',')
+ {
+ p++;
+
+ consume_improper_spaces (&p, body);
+ }
+ }
+
+ if (*p == ')')
+ {
+ p++;
+
+ if (*p == ' ')
+ /* Perfectly formed definition, no complaints. */
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p + 1);
+ else if (*p == '\0')
+ {
+ /* Complain, but do define it. */
+ complain (&dwarf2_macro_malformed_definition, body);
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p);
+ }
+ else
+ /* Just complain. */
+ complain (&dwarf2_macro_malformed_definition, body);
+ }
+ else
+ /* Just complain. */
+ complain (&dwarf2_macro_malformed_definition, body);
+
+ xfree (name);
+ {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ xfree (argv[i]);
+ }
+ xfree (argv);
+ }
+ else
+ complain (&dwarf2_macro_malformed_definition, body);
+ }
+
+
+ static void
+ dwarf_decode_macros (struct line_prologue *lp, unsigned int offset,
+ char *comp_dir, bfd *abfd,
+ const struct comp_unit_head *cu_header,
+ struct objfile *objfile)
+ {
+ char *mac_ptr, *mac_end;
+ struct macro_source_file *current_file = 0;
+
+ if (dwarf_macinfo_buffer == NULL)
+ {
+ complain (&dwarf2_missing_macinfo_section);
+ return;
+ }
+
+ mac_ptr = dwarf_macinfo_buffer + offset;
+ mac_end = dwarf_macinfo_buffer + dwarf_macinfo_size;
+
+ for (;;)
+ {
+ enum dwarf_macinfo_record_type macinfo_type;
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ complain (&dwarf2_macros_too_long);
+ return;
+ }
+
+ macinfo_type = read_1_byte (abfd, mac_ptr);
+ mac_ptr++;
+
+ switch (macinfo_type)
+ {
+ /* A zero macinfo type indicates the end of the macro
+ information. */
+ case 0:
+ return;
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ {
+ int bytes_read;
+ int line;
+ char *body;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ body = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ if (! current_file)
+ complain (&dwarf2_macro_outside_file,
+ macinfo_type == DW_MACINFO_define ? "definition" :
+ macinfo_type == DW_MACINFO_undef ? "undefinition" :
+ "something-or-other",
+ body);
+ else
+ {
+ if (macinfo_type == DW_MACINFO_define)
+ parse_macro_definition (current_file, line, body);
+ else if (macinfo_type == DW_MACINFO_undef)
+ macro_undef (current_file, line, body);
+ }
+ }
+ break;
+
+ case DW_MACINFO_start_file:
+ {
+ int bytes_read;
+ int line, file;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ current_file = macro_start_file (file, line,
+ current_file, comp_dir,
+ lp, objfile);
+ }
+ break;
+
+ case DW_MACINFO_end_file:
+ if (! current_file)
+ complain (&dwarf2_macro_unmatched_end_file);
+ else
+ {
+ current_file = current_file->included_by;
+ if (! current_file)
+ {
+ enum dwarf_macinfo_record_type next_type;
+
+ /* GCC circa March 2002 doesn't produce the zero
+ type byte marking the end of the compilation
+ unit. Complain if it's not there, but exit no
+ matter what. */
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ complain (&dwarf2_macros_too_long);
+ return;
+ }
+
+ /* We don't increment mac_ptr here, so this is just
+ a look-ahead. */
+ next_type = read_1_byte (abfd, mac_ptr);
+ if (next_type != 0)
+ complain (&dwarf2_macros_not_terminated);
+
+ return;
+ }
+ }
+ break;
+
+ case DW_MACINFO_vendor_ext:
+ {
+ int bytes_read;
+ int constant;
+ char *string;
+
+ constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ string = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ /* We don't recognize any vendor extensions. */
+ }
+ break;
+ }
+ }
}
Index: gdb/findvar.c
===================================================================
RCS file: /cvs/src/src/gdb/findvar.c,v
retrieving revision 1.29
diff -c -r1.29 findvar.c
*** gdb/findvar.c 2002/03/16 02:57:42 1.29
--- gdb/findvar.c 2002/03/28 06:50:42
***************
*** 551,557 ****
if (frame == NULL)
return 0;
! b = get_frame_block (frame);
if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
{
--- 551,557 ----
if (frame == NULL)
return 0;
! b = get_frame_block (frame, 0);
if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
{
Index: gdb/frame.h
===================================================================
RCS file: /cvs/src/src/gdb/frame.h,v
retrieving revision 1.9
diff -c -r1.9 frame.h
*** gdb/frame.h 2002/02/18 15:59:13 1.9
--- gdb/frame.h 2002/03/28 06:50:42
***************
*** 196,206 ****
extern struct frame_info *get_next_frame (struct frame_info *);
! extern struct block *get_frame_block (struct frame_info *);
! extern struct block *get_current_block (void);
! extern struct block *get_selected_block (void);
extern struct symbol *get_frame_function (struct frame_info *);
--- 196,207 ----
extern struct frame_info *get_next_frame (struct frame_info *);
! extern struct block *get_frame_block (struct frame_info *,
! CORE_ADDR *pc_in_block);
! extern struct block *get_current_block (CORE_ADDR *pc_in_block);
! extern struct block *get_selected_block (CORE_ADDR *pc_in_block);
extern struct symbol *get_frame_function (struct frame_info *);
Index: gdb/linespec.c
===================================================================
RCS file: /cvs/src/src/gdb/linespec.c,v
retrieving revision 1.17
diff -c -r1.17 linespec.c
*** gdb/linespec.c 2002/03/22 18:57:07 1.17
--- gdb/linespec.c 2002/03/28 06:50:43
***************
*** 1187,1193 ****
sym = lookup_symbol (copy,
(s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
! : get_selected_block ()),
VAR_NAMESPACE, 0, &sym_symtab);
symbol_found: /* We also jump here from inside the C++ class/namespace
--- 1187,1193 ----
sym = lookup_symbol (copy,
(s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
! : get_selected_block (0)),
VAR_NAMESPACE, 0, &sym_symtab);
symbol_found: /* We also jump here from inside the C++ class/namespace
Index: gdb/macrocmd.c
===================================================================
RCS file: macrocmd.c
diff -N macrocmd.c
*** gdb/macrocmd.c Tue May 5 13:32:27 1998
--- gdb/macrocmd.c Wed Mar 27 22:50:43 2002
***************
*** 0 ****
--- 1,287 ----
+ /* C preprocessor macro expansion commands 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 "macrotab.h"
+ #include "macroexp.h"
+ #include "macroscope.h"
+ #include "command.h"
+ #include "gdbcmd.h"
+
+
+ /* The `macro' prefix command. */
+
+ static struct cmd_list_element *macrolist;
+
+ static void
+ macro_command (char *arg, int from_tty)
+ {
+ printf_unfiltered
+ ("\"macro\" must be followed by the name of a macro command.\n");
+ help_list (macrolist, "macro ", -1, gdb_stdout);
+ }
+
+
+
+ /* Macro expansion commands. */
+
+
+ static void
+ macro_expand_command (char *exp, int from_tty)
+ {
+ struct macro_scope *ms = 0;
+ char *expanded = 0;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ make_cleanup (free_current_contents, &expanded);
+
+ /* You know, when the user doesn't specify any expression, it would be
+ really cool if this defaulted to the last expression evaluated.
+ Then it would be easy to ask, "Hey, what did I just evaluate?" But
+ at the moment, the `print' commands don't save the last expression
+ evaluated, just its value. */
+ if (! exp || ! *exp)
+ error ("You must follow the `macro expand' command with the"
+ " expression you\n"
+ "want to expand.");
+
+ ms = default_macro_scope ();
+ if (ms)
+ {
+ expanded = macro_expand (exp, standard_macro_lookup, ms);
+ fputs_filtered ("expands to: ", gdb_stdout);
+ fputs_filtered (expanded, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ }
+ else
+ fputs_filtered ("GDB has no preprocessor macro information for "
+ "that code.\n",
+ gdb_stdout);
+
+ do_cleanups (cleanup_chain);
+ return;
+ }
+
+
+ static void
+ macro_expand_once_command (char *exp, int from_tty)
+ {
+ struct macro_scope *ms = 0;
+ char *expanded = 0;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ make_cleanup (free_current_contents, &expanded);
+
+ /* You know, when the user doesn't specify any expression, it would be
+ really cool if this defaulted to the last expression evaluated.
+ And it should set the once-expanded text as the new `last
+ expression'. That way, you could just hit return over and over and
+ see the expression expanded one level at a time. */
+ if (! exp || ! *exp)
+ error ("You must follow the `macro expand-once' command with"
+ " the expression\n"
+ "you want to expand.");
+
+ ms = default_macro_scope ();
+ if (ms)
+ {
+ expanded = macro_expand_once (exp, standard_macro_lookup, ms);
+ fputs_filtered ("expands to: ", gdb_stdout);
+ fputs_filtered (expanded, gdb_stdout);
+ fputs_filtered ("\n", gdb_stdout);
+ }
+ else
+ fputs_filtered ("GDB has no preprocessor macro information for "
+ "that code.\n",
+ gdb_stdout);
+
+ do_cleanups (cleanup_chain);
+ return;
+ }
+
+
+ static void
+ show_pp_source_pos (struct ui_file *stream,
+ struct macro_source_file *file,
+ int line)
+ {
+ fprintf_filtered (stream, "%s:%d\n", file->filename, line);
+
+ while (file->included_by)
+ {
+ fprintf_filtered (gdb_stdout, " included at %s:%d\n",
+ file->included_by->filename,
+ file->included_at_line);
+ file = file->included_by;
+ }
+ }
+
+
+ static void
+ show_macro_command (char *name, int from_tty)
+ {
+ struct macro_scope *ms = 0;
+ struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+ struct macro_definition *d;
+
+ if (! name || ! *name)
+ error ("You must follow the `show macro' command with the name"
+ " of the macro\n"
+ "whose definition you want to see.");
+
+ ms = default_macro_scope ();
+ if (! ms)
+ error ("GDB has no preprocessor macro information for that code.\n");
+
+ d = macro_lookup_definition (ms->file, ms->line, name);
+ if (d)
+ {
+ int line;
+ struct macro_source_file *file
+ = macro_definition_location (ms->file, ms->line, name, &line);
+
+ fprintf_filtered (gdb_stdout, "Defined at ");
+ show_pp_source_pos (gdb_stdout, file, line);
+ fprintf_filtered (gdb_stdout, "#define %s", name);
+ if (d->kind == macro_function_like)
+ {
+ int i;
+
+ fputs_filtered ("(", gdb_stdout);
+ for (i = 0; i < d->argc; i++)
+ {
+ fputs_filtered (d->argv[i], gdb_stdout);
+ if (i + 1 < d->argc)
+ fputs_filtered (", ", gdb_stdout);
+ }
+ fputs_filtered (")", gdb_stdout);
+ }
+ fprintf_filtered (gdb_stdout, " %s\n", d->replacement);
+ }
+ else
+ {
+ fprintf_filtered (gdb_stdout,
+ "The symbol `%s' has no definition as a C/C++"
+ " preprocessor macro\n"
+ "at ", name);
+ show_pp_source_pos (gdb_stdout, ms->file, ms->line);
+ }
+
+ do_cleanups (cleanup_chain);
+ }
+
+
+
+ /* User-defined macros. */
+
+ /* A table of user-defined macros. Unlike the macro tables used for
+ symtabs, this one uses xmalloc for all its allocation, not an
+ obstack, and it doesn't bcache anything; it just xmallocs things. So
+ it's perfectly possible to remove things from this, or redefine
+ things. */
+ static struct macro_table *user_macros;
+
+ static void
+ macro_define_command (char *exp, int from_tty)
+ {
+ error ("Command not implemented yet.");
+ }
+
+
+ static void
+ macro_undef_command (char *exp, int from_tty)
+ {
+ error ("Command not implemented yet.");
+ }
+
+
+ static void
+ macro_list_command (char *exp, int from_tty)
+ {
+ error ("Command not implemented yet.");
+ }
+
+
+
+ /* Initializing the `macrocmd' module. */
+
+ void
+ _initialize_macrocmd (void)
+ {
+ struct cmd_list_element *c;
+
+ /* We introduce a new command prefix, `macro', under which we'll put
+ the various commands for working with preprocessor macros. */
+ add_prefix_cmd
+ ("macro", class_info, macro_command,
+ "Prefix for commands dealing with C preprocessor macros.",
+ ¯olist, "macro ", 0, &cmdlist);
+
+ add_cmd
+ ("expand", no_class, macro_expand_command,
+ "Fully expand any C/C++ preprocessor macro invocations in EXPRESSION.\n"
+ "Show the expanded expression.",
+ ¯olist);
+ add_alias_cmd ("exp", "expand", no_class, 1, ¯olist);
+ add_cmd
+ ("expand-once", no_class, macro_expand_once_command,
+ "Expand C/C++ preprocessor macro invocations appearing directly in"
+ " EXPRESSION.\n"
+ "Show the expanded expression.\n"
+ "\n"
+ "This command differs from `macro expand' in that it only expands macro\n"
+ "invocations that appear directly in EXPRESSION; if expanding a macro\n"
+ "introduces further macro invocations, those are left unexpanded.\n"
+ "\n"
+ "`macro expand-once' helps you see how a particular macro expands,\n"
+ "whereas `macro expand' shows you how all the macros involved in an\n"
+ "expression work together to yield a pre-processed expression.",
+ ¯olist);
+ add_alias_cmd ("exp1", "expand-once", no_class, 1, ¯olist);
+
+ add_cmd
+ ("macro", no_class, show_macro_command,
+ "Show the definition of MACRO, and its source location.",
+ &showlist);
+
+ add_cmd
+ ("define", no_class, macro_define_command,
+ "Define a new C/C++ preprocessor macro.\n"
+ "The GDB command `macro define DEFINITION' is equivalent to placing a\n"
+ "preprocessor directive of the form `#define DEFINITION' such that the\n"
+ "definition is visible in all the inferior's source files.\n"
+ "For example:\n"
+ " (gdb) macro define PI (3.1415926)\n"
+ " (gdb) macro define MIN(x,y) ((x) < (y) ? (x) : (y))",
+ ¯olist);
+
+ add_cmd
+ ("undef", no_class, macro_undef_command,
+ "Remove the definition of the C/C++ preprocessor macro with the"
+ " given name.",
+ ¯olist);
+
+ add_cmd
+ ("list", no_class, macro_list_command,
+ "List all the macros defined using the `macro define' command.",
+ ¯olist);
+
+ user_macros = new_macro_table (0, 0);
+ }
Index: gdb/macroexp.c
===================================================================
RCS file: macroexp.c
diff -N macroexp.c
*** gdb/macroexp.c Tue May 5 13:32:27 1998
--- gdb/macroexp.c Wed Mar 27 22:50:44 2002
***************
*** 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;
+ }
+ }
Index: gdb/macroexp.h
===================================================================
RCS file: macroexp.h
diff -N macroexp.h
*** gdb/macroexp.h Tue May 5 13:32:27 1998
--- gdb/macroexp.h Wed Mar 27 22:50:44 2002
***************
*** 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 */
Index: gdb/macroscope.c
===================================================================
RCS file: macroscope.c
diff -N macroscope.c
*** gdb/macroscope.c Tue May 5 13:32:27 1998
--- gdb/macroscope.c Wed Mar 27 22:50:44 2002
***************
*** 0 ****
--- 1,98 ----
+ /* Functions for deciding which macros are currently in scope.
+ 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 "macroscope.h"
+ #include "symtab.h"
+ #include "target.h"
+ #include "frame.h"
+ #include "inferior.h"
+
+
+ struct macro_scope *
+ sal_macro_scope (struct symtab_and_line sal)
+ {
+ struct macro_source_file *main;
+ struct macro_scope *ms;
+
+ if (! sal.pc
+ || ! sal.symtab
+ || ! sal.symtab->macro_table)
+ return 0;
+
+ ms = (struct macro_scope *) xmalloc (sizeof (*ms));
+
+ main = macro_main (sal.symtab->macro_table);
+ ms->file = macro_lookup_inclusion (main, sal.symtab->filename);
+
+ if (! ms->file)
+ internal_error
+ (__FILE__, __LINE__,
+ "\n"
+ "the symtab `%s' refers to a preprocessor macro table which doesn't\n"
+ "have any record of processing a file by that name.\n",
+ sal.symtab->filename);
+
+ ms->line = sal.line;
+
+ return ms;
+ }
+
+
+ struct macro_scope *
+ default_macro_scope ()
+ {
+ struct symtab_and_line sal;
+ struct macro_source_file *main;
+ struct macro_scope *ms;
+
+ /* If there's a selected frame, use its PC. */
+ if (selected_frame)
+ sal = find_pc_line (selected_frame->pc, 0);
+
+ /* If the target has any registers at all, then use its PC. Why we
+ would have registers but no stack, I'm not sure. */
+ else if (target_has_registers)
+ sal = find_pc_line (read_pc (), 0);
+
+ /* If all else fails, fall back to the current listing position. */
+ else
+ {
+ select_source_symtab (0);
+ sal.symtab = current_source_symtab;
+ sal.line = current_source_line;
+ }
+
+ return sal_macro_scope (sal);
+ }
+
+
+ /* Look up the definition of the macro named NAME in scope at the source
+ location given by BATON, which must be a pointer to a `struct
+ macro_scope' structure. */
+ struct macro_definition *
+ standard_macro_lookup (const char *name, void *baton)
+ {
+ struct macro_scope *ms = (struct macro_scope *) baton;
+
+ return macro_lookup_definition (ms->file, ms->line, name);
+ }
Index: gdb/macroscope.h
===================================================================
RCS file: macroscope.h
diff -N macroscope.h
*** gdb/macroscope.h Tue May 5 13:32:27 1998
--- gdb/macroscope.h Wed Mar 27 22:50:44 2002
***************
*** 0 ****
--- 1,63 ----
+ /* Interface to functions for deciding which macros are currently in scope.
+ 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 MACROSCOPE_H
+ #define MACROSCOPE_H
+
+ #include "macrotab.h"
+ #include "symtab.h"
+
+
+ /* All the information we need to decide which macro definitions are
+ in scope: a source file (either a main source file or an
+ #inclusion), and a line number in that file. */
+ struct macro_scope {
+ struct macro_source_file *file;
+ int line;
+ };
+
+
+ /* Return a `struct macro_scope' object corresponding to the symtab
+ and line given in SAL. If we have no macro information for that
+ location, or if SAL's pc is zero, return zero. */
+ struct macro_scope *sal_macro_scope (struct symtab_and_line sal);
+
+
+ /* Return a `struct macro_scope' object describing the scope the `macro
+ expand' and `macro expand-once' commands should use for looking up
+ macros. If we have a selected frame, this is the source location of
+ its PC; otherwise, this is the last listing position.
+
+ If we have no macro information for the current location, return zero.
+
+ The object returned is allocated using xmalloc; the caller is
+ responsible for freeing it. */
+ struct macro_scope *default_macro_scope (void);
+
+
+ /* Look up the definition of the macro named NAME in scope at the source
+ location given by BATON, which must be a pointer to a `struct
+ macro_scope' structure. This function is suitable for use as
+ a macro_lookup_ftype function. */
+ struct macro_definition *standard_macro_lookup (const char *name, void *baton);
+
+
+ #endif /* MACROSCOPE_H */
Index: gdb/macrotab.c
===================================================================
RCS file: macrotab.c
diff -N macrotab.c
*** gdb/macrotab.c Tue May 5 13:32:27 1998
--- gdb/macrotab.c Wed Mar 27 22:50:44 2002
***************
*** 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);
+ }
Index: gdb/macrotab.h
===================================================================
RCS file: macrotab.h
diff -N macrotab.h
*** gdb/macrotab.h Tue May 5 13:32:27 1998
--- gdb/macrotab.h Wed Mar 27 22:50:44 2002
***************
*** 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 */
Index: gdb/objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.19
diff -c -r1.19 objfiles.c
*** gdb/objfiles.c 2001/12/06 20:59:11 1.19
--- gdb/objfiles.c 2002/03/28 06:50:45
***************
*** 190,195 ****
--- 190,197 ----
/* Update pointers to functions to *our* copies */
obstack_chunkfun (&objfile->psymbol_cache.cache, xmmalloc);
obstack_freefun (&objfile->psymbol_cache.cache, xmfree);
+ obstack_chunkfun (&objfile->macro_cache.cache, xmmalloc);
+ obstack_freefun (&objfile->macro_cache.cache, xmfree);
obstack_chunkfun (&objfile->psymbol_obstack, xmmalloc);
obstack_freefun (&objfile->psymbol_obstack, xmfree);
obstack_chunkfun (&objfile->symbol_obstack, xmmalloc);
***************
*** 220,225 ****
--- 222,230 ----
obstack_specify_allocation_with_arg (&objfile->psymbol_cache.cache,
0, 0, xmmalloc, xmfree,
objfile->md);
+ obstack_specify_allocation_with_arg (&objfile->macro_cache.cache,
+ 0, 0, xmmalloc, xmfree,
+ objfile->md);
obstack_specify_allocation_with_arg (&objfile->psymbol_obstack,
0, 0, xmmalloc, xmfree,
objfile->md);
***************
*** 266,271 ****
--- 271,278 ----
objfile->md = NULL;
obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0,
xmalloc, xfree);
+ obstack_specify_allocation (&objfile->macro_cache.cache, 0, 0,
+ xmalloc, xfree);
obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc,
xfree);
obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc,
***************
*** 477,482 ****
--- 484,490 ----
xmfree (objfile->md, objfile->static_psymbols.list);
/* Free the obstacks for non-reusable objfiles */
free_bcache (&objfile->psymbol_cache);
+ free_bcache (&objfile->macro_cache);
obstack_free (&objfile->psymbol_obstack, 0);
obstack_free (&objfile->symbol_obstack, 0);
obstack_free (&objfile->type_obstack, 0);
Index: gdb/objfiles.h
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.h,v
retrieving revision 1.9
diff -c -r1.9 objfiles.h
*** gdb/objfiles.h 2001/10/12 19:07:07 1.9
--- gdb/objfiles.h 2002/03/28 06:50:46
***************
*** 277,282 ****
--- 277,283 ----
will not change. */
struct bcache psymbol_cache; /* Byte cache for partial syms */
+ struct bcache macro_cache; /* Byte cache for macros */
/* Vectors of all partial symbols read in from file. The actual data
is stored in the psymbol_obstack. */
Index: gdb/parse.c
===================================================================
RCS file: /cvs/src/src/gdb/parse.c,v
retrieving revision 1.19
diff -c -r1.19 parse.c
*** gdb/parse.c 2002/01/31 02:13:56 1.19
--- gdb/parse.c 2002/03/28 06:50:46
***************
*** 69,74 ****
--- 69,75 ----
int expout_size;
int expout_ptr;
struct block *expression_context_block;
+ CORE_ADDR expression_context_pc;
struct block *innermost_block;
int arglist_len;
union type_stack_elt *type_stack;
***************
*** 1134,1140 ****
old_chain = make_cleanup (free_funcalls, 0 /*ignore*/);
funcall_chain = 0;
! expression_context_block = block ? block : get_selected_block ();
namecopy = (char *) alloca (strlen (lexptr) + 1);
expout_size = 10;
--- 1135,1147 ----
old_chain = make_cleanup (free_funcalls, 0 /*ignore*/);
funcall_chain = 0;
! if (block)
! {
! expression_context_block = block;
! expression_context_pc = block->startaddr;
! }
! else
! expression_context_block = get_selected_block (&expression_context_pc);
namecopy = (char *) alloca (strlen (lexptr) + 1);
expout_size = 10;
Index: gdb/parser-defs.h
===================================================================
RCS file: /cvs/src/src/gdb/parser-defs.h,v
retrieving revision 1.6
diff -c -r1.6 parser-defs.h
*** gdb/parser-defs.h 2001/11/15 01:55:59 1.6
--- gdb/parser-defs.h 2002/03/28 06:50:47
***************
*** 44,49 ****
--- 44,55 ----
extern struct block *expression_context_block;
+ /* If expression_context_block is non-zero, then this is the PC within
+ the block that we want to evaluate expressions at. When debugging
+ C or C++ code, we use this to find the exact line we're at, and
+ then look up the macro definitions active at that point. */
+ CORE_ADDR expression_context_pc;
+
/* The innermost context required by the stack and register variables
we've encountered so far. */
extern struct block *innermost_block;
Index: gdb/printcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/printcmd.c,v
retrieving revision 1.37
diff -c -r1.37 printcmd.c
*** gdb/printcmd.c 2002/03/06 06:28:33 1.37
--- gdb/printcmd.c 2002/03/28 06:50:48
***************
*** 1113,1119 ****
if (exp == 0)
error ("Argument required.");
! sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE,
&is_a_field_of_this, (struct symtab **) NULL);
if (sym == NULL)
{
--- 1113,1119 ----
if (exp == 0)
error ("Argument required.");
! sym = lookup_symbol (exp, get_selected_block (0), VAR_NAMESPACE,
&is_a_field_of_this, (struct symtab **) NULL);
if (sym == NULL)
{
***************
*** 1549,1555 ****
return;
if (d->block)
! within_current_scope = contained_in (get_selected_block (), d->block);
else
within_current_scope = 1;
if (!within_current_scope)
--- 1549,1555 ----
return;
if (d->block)
! within_current_scope = contained_in (get_selected_block (0), d->block);
else
within_current_scope = 1;
if (!within_current_scope)
***************
*** 1683,1689 ****
else if (d->format.format)
printf_filtered ("/%c ", d->format.format);
print_expression (d->exp, gdb_stdout);
! if (d->block && !contained_in (get_selected_block (), d->block))
printf_filtered (" (cannot be evaluated in the current context)");
printf_filtered ("\n");
gdb_flush (gdb_stdout);
--- 1683,1689 ----
else if (d->format.format)
printf_filtered ("/%c ", d->format.format);
print_expression (d->exp, gdb_stdout);
! if (d->block && !contained_in (get_selected_block (0), d->block))
printf_filtered (" (cannot be evaluated in the current context)");
printf_filtered ("\n");
gdb_flush (gdb_stdout);
Index: gdb/solib-sunos.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-sunos.c,v
retrieving revision 1.3
diff -c -r1.3 solib-sunos.c
*** gdb/solib-sunos.c 2002/01/23 06:24:20 1.3
--- gdb/solib-sunos.c 2002/03/28 06:50:48
***************
*** 137,142 ****
--- 137,144 ----
objfile->md = NULL;
obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0,
xmalloc, xfree);
+ obstack_specify_allocation (&objfile->macro_cache.cache, 0, 0,
+ xmalloc, xfree);
obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc,
xfree);
obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc,
Index: gdb/stack.c
===================================================================
RCS file: /cvs/src/src/gdb/stack.c,v
retrieving revision 1.30
diff -c -r1.30 stack.c
*** gdb/stack.c 2002/03/23 17:38:13 1.30
--- gdb/stack.c 2002/03/28 06:50:50
***************
*** 1238,1244 ****
print_frame_local_vars (register struct frame_info *fi, register int num_tabs,
register struct ui_file *stream)
{
! register struct block *block = get_frame_block (fi);
register int values_printed = 0;
if (block == 0)
--- 1238,1244 ----
print_frame_local_vars (register struct frame_info *fi, register int num_tabs,
register struct ui_file *stream)
{
! register struct block *block = get_frame_block (fi, 0);
register int values_printed = 0;
if (block == 0)
***************
*** 1272,1278 ****
register struct ui_file *stream)
{
register struct blockvector *bl;
! register struct block *block = get_frame_block (fi);
register int values_printed = 0;
int index, have_default = 0;
char *blocks_printed;
--- 1272,1278 ----
register struct ui_file *stream)
{
register struct blockvector *bl;
! register struct block *block = get_frame_block (fi, 0);
register int values_printed = 0;
int index, have_default = 0;
char *blocks_printed;
***************
*** 1501,1517 ****
}
/* Return the symbol-block in which the selected frame is executing.
! Can return zero under various legitimate circumstances. */
struct block *
! get_selected_block (void)
{
if (!target_has_stack)
return 0;
if (!selected_frame)
! return get_current_block ();
! return get_frame_block (selected_frame);
}
/* Find a frame a certain number of levels away from FRAME.
--- 1501,1521 ----
}
/* Return the symbol-block in which the selected frame is executing.
! Can return zero under various legitimate circumstances.
+ If PC_IN_BLOCK is non-zero, set *PC_IN_BLOCK to the relevant PC
+ value within the block returned. We use this to decide which
+ macros are in scope. */
+
struct block *
! get_selected_block (CORE_ADDR *pc_in_block)
{
if (!target_has_stack)
return 0;
if (!selected_frame)
! return get_current_block (pc_in_block);
! return get_frame_block (selected_frame, pc_in_block);
}
/* Find a frame a certain number of levels away from FRAME.
Index: gdb/symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.56
diff -c -r1.56 symfile.c
*** gdb/symfile.c 2002/03/19 03:51:06 1.56
--- gdb/symfile.c 2002/03/28 06:50:51
***************
*** 1699,1704 ****
--- 1699,1705 ----
/* Free the obstacks for non-reusable objfiles */
free_bcache (&objfile->psymbol_cache);
+ free_bcache (&objfile->macro_cache);
obstack_free (&objfile->psymbol_obstack, 0);
obstack_free (&objfile->symbol_obstack, 0);
obstack_free (&objfile->type_obstack, 0);
***************
*** 1723,1728 ****
--- 1724,1731 ----
/* obstack_specify_allocation also initializes the obstack so
it is empty. */
obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0,
+ xmalloc, xfree);
+ obstack_specify_allocation (&objfile->macro_cache.cache, 0, 0,
xmalloc, xfree);
obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0,
xmalloc, xfree);
Index: gdb/symmisc.c
===================================================================
RCS file: /cvs/src/src/gdb/symmisc.c,v
retrieving revision 1.8
diff -c -r1.8 symmisc.c
*** gdb/symmisc.c 2002/03/22 18:57:08 1.8
--- gdb/symmisc.c 2002/03/28 06:50:52
***************
*** 197,202 ****
--- 197,204 ----
obstack_memory_used (&objfile->psymbol_obstack));
printf_filtered (" Total memory used for psymbol cache: %d\n",
obstack_memory_used (&objfile->psymbol_cache.cache));
+ printf_filtered (" Total memory used for macro cache: %d\n",
+ obstack_memory_used (&objfile->macro_cache.cache));
printf_filtered (" Total memory used for symbol obstack: %d\n",
obstack_memory_used (&objfile->symbol_obstack));
printf_filtered (" Total memory used for type obstack: %d\n",
Index: gdb/symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.59
diff -c -r1.59 symtab.c
*** gdb/symtab.c 2002/03/27 23:10:23 1.59
--- gdb/symtab.c 2002/03/28 06:50:54
***************
*** 3279,3285 ****
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
! for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b))
{
if (!BLOCK_SUPERBLOCK (b))
{
--- 3279,3285 ----
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
! for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
{
if (!BLOCK_SUPERBLOCK (b))
{
***************
*** 3812,3818 ****
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
! for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b))
{
if (!BLOCK_SUPERBLOCK (b))
{
--- 3812,3818 ----
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
! for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
{
if (!BLOCK_SUPERBLOCK (b))
{
Index: gdb/symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.29
diff -c -r1.29 symtab.h
*** gdb/symtab.h 2002/03/27 23:10:24 1.29
--- gdb/symtab.h 2002/03/28 06:50:55
***************
*** 820,825 ****
--- 820,830 ----
int primary;
+ /* The macro table for this symtab. Like the blockvector, this
+ may be shared between different symtabs --- and normally is for
+ all the symtabs in a given compilation unit. */
+ struct macro_table *macro_table;
+
/* Name of this source file. */
char *filename;
Index: gdb/varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.26
diff -c -r1.26 varobj.c
*** gdb/varobj.c 2002/01/13 20:17:55 1.26
--- gdb/varobj.c 2002/03/28 06:50:56
***************
*** 426,432 ****
block = NULL;
if (fi != NULL)
! block = get_frame_block (fi);
p = expression;
innermost_block = NULL;
--- 426,432 ----
block = NULL;
if (fi != NULL)
! block = get_frame_block (fi, 0);
p = expression;
innermost_block = NULL;
Index: gdb/mi/mi-cmd-stack.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmd-stack.c,v
retrieving revision 1.10
diff -c -r1.10 mi-cmd-stack.c
*** gdb/mi/mi-cmd-stack.c 2002/02/05 19:28:36 1.10
--- gdb/mi/mi-cmd-stack.c 2002/03/28 06:50:57
***************
*** 218,224 ****
stb = ui_out_stream_new (uiout);
! block = get_frame_block (fi);
ui_out_list_begin (uiout, locals ? "locals" : "args");
--- 218,224 ----
stb = ui_out_stream_new (uiout);
! block = get_frame_block (fi, 0);
ui_out_list_begin (uiout, locals ? "locals" : "args");