diff options
-rw-r--r-- | gdb/ChangeLog | 11 | ||||
-rwxr-xr-x | gdb/make-target-delegates | 253 | ||||
-rw-r--r-- | gdb/target-delegates.c | 14 | ||||
-rw-r--r-- | gdb/target.c | 9 | ||||
-rw-r--r-- | gdb/target.h | 24 |
5 files changed, 311 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bb6ce24..f49246c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,16 @@ 2014-02-19 Tom Tromey <tromey@redhat.com> + PR build/7701: + * target-delegates.c: New file. + * target.c: Include target-delegates.c. + (init_dummy_target): Call install_dummy_methods. + (complete_target_initialization): Call install_delegators. + * target.h (TARGET_DEFAULT_IGNORE, TARGET_DEFAULT_NORETURN) + (TARGET_DEFAULT_RETURN, TARGET_DEFAULT_FUNC): New defines. + * make-target-delegates: New file. + +2014-02-19 Tom Tromey <tromey@redhat.com> + * record.c (find_record_target): Use find_target_at. * target.c (find_target_at): New function. * target.h (find_target_at): Declare. diff --git a/gdb/make-target-delegates b/gdb/make-target-delegates new file mode 100755 index 0000000..f09f89d --- /dev/null +++ b/gdb/make-target-delegates @@ -0,0 +1,253 @@ +#!/usr/bin/perl + +# Copyright (C) 2013-2014 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# Usage: +# make-target-delegates target.h > target-delegates.c + +# The line we search for in target.h that marks where we should start +# looking for methods. +$TRIGGER = qr,^struct target_ops$,; +# The end of the methods part. +$ENDER = qr,^\s*};$,; + +# Match a C symbol. +$SYMBOL = qr,[a-zA-Z_][a-zA-Z0-9_]*,; +# Match the name part of a method in struct target_ops. +$NAME_PART = qr,\(\*(?<name>${SYMBOL}+)\)\s,; +# Match the start of arguments to a method. +$ARGS_PART = qr,(?<args>\(.*)$,; +# Match indentation. +$INTRO_PART = qr,^\s*,; + +# Match the return type when it is "ordinary". +$SIMPLE_RETURN_PART = qr,[^\(]+,; +# Match the return type when it is a VEC. +$VEC_RETURN_PART = qr,VEC\s*\([^\)]+\)[^\(]*,; + +# Match the TARGET_DEFAULT_* attribute for a method. +$TARGET_DEFAULT_PART = qr,TARGET_DEFAULT_(?<style>[A-Z_]+)\s*\((?<default_arg>.*)\),; + +# Match the introductory line to a method definition. +$METHOD = ($INTRO_PART . "(?<return_type>" . $SIMPLE_RETURN_PART + . "|" . $VEC_RETURN_PART . ")" + . $NAME_PART . $ARGS_PART); + +# Match the arguments and trailing attribute of a method definition. +$METHOD_TRAILER = qr,(?<args>\(.+\))\s*${TARGET_DEFAULT_PART};$,; + +sub trim($) { + my ($result) = @_; + $result =~ s,^\s*(\S*)\s*$,\1,; + return $result; +} + +# Read from the input files until we find the trigger line. +# Die if not found. +sub find_trigger() { + while (<>) { + chomp; + return if m/$TRIGGER/; + } + + die "could not find trigger line\n"; +} + +# Parse arguments into a list. +sub parse_argtypes($) { + my ($typestr) = @_; + + $typestr =~ s/^\((.*)\)$/\1/; + + my (@typelist) = split (/,\s*/, $typestr); + my (@result, $iter, $onetype); + + foreach $iter (@typelist) { + if ($iter =~ m/^(enum\s+${SYMBOL}\s*)(${SYMBOL})?$/) { + $onetype = $1; + } elsif ($iter =~ m/^(.*(enum\s+)?${SYMBOL}.*(\s|\*))${SYMBOL}+$/) { + $onetype = $1; + } elsif ($iter eq 'void') { + next; + } else { + $onetype = $iter; + } + push @result, trim ($onetype); + } + + return @result; +} + +sub dname($) { + my ($name) = @_; + $name =~ s/to_/delegate_/; + return $name; +} + +# Write function header given name, return type, and argtypes. +# Returns a list of actual argument names. +sub write_function_header($$@) { + my ($name, $return_type, @argtypes) = @_; + + print "static " . $return_type . "\n"; + print $name . ' ('; + + my $iter; + my @argdecls; + my @actuals; + my $i = 0; + foreach $iter (@argtypes) { + my $val = $iter; + + if ($iter !~ m,\*$,) { + $val .= ' '; + } + + my $vname; + if ($i == 0) { + # Just a random nicety. + $vname = 'self'; + } else { + $vname .= "arg$i"; + } + $val .= $vname; + + push @argdecls, $val; + push @actuals, $vname; + ++$i; + } + + print join (', ', @argdecls) . ")\n"; + print "{\n"; + + return @actuals; +} + +# Write out a delegation function. +sub write_delegator($$@) { + my ($name, $return_type, @argtypes) = @_; + + my (@names) = write_function_header (dname ($name), $return_type, + @argtypes); + + print " $names[0] = $names[0]->beneath;\n"; + print " "; + if ($return_type ne 'void') { + print "return "; + } + print "$names[0]->" . $name . " ("; + print join (', ', @names); + print ");\n"; + print "}\n\n"; +} + +sub tdname ($) { + my ($name) = @_; + $name =~ s/to_/tdefault_/; + return $name; +} + +# Write out a default function. +sub write_tdefault($$$$@) { + my ($content, $style, $name, $return_type, @argtypes) = @_; + + if ($style eq 'FUNC') { + return $content; + } + + write_function_header (tdname ($name), $return_type, @argtypes); + + if ($style eq 'RETURN') { + print " return $content;\n"; + } elsif ($style eq 'NORETURN') { + print " $content;\n"; + } elsif ($style eq 'IGNORE') { + # Nothing. + } else { + die "unrecognized style: $style\n"; + } + + print "}\n\n"; + + return tdname ($name); +} + +print "/* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */\n"; +print "/* vi:set ro: */\n\n"; +print "/* To regenerate this file, run:*/\n"; +print "/* make-target-delegates target.h > target-delegates.c */\n"; + +find_trigger(); + +%tdefault_names = (); +@delegators = (); +$current_line = ''; +while (<>) { + chomp; + last if m/$ENDER/; + + if ($current_line ne '') { + s/^\s*//; + $current_line .= $_; + } elsif (m/$METHOD/) { + $name = $+{name}; + $current_line = $+{args}; + $return_type = trim ($+{return_type}); + } + + if ($current_line =~ /\);\s*$/) { + if ($current_line =~ m,$METHOD_TRAILER,) { + $current_args = $+{args}; + $tdefault = $+{default_arg}; + $style = $+{style}; + + @argtypes = parse_argtypes ($current_args); + + # The first argument must be "this" to be delegatable. + if ($argtypes[0] =~ /\s*struct\s+target_ops\s*\*\s*/) { + write_delegator ($name, $return_type, @argtypes); + + push @delegators, $name; + + $tdefault_names{$name} = write_tdefault ($tdefault, $style, + $name, $return_type, + @argtypes); + } + } + + $current_line = ''; + } +} + +# Now the delegation code. +print "static void\ninstall_delegators (struct target_ops *ops)\n{\n"; + +for $iter (@delegators) { + print " if (ops->" . $iter . " == NULL)\n"; + print " ops->" . $iter . " = " . dname ($iter) . ";\n"; +} +print "}\n\n"; + +# Now the default method code. +print "static void\ninstall_dummy_methods (struct target_ops *ops)\n{\n"; + +for $iter (@delegators) { + print " ops->" . $iter . " = " . $tdefault_names{$iter} . ";\n"; +} +print "}\n"; diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c new file mode 100644 index 0000000..cf6364d --- /dev/null +++ b/gdb/target-delegates.c @@ -0,0 +1,14 @@ +/* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */ +/* vi:set ro: */ + +/* To regenerate this file, run:*/ +/* make-target-delegates target.h > target-delegates.c */ +static void +install_delegators (struct target_ops *ops) +{ +} + +static void +install_dummy_methods (struct target_ops *ops) +{ +} diff --git a/gdb/target.c b/gdb/target.c index 75f7506..9643b5e 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -79,6 +79,8 @@ static target_xfer_partial_ftype current_xfer_partial; static struct gdbarch *default_thread_architecture (struct target_ops *ops, ptid_t ptid); +#include "target-delegates.c" + static void init_dummy_target (void); static struct target_ops debug_target; @@ -353,6 +355,8 @@ complete_target_initialization (struct target_ops *t) if (t->to_has_execution == NULL) t->to_has_execution = (int (*) (struct target_ops *, ptid_t)) return_zero; + + install_delegators (t); } /* Add possible target architecture T to the list and add a new @@ -560,6 +564,9 @@ update_current_target (void) /* First, reset current's contents. */ memset (¤t_target, 0, sizeof (current_target)); + /* Install the delegators. */ + install_delegators (¤t_target); + #define INHERIT(FIELD, TARGET) \ if (!current_target.FIELD) \ current_target.FIELD = (TARGET)->FIELD @@ -3883,6 +3890,8 @@ init_dummy_target (void) dummy_target.to_stopped_data_address = (int (*) (struct target_ops *, CORE_ADDR *)) return_zero; dummy_target.to_magic = OPS_MAGIC; + + install_dummy_methods (&dummy_target); } static void diff --git a/gdb/target.h b/gdb/target.h index 1248734..be8c965 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -359,6 +359,30 @@ struct thread_info; /* fwd decl for parameter list below: */ typedef void async_callback_ftype (enum inferior_event_type event_type, void *context); +/* These defines are used to mark target_ops methods. The script + make-target-delegates scans these and auto-generates the base + method implementations. There are four macros that can be used: + + 1. TARGET_DEFAULT_IGNORE. There is no argument. The base method + does nothing. This is only valid if the method return type is + 'void'. + + 2. TARGET_DEFAULT_NORETURN. The argument is a function call, like + 'tcomplain ()'. The base method simply makes this call, which is + assumed not to return. + + 3. TARGET_DEFAULT_RETURN. The argument is a C expression. The + base method returns this expression's value. + + 4. TARGET_DEFAULT_FUNC. The argument is the name of a function. + make-target-delegates does not generate a base method in this case, + but instead uses the argument function as the base method. */ + +#define TARGET_DEFAULT_IGNORE() +#define TARGET_DEFAULT_NORETURN(ARG) +#define TARGET_DEFAULT_RETURN(ARG) +#define TARGET_DEFAULT_FUNC(ARG) + struct target_ops { struct target_ops *beneath; /* To the target under this one. */ |