the "compile" command

This final patch adds the new "compile" command and subcommands, and
all the machinery needed to make it work.

A shared library supplied by gcc is used for all communications with
gcc.  Types and most aspects of symbols are provided directly by gdb
to the compiler using this library.

gdb provides some information about the user's code using plain text.
Macros are emitted this way, and DWARF location expressions (and
bounds for VLA) are compiled to C code.

This hybrid approach was taken because, on the one hand, it is better
to provide global declarations and such on demand; but on the other
hand, for local variables, translating DWARF location expressions to C
was much simpler than exporting a full compiler API to gdb -- the same
result, only easier to implement, understand, and debug.

In the ordinary mode, the user's expression is wrapped in a dummy
function.  After compilation, gdb inserts the resulting object code
into the inferior, then calls this function.

Access to local variables is provided by noting which registers are
used by location expressions, and passing a structure of register
values into the function.  Writes to registers are supported by
copying out these values after the function returns.

This approach was taken so that we could eventually implement other
more interesting features based on this same infrastructure; for
example, we're planning to investigate inferior-side breakpoint
conditions.

gdb/ChangeLog
2014-12-12  Phil Muldoon  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Tom Tromey  <tromey@redhat.com>

	* NEWS: Update.
	* symtab.h (struct symbol_computed_ops) <generate_c_location>: New
	field.
	* p-lang.c (pascal_language_defn): Update.
	* opencl-lang.c (opencl_language_defn): Update.
	* objc-lang.c (objc_language_defn): Update.
	* m2-lang.c (m2_language_defn): Update.
	* language.h (struct language_defn) <la_get_compile_instance,
	la_compute_program>: New fields.
	* language.c (unknown_language_defn, auto_language_defn)
	(local_language_defn): Update.
	* jv-lang.c (java_language_defn): Update.
	* go-lang.c (go_language_defn): Update.
	* f-lang.c (f_language_defn): Update.
	* dwarf2loc.h (dwarf2_compile_property_to_c): Declare.
	* dwarf2loc.c (dwarf2_compile_property_to_c)
	(locexpr_generate_c_location, loclist_generate_c_location): New
	functions.
	(dwarf2_locexpr_funcs, dwarf2_loclist_funcs): Update.
	* defs.h (enum compile_i_scope_types): New.
	(enum command_control_type) <compile_control>: New constant.
	(struct command_line) <control_u>: New field.
	* d-lang.c (d_language_defn): Update.
	* compile/compile.c: New file.
	* compile/compile-c-support.c: New file.
	* compile/compile-c-symbols.c: New file.
	* compile/compile-c-types.c: New file.
	* compile/compile.h: New file.
	* compile/compile-internal.h: New file.
	* compile/compile-loc2c.c: New file.
	* compile/compile-object-load.c: New file.
	* compile/compile-object-load.h: New file.
	* compile/compile-object-run.c: New file.
	* compile/compile-object-run.h: New file.
	* cli/cli-script.c (multi_line_command_p, print_command_lines)
	(execute_control_command, process_next_line)
	(recurse_read_control_structure): Handle compile_control.
	* c-lang.h (c_get_compile_context, c_compute_program): Declare.
	* c-lang.c (c_language_defn, cplus_language_defn)
	(asm_language_defn, minimal_language_defn): Update.
	* ada-lang.c (ada_language_defn): Update.
	* Makefile.in (SUBDIR_GCC_COMPILE_OBS, SUBDIR_GCC_COMPILE_SRCS):
	New variables.
	(SFILES): Add SUBDIR_GCC_COMPILE_SRCS.
	(HFILES_NO_SRCDIR): Add compile.h.
	(COMMON_OBS): Add SUBDIR_GCC_COMPILE_OBS.
	(INIT_FILES): Add SUBDIR_GCC_COMPILE_SRCS.
	(compile.o, compile-c-types.o, compile-c-symbols.o)
	(compile-object-load.o, compile-object-run.o, compile-loc2c.o)
	(compile-c-support.o): New targets.

gdb/doc/ChangeLog
2014-12-12  Phil Muldoon  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.texinfo (Altering): Update.
	(Compiling and Injecting Code): New node.

gdb/testsuite/ChangeLog
2014-12-12  Phil Muldoon  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Tom Tromey  <tromey@redhat.com>

	* configure.ac: Add gdb.compile/.
	* configure: Regenerate.
	* gdb.compile/Makefile.in: New file.
	* gdb.compile/compile-ops.exp: New file.
	* gdb.compile/compile-ops.c: New file.
	* gdb.compile/compile-tls.c: New file.
	* gdb.compile/compile-tls.exp: New file.
	* gdb.compile/compile-constvar.S: New file.
	* gdb.compile/compile-constvar.c: New file.
	* gdb.compile/compile-mod.c: New file.
	* gdb.compile/compile-nodebug.c: New file.
	* gdb.compile/compile-setjmp-mod.c: New file.
	* gdb.compile/compile-setjmp.c: New file.
	* gdb.compile/compile-setjmp.exp: New file.
	* gdb.compile/compile-shlib.c: New file.
	* gdb.compile/compile.c: New file.
	* gdb.compile/compile.exp: New file.
	* lib/gdb.exp (skip_compile_feature_tests): New proc.
This commit is contained in:
Tom Tromey 2014-05-14 14:35:45 -06:00 committed by Jan Kratochvil
parent a2658febe2
commit bb2ec1b34e
53 changed files with 6451 additions and 11 deletions

View File

@ -1,3 +1,58 @@
2014-12-12 Phil Muldoon <pmuldoon@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
Tom Tromey <tromey@redhat.com>
* NEWS: Update.
* symtab.h (struct symbol_computed_ops) <generate_c_location>: New
field.
* p-lang.c (pascal_language_defn): Update.
* opencl-lang.c (opencl_language_defn): Update.
* objc-lang.c (objc_language_defn): Update.
* m2-lang.c (m2_language_defn): Update.
* language.h (struct language_defn) <la_get_compile_instance,
la_compute_program>: New fields.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Update.
* jv-lang.c (java_language_defn): Update.
* go-lang.c (go_language_defn): Update.
* f-lang.c (f_language_defn): Update.
* dwarf2loc.h (dwarf2_compile_property_to_c): Declare.
* dwarf2loc.c (dwarf2_compile_property_to_c)
(locexpr_generate_c_location, loclist_generate_c_location): New
functions.
(dwarf2_locexpr_funcs, dwarf2_loclist_funcs): Update.
* defs.h (enum compile_i_scope_types): New.
(enum command_control_type) <compile_control>: New constant.
(struct command_line) <control_u>: New field.
* d-lang.c (d_language_defn): Update.
* compile/compile.c: New file.
* compile/compile-c-support.c: New file.
* compile/compile-c-symbols.c: New file.
* compile/compile-c-types.c: New file.
* compile/compile.h: New file.
* compile/compile-internal.h: New file.
* compile/compile-loc2c.c: New file.
* compile/compile-object-load.c: New file.
* compile/compile-object-load.h: New file.
* compile/compile-object-run.c: New file.
* compile/compile-object-run.h: New file.
* cli/cli-script.c (multi_line_command_p, print_command_lines)
(execute_control_command, process_next_line)
(recurse_read_control_structure): Handle compile_control.
* c-lang.h (c_get_compile_context, c_compute_program): Declare.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Update.
* ada-lang.c (ada_language_defn): Update.
* Makefile.in (SUBDIR_GCC_COMPILE_OBS, SUBDIR_GCC_COMPILE_SRCS):
New variables.
(SFILES): Add SUBDIR_GCC_COMPILE_SRCS.
(HFILES_NO_SRCDIR): Add compile.h.
(COMMON_OBS): Add SUBDIR_GCC_COMPILE_OBS.
(INIT_FILES): Add SUBDIR_GCC_COMPILE_SRCS.
(compile.o, compile-c-types.o, compile-c-symbols.o)
(compile-object-load.o, compile-object-run.o, compile-loc2c.o)
(compile-c-support.o): New targets.
2014-12-12 Jan Kratochvil <jan.kratochvil@redhat.com>
* s390-linux-tdep.c (s390_gcc_target_options): New function.

View File

@ -280,6 +280,24 @@ SUBDIR_TUI_LDFLAGS=
SUBDIR_TUI_CFLAGS= \
-DTUI=1
#
# GCC Compile support sub-directory definitions
#
SUBDIR_GCC_COMPILE_OBS = \
compile.o compile-c-symbols.o compile-c-types.o \
compile-object-load.o compile-object-run.o \
compile-loc2c.o compile-c-support.o
SUBDIR_GCC_COMPILE_SRCS = \
compile/compile.c \
compile/compile-c-symbols.c \
compile/compile-c-types.c \
compile/compile-object-load.c \
compile/compile-object-load.h \
compile/compile-object-run.c \
compile/compile-object-run.h \
compile/compile-loc2c.c \
compile/compile-c-support.c
# Guile sub directory definitons for guile support.
SUBDIR_GUILE_OBS = \
@ -854,7 +872,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
target/waitstatus.c common/print-utils.c common/rsp-low.c \
common/errors.c common/common-debug.c common/common-exceptions.c
common/errors.c common/common-debug.c common/common-exceptions.c \
$(SUBDIR_GCC_COMPILE_SRCS)
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@ -876,7 +895,7 @@ nto-tdep.h serial.h \
c-lang.h d-lang.h go-lang.h frame.h event-loop.h block.h cli/cli-setshow.h \
cli/cli-decode.h cli/cli-cmds.h cli/cli-utils.h \
cli/cli-script.h macrotab.h symtab.h common/version.h \
gnulib/import/string.in.h gnulib/import/str-two-way.h \
compile/compile.h gnulib/import/string.in.h gnulib/import/str-two-way.h \
gnulib/import/stdint.in.h remote.h remote-notif.h gdb.h sparc-nat.h \
gdbthread.h dwarf2-frame.h dwarf2-frame-tailcall.h nbsd-nat.h dcache.h \
amd64-nat.h s390-linux-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \
@ -1041,7 +1060,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
format.o registry.o btrace.o record-btrace.o waitstatus.o \
print-utils.o rsp-low.o errors.o common-debug.o debug.o \
common-exceptions.o
common-exceptions.o \
$(SUBDIR_GCC_COMPILE_OBS)
TSOBS = inflow.o
@ -1284,7 +1304,7 @@ test-cp-name-parser$(EXEEXT): test-cp-name-parser.o $(LIBIBERTY)
# duplicates. Files in the gdb/ directory can end up appearing in
# COMMON_OBS (as a .o file) and CONFIG_SRCS (as a .c file).
INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS)
INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS) $(SUBDIR_GCC_COMPILE_SRCS)
init.c: $(INIT_FILES)
@echo Making init.c
@rm -f init.c-tmp init.l-tmp
@ -1916,6 +1936,39 @@ cli-utils.o: $(srcdir)/cli/cli-utils.c
$(COMPILE) $(srcdir)/cli/cli-utils.c
$(POSTCOMPILE)
# GCC Compile support dependencies
#
# Need to explicitly specify the compile rule as make will do nothing
# or try to compile the object file into the sub-directory.
compile.o: $(srcdir)/compile/compile.c
$(COMPILE) $(srcdir)/compile/compile.c
$(POSTCOMPILE)
compile-c-types.o: $(srcdir)/compile/compile-c-types.c
$(COMPILE) $(srcdir)/compile/compile-c-types.c
$(POSTCOMPILE)
compile-c-symbols.o: $(srcdir)/compile/compile-c-symbols.c
$(COMPILE) $(srcdir)/compile/compile-c-symbols.c
$(POSTCOMPILE)
compile-object-load.o: $(srcdir)/compile/compile-object-load.c
$(COMPILE) $(srcdir)/compile/compile-object-load.c
$(POSTCOMPILE)
compile-object-run.o: $(srcdir)/compile/compile-object-run.c
$(COMPILE) $(srcdir)/compile/compile-object-run.c
$(POSTCOMPILE)
compile-loc2c.o: $(srcdir)/compile/compile-loc2c.c
$(COMPILE) $(srcdir)/compile/compile-loc2c.c
$(POSTCOMPILE)
compile-c-support.o: $(srcdir)/compile/compile-c-support.c
$(COMPILE) $(srcdir)/compile/compile-c-support.c
$(POSTCOMPILE)
#
# GDBTK sub-directory

View File

@ -37,6 +37,16 @@
** $_any_caller_is(name [, number_of_frames])
** $_any_caller_matches(regexp [, number_of_frames])
* GDB now supports the compilation and injection of source code into
the inferior. GDB will use GCC 5.0 or higher built with libcc1.so
to compile the source code to object code, and if successful, inject
and execute that code within the current context of the inferior.
Currently the C language is supported. The commands used to
interface with this new feature are:
compile code [-raw|-r] [--] [source code]
compile file [-raw|-r] filename
* New commands
queue-signal signal-name-or-number
@ -49,6 +59,15 @@ add-auto-load-scripts-directory directory
maint print user-registers
List all currently available "user" registers.
compile code [-r|-raw] [--] [source code]
Compile, inject, and execute in the inferior the executable object
code produced by compiling the provided source code.
compile file [-r|-raw] filename
Compile and inject into the inferior the executable object code
produced by compiling the source code stored in the filename
provided.
* On resume, GDB now always passes the signal the program had stopped
for to the thread the signal was sent to, even if the user changed
threads before resuming. Previously GDB would often (but not

View File

@ -13630,6 +13630,8 @@ const struct language_defn ada_language_defn = {
ada_get_symbol_name_cmp, /* la_get_symbol_name_cmp */
ada_iterate_over_symbols,
&ada_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -865,6 +865,8 @@ const struct language_defn c_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&c_varobj_ops,
c_get_compile_context,
c_compute_program,
LANG_MAGIC
};
@ -990,6 +992,8 @@ const struct language_defn cplus_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&cplus_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};
@ -1033,6 +1037,8 @@ const struct language_defn asm_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};
@ -1081,6 +1087,8 @@ const struct language_defn minimal_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -141,5 +141,24 @@ extern int cp_is_vtbl_member (struct type *);
extern int c_textual_element_type (struct type *, char);
/* Create a new instance of the C compiler and return it. The new
compiler is owned by the caller and must be freed using the destroy
method. This function never returns NULL, but rather throws an
exception on failure. This is suitable for use as the
la_get_compile_instance language method. */
extern struct compile_instance *c_get_compile_context (void);
/* This takes the user-supplied text and returns a newly malloc'd bit
of code to compile.
This is used as the la_compute_program language method; see that
for a description of the arguments. */
extern char *c_compute_program (struct compile_instance *inst,
const char *input,
struct gdbarch *gdbarch,
const struct block *expr_block,
CORE_ADDR expr_pc);
#endif /* !defined (C_LANG_H) */

View File

@ -31,6 +31,7 @@
#include "extension.h"
#include "interps.h"
#include "compile/compile.h"
/* Prototypes for local functions. */
@ -87,6 +88,7 @@ multi_line_command_p (enum command_control_type type)
case while_control:
case while_stepping_control:
case commands_control:
case compile_control:
case python_control:
case guile_control:
return 1;
@ -272,6 +274,19 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
continue;
}
if (list->control_type == compile_control)
{
ui_out_field_string (uiout, NULL, "compile expression");
ui_out_text (uiout, "\n");
print_command_lines (uiout, *list->body_list, 0);
if (depth)
ui_out_spaces (uiout, 2 * depth);
ui_out_field_string (uiout, NULL, "end");
ui_out_text (uiout, "\n");
list = list->next;
continue;
}
if (list->control_type == guile_control)
{
ui_out_field_string (uiout, NULL, "guile");
@ -599,6 +614,11 @@ execute_control_command (struct command_line *cmd)
break;
}
case compile_control:
eval_compile_command (cmd, NULL, cmd->control_u.compile.scope);
ret = simple_control;
break;
case python_control:
case guile_control:
{
@ -1040,6 +1060,14 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
here. */
*command = build_command_line (python_control, "");
}
else if (p_end - p == 6 && !strncmp (p, "compile", 7))
{
/* Note that we ignore the inline "compile command" form
here. */
*command = build_command_line (compile_control, "");
(*command)->control_u.compile.scope = COMPILE_I_INVALID_SCOPE;
}
else if (p_end - p == 5 && !strncmp (p, "guile", 5))
{
/* Note that we ignore the inline "guile command" form here. */
@ -1133,7 +1161,8 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
next = NULL;
val = process_next_line (read_next_line_func (), &next,
current_cmd->control_type != python_control
&& current_cmd->control_type != guile_control,
&& current_cmd->control_type != guile_control
&& current_cmd->control_type != compile_control,
validator, closure);
/* Just skip blanks and comments. */

View File

@ -0,0 +1,399 @@
/* C language support for compilation.
Copyright (C) 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/>. */
#include "defs.h"
#include "compile-internal.h"
#include "compile.h"
#include "gdb-dlfcn.h"
#include "c-lang.h"
#include "macrotab.h"
#include "macroscope.h"
#include "regcache.h"
/* See compile-internal.h. */
const char *
c_get_mode_for_size (int size)
{
const char *mode = NULL;
switch (size)
{
case 1:
mode = "QI";
break;
case 2:
mode = "HI";
break;
case 4:
mode = "SI";
break;
case 8:
mode = "DI";
break;
default:
internal_error (__FILE__, __LINE__, _("Invalid GCC mode size %d."), size);
}
return mode;
}
/* See compile-internal.h. */
char *
c_get_range_decl_name (const struct dynamic_prop *prop)
{
return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop));
}
#define STR(x) #x
#define STRINGIFY(x) STR(x)
/* Helper function for c_get_compile_context. Open the GCC front-end
shared library and return the symbol specified by the current
GCC_C_FE_CONTEXT. */
static gcc_c_fe_context_function *
load_libcc (void)
{
void *handle;
gcc_c_fe_context_function *func;
/* gdb_dlopen will call error () on an error, so no need to check
value. */
handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
STRINGIFY (GCC_C_FE_CONTEXT));
if (func == NULL)
error (_("could not find symbol %s in library %s"),
STRINGIFY (GCC_C_FE_CONTEXT),
STRINGIFY (GCC_C_FE_LIBCC));
return func;
}
/* Return the compile instance associated with the current context.
This function calls the symbol returned from the load_libcc
function. This will provide the gcc_c_context. */
struct compile_instance *
c_get_compile_context (void)
{
static gcc_c_fe_context_function *func;
struct gcc_c_context *context;
if (func == NULL)
{
func = load_libcc ();
gdb_assert (func != NULL);
}
context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
if (context == NULL)
error (_("The loaded version of GCC does not support the required version "
"of the API."));
return new_compile_instance (context);
}
/* Write one macro definition. */
static void
print_one_macro (const char *name, const struct macro_definition *macro,
struct macro_source_file *source, int line,
void *user_data)
{
struct ui_file *file = user_data;
/* Don't print command-line defines. They will be supplied another
way. */
if (line == 0)
return;
fprintf_filtered (file, "#define %s", name);
if (macro->kind == macro_function_like)
{
int i;
fputs_filtered ("(", file);
for (i = 0; i < macro->argc; i++)
{
fputs_filtered (macro->argv[i], file);
if (i + 1 < macro->argc)
fputs_filtered (", ", file);
}
fputs_filtered (")", file);
}
fprintf_filtered (file, " %s\n", macro->replacement);
}
/* Write macro definitions at PC to FILE. */
static void
write_macro_definitions (const struct block *block, CORE_ADDR pc,
struct ui_file *file)
{
struct macro_scope *scope;
if (block != NULL)
scope = sal_macro_scope (find_pc_line (pc, 0));
else
scope = default_macro_scope ();
if (scope == NULL)
scope = user_macro_scope ();
if (scope != NULL && scope->file != NULL && scope->file->table != NULL)
macro_for_each_in_scope (scope->file, scope->line, print_one_macro, file);
}
/* Helper function to construct a header scope for a block of code.
Takes a scope argument which selects the correct header to
insert into BUF. */
static void
add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
{
switch (type)
{
case COMPILE_I_SIMPLE_SCOPE:
fputs_unfiltered ("void "
GCC_FE_WRAPPER_FUNCTION
" (struct "
COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
" *"
COMPILE_I_SIMPLE_REGISTER_ARG_NAME
") {\n",
buf);
break;
case COMPILE_I_RAW_SCOPE:
break;
default:
gdb_assert_not_reached (_("Unknown compiler scope reached."));
}
}
/* Helper function to construct a footer scope for a block of code.
Takes a scope argument which selects the correct footer to
insert into BUF. */
static void
add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
{
switch (type)
{
case COMPILE_I_SIMPLE_SCOPE:
fputs_unfiltered ("}\n", buf);
break;
case COMPILE_I_RAW_SCOPE:
break;
default:
gdb_assert_not_reached (_("Unknown compiler scope reached."));
}
}
/* Generate a structure holding all the registers used by the function
we're generating. */
static void
generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
const unsigned char *registers_used)
{
int i;
int seen = 0;
fputs_unfiltered ("struct " COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG " {\n",
stream);
if (registers_used != NULL)
for (i = 0; i < gdbarch_num_regs (gdbarch); ++i)
{
if (registers_used[i])
{
struct type *regtype = check_typedef (register_type (gdbarch, i));
char *regname = compile_register_name_mangled (gdbarch, i);
struct cleanup *cleanups = make_cleanup (xfree, regname);
seen = 1;
/* You might think we could use type_print here. However,
target descriptions often use types with names like
"int64_t", which may not be defined in the inferior
(and in any case would not be looked up due to the
#pragma business). So, we take a much simpler
approach: for pointer- or integer-typed registers, emit
the field in the most direct way; and for other
register types (typically flags or vectors), emit a
maximally-aligned array of the correct size. */
fputs_unfiltered (" ", stream);
switch (TYPE_CODE (regtype))
{
case TYPE_CODE_PTR:
fprintf_filtered (stream, "void *%s", regname);
break;
case TYPE_CODE_INT:
{
const char *mode
= c_get_mode_for_size (TYPE_LENGTH (regtype));
if (mode != NULL)
{
if (TYPE_UNSIGNED (regtype))
fputs_unfiltered ("unsigned ", stream);
fprintf_unfiltered (stream,
"int %s"
" __attribute__ ((__mode__(__%s__)))",
regname,
mode);
break;
}
}
/* Fall through. */
default:
fprintf_unfiltered (stream,
" unsigned char %s[%d]"
" __attribute__((__aligned__("
"__BIGGEST_ALIGNMENT__)))",
regname,
TYPE_LENGTH (regtype));
}
fputs_unfiltered (";\n", stream);
do_cleanups (cleanups);
}
}
if (!seen)
fputs_unfiltered (" char " COMPILE_I_SIMPLE_REGISTER_DUMMY ";\n",
stream);
fputs_unfiltered ("};\n\n", stream);
}
/* Take the source code provided by the user with the 'compile'
command, and compute the additional wrapping, macro, variable and
register operations needed. INPUT is the source code derived from
the 'compile' command, GDBARCH is the architecture to use when
computing above, EXPR_BLOCK denotes the block relevant contextually
to the inferior when the expression was created, and EXPR_PC
indicates the value of $PC. */
char *
c_compute_program (struct compile_instance *inst,
const char *input,
struct gdbarch *gdbarch,
const struct block *expr_block,
CORE_ADDR expr_pc)
{
struct ui_file *buf, *var_stream = NULL;
char *code;
struct cleanup *cleanup;
struct compile_c_instance *context = (struct compile_c_instance *) inst;
buf = mem_fileopen ();
cleanup = make_cleanup_ui_file_delete (buf);
write_macro_definitions (expr_block, expr_pc, buf);
/* Do not generate local variable information for "raw"
compilations. In this case we aren't emitting our own function
and the user's code may only refer to globals. */
if (inst->scope != COMPILE_I_RAW_SCOPE)
{
unsigned char *registers_used;
int i;
/* Generate the code to compute variable locations, but do it
before generating the function header, so we can define the
register struct before the function body. This requires a
temporary stream. */
var_stream = mem_fileopen ();
make_cleanup_ui_file_delete (var_stream);
registers_used = generate_c_for_variable_locations (context,
var_stream, gdbarch,
expr_block, expr_pc);
make_cleanup (xfree, registers_used);
generate_register_struct (buf, gdbarch, registers_used);
fputs_unfiltered ("typedef unsigned int"
" __attribute__ ((__mode__(__pointer__)))"
" __gdb_uintptr;\n",
buf);
fputs_unfiltered ("typedef int"
" __attribute__ ((__mode__(__pointer__)))"
" __gdb_intptr;\n",
buf);
// Iterate all log2 sizes in bytes supported by c_get_mode_for_size.
for (i = 0; i < 4; ++i)
{
const char *mode = c_get_mode_for_size (1 << i);
gdb_assert (mode != NULL);
fprintf_unfiltered (buf,
"typedef int"
" __attribute__ ((__mode__(__%s__)))"
" __gdb_int_%s;\n",
mode, mode);
}
}
add_code_header (inst->scope, buf);
if (inst->scope == COMPILE_I_SIMPLE_SCOPE)
{
ui_file_put (var_stream, ui_file_write_for_put, buf);
fputs_unfiltered ("#pragma GCC user_expression\n", buf);
}
/* The user expression has to be in its own scope, so that "extern"
works properly. Otherwise gcc thinks that the "extern"
declaration is in the same scope as the declaration provided by
gdb. */
if (inst->scope != COMPILE_I_RAW_SCOPE)
fputs_unfiltered ("{\n", buf);
fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
fputs_unfiltered (input, buf);
fputs_unfiltered ("\n", buf);
/* For larger user expressions the automatic semicolons may be
confusing. */
if (strchr (input, '\n') == NULL)
fputs_unfiltered (";\n", buf);
if (inst->scope != COMPILE_I_RAW_SCOPE)
fputs_unfiltered ("}\n", buf);
add_code_footer (inst->scope, buf);
code = ui_file_xstrdup (buf, NULL);
do_cleanups (cleanup);
return code;
}

View File

@ -0,0 +1,759 @@
/* Convert symbols from GDB to GCC
Copyright (C) 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/>. */
#include "defs.h"
#include "compile-internal.h"
#include "gdb_assert.h"
#include "symtab.h"
#include "parser-defs.h"
#include "block.h"
#include "objfiles.h"
#include "compile.h"
#include "value.h"
#include "exceptions.h"
#include "gdbtypes.h"
#include "dwarf2loc.h"
/* Object of this type are stored in the compiler's symbol_err_map. */
struct symbol_error
{
/* The symbol. */
const struct symbol *sym;
/* The error message to emit. This is malloc'd and owned by the
hash table. */
char *message;
};
/* Hash function for struct symbol_error. */
static hashval_t
hash_symbol_error (const void *a)
{
const struct symbol_error *se = a;
return htab_hash_pointer (se->sym);
}
/* Equality function for struct symbol_error. */
static int
eq_symbol_error (const void *a, const void *b)
{
const struct symbol_error *sea = a;
const struct symbol_error *seb = b;
return sea->sym == seb->sym;
}
/* Deletion function for struct symbol_error. */
static void
del_symbol_error (void *a)
{
struct symbol_error *se = a;
xfree (se->message);
xfree (se);
}
/* Associate SYMBOL with some error text. */
static void
insert_symbol_error (htab_t hash, const struct symbol *sym, const char *text)
{
struct symbol_error e;
void **slot;
e.sym = sym;
slot = htab_find_slot (hash, &e, INSERT);
if (*slot == NULL)
{
struct symbol_error *e = XNEW (struct symbol_error);
e->sym = sym;
e->message = xstrdup (text);
*slot = e;
}
}
/* Emit the error message corresponding to SYM, if one exists, and
arrange for it not to be emitted again. */
static void
error_symbol_once (struct compile_c_instance *context,
const struct symbol *sym)
{
struct symbol_error search;
struct symbol_error *err;
char *message;
if (context->symbol_err_map == NULL)
return;
search.sym = sym;
err = htab_find (context->symbol_err_map, &search);
if (err == NULL || err->message == NULL)
return;
message = err->message;
err->message = NULL;
make_cleanup (xfree, message);
error (_("%s"), message);
}
/* Compute the name of the pointer representing a local symbol's
address. */
static char *
symbol_substitution_name (struct symbol *sym)
{
return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
}
/* Convert a given symbol, SYM, to the compiler's representation.
CONTEXT is the compiler instance. IS_GLOBAL is true if the
symbol came from the global scope. IS_LOCAL is true if the symbol
came from a local scope. (Note that the two are not strictly
inverses because the symbol might have come from the static
scope.) */
static void
convert_one_symbol (struct compile_c_instance *context,
struct symbol *sym,
int is_global,
int is_local)
{
gcc_type sym_type;
const char *filename = SYMBOL_SYMTAB (sym)->filename;
unsigned short line = SYMBOL_LINE (sym);
error_symbol_once (context, sym);
if (SYMBOL_CLASS (sym) == LOC_LABEL)
sym_type = 0;
else
sym_type = convert_type (context, SYMBOL_TYPE (sym));
if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
{
/* Binding a tag, so we don't need to build a decl. */
C_CTX (context)->c_ops->tagbind (C_CTX (context),
SYMBOL_NATURAL_NAME (sym),
sym_type, filename, line);
}
else
{
gcc_decl decl;
enum gcc_c_symbol_kind kind;
CORE_ADDR addr = 0;
char *symbol_name = NULL;
switch (SYMBOL_CLASS (sym))
{
case LOC_TYPEDEF:
kind = GCC_C_SYMBOL_TYPEDEF;
break;
case LOC_LABEL:
kind = GCC_C_SYMBOL_LABEL;
addr = SYMBOL_VALUE_ADDRESS (sym);
break;
case LOC_BLOCK:
kind = GCC_C_SYMBOL_FUNCTION;
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
break;
case LOC_CONST:
if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
{
/* Already handled by convert_enum. */
return;
}
C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
SYMBOL_NATURAL_NAME (sym),
SYMBOL_VALUE (sym),
filename, line);
return;
case LOC_CONST_BYTES:
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym));
case LOC_UNDEF:
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
SYMBOL_PRINT_NAME (sym));
case LOC_COMMON_BLOCK:
error (_("Fortran common block is unsupported for compilation "
"evaluaton of symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym));
case LOC_OPTIMIZED_OUT:
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
"as it is optimized out."),
SYMBOL_PRINT_NAME (sym));
case LOC_COMPUTED:
if (is_local)
goto substitution;
/* Probably TLS here. */
warning (_("Symbol \"%s\" is thread-local and currently can only "
"be referenced from the current thread in "
"compiled code."),
SYMBOL_PRINT_NAME (sym));
/* FALLTHROUGH */
case LOC_UNRESOLVED:
/* 'symbol_name' cannot be used here as that one is used only for
local variables from compile_dwarf_expr_to_c.
Global variables can be accessed by GCC only by their address, not
by their name. */
{
struct value *val;
struct frame_info *frame = NULL;
if (symbol_read_needs_frame (sym))
{
frame = get_selected_frame (NULL);
if (frame == NULL)
error (_("Symbol \"%s\" cannot be used because "
"there is no selected frame"),
SYMBOL_PRINT_NAME (sym));
}
val = read_var_value (sym, frame);
if (VALUE_LVAL (val) != lval_memory)
error (_("Symbol \"%s\" cannot be used for compilation "
"evaluation as its address has not been found."),
SYMBOL_PRINT_NAME (sym));
kind = GCC_C_SYMBOL_VARIABLE;
addr = value_address (val);
}
break;
case LOC_REGISTER:
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM_ADDR:
case LOC_LOCAL:
substitution:
kind = GCC_C_SYMBOL_VARIABLE;
symbol_name = symbol_substitution_name (sym);
break;
case LOC_STATIC:
kind = GCC_C_SYMBOL_VARIABLE;
addr = SYMBOL_VALUE_ADDRESS (sym);
break;
case LOC_FINAL_VALUE:
default:
gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
}
/* Don't emit local variable decls for a raw expression. */
if (context->base.scope != COMPILE_I_RAW_SCOPE
|| symbol_name == NULL)
{
decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
SYMBOL_NATURAL_NAME (sym),
kind,
sym_type,
symbol_name, addr,
filename, line);
C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
}
xfree (symbol_name);
}
}
/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
use, IDENTIFIER is the name of the symbol, SYM is the symbol
itself, and DOMAIN is the domain which was searched. */
static void
convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
struct symbol *sym, domain_enum domain)
{
const struct block *static_block, *found_block;
int is_local_symbol;
found_block = block_found;
/* If we found a symbol and it is not in the static or global
scope, then we should first convert any static or global scope
symbol of the same name. This lets this unusual case work:
int x; // Global.
int func(void)
{
int x;
// At this spot, evaluate "extern int x; x"
}
*/
static_block = block_static_block (found_block);
/* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
is_local_symbol = (found_block != static_block && static_block != NULL);
if (is_local_symbol)
{
struct symbol *global_sym;
global_sym = lookup_symbol (identifier, NULL, domain, NULL);
/* If the outer symbol is in the static block, we ignore it, as
it cannot be referenced. */
if (global_sym != NULL
&& block_found != block_static_block (block_found))
{
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"gcc_convert_symbol \"%s\": global symbol\n",
identifier);
convert_one_symbol (context, global_sym, 1, 0);
}
}
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"gcc_convert_symbol \"%s\": local symbol\n",
identifier);
convert_one_symbol (context, sym, 0, is_local_symbol);
}
/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
to use and BMSYM is the minimal symbol to convert. */
static void
convert_symbol_bmsym (struct compile_c_instance *context,
struct bound_minimal_symbol bmsym)
{
struct minimal_symbol *msym = bmsym.minsym;
struct objfile *objfile = bmsym.objfile;
struct type *type;
enum gcc_c_symbol_kind kind;
gcc_type sym_type;
gcc_decl decl;
CORE_ADDR addr;
/* Conversion copied from write_exp_msymbol. */
switch (MSYMBOL_TYPE (msym))
{
case mst_text:
case mst_file_text:
case mst_solib_trampoline:
type = objfile_type (objfile)->nodebug_text_symbol;
kind = GCC_C_SYMBOL_FUNCTION;
break;
case mst_text_gnu_ifunc:
type = objfile_type (objfile)->nodebug_text_gnu_ifunc_symbol;
kind = GCC_C_SYMBOL_FUNCTION;
break;
case mst_data:
case mst_file_data:
case mst_bss:
case mst_file_bss:
type = objfile_type (objfile)->nodebug_data_symbol;
kind = GCC_C_SYMBOL_VARIABLE;
break;
case mst_slot_got_plt:
type = objfile_type (objfile)->nodebug_got_plt_symbol;
kind = GCC_C_SYMBOL_FUNCTION;
break;
default:
type = objfile_type (objfile)->nodebug_unknown_symbol;
kind = GCC_C_SYMBOL_VARIABLE;
break;
}
sym_type = convert_type (context, type);
addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
MSYMBOL_NATURAL_NAME (msym),
kind, sym_type, NULL, addr,
NULL, 0);
C_CTX (context)->c_ops->bind (C_CTX (context), decl, 1 /* is_global */);
}
/* See compile-internal.h. */
void
gcc_convert_symbol (void *datum,
struct gcc_c_context *gcc_context,
enum gcc_c_oracle_request request,
const char *identifier)
{
struct compile_c_instance *context = datum;
domain_enum domain;
volatile struct gdb_exception e;
int found = 0;
switch (request)
{
case GCC_C_ORACLE_SYMBOL:
domain = VAR_DOMAIN;
break;
case GCC_C_ORACLE_TAG:
domain = STRUCT_DOMAIN;
break;
case GCC_C_ORACLE_LABEL:
domain = LABEL_DOMAIN;
break;
default:
gdb_assert_not_reached ("Unrecognized oracle request.");
}
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
TRY_CATCH (e, RETURN_MASK_ALL)
{
struct symbol *sym;
sym = lookup_symbol (identifier, context->base.block, domain, NULL);
if (sym != NULL)
{
convert_symbol_sym (context, identifier, sym, domain);
found = 1;
}
else if (domain == VAR_DOMAIN)
{
struct bound_minimal_symbol bmsym;
bmsym = lookup_minimal_symbol (identifier, NULL, NULL);
if (bmsym.minsym != NULL)
{
convert_symbol_bmsym (context, bmsym);
found = 1;
}
}
}
if (e.reason < 0)
C_CTX (context)->c_ops->error (C_CTX (context), e.message);
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdout,
"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
identifier);
return;
}
/* See compile-internal.h. */
gcc_address
gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
const char *identifier)
{
struct compile_c_instance *context = datum;
volatile struct gdb_exception e;
gcc_address result = 0;
int found = 0;
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
TRY_CATCH (e, RETURN_MASK_ERROR)
{
struct symbol *sym;
/* We only need global functions here. */
sym = lookup_symbol (identifier, NULL, VAR_DOMAIN, NULL);
if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"gcc_symbol_address \"%s\": full symbol\n",
identifier);
result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
found = 1;
}
else
{
struct bound_minimal_symbol msym;
msym = lookup_bound_minimal_symbol (identifier);
if (msym.minsym != NULL)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"gcc_symbol_address \"%s\": minimal "
"symbol\n",
identifier);
result = BMSYMBOL_VALUE_ADDRESS (msym);
found = 1;
}
}
}
if (e.reason < 0)
C_CTX (context)->c_ops->error (C_CTX (context), e.message);
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdout,
"gcc_symbol_address \"%s\": failed\n",
identifier);
return result;
}
/* A hash function for symbol names. */
static hashval_t
hash_symname (const void *a)
{
const struct symbol *sym = a;
return htab_hash_string (SYMBOL_NATURAL_NAME (sym));
}
/* A comparison function for hash tables that just looks at symbol
names. */
static int
eq_symname (const void *a, const void *b)
{
const struct symbol *syma = a;
const struct symbol *symb = b;
return strcmp (SYMBOL_NATURAL_NAME (syma), SYMBOL_NATURAL_NAME (symb)) == 0;
}
/* If a symbol with the same name as SYM is already in HASHTAB, return
1. Otherwise, add SYM to HASHTAB and return 0. */
static int
symbol_seen (htab_t hashtab, struct symbol *sym)
{
void **slot;
slot = htab_find_slot (hashtab, sym, INSERT);
if (*slot != NULL)
return 1;
*slot = sym;
return 0;
}
/* Generate C code to compute the length of a VLA. */
static void
generate_vla_size (struct compile_c_instance *compiler,
struct ui_file *stream,
struct gdbarch *gdbarch,
unsigned char *registers_used,
CORE_ADDR pc,
struct type *type,
struct symbol *sym)
{
type = check_typedef (type);
if (TYPE_CODE (type) == TYPE_CODE_REF)
type = check_typedef (TYPE_TARGET_TYPE (type));
switch (TYPE_CODE (type))
{
case TYPE_CODE_RANGE:
{
if (TYPE_HIGH_BOUND_KIND (type) == PROP_LOCEXPR
|| TYPE_HIGH_BOUND_KIND (type) == PROP_LOCLIST)
{
const struct dynamic_prop *prop = &TYPE_RANGE_DATA (type)->high;
char *name = c_get_range_decl_name (prop);
struct cleanup *cleanup = make_cleanup (xfree, name);
dwarf2_compile_property_to_c (stream, name,
gdbarch, registers_used,
prop, pc, sym);
do_cleanups (cleanup);
}
}
break;
case TYPE_CODE_ARRAY:
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
TYPE_INDEX_TYPE (type), sym);
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
TYPE_TARGET_TYPE (type), sym);
break;
case TYPE_CODE_UNION:
case TYPE_CODE_STRUCT:
{
int i;
for (i = 0; i < TYPE_NFIELDS (type); ++i)
if (!field_is_static (&TYPE_FIELD (type, i)))
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
TYPE_FIELD_TYPE (type, i), sym);
}
break;
}
}
/* Generate C code to compute the address of SYM. */
static void
generate_c_for_for_one_variable (struct compile_c_instance *compiler,
struct ui_file *stream,
struct gdbarch *gdbarch,
unsigned char *registers_used,
CORE_ADDR pc,
struct symbol *sym)
{
volatile struct gdb_exception e;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
if (is_dynamic_type (SYMBOL_TYPE (sym)))
{
struct ui_file *size_file = mem_fileopen ();
struct cleanup *cleanup = make_cleanup_ui_file_delete (size_file);
generate_vla_size (compiler, size_file, gdbarch, registers_used, pc,
SYMBOL_TYPE (sym), sym);
ui_file_put (size_file, ui_file_write_for_put, stream);
do_cleanups (cleanup);
}
if (SYMBOL_COMPUTED_OPS (sym) != NULL)
{
char *generated_name = symbol_substitution_name (sym);
struct cleanup *cleanup = make_cleanup (xfree, generated_name);
/* We need to emit to a temporary buffer in case an error
occurs in the middle. */
struct ui_file *local_file = mem_fileopen ();
make_cleanup_ui_file_delete (local_file);
SYMBOL_COMPUTED_OPS (sym)->generate_c_location (sym, local_file,
gdbarch,
registers_used,
pc, generated_name);
ui_file_put (local_file, ui_file_write_for_put, stream);
do_cleanups (cleanup);
}
else
{
switch (SYMBOL_CLASS (sym))
{
case LOC_REGISTER:
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM_ADDR:
case LOC_LOCAL:
error (_("Local symbol unhandled when generating C code."));
case LOC_COMPUTED:
gdb_assert_not_reached (_("LOC_COMPUTED variable "
"missing a method."));
default:
/* Nothing to do for all other cases, as they don't represent
local variables. */
break;
}
}
}
if (e.reason >= 0)
return;
if (compiler->symbol_err_map == NULL)
compiler->symbol_err_map = htab_create_alloc (10,
hash_symbol_error,
eq_symbol_error,
del_symbol_error,
xcalloc,
xfree);
insert_symbol_error (compiler->symbol_err_map, sym, e.message);
}
/* See compile-internal.h. */
unsigned char *
generate_c_for_variable_locations (struct compile_c_instance *compiler,
struct ui_file *stream,
struct gdbarch *gdbarch,
const struct block *block,
CORE_ADDR pc)
{
struct cleanup *cleanup, *outer;
htab_t symhash;
const struct block *static_block = block_static_block (block);
unsigned char *registers_used;
/* If we're already in the static or global block, there is nothing
to write. */
if (static_block == NULL || block == static_block)
return NULL;
registers_used = XCNEWVEC (unsigned char, gdbarch_num_regs (gdbarch));
outer = make_cleanup (xfree, registers_used);
/* Ensure that a given name is only entered once. This reflects the
reality of shadowing. */
symhash = htab_create_alloc (1, hash_symname, eq_symname, NULL,
xcalloc, xfree);
cleanup = make_cleanup_htab_delete (symhash);
while (1)
{
struct symbol *sym;
struct block_iterator iter;
/* Iterate over symbols in this block, generating code to
compute the location of each local variable. */
for (sym = block_iterator_first (block, &iter);
sym != NULL;
sym = block_iterator_next (&iter))
{
if (!symbol_seen (symhash, sym))
generate_c_for_for_one_variable (compiler, stream, gdbarch,
registers_used, pc, sym);
}
/* If we just finished the outermost block of a function, we're
done. */
if (BLOCK_FUNCTION (block) != NULL)
break;
block = BLOCK_SUPERBLOCK (block);
}
do_cleanups (cleanup);
discard_cleanups (outer);
return registers_used;
}

View File

@ -0,0 +1,438 @@
/* Convert types from GDB to GCC
Copyright (C) 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/>. */
#include "defs.h"
#include "gdbtypes.h"
#include "compile-internal.h"
#include "gdb_assert.h"
/* An object that maps a gdb type to a gcc type. */
struct type_map_instance
{
/* The gdb type. */
struct type *type;
/* The corresponding gcc type handle. */
gcc_type gcc_type;
};
/* Hash a type_map_instance. */
static hashval_t
hash_type_map_instance (const void *p)
{
const struct type_map_instance *inst = p;
return htab_hash_pointer (inst->type);
}
/* Check two type_map_instance objects for equality. */
static int
eq_type_map_instance (const void *a, const void *b)
{
const struct type_map_instance *insta = a;
const struct type_map_instance *instb = b;
return insta->type == instb->type;
}
/* Insert an entry into the type map associated with CONTEXT that maps
from the gdb type TYPE to the gcc type GCC_TYPE. It is ok for a
given type to be inserted more than once, provided that the exact
same association is made each time. This simplifies how type
caching works elsewhere in this file -- see how struct type caching
is handled. */
static void
insert_type (struct compile_c_instance *context, struct type *type,
gcc_type gcc_type)
{
struct type_map_instance inst, *add;
void **slot;
inst.type = type;
inst.gcc_type = gcc_type;
slot = htab_find_slot (context->type_map, &inst, INSERT);
add = *slot;
/* The type might have already been inserted in order to handle
recursive types. */
gdb_assert (add == NULL || add->gcc_type == gcc_type);
if (add == NULL)
{
add = XNEW (struct type_map_instance);
*add = inst;
*slot = add;
}
}
/* Convert a pointer type to its gcc representation. */
static gcc_type
convert_pointer (struct compile_c_instance *context, struct type *type)
{
gcc_type target = convert_type (context, TYPE_TARGET_TYPE (type));
return C_CTX (context)->c_ops->build_pointer_type (C_CTX (context),
target);
}
/* Convert an array type to its gcc representation. */
static gcc_type
convert_array (struct compile_c_instance *context, struct type *type)
{
gcc_type element_type;
struct type *range = TYPE_INDEX_TYPE (type);
element_type = convert_type (context, TYPE_TARGET_TYPE (type));
if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
return C_CTX (context)->c_ops->error (C_CTX (context),
_("array type with non-constant"
" lower bound is not supported"));
if (TYPE_LOW_BOUND (range) != 0)
return C_CTX (context)->c_ops->error (C_CTX (context),
_("cannot convert array type with "
"non-zero lower bound to C"));
if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
|| TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
{
gcc_type result;
char *upper_bound;
if (TYPE_VECTOR (type))
return C_CTX (context)->c_ops->error (C_CTX (context),
_("variably-sized vector type"
" is not supported"));
upper_bound = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
result = C_CTX (context)->c_ops->build_vla_array_type (C_CTX (context),
element_type,
upper_bound);
xfree (upper_bound);
return result;
}
else
{
LONGEST low_bound, high_bound, count;
if (get_array_bounds (type, &low_bound, &high_bound) == 0)
count = -1;
else
{
gdb_assert (low_bound == 0); /* Ensured above. */
count = high_bound + 1;
}
if (TYPE_VECTOR (type))
return C_CTX (context)->c_ops->build_vector_type (C_CTX (context),
element_type,
count);
return C_CTX (context)->c_ops->build_array_type (C_CTX (context),
element_type, count);
}
}
/* Convert a struct or union type to its gcc representation. */
static gcc_type
convert_struct_or_union (struct compile_c_instance *context, struct type *type)
{
int i;
gcc_type result;
/* First we create the resulting type and enter it into our hash
table. This lets recursive types work. */
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
result = C_CTX (context)->c_ops->build_record_type (C_CTX (context));
else
{
gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
result = C_CTX (context)->c_ops->build_union_type (C_CTX (context));
}
insert_type (context, type, result);
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
gcc_type field_type;
unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i);
field_type = convert_type (context, TYPE_FIELD_TYPE (type, i));
if (bitsize == 0)
bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
C_CTX (context)->c_ops->build_add_field (C_CTX (context), result,
TYPE_FIELD_NAME (type, i),
field_type,
bitsize,
TYPE_FIELD_BITPOS (type, i));
}
C_CTX (context)->c_ops->finish_record_or_union (C_CTX (context), result,
TYPE_LENGTH (type));
return result;
}
/* Convert an enum type to its gcc representation. */
static gcc_type
convert_enum (struct compile_c_instance *context, struct type *type)
{
gcc_type int_type, result;
int i;
struct gcc_c_context *ctx = C_CTX (context);
int_type = ctx->c_ops->int_type (ctx,
TYPE_UNSIGNED (type),
TYPE_LENGTH (type));
result = ctx->c_ops->build_enum_type (ctx, int_type);
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
ctx->c_ops->build_add_enum_constant (ctx,
result,
TYPE_FIELD_NAME (type, i),
TYPE_FIELD_ENUMVAL (type, i));
}
ctx->c_ops->finish_enum_type (ctx, result);
return result;
}
/* Convert a function type to its gcc representation. */
static gcc_type
convert_func (struct compile_c_instance *context, struct type *type)
{
int i;
gcc_type result, return_type;
struct gcc_type_array array;
int is_varargs = TYPE_VARARGS (type) || !TYPE_PROTOTYPED (type);
/* This approach means we can't make self-referential function
types. Those are impossible in C, though. */
return_type = convert_type (context, TYPE_TARGET_TYPE (type));
array.n_elements = TYPE_NFIELDS (type);
array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type));
for (i = 0; i < TYPE_NFIELDS (type); ++i)
array.elements[i] = convert_type (context, TYPE_FIELD_TYPE (type, i));
result = C_CTX (context)->c_ops->build_function_type (C_CTX (context),
return_type,
&array, is_varargs);
xfree (array.elements);
return result;
}
/* Convert an integer type to its gcc representation. */
static gcc_type
convert_int (struct compile_c_instance *context, struct type *type)
{
return C_CTX (context)->c_ops->int_type (C_CTX (context),
TYPE_UNSIGNED (type),
TYPE_LENGTH (type));
}
/* Convert a floating-point type to its gcc representation. */
static gcc_type
convert_float (struct compile_c_instance *context, struct type *type)
{
return C_CTX (context)->c_ops->float_type (C_CTX (context),
TYPE_LENGTH (type));
}
/* Convert the 'void' type to its gcc representation. */
static gcc_type
convert_void (struct compile_c_instance *context, struct type *type)
{
return C_CTX (context)->c_ops->void_type (C_CTX (context));
}
/* Convert a boolean type to its gcc representation. */
static gcc_type
convert_bool (struct compile_c_instance *context, struct type *type)
{
return C_CTX (context)->c_ops->bool_type (C_CTX (context));
}
/* Convert a qualified type to its gcc representation. */
static gcc_type
convert_qualified (struct compile_c_instance *context, struct type *type)
{
struct type *unqual = make_unqualified_type (type);
gcc_type unqual_converted;
int quals = 0;
unqual_converted = convert_type (context, unqual);
if (TYPE_CONST (type))
quals |= GCC_QUALIFIER_CONST;
if (TYPE_VOLATILE (type))
quals |= GCC_QUALIFIER_VOLATILE;
if (TYPE_RESTRICT (type))
quals |= GCC_QUALIFIER_RESTRICT;
return C_CTX (context)->c_ops->build_qualified_type (C_CTX (context),
unqual_converted,
quals);
}
/* Convert a complex type to its gcc representation. */
static gcc_type
convert_complex (struct compile_c_instance *context, struct type *type)
{
gcc_type base = convert_type (context, TYPE_TARGET_TYPE (type));
return C_CTX (context)->c_ops->build_complex_type (C_CTX (context), base);
}
/* A helper function which knows how to convert most types from their
gdb representation to the corresponding gcc form. This examines
the TYPE and dispatches to the appropriate conversion function. It
returns the gcc type. */
static gcc_type
convert_type_basic (struct compile_c_instance *context, struct type *type)
{
/* If we are converting a qualified type, first convert the
unqualified type and then apply the qualifiers. */
if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST
| TYPE_INSTANCE_FLAG_VOLATILE
| TYPE_INSTANCE_FLAG_RESTRICT)) != 0)
return convert_qualified (context, type);
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
return convert_pointer (context, type);
case TYPE_CODE_ARRAY:
return convert_array (context, type);
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return convert_struct_or_union (context, type);
case TYPE_CODE_ENUM:
return convert_enum (context, type);
case TYPE_CODE_FUNC:
return convert_func (context, type);
case TYPE_CODE_INT:
return convert_int (context, type);
case TYPE_CODE_FLT:
return convert_float (context, type);
case TYPE_CODE_VOID:
return convert_void (context, type);
case TYPE_CODE_BOOL:
return convert_bool (context, type);
case TYPE_CODE_COMPLEX:
return convert_complex (context, type);
}
return C_CTX (context)->c_ops->error (C_CTX (context),
_("cannot convert gdb type "
"to gcc type"));
}
/* See compile-internal.h. */
gcc_type
convert_type (struct compile_c_instance *context, struct type *type)
{
struct type_map_instance inst, *found;
gcc_type result;
/* We don't ever have to deal with typedefs in this code, because
those are only needed as symbols by the C compiler. */
CHECK_TYPEDEF (type);
inst.type = type;
found = htab_find (context->type_map, &inst);
if (found != NULL)
return found->gcc_type;
result = convert_type_basic (context, type);
insert_type (context, type, result);
return result;
}
/* Delete the compiler instance C. */
static void
delete_instance (struct compile_instance *c)
{
struct compile_c_instance *context = (struct compile_c_instance *) c;
context->base.fe->ops->destroy (context->base.fe);
htab_delete (context->type_map);
if (context->symbol_err_map != NULL)
htab_delete (context->symbol_err_map);
xfree (context);
}
/* See compile-internal.h. */
struct compile_instance *
new_compile_instance (struct gcc_c_context *fe)
{
struct compile_c_instance *result = XCNEW (struct compile_c_instance);
result->base.fe = &fe->base;
result->base.destroy = delete_instance;
result->base.gcc_target_options = ("-std=gnu11"
/* Otherwise the .o file may need
"_Unwind_Resume" and
"__gcc_personality_v0". */
" -fno-exceptions");
result->type_map = htab_create_alloc (10, hash_type_map_instance,
eq_type_map_instance,
xfree, xcalloc, xfree);
fe->c_ops->set_callbacks (fe, gcc_convert_symbol,
gcc_symbol_address, result);
return &result->base;
}

View File

@ -0,0 +1,147 @@
/* Header file for GDB compile command and supporting functions.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_COMPILE_INTERNAL_H
#define GDB_COMPILE_INTERNAL_H
#include "hashtab.h"
#include "gcc-c-interface.h"
/* Debugging flag for the "compile" family of commands. */
extern int compile_debug;
struct block;
/* An object of this type holds state associated with a given
compilation job. */
struct compile_instance
{
/* The GCC front end. */
struct gcc_base_context *fe;
/* The "scope" of this compilation. */
enum compile_i_scope_types scope;
/* The block in which an expression is being parsed. */
const struct block *block;
/* Specify "-std=gnu11", "-std=gnu++11" or similar. These options are put
after CU's DW_AT_producer compilation options to override them. */
const char *gcc_target_options;
/* How to destroy this object. */
void (*destroy) (struct compile_instance *);
};
/* A subclass of compile_instance that is specific to the C front
end. */
struct compile_c_instance
{
/* Base class. Note that the base class vtable actually points to a
gcc_c_fe_vtable. */
struct compile_instance base;
/* Map from gdb types to gcc types. */
htab_t type_map;
/* Map from gdb symbols to gcc error messages to emit. */
htab_t symbol_err_map;
};
/* A helper macro that takes a compile_c_instance and returns its
corresponding gcc_c_context. */
#define C_CTX(I) ((struct gcc_c_context *) ((I)->base.fe))
/* Define header and footers for different scopes. */
/* A simple scope just declares a function named "_gdb_expr", takes no
arguments and returns no value. */
#define COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG "__gdb_regs"
#define COMPILE_I_SIMPLE_REGISTER_ARG_NAME "__regs"
#define COMPILE_I_SIMPLE_REGISTER_DUMMY "_dummy"
/* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
to a form suitable for the compiler source. The register names
should not clash with inferior defined macros. Returned pointer is
never NULL. Returned pointer needs to be deallocated by xfree. */
extern char *compile_register_name_mangled (struct gdbarch *gdbarch,
int regnum);
/* Convert compiler source register name to register number of
GDBARCH. Returned value is always >= 0, function throws an error
for non-matching REG_NAME. */
extern int compile_register_name_demangle (struct gdbarch *gdbarch,
const char *reg_name);
/* Convert a gdb type, TYPE, to a GCC type. CONTEXT is used to do the
actual conversion. The new GCC type is returned. */
struct type;
extern gcc_type convert_type (struct compile_c_instance *context,
struct type *type);
/* A callback suitable for use as the GCC C symbol oracle. */
extern gcc_c_oracle_function gcc_convert_symbol;
/* A callback suitable for use as the GCC C address oracle. */
extern gcc_c_symbol_address_function gcc_symbol_address;
/* Instantiate a GDB object holding state for the GCC context FE. The
new object is returned. */
extern struct compile_instance *new_compile_instance (struct gcc_c_context *fe);
/* Emit code to compute the address for all the local variables in
scope at PC in BLOCK. Returns a malloc'd vector, indexed by gdb
register number, where each element indicates if the corresponding
register is needed to compute a local variable. */
extern unsigned char *generate_c_for_variable_locations
(struct compile_c_instance *compiler,
struct ui_file *stream,
struct gdbarch *gdbarch,
const struct block *block,
CORE_ADDR pc);
/* Get the GCC mode attribute value for a given type size. */
extern const char *c_get_mode_for_size (int size);
/* Given a dynamic property, return an xmallocd name that is used to
represent its size. The result must be freed by the caller. The
contents of the resulting string will be the same each time for
each call with the same argument. */
struct dynamic_prop;
extern char *c_get_range_decl_name (const struct dynamic_prop *prop);
#endif /* GDB_COMPILE_INTERNAL_H */

1148
gdb/compile/compile-loc2c.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,588 @@
/* Load module for 'compile' command.
Copyright (C) 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/>. */
#include "defs.h"
#include "compile-object-load.h"
#include "compile-internal.h"
#include "command.h"
#include "objfiles.h"
#include "gdbcore.h"
#include "readline/tilde.h"
#include "bfdlink.h"
#include "gdbcmd.h"
#include "regcache.h"
#include "inferior.h"
#include "compile.h"
#include "arch-utils.h"
/* Helper data for setup_sections. */
struct setup_sections_data
{
/* Size of all recent sections with matching LAST_PROT. */
CORE_ADDR last_size;
/* First section matching LAST_PROT. */
asection *last_section_first;
/* Memory protection like the prot parameter of gdbarch_infcall_mmap. */
unsigned last_prot;
/* Maximum of alignments of all sections matching LAST_PROT.
This value is always at least 1. This value is always a power of 2. */
CORE_ADDR last_max_alignment;
};
/* Place all ABFD sections next to each other obeying all constraints. */
static void
setup_sections (bfd *abfd, asection *sect, void *data_voidp)
{
struct setup_sections_data *data = data_voidp;
CORE_ADDR alignment;
unsigned prot;
if (sect != NULL)
{
/* It is required by later bfd_get_relocated_section_contents. */
if (sect->output_section == NULL)
sect->output_section = sect;
if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
return;
// Make the memory always readable.
prot = GDB_MMAP_PROT_READ;
if ((bfd_get_section_flags (abfd, sect) & SEC_READONLY) == 0)
prot |= GDB_MMAP_PROT_WRITE;
if ((bfd_get_section_flags (abfd, sect) & SEC_CODE) != 0)
prot |= GDB_MMAP_PROT_EXEC;
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"module \"%s\" section \"%s\" size %s prot %u\n",
bfd_get_filename (abfd),
bfd_get_section_name (abfd, sect),
paddress (target_gdbarch (),
bfd_get_section_size (sect)),
prot);
}
else
prot = -1;
if (sect == NULL
|| (data->last_prot != prot && bfd_get_section_size (sect) != 0))
{
CORE_ADDR addr;
asection *sect_iter;
if (data->last_size != 0)
{
addr = gdbarch_infcall_mmap (target_gdbarch (), data->last_size,
data->last_prot);
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"allocated %s bytes at %s prot %u\n",
paddress (target_gdbarch (), data->last_size),
paddress (target_gdbarch (), addr),
data->last_prot);
}
else
addr = 0;
if ((addr & (data->last_max_alignment - 1)) != 0)
error (_("Inferior compiled module address %s "
"is not aligned to BFD required %s."),
paddress (target_gdbarch (), addr),
paddress (target_gdbarch (), data->last_max_alignment));
for (sect_iter = data->last_section_first; sect_iter != sect;
sect_iter = sect_iter->next)
if ((bfd_get_section_flags (abfd, sect_iter) & SEC_ALLOC) != 0)
bfd_set_section_vma (abfd, sect_iter,
addr + bfd_get_section_vma (abfd, sect_iter));
data->last_size = 0;
data->last_section_first = sect;
data->last_prot = prot;
data->last_max_alignment = 1;
}
if (sect == NULL)
return;
alignment = ((CORE_ADDR) 1) << bfd_get_section_alignment (abfd, sect);
data->last_max_alignment = max (data->last_max_alignment, alignment);
data->last_size = (data->last_size + alignment - 1) & -alignment;
bfd_set_section_vma (abfd, sect, data->last_size);
data->last_size += bfd_get_section_size (sect);
data->last_size = (data->last_size + alignment - 1) & -alignment;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_multiple_definition (struct bfd_link_info *link_info,
struct bfd_link_hash_entry *h, bfd *nbfd,
asection *nsec, bfd_vma nval)
{
bfd *abfd = link_info->input_bfds;
if (link_info->allow_multiple_definition)
return TRUE;
warning (_("Compiled module \"%s\": multiple symbol definitions: %s\n"),
bfd_get_filename (abfd), h->root.string);
return FALSE;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_warning (struct bfd_link_info *link_info, const char *xwarning,
const char *symbol, bfd *abfd, asection *section,
bfd_vma address)
{
warning (_("Compiled module \"%s\" section \"%s\": warning: %s\n"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
xwarning);
/* Maybe permit running as a module? */
return FALSE;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_undefined_symbol (struct bfd_link_info *link_info,
const char *name, bfd *abfd, asection *section,
bfd_vma address, bfd_boolean is_fatal)
{
warning (_("Cannot resolve relocation to \"%s\" "
"from compiled module \"%s\" section \"%s\"."),
name, bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
return FALSE;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_reloc_overflow (struct bfd_link_info *link_info,
struct bfd_link_hash_entry *entry,
const char *name, const char *reloc_name,
bfd_vma addend, bfd *abfd, asection *section,
bfd_vma address)
{
/* TRUE is required for intra-module relocations. */
return TRUE;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_reloc_dangerous (struct bfd_link_info *link_info,
const char *message, bfd *abfd,
asection *section, bfd_vma address)
{
warning (_("Compiled module \"%s\" section \"%s\": dangerous "
"relocation: %s\n"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
message);
return FALSE;
}
/* Helper for link_callbacks callbacks vector. */
static bfd_boolean
link_callbacks_unattached_reloc (struct bfd_link_info *link_info,
const char *name, bfd *abfd, asection *section,
bfd_vma address)
{
warning (_("Compiled module \"%s\" section \"%s\": unattached "
"relocation: %s\n"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
name);
return FALSE;
}
/* Helper for link_callbacks callbacks vector. */
static void
link_callbacks_einfo (const char *fmt, ...)
{
struct cleanup *cleanups;
va_list ap;
char *str;
va_start (ap, fmt);
str = xstrvprintf (fmt, ap);
va_end (ap);
cleanups = make_cleanup (xfree, str);
warning (_("Compile module: warning: %s\n"), str);
do_cleanups (cleanups);
}
/* Helper for bfd_get_relocated_section_contents.
Only these symbols are set by bfd_simple_get_relocated_section_contents
but bfd/ seems to use even the NULL ones without checking them first. */
static const struct bfd_link_callbacks link_callbacks =
{
NULL, /* add_archive_element */
link_callbacks_multiple_definition, /* multiple_definition */
NULL, /* multiple_common */
NULL, /* add_to_set */
NULL, /* constructor */
link_callbacks_warning, /* warning */
link_callbacks_undefined_symbol, /* undefined_symbol */
link_callbacks_reloc_overflow, /* reloc_overflow */
link_callbacks_reloc_dangerous, /* reloc_dangerous */
link_callbacks_unattached_reloc, /* unattached_reloc */
NULL, /* notice */
link_callbacks_einfo, /* einfo */
NULL, /* info */
NULL, /* minfo */
NULL, /* override_segment_assignment */
};
struct link_hash_table_cleanup_data
{
bfd *abfd;
bfd *link_next;
};
/* Cleanup callback for struct bfd_link_info. */
static void
link_hash_table_free (void *d)
{
struct link_hash_table_cleanup_data *data = d;
if (data->abfd->is_linker_output)
(*data->abfd->link.hash->hash_table_free) (data->abfd);
data->abfd->link.next = data->link_next;
}
/* Relocate and store into inferior memory each section SECT of ABFD. */
static void
copy_sections (bfd *abfd, asection *sect, void *data)
{
asymbol **symbol_table = data;
bfd_byte *sect_data, *sect_data_got;
struct cleanup *cleanups;
struct bfd_link_info link_info;
struct bfd_link_order link_order;
CORE_ADDR inferior_addr;
struct link_hash_table_cleanup_data cleanup_data;
if ((bfd_get_section_flags (abfd, sect) & (SEC_ALLOC | SEC_LOAD))
!= (SEC_ALLOC | SEC_LOAD))
return;
if (bfd_get_section_size (sect) == 0)
return;
/* Mostly a copy of bfd_simple_get_relocated_section_contents which GDB
cannot use as it does not report relocations to undefined symbols. */
memset (&link_info, 0, sizeof (link_info));
link_info.output_bfd = abfd;
link_info.input_bfds = abfd;
link_info.input_bfds_tail = &abfd->link.next;
cleanup_data.abfd = abfd;
cleanup_data.link_next = abfd->link.next;
abfd->link.next = NULL;
link_info.hash = bfd_link_hash_table_create (abfd);
cleanups = make_cleanup (link_hash_table_free, &cleanup_data);
link_info.callbacks = &link_callbacks;
memset (&link_order, 0, sizeof (link_order));
link_order.next = NULL;
link_order.type = bfd_indirect_link_order;
link_order.offset = 0;
link_order.size = bfd_get_section_size (sect);
link_order.u.indirect.section = sect;
sect_data = xmalloc (bfd_get_section_size (sect));
make_cleanup (xfree, sect_data);
sect_data_got = bfd_get_relocated_section_contents (abfd, &link_info,
&link_order, sect_data,
FALSE, symbol_table);
if (sect_data_got == NULL)
error (_("Cannot map compiled module \"%s\" section \"%s\": %s"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, sect),
bfd_errmsg (bfd_get_error ()));
gdb_assert (sect_data_got == sect_data);
inferior_addr = bfd_get_section_vma (abfd, sect);
if (0 != target_write_memory (inferior_addr, sect_data,
bfd_get_section_size (sect)))
error (_("Cannot write compiled module \"%s\" section \"%s\" "
"to inferior memory range %s-%s."),
bfd_get_filename (abfd), bfd_get_section_name (abfd, sect),
paddress (target_gdbarch (), inferior_addr),
paddress (target_gdbarch (),
inferior_addr + bfd_get_section_size (sect)));
do_cleanups (cleanups);
}
/* Fetch the type of first parameter of GCC_FE_WRAPPER_FUNCTION.
Return NULL if GCC_FE_WRAPPER_FUNCTION has no parameters.
Throw an error otherwise. */
static struct type *
get_regs_type (struct objfile *objfile)
{
struct symbol *func_sym;
struct type *func_type, *regsp_type, *regs_type;
func_sym = lookup_global_symbol_from_objfile (objfile,
GCC_FE_WRAPPER_FUNCTION,
VAR_DOMAIN);
if (func_sym == NULL)
error (_("Cannot find function \"%s\" in compiled module \"%s\"."),
GCC_FE_WRAPPER_FUNCTION, objfile_name (objfile));
func_type = SYMBOL_TYPE (func_sym);
if (TYPE_CODE (func_type) != TYPE_CODE_FUNC)
error (_("Invalid type code %d of function \"%s\" in compiled "
"module \"%s\"."),
TYPE_CODE (func_type), GCC_FE_WRAPPER_FUNCTION,
objfile_name (objfile));
/* No register parameter present. */
if (TYPE_NFIELDS (func_type) == 0)
return NULL;
if (TYPE_NFIELDS (func_type) != 1)
error (_("Invalid %d parameters of function \"%s\" in compiled "
"module \"%s\"."),
TYPE_NFIELDS (func_type), GCC_FE_WRAPPER_FUNCTION,
objfile_name (objfile));
regsp_type = check_typedef (TYPE_FIELD_TYPE (func_type, 0));
if (TYPE_CODE (regsp_type) != TYPE_CODE_PTR)
error (_("Invalid type code %d of first parameter of function \"%s\" "
"in compiled module \"%s\"."),
TYPE_CODE (regsp_type), GCC_FE_WRAPPER_FUNCTION,
objfile_name (objfile));
regs_type = check_typedef (TYPE_TARGET_TYPE (regsp_type));
if (TYPE_CODE (regs_type) != TYPE_CODE_STRUCT)
error (_("Invalid type code %d of dereferenced first parameter "
"of function \"%s\" in compiled module \"%s\"."),
TYPE_CODE (regs_type), GCC_FE_WRAPPER_FUNCTION,
objfile_name (objfile));
return regs_type;
}
/* Store all inferior registers required by REGS_TYPE to inferior memory
starting at inferior address REGS_BASE. */
static void
store_regs (struct type *regs_type, CORE_ADDR regs_base)
{
struct gdbarch *gdbarch = target_gdbarch ();
struct regcache *regcache = get_thread_regcache (inferior_ptid);
int fieldno;
for (fieldno = 0; fieldno < TYPE_NFIELDS (regs_type); fieldno++)
{
const char *reg_name = TYPE_FIELD_NAME (regs_type, fieldno);
ULONGEST reg_bitpos = TYPE_FIELD_BITPOS (regs_type, fieldno);
ULONGEST reg_bitsize = TYPE_FIELD_BITSIZE (regs_type, fieldno);
ULONGEST reg_offset;
struct type *reg_type = check_typedef (TYPE_FIELD_TYPE (regs_type,
fieldno));
ULONGEST reg_size = TYPE_LENGTH (reg_type);
int regnum;
struct value *regval;
CORE_ADDR inferior_addr;
if (strcmp (reg_name, COMPILE_I_SIMPLE_REGISTER_DUMMY) == 0)
continue;
if ((reg_bitpos % 8) != 0 || reg_bitsize != 0)
error (_("Invalid register \"%s\" position %s bits or size %s bits"),
reg_name, pulongest (reg_bitpos), pulongest (reg_bitsize));
reg_offset = reg_bitpos / 8;
if (TYPE_CODE (reg_type) != TYPE_CODE_INT
&& TYPE_CODE (reg_type) != TYPE_CODE_PTR)
error (_("Invalid register \"%s\" type code %d"), reg_name,
TYPE_CODE (reg_type));
regnum = compile_register_name_demangle (gdbarch, reg_name);
regval = value_from_register (reg_type, regnum, get_current_frame ());
if (value_optimized_out (regval))
error (_("Register \"%s\" is optimized out."), reg_name);
if (!value_entirely_available (regval))
error (_("Register \"%s\" is not available."), reg_name);
inferior_addr = regs_base + reg_offset;
if (0 != target_write_memory (inferior_addr, value_contents (regval),
reg_size))
error (_("Cannot write register \"%s\" to inferior memory at %s."),
reg_name, paddress (gdbarch, inferior_addr));
}
}
/* Load OBJECT_FILE into inferior memory. Throw an error otherwise.
Caller must fully dispose the return value by calling compile_object_run.
SOURCE_FILE's copy is stored into the returned object.
Caller should free both OBJECT_FILE and SOURCE_FILE immediatelly after this
function returns. */
struct compile_module *
compile_object_load (const char *object_file, const char *source_file)
{
struct cleanup *cleanups, *cleanups_free_objfile;
bfd *abfd;
struct setup_sections_data setup_sections_data;
CORE_ADDR addr, func_addr, regs_addr;
struct bound_minimal_symbol bmsym;
long storage_needed;
asymbol **symbol_table, **symp;
long number_of_symbols, missing_symbols;
struct type *dptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
unsigned dptr_type_len = TYPE_LENGTH (dptr_type);
struct compile_module *retval;
struct type *regs_type;
char *filename, **matching;
struct objfile *objfile;
filename = tilde_expand (object_file);
cleanups = make_cleanup (xfree, filename);
abfd = gdb_bfd_open (filename, gnutarget, -1);
if (abfd == NULL)
error (_("\"%s\": could not open as compiled module: %s"),
filename, bfd_errmsg (bfd_get_error ()));
make_cleanup_bfd_unref (abfd);
if (!bfd_check_format_matches (abfd, bfd_object, &matching))
error (_("\"%s\": not in loadable format: %s"),
filename, gdb_bfd_errmsg (bfd_get_error (), matching));
if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) != 0)
error (_("\"%s\": not in object format."), filename);
setup_sections_data.last_size = 0;
setup_sections_data.last_section_first = abfd->sections;
setup_sections_data.last_prot = -1;
setup_sections_data.last_max_alignment = 1;
bfd_map_over_sections (abfd, setup_sections, &setup_sections_data);
setup_sections (abfd, NULL, &setup_sections_data);
storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed < 0)
error (_("Cannot read symbols of compiled module \"%s\": %s"),
filename, bfd_errmsg (bfd_get_error ()));
/* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in
"Reading symbols from ..." message for automatically generated file. */
objfile = symbol_file_add_from_bfd (abfd, filename, 0, NULL, 0, NULL);
cleanups_free_objfile = make_cleanup_free_objfile (objfile);
bmsym = lookup_minimal_symbol_text (GCC_FE_WRAPPER_FUNCTION, objfile);
if (bmsym.minsym == NULL || MSYMBOL_TYPE (bmsym.minsym) == mst_file_text)
error (_("Could not find symbol \"%s\" of compiled module \"%s\"."),
GCC_FE_WRAPPER_FUNCTION, filename);
func_addr = BMSYMBOL_VALUE_ADDRESS (bmsym);
/* The memory may be later needed
by bfd_generic_get_relocated_section_contents
called from default_symfile_relocate. */
symbol_table = obstack_alloc (&objfile->objfile_obstack, storage_needed);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
if (number_of_symbols < 0)
error (_("Cannot parse symbols of compiled module \"%s\": %s"),
filename, bfd_errmsg (bfd_get_error ()));
missing_symbols = 0;
for (symp = symbol_table; symp < symbol_table + number_of_symbols; symp++)
{
asymbol *sym = *symp;
if (sym->flags != 0)
continue;
if (compile_debug)
fprintf_unfiltered (gdb_stdout,
"lookup undefined ELF symbol \"%s\"\n",
sym->name);
sym->flags = BSF_GLOBAL;
sym->section = bfd_abs_section_ptr;
if (strcmp (sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
{
sym->value = 0;
continue;
}
bmsym = lookup_minimal_symbol (sym->name, NULL, NULL);
switch (bmsym.minsym == NULL
? mst_unknown : MSYMBOL_TYPE (bmsym.minsym))
{
case mst_text:
sym->value = BMSYMBOL_VALUE_ADDRESS (bmsym);
break;
default:
warning (_("Could not find symbol \"%s\" "
"for compiled module \"%s\"."),
sym->name, filename);
missing_symbols++;
}
}
if (missing_symbols)
error (_("%ld symbols were missing, cannot continue."), missing_symbols);
bfd_map_over_sections (abfd, copy_sections, symbol_table);
regs_type = get_regs_type (objfile);
if (regs_type == NULL)
regs_addr = 0;
else
{
/* Use read-only non-executable memory protection. */
regs_addr = gdbarch_infcall_mmap (target_gdbarch (),
TYPE_LENGTH (regs_type),
GDB_MMAP_PROT_READ);
gdb_assert (regs_addr != 0);
store_regs (regs_type, regs_addr);
}
discard_cleanups (cleanups_free_objfile);
do_cleanups (cleanups);
retval = xmalloc (sizeof (*retval));
retval->objfile = objfile;
retval->source_file = xstrdup (source_file);
retval->func_addr = func_addr;
retval->regs_addr = regs_addr;
return retval;
}

View File

@ -0,0 +1,39 @@
/* Header file to load module for 'compile' command.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_COMPILE_OBJECT_LOAD_H
#define GDB_COMPILE_OBJECT_LOAD_H
struct compile_module
{
/* objfile for the compiled module. */
struct objfile *objfile;
/* .c file OBJFILE was built from. It needs to be xfree-d. */
char *source_file;
/* Inferior function address. */
CORE_ADDR func_addr;
/* Inferior registers address or NULL if the inferior function does not
require any. */
CORE_ADDR regs_addr;
};
extern struct compile_module *compile_object_load (const char *object_file,
const char *source_file);
#endif /* GDB_COMPILE_OBJECT_LOAD_H */

View File

@ -0,0 +1,138 @@
/* Call module for 'compile' command.
Copyright (C) 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/>. */
#include "defs.h"
#include "compile-object-run.h"
#include "value.h"
#include "infcall.h"
#include "objfiles.h"
#include "compile-internal.h"
#include "dummy-frame.h"
/* Helper for do_module_cleanup. */
struct do_module_cleanup
{
/* Boolean to set true upon a call of do_module_cleanup.
The pointer may be NULL. */
int *executedp;
/* .c file OBJFILE was built from. It needs to be xfree-d. */
char *source_file;
/* objfile_name of our objfile. */
char objfile_name_string[1];
};
/* Cleanup everything after the inferior function dummy frame gets
discarded. */
static dummy_frame_dtor_ftype do_module_cleanup;
static void
do_module_cleanup (void *arg)
{
struct do_module_cleanup *data = arg;
struct objfile *objfile;
if (data->executedp != NULL)
*data->executedp = 1;
ALL_OBJFILES (objfile)
if ((objfile->flags & OBJF_USERLOADED) == 0
&& (strcmp (objfile_name (objfile), data->objfile_name_string) == 0))
{
free_objfile (objfile);
/* It may be a bit too pervasive in this dummy_frame dtor callback. */
clear_symtab_users (0);
break;
}
/* Delete the .c file. */
unlink (data->source_file);
xfree (data->source_file);
/* Delete the .o file. */
unlink (data->objfile_name_string);
xfree (data);
}
/* Perform inferior call of MODULE. This function may throw an error.
This function may leave files referenced by MODULE on disk until
the inferior call dummy frame is discarded. This function may throw errors.
Thrown errors and left MODULE files are unrelated events. Caller must no
longer touch MODULE's memory after this function has been called. */
void
compile_object_run (struct compile_module *module)
{
struct value *func_val;
struct frame_id dummy_id;
struct cleanup *cleanups;
struct do_module_cleanup *data;
volatile struct gdb_exception ex;
const char *objfile_name_s = objfile_name (module->objfile);
int dtor_found, executed = 0;
CORE_ADDR func_addr = module->func_addr;
CORE_ADDR regs_addr = module->regs_addr;
data = xmalloc (sizeof (*data) + strlen (objfile_name_s));
data->executedp = &executed;
data->source_file = xstrdup (module->source_file);
strcpy (data->objfile_name_string, objfile_name_s);
xfree (module->source_file);
xfree (module);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
func_val = value_from_pointer
(builtin_type (target_gdbarch ())->builtin_func_ptr,
func_addr);
if (regs_addr == 0)
call_function_by_hand_dummy (func_val, 0, NULL,
do_module_cleanup, data);
else
{
struct value *arg_val;
arg_val = value_from_pointer
(builtin_type (target_gdbarch ())->builtin_func_ptr,
regs_addr);
call_function_by_hand_dummy (func_val, 1, &arg_val,
do_module_cleanup, data);
}
}
dtor_found = find_dummy_frame_dtor (do_module_cleanup, data);
if (!executed)
data->executedp = NULL;
if (ex.reason >= 0)
gdb_assert (!dtor_found && executed);
else
{
/* In the case od DTOR_FOUND or in the case of EXECUTED nothing
needs to be done. */
gdb_assert (!(dtor_found && executed));
if (!dtor_found && !executed)
do_module_cleanup (data);
throw_exception (ex);
}
}

View File

@ -0,0 +1,24 @@
/* Header file to call module for 'compile' command.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_COMPILE_OBJECT_RUN_H
#define GDB_COMPILE_OBJECT_RUN_H
#include "compile-object-load.h"
extern void compile_object_run (struct compile_module *module);
#endif /* GDB_COMPILE_OBJECT_RUN_H */

651
gdb/compile/compile.c Normal file
View File

@ -0,0 +1,651 @@
/* General Compile and inject code
Copyright (C) 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/>. */
#include "defs.h"
#include "interps.h"
#include "ui-out.h"
#include "command.h"
#include "cli/cli-script.h"
#include "cli/cli-utils.h"
#include "completer.h"
#include "gdbcmd.h"
#include "compile.h"
#include "compile-internal.h"
#include "compile-object-load.h"
#include "compile-object-run.h"
#include "language.h"
#include "frame.h"
#include "source.h"
#include "block.h"
#include "arch-utils.h"
#include "filestuff.h"
#include "target.h"
#include "osabi.h"
/* Initial filename for temporary files. */
#define TMP_PREFIX "/tmp/gdbobj-"
/* Hold "compile" commands. */
static struct cmd_list_element *compile_command_list;
/* Debug flag for "compile" commands. */
int compile_debug;
/* Implement "show debug compile". */
static void
show_compile_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Compile debugging is %s.\n"), value);
}
/* Check *ARG for a "-raw" or "-r" argument. Return 0 if not seen.
Return 1 if seen and update *ARG. */
static int
check_raw_argument (char **arg)
{
*arg = skip_spaces (*arg);
if (arg != NULL
&& (check_for_argument (arg, "-raw", sizeof ("-raw") - 1)
|| check_for_argument (arg, "-r", sizeof ("-r") - 1)))
return 1;
return 0;
}
/* Handle the input from the 'compile file' command. The "compile
file" command is used to evaluate an expression contained in a file
that may contain calls to the GCC compiler. */
static void
compile_file_command (char *arg, int from_tty)
{
enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
char *buffer;
struct cleanup *cleanup;
cleanup = make_cleanup_restore_integer (&interpreter_async);
interpreter_async = 0;
/* Check the user did not just <enter> after command. */
if (arg == NULL)
error (_("You must provide a filename for this command."));
/* Check if a raw (-r|-raw) argument is provided. */
if (arg != NULL && check_raw_argument (&arg))
{
scope = COMPILE_I_RAW_SCOPE;
arg = skip_spaces (arg);
}
/* After processing arguments, check there is a filename at the end
of the command. */
if (arg[0] == '\0')
error (_("You must provide a filename with the raw option set."));
if (arg[0] == '-')
error (_("Unknown argument specified."));
arg = skip_spaces (arg);
arg = gdb_abspath (arg);
make_cleanup (xfree, arg);
buffer = xstrprintf ("#include \"%s\"\n", arg);
make_cleanup (xfree, buffer);
eval_compile_command (NULL, buffer, scope);
do_cleanups (cleanup);
}
/* Handle the input from the 'compile code' command. The
"compile code" command is used to evaluate an expression that may
contain calls to the GCC compiler. The language expected in this
compile command is the language currently set in GDB. */
static void
compile_code_command (char *arg, int from_tty)
{
struct cleanup *cleanup;
enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
cleanup = make_cleanup_restore_integer (&interpreter_async);
interpreter_async = 0;
if (arg != NULL && check_raw_argument (&arg))
{
scope = COMPILE_I_RAW_SCOPE;
arg = skip_spaces (arg);
}
arg = skip_spaces (arg);
if (arg != NULL && !check_for_argument (&arg, "--", sizeof ("--") - 1))
{
if (arg[0] == '-')
error (_("Unknown argument specified."));
}
if (arg && *arg)
eval_compile_command (NULL, arg, scope);
else
{
struct command_line *l = get_command_line (compile_control, "");
make_cleanup_free_command_lines (&l);
l->control_u.compile.scope = scope;
execute_control_command_untraced (l);
}
do_cleanups (cleanup);
}
/* A cleanup function to remove a directory and all its contents. */
static void
do_rmdir (void *arg)
{
const char *dir = arg;
char *zap;
gdb_assert (strncmp (dir, TMP_PREFIX, strlen (TMP_PREFIX)) == 0);
zap = concat ("rm -rf ", dir, (char *) NULL);
system (zap);
}
/* Return the name of the temporary directory to use for .o files, and
arrange for the directory to be removed at shutdown. */
static const char *
get_compile_file_tempdir (void)
{
static char *tempdir_name;
#define TEMPLATE TMP_PREFIX "XXXXXX"
char tname[sizeof (TEMPLATE)];
if (tempdir_name != NULL)
return tempdir_name;
strcpy (tname, TEMPLATE);
#undef TEMPLATE
tempdir_name = mkdtemp (tname);
if (tempdir_name == NULL)
perror_with_name (_("Could not make temporary directory"));
tempdir_name = xstrdup (tempdir_name);
make_final_cleanup (do_rmdir, tempdir_name);
return tempdir_name;
}
/* Compute the names of source and object files to use. The names are
allocated by malloc and should be freed by the caller. */
static void
get_new_file_names (char **source_file, char **object_file)
{
static int seq;
const char *dir = get_compile_file_tempdir ();
++seq;
*source_file = xstrprintf ("%s%sout%d.c", dir, SLASH_STRING, seq);
*object_file = xstrprintf ("%s%sout%d.o", dir, SLASH_STRING, seq);
}
/* Get the block and PC at which to evaluate an expression. */
static const struct block *
get_expr_block_and_pc (CORE_ADDR *pc)
{
const struct block *block = get_selected_block (pc);
if (block == NULL)
{
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
if (cursal.symtab)
block = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (cursal.symtab),
STATIC_BLOCK);
if (block != NULL)
*pc = BLOCK_START (block);
}
else
*pc = BLOCK_START (block);
return block;
}
/* Call gdb_buildargv, set its result for S into *ARGVP but calculate also the
number of parsed arguments into *ARGCP. If gdb_buildargv has returned NULL
then *ARGCP is set to zero. */
static void
build_argc_argv (const char *s, int *argcp, char ***argvp)
{
*argvp = gdb_buildargv (s);
*argcp = countargv (*argvp);
}
/* String for 'set compile-args' and 'show compile-args'. */
static char *compile_args;
/* Parsed form of COMPILE_ARGS. COMPILE_ARGS_ARGV is NULL terminated. */
static int compile_args_argc;
static char **compile_args_argv;
/* Implement 'set compile-args'. */
static void
set_compile_args (char *args, int from_tty, struct cmd_list_element *c)
{
freeargv (compile_args_argv);
build_argc_argv (compile_args, &compile_args_argc, &compile_args_argv);
}
/* Implement 'show compile-args'. */
static void
show_compile_args (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Compile command command-line arguments "
"are \"%s\".\n"),
value);
}
/* Append ARGC and ARGV (as parsed by build_argc_argv) to *ARGCP and *ARGVP.
ARGCP+ARGVP can be zero+NULL and also ARGC+ARGV can be zero+NULL. */
static void
append_args (int *argcp, char ***argvp, int argc, char **argv)
{
int argi;
*argvp = xrealloc (*argvp, (*argcp + argc + 1) * sizeof (**argvp));
for (argi = 0; argi < argc; argi++)
(*argvp)[(*argcp)++] = xstrdup (argv[argi]);
(*argvp)[(*argcp)] = NULL;
}
/* Return DW_AT_producer parsed for get_selected_frame () (if any).
Return NULL otherwise.
GCC already filters its command-line arguments only for the suitable ones to
put into DW_AT_producer - see GCC function gen_producer_string. */
static const char *
get_selected_pc_producer_options (void)
{
CORE_ADDR pc = get_frame_pc (get_selected_frame (NULL));
struct compunit_symtab *symtab = find_pc_compunit_symtab (pc);
const char *cs;
if (symtab == NULL || symtab->producer == NULL
|| strncmp (symtab->producer, "GNU ", strlen ("GNU ")) != 0)
return NULL;
cs = symtab->producer;
while (*cs != 0 && *cs != '-')
cs = skip_spaces_const (skip_to_space_const (cs));
if (*cs != '-')
return NULL;
return cs;
}
/* Produce final vector of GCC compilation options. First element is target
size ("-m64", "-m32" etc.), optionally followed by DW_AT_producer options
and then compile-args string GDB variable. */
static void
get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch,
int *argcp, char ***argvp)
{
const char *cs_producer_options;
int argc_compiler;
char **argv_compiler;
build_argc_argv (gdbarch_gcc_target_options (gdbarch),
argcp, argvp);
cs_producer_options = get_selected_pc_producer_options ();
if (cs_producer_options != NULL)
{
int argc_producer;
char **argv_producer;
build_argc_argv (cs_producer_options, &argc_producer, &argv_producer);
append_args (argcp, argvp, argc_producer, argv_producer);
freeargv (argv_producer);
}
build_argc_argv (compiler->gcc_target_options,
&argc_compiler, &argv_compiler);
append_args (argcp, argvp, argc_compiler, argv_compiler);
freeargv (argv_compiler);
append_args (argcp, argvp, compile_args_argc, compile_args_argv);
}
/* A cleanup function to destroy a gdb_gcc_instance. */
static void
cleanup_compile_instance (void *arg)
{
struct compile_instance *inst = arg;
inst->destroy (inst);
}
/* A cleanup function to unlink a file. */
static void
cleanup_unlink_file (void *arg)
{
const char *filename = arg;
unlink (filename);
}
/* A helper function suitable for use as the "print_callback" in the
compiler object. */
static void
print_callback (void *ignore, const char *message)
{
fputs_filtered (message, gdb_stderr);
}
/* Process the compilation request. On success it returns the object
file name and *SOURCE_FILEP is set to source file name. On an
error condition, error () is called. The caller is responsible for
freeing both strings. */
static char *
compile_to_object (struct command_line *cmd, char *cmd_string,
enum compile_i_scope_types scope,
char **source_filep)
{
char *code;
char *source_file, *object_file;
struct compile_instance *compiler;
struct cleanup *cleanup, *inner_cleanup;
const struct block *expr_block;
CORE_ADDR trash_pc, expr_pc;
int argc;
char **argv;
int ok;
FILE *src;
struct gdbarch *gdbarch = get_current_arch ();
const char *os_rx;
const char *arch_rx;
char *triplet_rx;
char *error_message;
if (!target_has_execution)
error (_("The program must be running for the compile command to "\
"work."));
expr_block = get_expr_block_and_pc (&trash_pc);
expr_pc = get_frame_address_in_block (get_selected_frame (NULL));
/* Set up instance and context for the compiler. */
if (current_language->la_get_compile_instance == NULL)
error (_("No compiler support for this language."));
compiler = current_language->la_get_compile_instance ();
cleanup = make_cleanup (cleanup_compile_instance, compiler);
compiler->fe->ops->set_print_callback (compiler->fe, print_callback, NULL);
compiler->scope = scope;
compiler->block = expr_block;
/* From the provided expression, build a scope to pass to the
compiler. */
if (cmd != NULL)
{
struct ui_file *stream = mem_fileopen ();
struct command_line *iter;
make_cleanup_ui_file_delete (stream);
for (iter = cmd->body_list[0]; iter; iter = iter->next)
{
fputs_unfiltered (iter->line, stream);
fputs_unfiltered ("\n", stream);
}
code = ui_file_xstrdup (stream, NULL);
make_cleanup (xfree, code);
}
else if (cmd_string != NULL)
code = cmd_string;
else
error (_("Neither a simple expression, or a multi-line specified."));
code = current_language->la_compute_program (compiler, code, gdbarch,
expr_block, expr_pc);
make_cleanup (xfree, code);
if (compile_debug)
fprintf_unfiltered (gdb_stdout, "debug output:\n\n%s", code);
os_rx = osabi_triplet_regexp (gdbarch_osabi (gdbarch));
arch_rx = gdbarch_gnu_triplet_regexp (gdbarch);
triplet_rx = concat (arch_rx, "-[^-]*-", os_rx, (char *) NULL);
make_cleanup (xfree, triplet_rx);
/* Set compiler command-line arguments. */
get_args (compiler, gdbarch, &argc, &argv);
make_cleanup_freeargv (argv);
error_message = compiler->fe->ops->set_arguments (compiler->fe, triplet_rx,
argc, argv);
if (error_message != NULL)
{
make_cleanup (xfree, error_message);
error ("%s", error_message);
}
if (compile_debug)
{
int argi;
fprintf_unfiltered (gdb_stdout, "Passing %d compiler options:\n", argc);
for (argi = 0; argi < argc; argi++)
fprintf_unfiltered (gdb_stdout, "Compiler option %d: <%s>\n",
argi, argv[argi]);
}
get_new_file_names (&source_file, &object_file);
inner_cleanup = make_cleanup (xfree, source_file);
make_cleanup (xfree, object_file);
src = gdb_fopen_cloexec (source_file, "w");
if (src == NULL)
perror_with_name (_("Could not open source file for writing"));
make_cleanup (cleanup_unlink_file, source_file);
if (fputs (code, src) == EOF)
perror_with_name (_("Could not write to source file"));
fclose (src);
if (compile_debug)
fprintf_unfiltered (gdb_stdout, "source file produced: %s\n\n",
source_file);
/* Call the compiler and start the compilation process. */
compiler->fe->ops->set_source_file (compiler->fe, source_file);
if (!compiler->fe->ops->compile (compiler->fe, object_file,
compile_debug))
error (_("Compilation failed."));
if (compile_debug)
fprintf_unfiltered (gdb_stdout, "object file produced: %s\n\n",
object_file);
discard_cleanups (inner_cleanup);
do_cleanups (cleanup);
*source_filep = source_file;
return object_file;
}
/* The "compile" prefix command. */
static void
compile_command (char *args, int from_tty)
{
/* If a sub-command is not specified to the compile prefix command,
assume it is a direct code compilation. */
compile_code_command (args, from_tty);
}
/* See compile.h. */
void
eval_compile_command (struct command_line *cmd, char *cmd_string,
enum compile_i_scope_types scope)
{
char *object_file, *source_file;
object_file = compile_to_object (cmd, cmd_string, scope, &source_file);
if (object_file != NULL)
{
struct cleanup *cleanup_xfree, *cleanup_unlink;
struct compile_module *compile_module;
cleanup_xfree = make_cleanup (xfree, object_file);
make_cleanup (xfree, source_file);
cleanup_unlink = make_cleanup (cleanup_unlink_file, object_file);
make_cleanup (cleanup_unlink_file, source_file);
compile_module = compile_object_load (object_file, source_file);
discard_cleanups (cleanup_unlink);
do_cleanups (cleanup_xfree);
compile_object_run (compile_module);
}
}
/* See compile/compile-internal.h. */
char *
compile_register_name_mangled (struct gdbarch *gdbarch, int regnum)
{
const char *regname = gdbarch_register_name (gdbarch, regnum);
return xstrprintf ("__%s", regname);
}
/* See compile/compile-internal.h. */
int
compile_register_name_demangle (struct gdbarch *gdbarch,
const char *regname)
{
int regnum;
if (regname[0] != '_' || regname[1] != '_')
error (_("Invalid register name \"%s\"."), regname);
regname += 2;
for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++)
if (strcmp (regname, gdbarch_register_name (gdbarch, regnum)) == 0)
return regnum;
error (_("Cannot find gdbarch register \"%s\"."), regname);
}
extern initialize_file_ftype _initialize_compile;
void
_initialize_compile (void)
{
struct cmd_list_element *c = NULL;
add_prefix_cmd ("compile", class_obscure, compile_command,
_("\
Command to compile source code and inject it into the inferior."),
&compile_command_list, "compile ", 1, &cmdlist);
add_com_alias ("expression", "compile", class_obscure, 0);
add_cmd ("code", class_obscure, compile_code_command,
_("\
Compile, inject, and execute code.\n\
\n\
Usage: compile code [-r|-raw] [--] [CODE]\n\
-r|-raw: Suppress automatic 'void _gdb_expr () { CODE }' wrapping.\n\
--: Do not parse any options beyond this delimiter. All text to the\n\
right will be treated as source code.\n\
\n\
The source code may be specified as a simple one line expression, e.g.:\n\
\n\
compile code printf(\"Hello world\\n\");\n\
\n\
Alternatively, you can type the source code interactively.\n\
You can invoke this mode when no argument is given to the command\n\
(i.e.,\"compile code\" is typed with nothing after it). An\n\
interactive prompt will be shown allowing you to enter multiple\n\
lines of source code. Type a line containing \"end\" to indicate\n\
the end of the source code."),
&compile_command_list);
c = add_cmd ("file", class_obscure, compile_file_command,
_("\
Evaluate a file containing source code.\n\
\n\
Usage: compile file [-r|-raw] [filename]\n\
-r|-raw: Suppress automatic 'void _gdb_expr () { CODE }' wrapping."),
&compile_command_list);
set_cmd_completer (c, filename_completer);
add_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
Set compile command debugging."), _("\
Show compile command debugging."), _("\
When on, compile command debugging is enabled."),
NULL, show_compile_debug,
&setdebuglist, &showdebuglist);
add_setshow_string_cmd ("compile-args", class_support,
&compile_args,
_("Set compile command GCC command-line arguments"),
_("Show compile command GCC command-line arguments"),
_("\
Use options like -I (include file directory) or ABI settings.\n\
String quoting is parsed like in shell, for example:\n\
-mno-align-double \"-I/dir with a space/include\""),
set_compile_args, show_compile_args, &setlist, &showlist);
/* Override flags possibly coming from DW_AT_producer. */
compile_args = xstrdup ("-O0 -gdwarf-4"
/* We use -fPIC Otherwise GDB would need to reserve space large enough for
any object file in the inferior in advance to get the final address when
to link the object file to and additionally the default system linker
script would need to be modified so that one can specify there the
absolute target address. */
" -fPIC"
/* We don't want warnings. */
" -w"
/* Override CU's possible -fstack-protector-strong. */
" -fno-stack-protector"
);
set_compile_args (compile_args, 0, NULL);
}

102
gdb/compile/compile.h Normal file
View File

@ -0,0 +1,102 @@
/* Header file for Compile and inject module.
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_COMPILE_H
#define GDB_COMPILE_H
struct ui_file;
struct gdbarch;
struct dwarf2_per_cu_data;
struct symbol;
struct dynamic_prop;
/* Public function that is called from compile_control case in the
expression command. GDB returns either a CMD, or a CMD_STRING, but
never both. */
extern void eval_compile_command (struct command_line *cmd, char *cmd_string,
enum compile_i_scope_types scope);
/* Compile a DWARF location expression to C, suitable for use by the
compiler.
STREAM is the stream where the code should be written.
RESULT_NAME is the name of a variable in the resulting C code. The
result of the expression will be assigned to this variable.
SYM is the symbol corresponding to this expression.
PC is the location at which the expression is being evaluated.
ARCH is the architecture to use.
REGISTERS_USED is an out parameter which is updated to note which
registers were needed by this expression.
ADDR_SIZE is the DWARF address size to use.
OPT_PTR and OP_END are the bounds of the DWARF expression.
PER_CU is the per-CU object used for looking up various other
things. */
extern void compile_dwarf_expr_to_c (struct ui_file *stream,
const char *result_name,
struct symbol *sym,
CORE_ADDR pc,
struct gdbarch *arch,
unsigned char *registers_used,
unsigned int addr_size,
const gdb_byte *op_ptr,
const gdb_byte *op_end,
struct dwarf2_per_cu_data *per_cu);
/* Compile a DWARF bounds expression to C, suitable for use by the
compiler.
STREAM is the stream where the code should be written.
RESULT_NAME is the name of a variable in the resulting C code. The
result of the expression will be assigned to this variable.
PROP is the dynamic property for which we're compiling.
SYM is the symbol corresponding to this expression.
PC is the location at which the expression is being evaluated.
ARCH is the architecture to use.
REGISTERS_USED is an out parameter which is updated to note which
registers were needed by this expression.
ADDR_SIZE is the DWARF address size to use.
OPT_PTR and OP_END are the bounds of the DWARF expression.
PER_CU is the per-CU object used for looking up various other
things. */
extern void compile_dwarf_bounds_to_c (struct ui_file *stream,
const char *result_name,
const struct dynamic_prop *prop,
struct symbol *sym, CORE_ADDR pc,
struct gdbarch *arch,
unsigned char *registers_used,
unsigned int addr_size,
const gdb_byte *op_ptr,
const gdb_byte *op_end,
struct dwarf2_per_cu_data *per_cu);
#endif /* GDB_COMPILE_H */

View File

@ -231,6 +231,8 @@ static const struct language_defn d_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -55,6 +55,24 @@
#include "host-defs.h"
/* Scope types enumerator. List the types of scopes the compiler will
accept. */
enum compile_i_scope_types
{
COMPILE_I_INVALID_SCOPE,
/* A simple scope. Wrap an expression into a simple scope that
takes no arguments, returns no value, and uses the generic
function name "_gdb_expr". */
COMPILE_I_SIMPLE_SCOPE,
/* Do not wrap the expression,
it has to provide function "_gdb_expr" on its own. */
COMPILE_I_RAW_SCOPE,
};
/* Just in case they're not defined in stdio.h. */
#ifndef SEEK_SET
@ -364,6 +382,7 @@ enum command_control_type
if_control,
commands_control,
python_control,
compile_control,
guile_control,
while_stepping_control,
invalid_control
@ -377,6 +396,15 @@ struct command_line
struct command_line *next;
char *line;
enum command_control_type control_type;
union
{
struct
{
enum compile_i_scope_types scope;
}
compile;
}
control_u;
/* * The number of elements in body_list. */
int body_count;
/* * For composite commands, the nested lists of commands. For

View File

@ -1,3 +1,9 @@
2014-12-12 Phil Muldoon <pmuldoon@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.texinfo (Altering): Update.
(Compiling and Injecting Code): New node.
2014-12-12 Doug Evans <dje@google.com>
* python.texi (Objfiles In Python): Document gdb.lookup_objfile.

View File

@ -16494,6 +16494,7 @@ address, or even return prematurely from a function.
* Returning:: Returning from a function
* Calling:: Calling your program's functions
* Patching:: Patching your program
* Compiling and Injecting Code:: Compiling and injecting code in @value{GDBN}
@end menu
@node Assignment
@ -16916,6 +16917,237 @@ Display whether executable files and core files are opened for writing
as well as reading.
@end table
@node Compiling and Injecting Code
@section Compiling and injecting code in @value{GDBN}
@cindex injecting code
@cindex writing into executables
@cindex compiling code
@value{GDBN} supports on-demand compilation and code injection into
programs running under @value{GDBN}. GCC 5.0 or higher built with
@file{libcc1.so} must be installed for this functionality to be enabled.
This functionality is implemented with the following commands.
@table @code
@kindex compile code
@item compile code @var{source-code}
@itemx compile code -raw @var{--} @var{source-code}
Compile @var{source-code} with the compiler language found as the current
language in @value{GDBN} (@pxref{Languages}). If compilation and
injection is not supported with the current language specified in
@value{GDBN}, or the compiler does not support this feature, an error
message will be printed. If @var{source-code} compiles and links
successfully, @value{GDBN} will load the object-code emitted,
and execute it within the context of the currently selected inferior.
It is important to note that the compiled code is executed immediately.
After execution, the compiled code is removed from @value{GDBN} and any
new types or variables you have defined will be deleted.
The command allows you to specify @var{source-code} in two ways.
The simplest method is to provide a single line of code to the command.
E.g.:
@smallexample
compile code printf ("hello world\n");
@end smallexample
If you specify options on the command line as well as source code, they
may conflict. The @samp{--} delimiter can be used to separate options
from actual source code. E.g.:
@smallexample
compile code -r -- printf ("hello world\n");
@end smallexample
Alternatively you can enter source code as multiple lines of text. To
enter this mode, invoke the @samp{compile code} command without any text
following the command. This will start the multiple-line editor and
allow you to type as many lines of source code as required. When you
have completed typing, enter @samp{end} on its own line to exit the
editor.
@smallexample
compile code
>printf ("hello\n");
>printf ("world\n");
>end
@end smallexample
Specifying @samp{-raw}, prohibits @value{GDBN} from wrapping the
provided @var{source-code} in a callable scope. In this case, you must
specify the entry point of the code by defining a function named
@code{_gdb_expr_}. The @samp{-raw} code cannot access variables of the
inferior. Using @samp{-raw} option may be needed for example when
@var{source-code} requires @samp{#include} lines which may conflict with
inferior symbols otherwise.
@kindex compile file
@item compile file @var{filename}
@itemx compile file -raw @var{filename}
Like @code{compile code}, but take the source code from @var{filename}.
@smallexample
compile file /home/user/example.c
@end smallexample
@end table
@subsection Caveats when using the @code{compile} command
There are a few caveats to keep in mind when using the @code{compile}
command. As the caveats are different per language, the table below
highlights specific issues on a per language basis.
@table @asis
@item C code examples and caveats
When the language in @value{GDBN} is set to @samp{C}, the compiler will
attempt to compile the source code with a @samp{C} compiler. The source
code provided to the @code{compile} command will have much the same
access to variables and types as it normally would if it were part of
the program currently being debugged in @value{GDBN}.
Below is a sample program that forms the basis of the examples that
follow. This program has been compiled and loaded into @value{GDBN},
much like any other normal debugging session.
@smallexample
void function1 (void)
@{
int i = 42;
printf ("function 1\n");
@}
void function2 (void)
@{
int j = 12;
function1 ();
@}
int main(void)
@{
int k = 6;
int *p;
function2 ();
return 0;
@}
@end smallexample
For the purposes of the examples in this section, the program above has
been compiled, loaded into @value{GDBN}, stopped at the function
@code{main}, and @value{GDBN} is awaiting input from the user.
To access variables and types for any program in @value{GDBN}, the
program must be compiled and packaged with debug information. The
@code{compile} command is not an exception to this rule. Without debug
information, you can still use the @code{compile} command, but you will
be very limited in what variables and types you can access.
So with that in mind, the example above has been compiled with debug
information enabled. The @code{compile} command will have access to
all variables and types (except those that may have been optimized
out). Currently, as @value{GDBN} has stopped the program in the
@code{main} function, the @code{compile} command would have access to
the variable @code{k}. You could invoke the @code{compile} command
and type some source code to set the value of @code{k}. You can also
read it, or do anything with that variable you would normally do in
@code{C}. Be aware that changes to inferior variables in the
@code{compile} command are persistent. In the following example:
@smallexample
compile code k = 3;
@end smallexample
@noindent
the variable @code{k} is now 3. It will retain that value until
something else in the example program changes it, or another
@code{compile} command changes it.
Normal scope and access rules apply to source code compiled and
injected by the @code{compile} command. In the example, the variables
@code{j} and @code{k} are not accessible yet, because the program is
currently stopped in the @code{main} function, where these variables
are not in scope. Therefore, the following command
@smallexample
compile code j = 3;
@end smallexample
@noindent
will result in a compilation error message.
Once the program is continued, execution will bring these variables in
scope, and they will become accessible; then the code you specify via
the @code{compile} command will be able to access them.
You can create variables and types with the @code{compile} command as
part of your source code. Variables and types that are created as part
of the @code{compile} command are not visible to the rest of the program for
the duration of its run. This example is valid:
@smallexample
compile code int ff = 5; printf ("ff is %d\n", ff);
@end smallexample
However, if you were to type the following into @value{GDBN} after that
command has completed:
@smallexample
compile code printf ("ff is %d\n'', ff);
@end smallexample
@noindent
a compiler error would be raised as the variable @code{ff} no longer
exists. Object code generated and injected by the @code{compile}
command is removed when its execution ends. Caution is advised
when assigning to program variables values of variables created by the
code submitted to the @code{compile} command. This example is valid:
@smallexample
compile code int ff = 5; k = ff;
@end smallexample
The value of the variable @code{ff} is assigned to @code{k}. The variable
@code{k} does not require the existence of @code{ff} to maintain the value
it has been assigned. However, pointers require particular care in
assignment. If the source code compiled with the @code{compile} command
changed the address of a pointer in the example program, perhaps to a
variable created in the @code{compile} command, that pointer would point
to an invalid location when the command exits. The following example
would likely cause issues with your debugged program:
@smallexample
compile code int ff = 5; p = &ff;
@end smallexample
In this example, @code{p} would point to @code{ff} when the
@code{compile} command is executing the source code provided to it.
However, as variables in the (example) program persist with their
assigned values, the variable @code{p} would point to an invalid
location when the command exists. A general rule should be followed
in that you should either assign @code{NULL} to any assigned pointers,
or restore a valid location to the pointer before the command exits.
Similar caution must be exercised with any structs, unions, and typedefs
defined in @code{compile} command. Types defined in the @code{compile}
command will no longer be available in the next @code{compile} command.
Therefore, if you cast a variable to a type defined in the
@code{compile} command, care must be taken to ensure that any future
need to resolve the type can be achieved.
@smallexample
(gdb) compile code static struct a @{ int a; @} v = @{ 42 @}; argv = &v;
(gdb) compile code printf ("%d\n", ((struct a *) argv)->a);
gdb command line:1:36: error: dereferencing pointer to incomplete type struct a
Compilation failed.
(gdb) compile code struct a @{ int a; @}; printf ("%d\n", ((struct a *) argv)->a);
42
@end smallexample
Variables that have been optimized away by the compiler are not
accessible to the code submitted to the @code{compile} command.
Access to those variables will generate a compiler error which @value{GDBN}
will print to the console.
@end table
@node GDB Files
@chapter @value{GDBN} Files

View File

@ -37,6 +37,7 @@
#include "dwarf2expr.h"
#include "dwarf2loc.h"
#include "dwarf2-frame.h"
#include "compile/compile.h"
extern int dwarf2_always_disassemble;
@ -2509,6 +2510,42 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop,
return 0;
}
/* See dwarf2loc.h. */
void
dwarf2_compile_property_to_c (struct ui_file *stream,
const char *result_name,
struct gdbarch *gdbarch,
unsigned char *registers_used,
const struct dynamic_prop *prop,
CORE_ADDR pc,
struct symbol *sym)
{
struct dwarf2_property_baton *baton = prop->data.baton;
const gdb_byte *data;
size_t size;
struct dwarf2_per_cu_data *per_cu;
if (prop->kind == PROP_LOCEXPR)
{
data = baton->locexpr.data;
size = baton->locexpr.size;
per_cu = baton->locexpr.per_cu;
}
else
{
gdb_assert (prop->kind == PROP_LOCLIST);
data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
per_cu = baton->loclist.per_cu;
}
compile_dwarf_bounds_to_c (stream, result_name, prop, sym, pc,
gdbarch, registers_used,
dwarf2_per_cu_addr_size (per_cu),
data, data + size, per_cu);
}
/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
@ -4176,6 +4213,26 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
dlbaton->per_cu);
}
/* symbol_computed_ops 'generate_c_location' method. */
static void
locexpr_generate_c_location (struct symbol *sym, struct ui_file *stream,
struct gdbarch *gdbarch,
unsigned char *registers_used,
CORE_ADDR pc, const char *result_name)
{
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (sym);
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
if (dlbaton->size == 0)
error (_("symbol \"%s\" is optimized out"), SYMBOL_NATURAL_NAME (sym));
compile_dwarf_expr_to_c (stream, result_name,
sym, pc, gdbarch, registers_used, addr_size,
dlbaton->data, dlbaton->data + dlbaton->size,
dlbaton->per_cu);
}
/* The set of location functions used with the DWARF-2 expression
evaluator. */
const struct symbol_computed_ops dwarf2_locexpr_funcs = {
@ -4184,7 +4241,8 @@ const struct symbol_computed_ops dwarf2_locexpr_funcs = {
locexpr_read_needs_frame,
locexpr_describe_location,
0, /* location_has_loclist */
locexpr_tracepoint_var_ref
locexpr_tracepoint_var_ref,
locexpr_generate_c_location
};
@ -4358,6 +4416,29 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
dlbaton->per_cu);
}
/* symbol_computed_ops 'generate_c_location' method. */
static void
loclist_generate_c_location (struct symbol *sym, struct ui_file *stream,
struct gdbarch *gdbarch,
unsigned char *registers_used,
CORE_ADDR pc, const char *result_name)
{
struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (sym);
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
const gdb_byte *data;
size_t size;
data = dwarf2_find_location_expression (dlbaton, &size, pc);
if (size == 0)
error (_("symbol \"%s\" is optimized out"), SYMBOL_NATURAL_NAME (sym));
compile_dwarf_expr_to_c (stream, result_name,
sym, pc, gdbarch, registers_used, addr_size,
data, data + size,
dlbaton->per_cu);
}
/* The set of location functions used with the DWARF-2 expression
evaluator and location lists. */
const struct symbol_computed_ops dwarf2_loclist_funcs = {
@ -4366,7 +4447,8 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = {
loclist_read_needs_frame,
loclist_describe_location,
1, /* location_has_loclist */
loclist_tracepoint_var_ref
loclist_tracepoint_var_ref,
loclist_generate_c_location
};
/* Provide a prototype to silence -Wmissing-prototypes. */

View File

@ -111,6 +111,27 @@ int dwarf2_evaluate_property (const struct dynamic_prop *prop,
CORE_ADDR address,
CORE_ADDR *value);
/* A helper for the compiler interface that compiles a single dynamic
property to C code.
STREAM is where the C code is to be written.
RESULT_NAME is the name of the generated variable.
GDBARCH is the architecture to use.
REGISTERS_USED is a bit-vector that is filled to note which
registers are required by the generated expression.
PROP is the property for which code is generated.
ADDRESS is the address at which the property is considered to be
evaluated.
SYM the originating symbol, used for error reporting. */
void dwarf2_compile_property_to_c (struct ui_file *stream,
const char *result_name,
struct gdbarch *gdbarch,
unsigned char *registers_used,
const struct dynamic_prop *prop,
CORE_ADDR address,
struct symbol *sym);
CORE_ADDR dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu,
unsigned int addr_index);

View File

@ -275,6 +275,8 @@ const struct language_defn f_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -597,6 +597,8 @@ static const struct language_defn go_language_defn =
NULL,
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -1198,6 +1198,8 @@ const struct language_defn java_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&java_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -827,6 +827,8 @@ const struct language_defn unknown_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};
@ -872,6 +874,8 @@ const struct language_defn auto_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};
@ -915,6 +919,8 @@ const struct language_defn local_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -35,6 +35,7 @@ struct value_print_options;
struct type_print_options;
struct lang_varobj_ops;
struct parser_state;
struct compile_instance;
#define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims. */
@ -355,6 +356,36 @@ struct language_defn
/* Various operations on varobj. */
const struct lang_varobj_ops *la_varobj_ops;
/* If this language allows compilation from the gdb command line,
this method should be non-NULL. When called it should return
an instance of struct gcc_context appropriate to the language.
When defined this method must never return NULL; instead it
should throw an exception on failure. The returned compiler
instance is owned by its caller and must be deallocated by
calling its 'destroy' method. */
struct compile_instance *(*la_get_compile_instance) (void);
/* This method must be defined if 'la_get_gcc_context' is defined.
If 'la_get_gcc_context' is not defined, then this method is
ignored.
This takes the user-supplied text and returns a newly malloc'd
bit of code to compile. The caller owns the result.
INST is the compiler instance being used.
INPUT is the user's input text.
GDBARCH is the architecture to use.
EXPR_BLOCK is the block in which the expression is being
parsed.
EXPR_PC is the PC at which the expression is being parsed. */
char *(*la_compute_program) (struct compile_instance *inst,
const char *input,
struct gdbarch *gdbarch,
const struct block *expr_block,
CORE_ADDR expr_pc);
/* Add fields above this point, so the magic number is always last. */
/* Magic number for compat checking. */

View File

@ -394,6 +394,8 @@ const struct language_defn m2_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -389,6 +389,8 @@ const struct language_defn objc_language_defn = {
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -1083,6 +1083,8 @@ const struct language_defn opencl_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -451,6 +451,8 @@ const struct language_defn pascal_language_defn =
NULL, /* la_get_symbol_name_cmp */
iterate_over_symbols,
&default_varobj_ops,
NULL,
NULL,
LANG_MAGIC
};

View File

@ -632,6 +632,21 @@ struct symbol_computed_ops
void (*tracepoint_var_ref) (struct symbol *symbol, struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value);
/* Generate C code to compute the location of SYMBOL. The C code is
emitted to STREAM. GDBARCH is the current architecture and PC is
the PC at which SYMBOL's location should be evaluated.
REGISTERS_USED is a vector indexed by register number; the
generator function should set an element in this vector if the
corresponding register is needed by the location computation.
The generated C code must assign the location to a local
variable; this variable's name is RESULT_NAME. */
void (*generate_c_location) (struct symbol *symbol, struct ui_file *stream,
struct gdbarch *gdbarch,
unsigned char *registers_used,
CORE_ADDR pc, const char *result_name);
};
/* The methods needed to implement LOC_BLOCK for inferior functions.

View File

@ -1,3 +1,26 @@
2014-12-12 Phil Muldoon <pmuldoon@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
Tom Tromey <tromey@redhat.com>
* configure.ac: Add gdb.compile/.
* configure: Regenerate.
* gdb.compile/Makefile.in: New file.
* gdb.compile/compile-ops.exp: New file.
* gdb.compile/compile-ops.c: New file.
* gdb.compile/compile-tls.c: New file.
* gdb.compile/compile-tls.exp: New file.
* gdb.compile/compile-constvar.S: New file.
* gdb.compile/compile-constvar.c: New file.
* gdb.compile/compile-mod.c: New file.
* gdb.compile/compile-nodebug.c: New file.
* gdb.compile/compile-setjmp-mod.c: New file.
* gdb.compile/compile-setjmp.c: New file.
* gdb.compile/compile-setjmp.exp: New file.
* gdb.compile/compile-shlib.c: New file.
* gdb.compile/compile.c: New file.
* gdb.compile/compile.exp: New file.
* lib/gdb.exp (skip_compile_feature_tests): New proc.
2014-12-12 Tom Tromey <tromey@redhat.com>
* lib/dwarf.exp (_location): Ignore blank lines. Allow comments.

View File

@ -3458,7 +3458,7 @@ if test "${build}" = "${host}" -a "${host}" = "${target}"; then
fi
ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.guile/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.perf/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile gdb.cell/Makefile gdb.compile/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.guile/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.perf/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -4165,6 +4165,7 @@ do
"gdb.base/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.base/Makefile" ;;
"gdb.btrace/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.btrace/Makefile" ;;
"gdb.cell/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.cell/Makefile" ;;
"gdb.compile/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.compile/Makefile" ;;
"gdb.cp/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.cp/Makefile" ;;
"gdb.disasm/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.disasm/Makefile" ;;
"gdb.dwarf2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.dwarf2/Makefile" ;;

View File

@ -99,9 +99,9 @@ AC_SUBST(EXTRA_RULES)
AC_OUTPUT([Makefile \
gdb.ada/Makefile \
gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile \
gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile \
gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile gdb.go/Makefile \
gdb.server/Makefile gdb.java/Makefile \
gdb.cell/Makefile gdb.compile/Makefile gdb.cp/Makefile gdb.disasm/Makefile \
gdb.dwarf2/Makefile gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile \
gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
gdb.hp/gdb.defects/Makefile gdb.guile/Makefile gdb.linespec/Makefile \

View File

@ -0,0 +1,21 @@
VPATH = @srcdir@
srcdir = @srcdir@
EXECUTABLES = \
chan handcall hello integers methods package \
strings types unsafe
all info install-info dvi install uninstall installcheck check:
@echo "Nothing to be done for $@..."
clean mostlyclean:
-find . -name '*.o' -print | xargs rm -f
-find . -name '*.ali' -print | xargs rm -f
-rm -f *~ a.out
-rm -f *.dwo *.dwp
-rm -f core core.coremaker coremaker.core corefile $(EXECUTABLES)
distclean maintainer-clean realclean: clean
-rm -f Makefile config.status config.log
-rm -f *-init.exp gdb.log gdb.sum
-rm -fr *.log summary detail *.plog *.sum *.psum site.*

View File

@ -0,0 +1,95 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
// gcc -o gdb.base/compile-constvar.S -dA -S -g gdb.base/compile-constvar.c
.file "compile-constvar.c"
.file 1 "gdb.base/compile-constvar.c"
.section .debug_info,"",@progbits
.Ldebug_info0:
.long .Lend-.Lstart # Length of Compilation Unit Info
.Lstart:
.value 0x4 # DWARF version number
.long .Ldebug_abbrev0 # Offset Into Abbrev. Section
.byte 0x8 # Pointer Size (in bytes)
.uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit)
.long .LASF0 # DW_AT_producer: "GNU C 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g"
.byte 0x1 # DW_AT_language
.long .LASF1 # DW_AT_name: "gdb.base/compile-constvar.c"
.long .LASF2 # DW_AT_comp_dir: "/home/jkratoch/redhat/gdb-gdbjit/gdb/testsuite"
.uleb128 0x2 # (DIE (0x1d) DW_TAG_variable)
.long .LASF3 # DW_AT_name: "constvar"
.long .Linttype-.Ldebug_info0 # DW_AT_type
# DW_AT_external
.byte 0x3 # DW_AT_const_value
.Linttype:
.uleb128 0x3 # (DIE (0x32) DW_TAG_base_type)
.byte 0x4 # DW_AT_byte_size
.byte 0x5 # DW_AT_encoding
.ascii "int\0" # DW_AT_name
.byte 0 # end of children of DIE 0xb
.Lend:
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.uleb128 0x1 # (abbrev code)
.uleb128 0x11 # (TAG: DW_TAG_compile_unit)
.byte 0x1 # DW_children_yes
.uleb128 0x25 # (DW_AT_producer)
.uleb128 0xe # (DW_FORM_strp)
.uleb128 0x13 # (DW_AT_language)
.uleb128 0xb # (DW_FORM_data1)
.uleb128 0x3 # (DW_AT_name)
.uleb128 0xe # (DW_FORM_strp)
.uleb128 0x1b # (DW_AT_comp_dir)
.uleb128 0xe # (DW_FORM_strp)
.byte 0
.byte 0
.uleb128 0x2 # (abbrev code)
.uleb128 0x34 # (TAG: DW_TAG_variable)
.byte 0 # DW_children_no
.uleb128 0x3 # (DW_AT_name)
.uleb128 0xe # (DW_FORM_strp)
.uleb128 0x49 # (DW_AT_type)
.uleb128 0x13 # (DW_FORM_ref4)
.uleb128 0x3f # (DW_AT_external)
.uleb128 0x19 # (DW_FORM_flag_present)
.uleb128 0x1c # (DW_AT_const_value)
.uleb128 0xb # (DW_FORM_data1)
.byte 0
.byte 0
.uleb128 0x3 # (abbrev code)
.uleb128 0x24 # (TAG: DW_TAG_base_type)
.byte 0 # DW_children_no
.uleb128 0xb # (DW_AT_byte_size)
.uleb128 0xb # (DW_FORM_data1)
.uleb128 0x3e # (DW_AT_encoding)
.uleb128 0xb # (DW_FORM_data1)
.uleb128 0x3 # (DW_AT_name)
.uleb128 0x8 # (DW_FORM_string)
.byte 0
.byte 0
.byte 0
.section .debug_str,"MS",@progbits,1
.LASF1:
.string "gdb.base/compile-constvar.c"
.LASF3:
.string "constvar"
.LASF2:
.string ""
.LASF0:
.string "GNU C 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g"
.ident "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)"

View File

@ -0,0 +1,18 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
int constvar = 5;

View File

@ -0,0 +1,26 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
// Make 'globalvar' lookup working.
#pragma GCC user_expression
void
_gdb_expr (void)
{
globalvar = 3;
globalvar += 4;
}

View File

@ -0,0 +1,24 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
int
func_nodebug (int neg)
{
return -neg;
}
int unresolved = 20;

View File

@ -0,0 +1,37 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2011-2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
int value = 0xdeadf00d;
int *ptr = &value;
asm (".section \".text\"");
asm (".balign 8");
asm ("func_start: .globl func_start");
static void
func (void)
{
}
asm ("func_end: .globl func_end");
int
main (void)
{
func ();
return 0;
}

View File

@ -0,0 +1,424 @@
# Copyright 2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Some coverage testing of DWARF operators for the compiler
# integration.
load_lib dwarf.exp
# This test can only be run on targets which support DWARF-2 and use gas.
if {![dwarf2_support]} {
return 0
}
standard_testfile .c gdbjit-ops.S
#
# A port of the pr10770.c test code to the DWARF assembler format.
#
set assert_tos_non0 {
bra 3
skip -3
}
set assert_tos_0 [subst {
lit0
eq
$assert_tos_non0
}]
set program [subst {
lit0
nop
$assert_tos_0
lit1
const1u 1
eq
$assert_tos_non0
lit16
const2u 16
eq
$assert_tos_non0
lit31
const4u 31
ne
$assert_tos_0
lit1
neg
const1s -1
eq
$assert_tos_non0
lit16
neg
const2s -16
ne
$assert_tos_0
lit31
const4s -31
neg
ne
$assert_tos_0
lit7
dup
plus_uconst 2
lit9
eq
$assert_tos_non0
lit7
eq
$assert_tos_non0
lit20
lit1
drop
lit20
eq
$assert_tos_non0
lit17
lit19
over
lit17
eq
$assert_tos_non0
lit19
eq
$assert_tos_non0
lit17
eq
$assert_tos_non0
lit1
lit2
lit3
lit4
pick 2
lit2
eq
$assert_tos_non0
lit4
eq
$assert_tos_non0
lit3
eq
$assert_tos_non0
pick 0
lit2
eq
$assert_tos_non0
lit2
eq
$assert_tos_non0
lit1
eq
$assert_tos_non0
lit6
lit12
swap
lit6
eq
$assert_tos_non0
lit12
eq
$assert_tos_non0
lit7
lit8
lit9
rot
lit8
eq
$assert_tos_non0
lit7
eq
$assert_tos_non0
lit9
eq
$assert_tos_non0
lit7
abs
lit7
eq
$assert_tos_non0
const1s -123
abs
const1u 123
eq
$assert_tos_non0
lit3
lit6
and
lit2
eq
$assert_tos_non0
lit3
lit6
or
lit7
eq
$assert_tos_non0
lit17
lit2
minus
lit15
eq
$assert_tos_non0
# Divide is signed truncating toward zero.
const1s -6
const1s -2
div
lit3
eq
$assert_tos_non0
const1s -7
const1s 3
div
const1s -2
eq
$assert_tos_non0
# Modulo is unsigned.
const1s -6
const1s -4
mod
const1s -6
eq
$assert_tos_non0
const1s -6
lit4
mod
lit2
eq
$assert_tos_non0
lit6
const1s -4
mod
lit6
eq
$assert_tos_non0
# Signed modulo can be implemented using 'over over div mul minus'.
const1s -6
const1s -4
over
over
div
mul
minus
const1s -2
eq
$assert_tos_non0
const1s -7
lit3
over
over
div
mul
minus
const1s -1
eq
$assert_tos_non0
lit7
const1s -3
over
over
div
mul
minus
lit1
eq
$assert_tos_non0
lit16
lit31
plus_uconst 1
mul
const2u 512
eq
$assert_tos_non0
lit5
not
lit31
and
lit26
eq
$assert_tos_non0
lit12
lit31
plus
const1u 43
eq
$assert_tos_non0
const1s -6
lit2
plus
const1s -4
eq
$assert_tos_non0
const1s -6
plus_uconst 3
const1s -3
eq
$assert_tos_non0
lit16
lit4
shl
const2u 256
eq
$assert_tos_non0
lit16
lit3
shr
lit2
eq
$assert_tos_non0
const1s -16
lit3
shra
const1s -2
eq
$assert_tos_non0
lit3
lit6
xor
lit5
eq
$assert_tos_non0
lit3
lit6
le
$assert_tos_non0
lit3
lit3
le
$assert_tos_non0
lit6
lit3
le
$assert_tos_0
lit3
lit6
lt
$assert_tos_non0
lit3
lit3
lt
$assert_tos_0
lit6
lit3
lt
$assert_tos_0
lit3
lit6
ge
$assert_tos_0
lit3
lit3
ge
$assert_tos_non0
lit6
lit3
ge
$assert_tos_non0
lit3
lit6
gt
$assert_tos_0
lit3
lit3
gt
$assert_tos_0
lit6
lit3
gt
$assert_tos_non0
const1s -6
lit1
shr
lit0
gt
$assert_tos_non0
const1s -6
lit1
shra
lit0
lt
$assert_tos_non0
# Finally some result.
addr ptr
}]
# Make some DWARF for the test.
set asm_file [standard_output_file $srcfile2]
Dwarf::assemble $asm_file {
# Creating a CU with 4-byte addresses lets this test link on both
# 32- and 64-bit machines.
cu { addr_size 4 } {
declare_labels int_label
extern func_start func_end ptr
compile_unit {
{name file1.txt}
{language @DW_LANG_C}
{low_pc func_start addr}
{high_pc func_end addr}
} {
global program
int_label: base_type {
{name int}
{byte_size 4 sdata}
{encoding @DW_ATE_signed}
}
subprogram {
{external 1 flag}
{name func}
{low_pc func_start addr}
{high_pc func_end addr}
} {
formal_parameter {
{name param}
{variable_parameter 1 flag}
{type :$int_label}
{location $program SPECIAL_expr}
}
formal_parameter {
{name optimized_out}
{variable_parameter 1 flag}
{type :$int_label}
}
}
}
}
}
if { [prepare_for_testing ${testfile}.exp ${testfile} \
[list $srcfile $asm_file] {nodebug}] } {
return -1
}
if ![runto func] {
return -1
}
if {[skip_compile_feature_tests]} {
untested "could not find libcc1 shared library"
return -1
}
# If we have a bug, this will hang.
gdb_test_no_output "compile code param"
# We can't access optimized-out variables, but their presence should
# not affect compilations that don't refer to them.
gdb_test "compile code optimized_out" \
".*optimized out.*Compilation failed."

View File

@ -0,0 +1,46 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
// Make 'done' lookup working.
#pragma GCC user_expression
static void
foo ()
{
jmp_buf env;
switch (setjmp (env))
{
case 2:
done = 1;
return;
case 0:
longjmp (env, 2);
break;
}
abort ();
}
void
_gdb_expr (void)
{
foo ();
}

View File

@ -0,0 +1,24 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
static int done;
int
main (void)
{
return 0;
}

View File

@ -0,0 +1,34 @@
# Copyright 2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
standard_testfile .c compile-setjmp-mod.c
if { [prepare_for_testing ${testfile}.exp $testfile] } {
return -1
}
if ![runto_main] {
return -1
}
if {[skip_compile_feature_tests]} {
untested "could not find libcc1 shared library"
return -1
}
gdb_test_no_output "compile file -r ${srcdir}/${subdir}/$srcfile2" \
"compile file -r"
gdb_test "p done" " = 1"

View File

@ -0,0 +1,26 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
extern int globalvar;
int shlibvar = 10;
void
shlib_func (void)
{
globalvar = 1;
}

View File

@ -0,0 +1,40 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <pthread.h>
__thread int global_scope;
static __thread int static_scope;
int foo ()
{
/* Ensure we link against pthreads even with --as-needed. */
pthread_testcancel();
return 27;
}
int
main (void)
{
static __thread int local_scope;
/* break-here */
foo ();
return 0;
}

View File

@ -0,0 +1,42 @@
# Copyright 2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. */
standard_testfile .c
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
executable {debug}] != "" } {
return -1
}
clean_restart ${binfile}
if ![runto_main] then {
fail "Can't run to main"
return 0
}
if {[skip_compile_feature_tests]} {
untested "could not find libcc1 shared library"
return -1
}
gdb_test "compile code local_scope = 1" \
"warning: .* compiled code."
gdb_test "print local_scope" " = 1"
gdb_test "compile code static_scope = 2" \
"warning: .* compiled code."
gdb_test "print static_scope" " = 2"
gdb_test "compile code global_scope = 3" \
"warning: .* compiled code."
gdb_test "print global_scope" " = 3"

View File

@ -0,0 +1,130 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#define SOME_MACRO 23
#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
enum enum_type {
ONE = 1,
TWO = 2
};
typedef int v4 __attribute__ ((vector_size (16)));
union union_type;
struct struct_type {
char charfield;
unsigned char ucharfield;
short shortfield;
unsigned short ushortfield;
int intfield;
unsigned int uintfield;
unsigned int bitfield : 3;
long longfield;
unsigned long ulongfield;
enum enum_type enumfield;
float floatfield;
double doublefield;
const union union_type *ptrfield;
struct struct_type *selffield;
int arrayfield[5];
_Complex double complexfield;
_Bool boolfield;
v4 vectorfield;
};
typedef int inttypedef;
union union_type {
int intfield;
inttypedef typedeffield;
};
/* volatile provides some coverage of the conversion code. */
volatile struct struct_type struct_object;
union union_type union_object;
enum ulonger_enum_type {
REALLY_MINUS_1 = -1UL,
};
enum ulonger_enum_type ulonger;
enum longer_enum_type {
MINUS_1 = -1,
FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
};
enum longer_enum_type longer;
int globalvar = 10;
static void
func_static (int addend)
{
globalvar += addend;
}
void
func_global (int subtrahend)
{
globalvar -= subtrahend;
}
void
no_args_or_locals (void)
{
/* no_args_or_locals breakpoint */
}
int *intptr;
int globalshadow = 10;
static int staticshadow = 20;
int externed = 7;
int
main (void)
{
int localvar = 50;
int shadowed = 51;
int bound = 3;
int unresolved = 10;
int globalshadow = 100;
int staticshadow = 200;
int externed = 9;
int f = 0;
static int static_local = 77000;
{
int another_local = 7;
int shadowed = 52;
extern int unresolved;
extern int externed;
int vla[bound];
func_static (0); /* break-here */
no_args_or_locals ();
}
return 0;
}

View File

@ -0,0 +1,357 @@
# Copyright 2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
get_compiler_info
set options {}
if [test_compiler_info gcc*] {
lappend options additional_flags=-g3
}
if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
verbose "Skipping x86_64 LOC_CONST test."
set srcfile3 ""
}
set srcfilesoptions [list ${srcfile} ${options}]
if { $srcfile3 != "" } {
lappend srcfilesoptions $srcfile3 ${options}
}
lappend srcfilesoptions $srcfile4 "nodebug"
if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
return -1
}
clean_restart ${testfile}
#
# Test command without an running inferior.
#
gdb_test "compile code int i=2;" \
"The program must be running for the compile command to work.*" \
"Test compile code command without running inferior"
gdb_test "compile int i=2;" \
"The program must be running for the compile command to work.*" \
"Test compile command without running inferior"
gdb_test "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
"The program must be running for the compile command to work.*" \
"Test compile file command without running inferior"
if ![runto_main] {
return -1
}
if {[skip_compile_feature_tests]} {
untested "could not find libcc1 shared library"
return -1
}
#
# Test delimiter for code, and arguments.
#
gdb_test_no_output "compile -- f = 10" \
"Test abbreviations and code delimiter"
gdb_test "compile f = 10;" ".*= 10;: No such file.*" \
"Test abbreviations and code collision"
gdb_test_no_output "compile -r -- _gdb_expr(){int i = 5;}" \
"Test delimiter with -r"
gdb_test_no_output "compile -raw -- _gdb_expr(){int i = 5;}" \
"Test delimiter with -raw"
gdb_test "compile -- -r _gdb_expr(){int i = 5;}" \
".* error: 'r' undeclared \\(first use in this function\\).*" \
"Test delimiter with -r after it"
gdb_test "p globalvar" " = 10" "expect 10"
gdb_test_no_output "compile code globalvar = 11" \
"set variable without trailing semicolon"
gdb_test "p globalvar" " = 11" "check variable without trailing semicolon"
gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
"set variable from macro"
gdb_test "p globalvar" " = 23" "expect 23"
gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
"set variable from function-like macro"
gdb_test "p globalvar" " = -1" "expect -1"
gdb_test_no_output "compile code globalvar = 42;" "set variable"
gdb_test "p globalvar" " = 42" "expect 42"
gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
gdb_test "p globalvar" " = 84" "expect 84"
gdb_test_multiple "compile code" "compile code multiline 1" { -re "\r\n>$" {} }
gdb_test_multiple "globalvar = 10;" "compile code multiline 2" { -re "\r\n>$" {} }
gdb_test_multiple "globalvar *= 2;" "compile code multiline 3" { -re "\r\n>$" {} }
gdb_test_no_output "end" "compile code multiline 4"
gdb_test "p globalvar" " = 20" "expect 20"
gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
"use external source file"
gdb_test "p globalvar" " = 7" "expect 7"
gdb_test_no_output "compile code func_static (2);" "call static function"
gdb_test "p globalvar" " = 9" "expect 9"
gdb_test_no_output "compile code func_global (1);" "call global function"
gdb_test "p globalvar" " = 8" "expect 8"
gdb_test_no_output \
"compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
"compute size of ulonger"
gdb_test "p globalvar" " = 1" "check size of ulonger"
gdb_test_no_output \
"compile code globalvar = (sizeof (longer) == sizeof (long))" \
"compute size of longer"
gdb_test "p globalvar" " = 1" "check size of longer"
gdb_test_no_output "compile code globalvar = MINUS_1"
gdb_test "p globalvar" " = -1" "check MINUS_1"
gdb_test_no_output "compile code globalvar = static_local"
gdb_test "p globalvar" " = 77000" "check static_local"
gdb_test_no_output "compile code static int staticvar = 5; intptr = &staticvar" \
"keep jit in memory"
gdb_test "p *intptr" " = 5" "expect 5"
gdb_test "compile code func_doesnotexist ();" "warning: Could not find symbol \"func_doesnotexist\" for .*"
gdb_test "compile code *(volatile int *) 0 = 0;" \
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
"compile code segfault first"
gdb_test "bt" \
"\r\n#0 \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1 <function called from gdb>\r\n.*"
set test "p/x \$pc"
set infcall_pc 0
gdb_test_multiple $test $test {
-re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
set infcall_pc $expect_out(1,string)
pass $test
}
}
gdb_test "info sym $infcall_pc" "\r\n_gdb_expr .*" "info sym found"
gdb_test "return" "\r\n#0 main .*" "return" \
"Make _gdb_expr return now\\? \\(y or n\\) " "y"
gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
gdb_test_no_output "set unwindonsignal on"
gdb_test "compile code *(volatile int *) 0 = 0;" \
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
"compile code segfault second"
gdb_breakpoint [gdb_get_line_number "break-here"]
gdb_continue_to_breakpoint "break-here" ".* break-here .*"
gdb_test "p localvar" " = 50" "expect localvar 50"
gdb_test_no_output "compile code localvar = 12;" "set localvar"
gdb_test "p localvar" " = 12" "expect 12"
gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
gdb_test "p localvar" " = 24" "expect 24"
gdb_test_no_output "compile code localvar = shadowed" \
"test shadowing"
gdb_test "p localvar" " = 52" "expect 52"
gdb_test_no_output "compile code localvar = externed"
gdb_test "p localvar" " = 7" "test extern in inner scope"
gdb_test_no_output "compile code vla\[2\] = 7"
gdb_test "p vla\[2\]" " = 7"
gdb_test_no_output \
"compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
gdb_test "p localvar" " = 1"
#
# Test setting fields and also many different types.
#
gdb_test_no_output "compile code struct_object.selffield = &struct_object"
gdb_test "print struct_object.selffield == &struct_object" " = 1"
gdb_test_no_output "compile code struct_object.charfield = 1"
gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
gdb_test_no_output "compile code struct_object.ucharfield = 1"
gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
foreach {field value} {
shortfield -5
ushortfield 5
intfield -7
uintfield 7
bitfield 2
longfield -9
ulongfield 9
enumfield ONE
floatfield 1
doublefield 2
} {
gdb_test_no_output "compile code struct_object.$field = $value"
gdb_test "print struct_object.$field" " = $value"
}
gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
gdb_test "print struct_object.arrayfield" \
" = \\{0, 0, 7, 0, 0\\}"
gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
gdb_test_no_output "compile code struct_object.boolfield = 1"
gdb_test "print struct_object.boolfield" " = true"
gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
gdb_test "print struct_object.vectorfield" \
" = \\{0, 0, 7, 0\\}"
gdb_test_no_output "compile code union_object.typedeffield = 7"
gdb_test "print union_object.typedeffield" " = 7"
gdb_test "print union_object.intfield" " = 7"
# LOC_UNRESOLVED tests.
gdb_test "print unresolved" " = 20"
gdb_test "compile code globalvar = unresolved;"
gdb_test "print globalvar" " = 20" "print unresolved value"
# Test shadowing with global and static variables.
gdb_test_no_output "compile code globalshadow += 1;"
gdb_test "print globalshadow" " = 101"
gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
gdb_test "print 'compile.c'::globalshadow" " = 15"
gdb_test "print globalshadow" " = 101" "print globalshadow second time"
gdb_test_no_output "compile code staticshadow += 2;"
gdb_test "print staticshadow" " = 202"
# "extern int staticshadow;" cannot access static variable.
# Raw code cannot refer to locals.
# As it references global variable we need the #pragma.
# For #pragma we need multiline input.
gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
gdb_test_multiple "#pragma GCC user_expression" "compile code -r multiline 2" { -re "\r\n>$" {} }
gdb_test_multiple "void _gdb_expr(void) { globalshadow = 77000; }" "compile code -r multiline 3" { -re "\r\n>$" {} }
gdb_test_no_output "end" "compile code -r multiline 4"
gdb_test "print 'compile.c'::globalshadow" " = 77000" \
"check globalshadow with -r"
#
# Test the case where the registers structure would not normally have
# any fields.
#
gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
gdb_continue_to_breakpoint "no_args_or_locals"
gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
gdb_test "p globalvar" " = 77" "expect 77"
# Test reference to minimal_symbol, not (full) symbol.
gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
"call func_nodebug"
gdb_test "p globalvar" " = -75" "expect -75"
gdb_test_no_output \
"compile code int (*funcp) (int) = func_nodebug; globalvar = funcp (76);" \
"call func_nodebug indirectly"
gdb_test "p globalvar" " = -76" "expect -76"
# Test compiled module memory protection.
gdb_test_no_output "set debug compile on"
gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
"The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
gdb_test_no_output "set debug compile off"
#
# Some simple coverage tests.
#
gdb_test "show debug compile" "Compile debugging is .*"
gdb_test "show compile-args" \
"Compile command command-line arguments are .*"
gdb_test "compile code -z" "Unknown argument.*"
gdb_test "set lang java" \
"Warning: the current language does not match this frame."
gdb_test "compile code globalvar" "No compiler support for this language\."
gdb_test_no_output "set lang auto"
gdb_test_no_output "compile code union union_type newdecl_u"
gdb_test_no_output "compile code struct struct_type newdecl_s"
gdb_test_no_output "compile code inttypedef newdecl_i"
gdb_test "compile file" \
"You must provide a filename for this command.*" \
"Test compile file without a filename"
gdb_test "compile file -r" \
"You must provide a filename with the raw option set.*" \
"Test compile file and raw option without a filename"
gdb_test "compile file -z" \
"Unknown argument.*" \
"Test compile file with unknown argument"
# LOC_CONST tests.
if { $srcfile3 != "" } {
gdb_test "p constvar" " = 3"
gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
gdb_test "compile code globalvar = constvar;"
gdb_test "print globalvar" " = 3" "print constvar value"
} else {
untested "print constvar value"
}
# Shared library tests.
if {[skip_shlib_tests]} {
untested "skipping shlib tests"
return;
}
set libbin [standard_output_file ${testfile}-shlib.so]
if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile2} $libbin {debug}] != ""
|| [build_executable $testfile ${testfile}-shlib $srcfile \
[list debug ldflags=$libbin]] == -1 } {
return -1
}
clean_restart ${testfile}-shlib
if ![runto_main] {
return -1
}
gdb_test_no_output "compile code shlib_func ();" "call shared library function"
gdb_test "p globalvar" " = 1" "expect 1"
gdb_test_no_output "compile code shlibvar += 5;" "modify shared library variable"
gdb_test "p shlibvar" " = 15" "expect 15"

View File

@ -2518,6 +2518,23 @@ proc skip_libstdcxx_probe_tests {} {
return $ok
}
# Return 1 if we should skip tests of the "compile" feature.
# This must be invoked after the inferior has been started.
proc skip_compile_feature_tests {} {
global gdb_prompt
set result 0
gdb_test_multiple "compile code -- ;" "check for working compile command" {
"Could not load libcc1.*\r\n$gdb_prompt $" {
set result 1
}
-re "\r\n$gdb_prompt $" {
}
}
return $result
}
# Check whether we're testing with the remote or extended-remote
# targets.