| Index: gdb/i386-tdep.c
|
| diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
|
| index 549297e701c9088336764ced85d21a4d6369261f..fd5969d61e0a6ff57184300e6f85082d75d27d0a 100644
|
| --- a/gdb/i386-tdep.c
|
| +++ b/gdb/i386-tdep.c
|
| @@ -61,6 +61,13 @@
|
| #include "ax.h"
|
| #include "ax-gdb.h"
|
|
|
| +#include "stap-probe.h"
|
| +#include "user-regs.h"
|
| +#include "cli/cli-utils.h"
|
| +#include "expression.h"
|
| +#include "parser-defs.h"
|
| +#include <ctype.h>
|
| +
|
| /* Register names. */
|
|
|
| static const char *i386_register_names[] =
|
| @@ -376,7 +383,7 @@ i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg)
|
| its legitimate values. */
|
| static const char att_flavor[] = "att";
|
| static const char intel_flavor[] = "intel";
|
| -static const char *valid_flavors[] =
|
| +static const char *const valid_flavors[] =
|
| {
|
| att_flavor,
|
| intel_flavor,
|
| @@ -521,7 +528,12 @@ i386_call_p (const gdb_byte *insn)
|
| static int
|
| i386_syscall_p (const gdb_byte *insn, int *lengthp)
|
| {
|
| - if (insn[0] == 0xcd)
|
| + /* Is it 'int $0x80'? */
|
| + if ((insn[0] == 0xcd && insn[1] == 0x80)
|
| + /* Or is it 'sysenter'? */
|
| + || (insn[0] == 0x0f && insn[1] == 0x34)
|
| + /* Or is it 'syscall'? */
|
| + || (insn[0] == 0x0f && insn[1] == 0x05))
|
| {
|
| *lengthp = 2;
|
| return 1;
|
| @@ -1185,7 +1197,6 @@ i386_match_insn_block (CORE_ADDR pc, struct i386_insn *insn_patterns)
|
| {
|
| CORE_ADDR current_pc;
|
| int ix, i;
|
| - gdb_byte op;
|
| struct i386_insn *insn;
|
|
|
| insn = i386_match_insn (pc, insn_patterns);
|
| @@ -2036,7 +2047,7 @@ static int
|
| i386_in_stack_tramp_p (struct gdbarch *gdbarch, CORE_ADDR pc)
|
| {
|
| gdb_byte insn;
|
| - char *name;
|
| + const char *name;
|
|
|
| /* A stack trampoline is detected if no name is associated
|
| to the current pc and if it points inside a trampoline
|
| @@ -2321,6 +2332,22 @@ i386_16_byte_align_p (struct type *type)
|
| return 0;
|
| }
|
|
|
| +/* Implementation for set_gdbarch_push_dummy_code. */
|
| +
|
| +static CORE_ADDR
|
| +i386_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
|
| + struct value **args, int nargs, struct type *value_type,
|
| + CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
|
| + struct regcache *regcache)
|
| +{
|
| + /* Use 0xcc breakpoint - 1 byte. */
|
| + *bp_addr = sp - 1;
|
| + *real_pc = funaddr;
|
| +
|
| + /* Keep the stack aligned. */
|
| + return sp - 16;
|
| +}
|
| +
|
| static CORE_ADDR
|
| i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
| struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
|
| @@ -2340,7 +2367,6 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
| for (write_pass = 0; write_pass < 2; write_pass++)
|
| {
|
| int args_space_used = 0;
|
| - int have_16_byte_aligned_arg = 0;
|
|
|
| if (struct_return)
|
| {
|
| @@ -2378,19 +2404,20 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
| else
|
| {
|
| if (i386_16_byte_align_p (value_enclosing_type (args[i])))
|
| - {
|
| - args_space = align_up (args_space, 16);
|
| - have_16_byte_aligned_arg = 1;
|
| - }
|
| + args_space = align_up (args_space, 16);
|
| args_space += align_up (len, 4);
|
| }
|
| }
|
|
|
| if (!write_pass)
|
| {
|
| - if (have_16_byte_aligned_arg)
|
| - args_space = align_up (args_space, 16);
|
| sp -= args_space;
|
| +
|
| + /* The original System V ABI only requires word alignment,
|
| + but modern incarnations need 16-byte alignment in order
|
| + to support SSE. Since wasting a few bytes here isn't
|
| + harmful we unconditionally enforce 16-byte alignment. */
|
| + sp &= ~0xf;
|
| }
|
| }
|
|
|
| @@ -2545,7 +2572,7 @@ i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
|
| static const char default_struct_convention[] = "default";
|
| static const char pcc_struct_convention[] = "pcc";
|
| static const char reg_struct_convention[] = "reg";
|
| -static const char *valid_conventions[] =
|
| +static const char *const valid_conventions[] =
|
| {
|
| default_struct_convention,
|
| pcc_struct_convention,
|
| @@ -2593,7 +2620,7 @@ i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
|
| from WRITEBUF into REGCACHE. */
|
|
|
| static enum return_value_convention
|
| -i386_return_value (struct gdbarch *gdbarch, struct type *func_type,
|
| +i386_return_value (struct gdbarch *gdbarch, struct value *function,
|
| struct type *type, struct regcache *regcache,
|
| gdb_byte *readbuf, const gdb_byte *writebuf)
|
| {
|
| @@ -2644,7 +2671,7 @@ i386_return_value (struct gdbarch *gdbarch, struct type *func_type,
|
| if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
|
| {
|
| type = check_typedef (TYPE_FIELD_TYPE (type, 0));
|
| - return i386_return_value (gdbarch, func_type, type, regcache,
|
| + return i386_return_value (gdbarch, function, type, regcache,
|
| readbuf, writebuf);
|
| }
|
|
|
| @@ -2769,7 +2796,7 @@ i386_mmx_type (struct gdbarch *gdbarch)
|
| /* Return the GDB type object for the "standard" data type of data in
|
| register REGNUM. */
|
|
|
| -static struct type *
|
| +struct type *
|
| i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
|
| {
|
| if (i386_mmx_regnum_p (gdbarch, regnum))
|
| @@ -3273,7 +3300,7 @@ i386_pe_skip_trampoline_code (struct frame_info *frame,
|
| read_memory_unsigned_integer (pc + 2, 4, byte_order);
|
| struct minimal_symbol *indsym =
|
| indirect ? lookup_minimal_symbol_by_pc (indirect) : 0;
|
| - char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : 0;
|
| + const char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : 0;
|
|
|
| if (symname)
|
| {
|
| @@ -3294,7 +3321,7 @@ int
|
| i386_sigtramp_p (struct frame_info *this_frame)
|
| {
|
| CORE_ADDR pc = get_frame_pc (this_frame);
|
| - char *name;
|
| + const char *name;
|
|
|
| find_pc_partial_function (pc, &name, NULL, NULL);
|
| return (name && strcmp ("_sigtramp", name) == 0);
|
| @@ -3332,7 +3359,7 @@ static int
|
| i386_svr4_sigtramp_p (struct frame_info *this_frame)
|
| {
|
| CORE_ADDR pc = get_frame_pc (this_frame);
|
| - char *name;
|
| + const char *name;
|
|
|
| /* UnixWare uses _sigacthandler. The origin of the other symbols is
|
| currently unknown. */
|
| @@ -3358,6 +3385,323 @@ i386_svr4_sigcontext_addr (struct frame_info *this_frame)
|
|
|
| return read_memory_unsigned_integer (sp + 8, 4, byte_order);
|
| }
|
| +
|
| +
|
| +
|
| +/* Implementation of `gdbarch_stap_is_single_operand', as defined in
|
| + gdbarch.h. */
|
| +
|
| +int
|
| +i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
|
| +{
|
| + return (*s == '$' /* Literal number. */
|
| + || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement. */
|
| + || (*s == '(' && s[1] == '%') /* Register indirection. */
|
| + || (*s == '%' && isalpha (s[1]))); /* Register access. */
|
| +}
|
| +
|
| +/* Implementation of `gdbarch_stap_parse_special_token', as defined in
|
| + gdbarch.h. */
|
| +
|
| +int
|
| +i386_stap_parse_special_token (struct gdbarch *gdbarch,
|
| + struct stap_parse_info *p)
|
| +{
|
| + /* In order to parse special tokens, we use a state-machine that go
|
| + through every known token and try to get a match. */
|
| + enum
|
| + {
|
| + TRIPLET,
|
| + THREE_ARG_DISPLACEMENT,
|
| + DONE
|
| + } current_state;
|
| +
|
| + current_state = TRIPLET;
|
| +
|
| + /* The special tokens to be parsed here are:
|
| +
|
| + - `register base + (register index * size) + offset', as represented
|
| + in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
|
| +
|
| + - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
|
| + `*(-8 + 3 - 1 + (void *) $eax)'. */
|
| +
|
| + while (current_state != DONE)
|
| + {
|
| + const char *s = p->arg;
|
| +
|
| + switch (current_state)
|
| + {
|
| + case TRIPLET:
|
| + {
|
| + if (isdigit (*s) || *s == '-' || *s == '+')
|
| + {
|
| + int got_minus[3];
|
| + int i;
|
| + long displacements[3];
|
| + const char *start;
|
| + char *regname;
|
| + int len;
|
| + struct stoken str;
|
| +
|
| + got_minus[0] = 0;
|
| + if (*s == '+')
|
| + ++s;
|
| + else if (*s == '-')
|
| + {
|
| + ++s;
|
| + got_minus[0] = 1;
|
| + }
|
| +
|
| + displacements[0] = strtol (s, (char **) &s, 10);
|
| +
|
| + if (*s != '+' && *s != '-')
|
| + {
|
| + /* We are not dealing with a triplet. */
|
| + break;
|
| + }
|
| +
|
| + got_minus[1] = 0;
|
| + if (*s == '+')
|
| + ++s;
|
| + else
|
| + {
|
| + ++s;
|
| + got_minus[1] = 1;
|
| + }
|
| +
|
| + displacements[1] = strtol (s, (char **) &s, 10);
|
| +
|
| + if (*s != '+' && *s != '-')
|
| + {
|
| + /* We are not dealing with a triplet. */
|
| + break;
|
| + }
|
| +
|
| + got_minus[2] = 0;
|
| + if (*s == '+')
|
| + ++s;
|
| + else
|
| + {
|
| + ++s;
|
| + got_minus[2] = 1;
|
| + }
|
| +
|
| + displacements[2] = strtol (s, (char **) &s, 10);
|
| +
|
| + if (*s != '(' || s[1] != '%')
|
| + break;
|
| +
|
| + s += 2;
|
| + start = s;
|
| +
|
| + while (isalnum (*s))
|
| + ++s;
|
| +
|
| + if (*s++ != ')')
|
| + break;
|
| +
|
| + len = s - start;
|
| + regname = alloca (len + 1);
|
| +
|
| + strncpy (regname, start, len);
|
| + regname[len] = '\0';
|
| +
|
| + if (user_reg_map_name_to_regnum (gdbarch,
|
| + regname, len) == -1)
|
| + error (_("Invalid register name `%s' "
|
| + "on expression `%s'."),
|
| + regname, p->saved_arg);
|
| +
|
| + for (i = 0; i < 3; i++)
|
| + {
|
| + write_exp_elt_opcode (OP_LONG);
|
| + write_exp_elt_type
|
| + (builtin_type (gdbarch)->builtin_long);
|
| + write_exp_elt_longcst (displacements[i]);
|
| + write_exp_elt_opcode (OP_LONG);
|
| + if (got_minus[i])
|
| + write_exp_elt_opcode (UNOP_NEG);
|
| + }
|
| +
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| + str.ptr = regname;
|
| + str.length = len;
|
| + write_exp_string (str);
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| +
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| + write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| +
|
| + write_exp_elt_opcode (BINOP_ADD);
|
| + write_exp_elt_opcode (BINOP_ADD);
|
| + write_exp_elt_opcode (BINOP_ADD);
|
| +
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| + write_exp_elt_type (lookup_pointer_type (p->arg_type));
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| +
|
| + write_exp_elt_opcode (UNOP_IND);
|
| +
|
| + p->arg = s;
|
| +
|
| + return 1;
|
| + }
|
| + break;
|
| + }
|
| + case THREE_ARG_DISPLACEMENT:
|
| + {
|
| + if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
|
| + {
|
| + int offset_minus = 0;
|
| + long offset = 0;
|
| + int size_minus = 0;
|
| + long size = 0;
|
| + const char *start;
|
| + char *base;
|
| + int len_base;
|
| + char *index;
|
| + int len_index;
|
| + struct stoken base_token, index_token;
|
| +
|
| + if (*s == '+')
|
| + ++s;
|
| + else if (*s == '-')
|
| + {
|
| + ++s;
|
| + offset_minus = 1;
|
| + }
|
| +
|
| + if (offset_minus && !isdigit (*s))
|
| + break;
|
| +
|
| + if (isdigit (*s))
|
| + offset = strtol (s, (char **) &s, 10);
|
| +
|
| + if (*s != '(' || s[1] != '%')
|
| + break;
|
| +
|
| + s += 2;
|
| + start = s;
|
| +
|
| + while (isalnum (*s))
|
| + ++s;
|
| +
|
| + if (*s != ',' || s[1] != '%')
|
| + break;
|
| +
|
| + len_base = s - start;
|
| + base = alloca (len_base + 1);
|
| + strncpy (base, start, len_base);
|
| + base[len_base] = '\0';
|
| +
|
| + if (user_reg_map_name_to_regnum (gdbarch,
|
| + base, len_base) == -1)
|
| + error (_("Invalid register name `%s' "
|
| + "on expression `%s'."),
|
| + base, p->saved_arg);
|
| +
|
| + s += 2;
|
| + start = s;
|
| +
|
| + while (isalnum (*s))
|
| + ++s;
|
| +
|
| + len_index = s - start;
|
| + index = alloca (len_index + 1);
|
| + strncpy (index, start, len_index);
|
| + index[len_index] = '\0';
|
| +
|
| + if (user_reg_map_name_to_regnum (gdbarch,
|
| + index, len_index) == -1)
|
| + error (_("Invalid register name `%s' "
|
| + "on expression `%s'."),
|
| + index, p->saved_arg);
|
| +
|
| + if (*s != ',' && *s != ')')
|
| + break;
|
| +
|
| + if (*s == ',')
|
| + {
|
| + ++s;
|
| + if (*s == '+')
|
| + ++s;
|
| + else if (*s == '-')
|
| + {
|
| + ++s;
|
| + size_minus = 1;
|
| + }
|
| +
|
| + size = strtol (s, (char **) &s, 10);
|
| +
|
| + if (*s != ')')
|
| + break;
|
| + }
|
| +
|
| + ++s;
|
| +
|
| + if (offset)
|
| + {
|
| + write_exp_elt_opcode (OP_LONG);
|
| + write_exp_elt_type
|
| + (builtin_type (gdbarch)->builtin_long);
|
| + write_exp_elt_longcst (offset);
|
| + write_exp_elt_opcode (OP_LONG);
|
| + if (offset_minus)
|
| + write_exp_elt_opcode (UNOP_NEG);
|
| + }
|
| +
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| + base_token.ptr = base;
|
| + base_token.length = len_base;
|
| + write_exp_string (base_token);
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| +
|
| + if (offset)
|
| + write_exp_elt_opcode (BINOP_ADD);
|
| +
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| + index_token.ptr = index;
|
| + index_token.length = len_index;
|
| + write_exp_string (index_token);
|
| + write_exp_elt_opcode (OP_REGISTER);
|
| +
|
| + if (size)
|
| + {
|
| + write_exp_elt_opcode (OP_LONG);
|
| + write_exp_elt_type
|
| + (builtin_type (gdbarch)->builtin_long);
|
| + write_exp_elt_longcst (size);
|
| + write_exp_elt_opcode (OP_LONG);
|
| + if (size_minus)
|
| + write_exp_elt_opcode (UNOP_NEG);
|
| + write_exp_elt_opcode (BINOP_MUL);
|
| + }
|
| +
|
| + write_exp_elt_opcode (BINOP_ADD);
|
| +
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| + write_exp_elt_type (lookup_pointer_type (p->arg_type));
|
| + write_exp_elt_opcode (UNOP_CAST);
|
| +
|
| + write_exp_elt_opcode (UNOP_IND);
|
| +
|
| + p->arg = s;
|
| +
|
| + return 1;
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* Advancing to the next state. */
|
| + ++current_state;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
|
|
|
|
| /* Generic ELF. */
|
| @@ -3367,6 +3711,16 @@ i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| {
|
| /* We typically use stabs-in-ELF with the SVR4 register numbering. */
|
| set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
|
| +
|
| + /* Registering SystemTap handlers. */
|
| + set_gdbarch_stap_integer_prefix (gdbarch, "$");
|
| + set_gdbarch_stap_register_prefix (gdbarch, "%");
|
| + set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
|
| + set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
|
| + set_gdbarch_stap_is_single_operand (gdbarch,
|
| + i386_stap_is_single_operand);
|
| + set_gdbarch_stap_parse_special_token (gdbarch,
|
| + i386_stap_parse_special_token);
|
| }
|
|
|
| /* System V Release 4 (SVR4). */
|
| @@ -3515,7 +3869,7 @@ i386_fetch_pointer_argument (struct frame_info *frame, int argi,
|
| {
|
| struct gdbarch *gdbarch = get_frame_arch (frame);
|
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
| - CORE_ADDR sp = get_frame_register_unsigned (frame, I386_ESP_REGNUM);
|
| + CORE_ADDR sp = get_frame_register_unsigned (frame, I386_ESP_REGNUM);
|
| return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4, byte_order);
|
| }
|
|
|
| @@ -3978,7 +4332,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
|
| int prefixes = 0;
|
| int regnum = 0;
|
| uint32_t opcode;
|
| - uint8_t opcode8;
|
| + uint8_t opcode8;
|
| ULONGEST addr;
|
| gdb_byte buf[MAX_REGISTER_SIZE];
|
| struct i386_record_s ir;
|
| @@ -7367,6 +7721,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
| set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
|
|
|
| /* Call dummy code. */
|
| + set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
|
| + set_gdbarch_push_dummy_code (gdbarch, i386_push_dummy_code);
|
| set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
|
| set_gdbarch_frame_align (gdbarch, i386_frame_align);
|
|
|
|
|