aboutsummaryrefslogtreecommitdiff
path: root/gdb/compile
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/compile')
-rw-r--r--gdb/compile/compile-c-support.c44
-rw-r--r--gdb/compile/compile-internal.h4
-rw-r--r--gdb/compile/compile-object-load.c148
-rw-r--r--gdb/compile/compile-object-load.h8
-rw-r--r--gdb/compile/compile-object-run.c33
-rw-r--r--gdb/compile/compile.c83
-rw-r--r--gdb/compile/compile.h2
7 files changed, 310 insertions, 12 deletions
diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index 48a17e2..39f06c6 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -190,6 +190,24 @@ add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
") {\n",
buf);
break;
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ /* <string.h> is needed for a memcpy call below. */
+ fputs_unfiltered ("#include <string.h>\n"
+ "void "
+ GCC_FE_WRAPPER_FUNCTION
+ " (struct "
+ COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+ " *"
+ COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+ ", "
+ COMPILE_I_PRINT_OUT_ARG_TYPE
+ " "
+ COMPILE_I_PRINT_OUT_ARG
+ ") {\n",
+ buf);
+ break;
+
case COMPILE_I_RAW_SCOPE:
break;
default:
@@ -207,6 +225,8 @@ add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
switch (type)
{
case COMPILE_I_SIMPLE_SCOPE:
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
fputs_unfiltered ("}\n", buf);
break;
case COMPILE_I_RAW_SCOPE:
@@ -369,7 +389,9 @@ c_compute_program (struct compile_instance *inst,
add_code_header (inst->scope, buf);
- if (inst->scope == COMPILE_I_SIMPLE_SCOPE)
+ if (inst->scope == COMPILE_I_SIMPLE_SCOPE
+ || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
+ || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE)
{
ui_file_put (var_stream, ui_file_write_for_put, buf);
fputs_unfiltered ("#pragma GCC user_expression\n", buf);
@@ -383,7 +405,25 @@ c_compute_program (struct compile_instance *inst,
fputs_unfiltered ("{\n", buf);
fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
- fputs_unfiltered (input, buf);
+
+ switch (inst->scope)
+ {
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ fprintf_unfiltered (buf,
+"__auto_type " COMPILE_I_EXPR_VAL " = %s;\n"
+"typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
+"memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n"
+ "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+ , input, input,
+ (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
+ ? "&" : ""));
+ break;
+ default:
+ fputs_unfiltered (input, buf);
+ break;
+ }
+
fputs_unfiltered ("\n", buf);
/* For larger user expressions the automatic semicolons may be
diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
index c369d46..b1a5a88 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -84,6 +84,10 @@ struct compile_c_instance
#define COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG "__gdb_regs"
#define COMPILE_I_SIMPLE_REGISTER_ARG_NAME "__regs"
#define COMPILE_I_SIMPLE_REGISTER_DUMMY "_dummy"
+#define COMPILE_I_PRINT_OUT_ARG_TYPE "void *"
+#define COMPILE_I_PRINT_OUT_ARG "__gdb_out_param"
+#define COMPILE_I_EXPR_VAL "__gdb_expr_val"
+#define COMPILE_I_EXPR_PTR_TYPE "__gdb_expr_ptr_type"
/* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
to a form suitable for the compiler source. The register names
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index f04b43c..ed5ef88 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -29,6 +29,7 @@
#include "regcache.h"
#include "inferior.h"
#include "compile.h"
+#include "block.h"
#include "arch-utils.h"
/* Helper data for setup_sections. */
@@ -354,6 +355,115 @@ copy_sections (bfd *abfd, asection *sect, void *data)
do_cleanups (cleanups);
}
+/* Fetch the type of COMPILE_I_EXPR_PTR_TYPE and COMPILE_I_EXPR_VAL
+ symbols in OBJFILE so we can calculate how much memory to allocate
+ for the out parameter. This avoids needing a malloc in the generated
+ code. Throw an error if anything fails.
+ GDB first tries to compile the code with COMPILE_I_PRINT_ADDRESS_SCOPE.
+ If it finds user tries to print an array type this function returns
+ NULL. Caller will then regenerate the code with
+ COMPILE_I_PRINT_VALUE_SCOPE, recompiles it again and finally runs it.
+ This is because __auto_type array-to-pointer type conversion of
+ COMPILE_I_EXPR_VAL which gets detected by COMPILE_I_EXPR_PTR_TYPE
+ preserving the array type. */
+
+static struct type *
+get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
+ enum compile_i_scope_types scope)
+{
+ struct symbol *gdb_ptr_type_sym, *gdb_val_sym;
+ struct type *gdb_ptr_type, *gdb_type_from_ptr, *gdb_type;
+ const struct block *block;
+ const struct blockvector *bv;
+ int nblocks = 0;
+ int block_loop = 0;
+
+ bv = SYMTAB_BLOCKVECTOR (func_sym->owner.symtab);
+ nblocks = BLOCKVECTOR_NBLOCKS (bv);
+
+ gdb_ptr_type_sym = NULL;
+ for (block_loop = 0; block_loop < nblocks; block_loop++)
+ {
+ struct symbol *function;
+ const struct block *function_block;
+
+ block = BLOCKVECTOR_BLOCK (bv, block_loop);
+ if (BLOCK_FUNCTION (block) != NULL)
+ continue;
+ gdb_val_sym = block_lookup_symbol (block, COMPILE_I_EXPR_VAL, VAR_DOMAIN);
+ if (gdb_val_sym == NULL)
+ continue;
+
+ function_block = block;
+ while (function_block != BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)
+ && function_block != BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK))
+ {
+ function_block = BLOCK_SUPERBLOCK (function_block);
+ function = BLOCK_FUNCTION (function_block);
+ if (function != NULL)
+ break;
+ }
+ if (function != NULL
+ && (BLOCK_SUPERBLOCK (function_block)
+ == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
+ && (strcmp (SYMBOL_LINKAGE_NAME (function), GCC_FE_WRAPPER_FUNCTION)
+ == 0))
+ break;
+ }
+ if (block_loop == nblocks)
+ error (_("No \"%s\" symbol found"), COMPILE_I_EXPR_PTR_TYPE);
+
+ gdb_type = SYMBOL_TYPE (gdb_val_sym);
+ CHECK_TYPEDEF (gdb_type);
+
+ gdb_ptr_type_sym = block_lookup_symbol (block, COMPILE_I_EXPR_PTR_TYPE,
+ VAR_DOMAIN);
+ if (gdb_ptr_type_sym == NULL)
+ error (_("No \"%s\" symbol found"), COMPILE_I_EXPR_PTR_TYPE);
+ gdb_ptr_type = SYMBOL_TYPE (gdb_ptr_type_sym);
+ CHECK_TYPEDEF (gdb_ptr_type);
+ if (TYPE_CODE (gdb_ptr_type) != TYPE_CODE_PTR)
+ error (_("Type of \"%s\" is not a pointer"), COMPILE_I_EXPR_PTR_TYPE);
+ gdb_type_from_ptr = TYPE_TARGET_TYPE (gdb_ptr_type);
+
+ if (types_deeply_equal (gdb_type, gdb_type_from_ptr))
+ {
+ if (scope != COMPILE_I_PRINT_ADDRESS_SCOPE)
+ error (_("Expected address scope in compiled module \"%s\"."),
+ objfile_name (objfile));
+ return gdb_type;
+ }
+
+ if (TYPE_CODE (gdb_type) != TYPE_CODE_PTR)
+ error (_("Invalid type code %d of symbol \"%s\" "
+ "in compiled module \"%s\"."),
+ TYPE_CODE (gdb_type_from_ptr), COMPILE_I_EXPR_VAL,
+ objfile_name (objfile));
+
+ switch (TYPE_CODE (gdb_type_from_ptr))
+ {
+ case TYPE_CODE_ARRAY:
+ gdb_type_from_ptr = TYPE_TARGET_TYPE (gdb_type_from_ptr);
+ break;
+ case TYPE_CODE_FUNC:
+ break;
+ default:
+ error (_("Invalid type code %d of symbol \"%s\" "
+ "in compiled module \"%s\"."),
+ TYPE_CODE (gdb_type_from_ptr), COMPILE_I_EXPR_PTR_TYPE,
+ objfile_name (objfile));
+ }
+ if (!types_deeply_equal (gdb_type_from_ptr,
+ TYPE_TARGET_TYPE (gdb_type)))
+ error (_("Referenced types do not match for symbols \"%s\" and \"%s\" "
+ "in compiled module \"%s\"."),
+ COMPILE_I_EXPR_PTR_TYPE, COMPILE_I_EXPR_VAL,
+ objfile_name (objfile));
+ if (scope == COMPILE_I_PRINT_ADDRESS_SCOPE)
+ return NULL;
+ return gdb_type_from_ptr;
+}
+
/* Fetch the type of first parameter of FUNC_SYM.
Return NULL if FUNC_SYM has no parameters. Throw an error otherwise. */
@@ -440,7 +550,9 @@ store_regs (struct type *regs_type, CORE_ADDR regs_base)
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. */
+ function returns.
+ Function returns NULL only for COMPILE_I_PRINT_ADDRESS_SCOPE when
+ COMPILE_I_PRINT_VALUE_SCOPE should have been used instead. */
struct compile_module *
compile_object_load (const char *object_file, const char *source_file,
@@ -449,7 +561,7 @@ 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, regs_addr;
+ CORE_ADDR addr, regs_addr, out_value_addr = 0;
struct symbol *func_sym;
struct type *func_type;
struct bound_minimal_symbol bmsym;
@@ -459,7 +571,7 @@ compile_object_load (const char *object_file, const char *source_file,
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;
+ struct type *regs_type, *out_value_type = NULL;
char *filename, **matching;
struct objfile *objfile;
int expect_parameters;
@@ -521,6 +633,11 @@ compile_object_load (const char *object_file, const char *source_file,
expect_parameters = 0;
expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
break;
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ expect_parameters = 2;
+ expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
+ break;
default:
internal_error (__FILE__, __LINE__, _("invalid scope %d"), scope);
}
@@ -603,6 +720,29 @@ compile_object_load (const char *object_file, const char *source_file,
store_regs (regs_type, regs_addr);
}
+ if (scope == COMPILE_I_PRINT_ADDRESS_SCOPE
+ || scope == COMPILE_I_PRINT_VALUE_SCOPE)
+ {
+ out_value_type = get_out_value_type (func_sym, objfile, scope);
+ if (out_value_type == NULL)
+ {
+ do_cleanups (cleanups);
+ return NULL;
+ }
+ check_typedef (out_value_type);
+ out_value_addr = gdbarch_infcall_mmap (target_gdbarch (),
+ TYPE_LENGTH (out_value_type),
+ (GDB_MMAP_PROT_READ
+ | GDB_MMAP_PROT_WRITE));
+ gdb_assert (out_value_addr != 0);
+ if (compile_debug)
+ fprintf_unfiltered (gdb_stdout,
+ "allocated %s bytes at %s for printed value\n",
+ paddress (target_gdbarch (),
+ TYPE_LENGTH (out_value_type)),
+ paddress (target_gdbarch (), out_value_addr));
+ }
+
discard_cleanups (cleanups_free_objfile);
do_cleanups (cleanups);
@@ -613,5 +753,7 @@ compile_object_load (const char *object_file, const char *source_file,
retval->regs_addr = regs_addr;
retval->scope = scope;
retval->scope_data = scope_data;
+ retval->out_value_type = out_value_type;
+ retval->out_value_addr = out_value_addr;
return retval;
}
diff --git a/gdb/compile/compile-object-load.h b/gdb/compile/compile-object-load.h
index f5e887d..5afacda 100644
--- a/gdb/compile/compile-object-load.h
+++ b/gdb/compile/compile-object-load.h
@@ -37,6 +37,14 @@ struct compile_module
/* User data for SCOPE in use. */
void *scope_data;
+
+ /* Inferior parameter out value type or NULL if the inferior function does not
+ have one. */
+ struct type *out_value_type;
+
+ /* If the inferior function has an out value, this is its address.
+ Otherwise it is zero. */
+ CORE_ADDR out_value_addr;
};
extern struct compile_module *compile_object_load
diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
index 15d3130..771a209 100644
--- a/gdb/compile/compile-object-run.c
+++ b/gdb/compile/compile-object-run.c
@@ -25,6 +25,8 @@
#include "compile-internal.h"
#include "dummy-frame.h"
#include "block.h"
+#include "valprint.h"
+#include "compile.h"
/* Helper for do_module_cleanup. */
@@ -41,6 +43,10 @@ struct do_module_cleanup
enum compile_i_scope_types scope;
void *scope_data;
+ /* Copy from struct compile_module. */
+ struct type *out_value_type;
+ CORE_ADDR out_value_addr;
+
/* objfile_name of our objfile. */
char objfile_name_string[1];
};
@@ -56,7 +62,23 @@ do_module_cleanup (void *arg, int registers_valid)
struct objfile *objfile;
if (data->executedp != NULL)
- *data->executedp = 1;
+ {
+ *data->executedp = 1;
+
+ /* This code cannot be in compile_object_run as OUT_VALUE_TYPE
+ no longer exists there. */
+ if (data->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
+ || data->scope == COMPILE_I_PRINT_VALUE_SCOPE)
+ {
+ struct value *addr_value;
+ struct type *ptr_type = lookup_pointer_type (data->out_value_type);
+
+ addr_value = value_from_pointer (ptr_type, data->out_value_addr);
+
+ /* SCOPE_DATA would be stale unlesse EXECUTEDP != NULL. */
+ compile_print_value (value_ind (addr_value), data->scope_data);
+ }
+ }
ALL_OBJFILES (objfile)
if ((objfile->flags & OBJF_USERLOADED) == 0
@@ -104,6 +126,8 @@ compile_object_run (struct compile_module *module)
strcpy (data->objfile_name_string, objfile_name_s);
data->scope = module->scope;
data->scope_data = module->scope_data;
+ data->out_value_type = module->out_value_type;
+ data->out_value_addr = module->out_value_addr;
xfree (module->source_file);
xfree (module);
@@ -133,6 +157,13 @@ compile_object_run (struct compile_module *module)
(TYPE_FIELD_TYPE (func_type, current_arg), regs_addr);
++current_arg;
}
+ if (TYPE_NFIELDS (func_type) >= 2)
+ {
+ gdb_assert (data->out_value_addr != 0);
+ vargs[current_arg] = value_from_pointer
+ (TYPE_FIELD_TYPE (func_type, current_arg), data->out_value_addr);
+ ++current_arg;
+ }
gdb_assert (current_arg == TYPE_NFIELDS (func_type));
call_function_by_hand_dummy (func_val, TYPE_NFIELDS (func_type), vargs,
do_module_cleanup, data);
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index ab19a5d..fbecf8c 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -38,6 +38,7 @@
#include "target.h"
#include "osabi.h"
#include "gdb_wait.h"
+#include "valprint.h"
@@ -163,6 +164,51 @@ compile_code_command (char *arg, int from_tty)
do_cleanups (cleanup);
}
+/* Callback for compile_print_command. */
+
+void
+compile_print_value (struct value *val, void *data_voidp)
+{
+ const struct format_data *fmtp = data_voidp;
+
+ print_value (val, fmtp);
+}
+
+/* Handle the input from the 'compile print' command. The "compile
+ print" command is used to evaluate and print 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_print_command (char *arg_param, int from_tty)
+{
+ const char *arg = arg_param;
+ struct cleanup *cleanup;
+ enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
+ struct format_data fmt;
+
+ cleanup = make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
+ /* Passing &FMT as SCOPE_DATA is safe as do_module_cleanup will not
+ touch the stale pointer if compile_object_run has already quit. */
+ print_command_parse_format (&arg, "compile print", &fmt);
+
+ if (arg && *arg)
+ eval_compile_command (NULL, arg, scope, &fmt);
+ else
+ {
+ struct command_line *l = get_command_line (compile_control, "");
+
+ make_cleanup_free_command_lines (&l);
+ l->control_u.compile.scope = scope;
+ l->control_u.compile.scope_data = &fmt;
+ execute_control_command_untraced (l);
+ }
+
+ do_cleanups (cleanup);
+}
+
/* A cleanup function to remove a directory and all its contents. */
static void
@@ -576,6 +622,14 @@ eval_compile_command (struct command_line *cmd, const char *cmd_string,
make_cleanup (cleanup_unlink_file, source_file);
compile_module = compile_object_load (object_file, source_file,
scope, scope_data);
+ if (compile_module == NULL)
+ {
+ gdb_assert (scope == COMPILE_I_PRINT_ADDRESS_SCOPE);
+ do_cleanups (cleanup_xfree);
+ eval_compile_command (cmd, cmd_string,
+ COMPILE_I_PRINT_VALUE_SCOPE, scope_data);
+ return;
+ }
discard_cleanups (cleanup_unlink);
do_cleanups (cleanup_xfree);
compile_object_run (compile_module);
@@ -637,12 +691,10 @@ 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."),
+Alternatively, you can type a multiline expression by invoking\n\
+this command with no argument. GDB will then prompt for the\n\
+expression interactively; type a line containing \"end\" to\n\
+indicate the end of the expression."),
&compile_command_list);
c = add_cmd ("file", class_obscure, compile_file_command,
@@ -654,6 +706,25 @@ Usage: compile file [-r|-raw] [filename]\n\
&compile_command_list);
set_cmd_completer (c, filename_completer);
+ add_cmd ("print", class_obscure, compile_print_command,
+ _("\
+Evaluate EXPR by using the compiler and print result.\n\
+\n\
+Usage: compile print[/FMT] [EXPR]\n\
+\n\
+The expression may be specified on the same line as the command, e.g.:\n\
+\n\
+ compile print i\n\
+\n\
+Alternatively, you can type a multiline expression by invoking\n\
+this command with no argument. GDB will then prompt for the\n\
+expression interactively; type a line containing \"end\" to\n\
+indicate the end of the expression.\n\
+\n\
+EXPR may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command)."),
+ &compile_command_list);
+
add_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
Set compile command debugging."), _("\
Show compile command debugging."), _("\
diff --git a/gdb/compile/compile.h b/gdb/compile/compile.h
index a973167..6e108c7 100644
--- a/gdb/compile/compile.h
+++ b/gdb/compile/compile.h
@@ -101,4 +101,6 @@ extern void compile_dwarf_bounds_to_c (struct ui_file *stream,
const gdb_byte *op_end,
struct dwarf2_per_cu_data *per_cu);
+extern void compile_print_value (struct value *val, void *data_voidp);
+
#endif /* GDB_COMPILE_H */