X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Favr-tdep.c;h=cb23746819eb9aa7441e03a7f3e120efb75fde9e;hb=3605c34ae8991579487a42f8f1f765b298d8489f;hp=52994bf101b4c0d3a01b99ff6efda59d09000d35;hpb=1bf6d5cced30fb7670ad45b0b51a2ea77ec3dc4b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c index 52994bf101..cb23746819 100644 --- a/gdb/avr-tdep.c +++ b/gdb/avr-tdep.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Contributed by Theodore A. Roth, troth@verinet.com */ +/* Contributed by Theodore A. Roth, troth@openavr.org */ /* Portions of this file were taken from the original gdb-4.18 patch developed by Denis Chertykov, denisc@overta.ru */ @@ -176,60 +176,18 @@ avr_register_name (int regnum) return register_names[regnum]; } -/* Index within `registers' of the first byte of the space for - register REGNUM. */ - -static int -avr_register_byte (int regnum) -{ - if (regnum < AVR_PC_REGNUM) - return regnum; - else - return AVR_PC_REG_INDEX; -} - -/* Number of bytes of storage in the actual machine representation for - register REGNUM. */ - -static int -avr_register_raw_size (int regnum) -{ - switch (regnum) - { - case AVR_PC_REGNUM: - return 4; - case AVR_SP_REGNUM: - case AVR_FP_REGNUM: - return 2; - default: - return 1; - } -} - -/* Number of bytes of storage in the program's representation - for register N. */ - -static int -avr_register_virtual_size (int regnum) -{ - return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)); -} - /* Return the GDB type object for the "standard" data type of data in register N. */ static struct type * -avr_register_virtual_type (int regnum) +avr_register_type (struct gdbarch *gdbarch, int reg_nr) { - switch (regnum) - { - case AVR_PC_REGNUM: - return builtin_type_unsigned_long; - case AVR_SP_REGNUM: - return builtin_type_unsigned_short; - default: - return builtin_type_unsigned_char; - } + if (reg_nr == AVR_PC_REGNUM) + return builtin_type_uint32; + if (reg_nr == AVR_SP_REGNUM) + return builtin_type_void_data_ptr; + else + return builtin_type_uint8; } /* Instruction address checks and convertions. */ @@ -311,7 +269,7 @@ avr_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr) || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD) { store_unsigned_integer (buf, TYPE_LENGTH (type), - avr_convert_iaddr_to_raw (addr)); + avr_convert_iaddr_to_raw (addr >> 1)); } else { @@ -324,21 +282,13 @@ avr_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr) static CORE_ADDR avr_pointer_to_address (struct type *type, const void *buf) { - CORE_ADDR addr = extract_address (buf, TYPE_LENGTH (type)); - - if (TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type))) - { - fprintf_unfiltered (gdb_stderr, "CODE_SPACE ---->> ptr->addr: 0x%lx\n", - addr); - fprintf_unfiltered (gdb_stderr, - "+++ If you see this, please send me an email \n"); - } + CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type)); /* Is it a code address? */ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type))) - return avr_make_iaddr (addr); + return avr_make_iaddr (addr << 1); else return avr_make_saddr (addr); } @@ -384,38 +334,12 @@ avr_write_sp (CORE_ADDR val) static CORE_ADDR avr_read_fp (void) { - return (avr_make_saddr (read_register (AVR_FP_REGNUM))); -} - -/* Translate a GDB virtual ADDR/LEN into a format the remote target - understands. Returns number of bytes that can be transfered - starting at TARG_ADDR. Return ZERO if no bytes can be transfered - (segmentation fault). - - TRoth/2002-04-08: Could this be used to check for dereferencing an invalid - pointer? */ - -static void -avr_remote_translate_xfer_address (CORE_ADDR memaddr, int nr_bytes, - CORE_ADDR *targ_addr, int *targ_len) -{ - long out_addr; - long out_len; - - /* FIXME: TRoth: Do nothing for now. Will need to examine memaddr at this - point and see if the high bit are set with the masks that we want. */ - - *targ_addr = memaddr; - *targ_len = nr_bytes; -} + CORE_ADDR fp; -/* Function pointers obtained from the target are half of what gdb expects so - multiply by 2. */ + fp = read_register (AVR_FP_REGNUM); + fp += (read_register (AVR_FP_REGNUM+1) << 8); -static CORE_ADDR -avr_convert_from_func_ptr_addr (CORE_ADDR addr) -{ - return addr * 2; + return (avr_make_saddr (fp)); } /* avr_scan_prologue is also used as the @@ -434,26 +358,81 @@ avr_convert_from_func_ptr_addr (CORE_ADDR addr) 3) the offsets of saved regs This information is stored in the "extra_info" field of the frame_info. - A typical AVR function prologue might look like this: - push rXX - push r28 - push r29 - in r28,__SP_L__ - in r29,__SP_H__ - sbiw r28, - in __tmp_reg__,__SREG__ + Some devices lack the sbiw instruction, so on those replace this: + sbiw r28, XX + with this: + subi r28,lo8(XX) + sbci r29,hi8(XX) + + A typical AVR function prologue with a frame pointer might look like this: + push rXX ; saved regs + ... + push r28 + push r29 + in r28,__SP_L__ + in r29,__SP_H__ + sbiw r28, + in __tmp_reg__,__SREG__ cli - out __SP_L__,r28 - out __SREG__,__tmp_reg__ - out __SP_H__,r29 - - A `-mcall-prologues' prologue look like this: - ldi r26, - ldi r27,/265 - ldi r30,pm_lo8(.L_foo_body) - ldi r31,pm_hi8(.L_foo_body) - rjmp __prologue_saves__+RRR - .L_foo_body: */ + out __SP_H__,r29 + out __SREG__,__tmp_reg__ + out __SP_L__,r28 + + A typical AVR function prologue without a frame pointer might look like + this: + push rXX ; saved regs + ... + + A main function prologue looks like this: + ldi r28,lo8( - ) + ldi r29,hi8( - ) + out __SP_H__,r29 + out __SP_L__,r28 + + A signal handler prologue looks like this: + push __zero_reg__ + push __tmp_reg__ + in __tmp_reg__, __SREG__ + push __tmp_reg__ + clr __zero_reg__ + push rXX ; save registers r18:r27, r30:r31 + ... + push r28 ; save frame pointer + push r29 + in r28, __SP_L__ + in r29, __SP_H__ + sbiw r28, + out __SP_H__, r29 + out __SP_L__, r28 + + A interrupt handler prologue looks like this: + sei + push __zero_reg__ + push __tmp_reg__ + in __tmp_reg__, __SREG__ + push __tmp_reg__ + clr __zero_reg__ + push rXX ; save registers r18:r27, r30:r31 + ... + push r28 ; save frame pointer + push r29 + in r28, __SP_L__ + in r29, __SP_H__ + sbiw r28, + cli + out __SP_H__, r29 + sei + out __SP_L__, r28 + + A `-mcall-prologues' prologue looks like this (Note that the megas use a + jmp instead of a rjmp, thus the prologue is one word larger since jmp is a + 32 bit insn and rjmp is a 16 bit insn): + ldi r26,lo8() + ldi r27,hi8() + ldi r30,pm_lo8(.L_foo_body) + ldi r31,pm_hi8(.L_foo_body) + rjmp __prologue_saves__+RRR + .L_foo_body: */ static void avr_scan_prologue (struct frame_info *fi) @@ -493,7 +472,7 @@ avr_scan_prologue (struct frame_info *fi) frame pointer, adjust the stack pointer, and save registers. */ get_frame_extra_info (fi)->framesize = 0; - prologue_len = prologue_end - prologue_start; + prologue_len = min (prologue_end - prologue_start, AVR_MAX_PROLOGUE_SIZE); read_memory (prologue_start, prologue, prologue_len); /* Scanning main()'s prologue @@ -532,10 +511,9 @@ avr_scan_prologue (struct frame_info *fi) } } - /* Scanning `-mcall-prologues' prologue - FIXME: mega prologue have a 12 bytes long */ + /* Scanning `-mcall-prologues' prologue */ - while (prologue_len <= 12) /* I'm use while to avoit many goto's */ + while (1) /* Using a while to avoid many goto's */ { int loc_size; int body_addr; @@ -565,9 +543,6 @@ avr_scan_prologue (struct frame_info *fi) break; body_addr |= ((insn & 0xf) | ((insn & 0x0f00) >> 4)) << 8; - if (body_addr != (prologue_start + 10) / 2) - break; - msymbol = lookup_minimal_symbol ("__prologue_saves__", NULL, NULL); if (!msymbol) break; @@ -575,15 +550,33 @@ avr_scan_prologue (struct frame_info *fi) /* FIXME: prologue for mega have a JMP instead of RJMP */ insn = EXTRACT_INSN (&prologue[vpc + 8]); /* rjmp __prologue_saves__+RRR */ - if ((insn & 0xf000) != 0xc000) - break; + if ((insn & 0xf000) == 0xc000) + { + /* Extract PC relative offset from RJMP */ + i = (insn & 0xfff) | (insn & 0x800 ? (-1 ^ 0xfff) : 0); + /* Convert offset to byte addressable mode */ + i *= 2; + /* Destination address */ + i += prologue_start + 10; + + if (body_addr != (prologue_start + 10) / 2) + break; + } + /* jmp __prologue_saves__+RRR */ + else if ((insn & 0xfe0e) == 0x940c) + { + /* Extract absolute PC address from JMP */ + i = (((insn & 0x1) | ((insn & 0x1f0) >> 3) << 16) + | (EXTRACT_INSN (&prologue[vpc + 10]) & 0xffff)); + /* Convert address to byte addressable mode */ + i *= 2; + + if (body_addr != (prologue_start + 12)/2) + break; + } + else + break; - /* Extract PC relative offset from RJMP */ - i = (insn & 0xfff) | (insn & 0x800 ? (-1 ^ 0xfff) : 0); - /* Convert offset to byte addressable mode */ - i *= 2; - /* Destination address */ - i += vpc + prologue_start + 10; /* Resovle offset (in words) from __prologue_saves__ symbol. Which is a pushes count in `-mcall-prologues' mode */ num_pushes = AVR_MAX_PUSHES - (i - SYMBOL_VALUE_ADDRESS (msymbol)) / 2; @@ -678,12 +671,12 @@ avr_scan_prologue (struct frame_info *fi) /* Third stage of the prologue scanning. (Really two stages) Scan for: sbiw r28,XX or subi r28,lo8(XX) - sbci r29,hi8(XX) + sbci r29,hi8(XX) in __tmp_reg__,__SREG__ cli - out __SP_L__,r28 + out __SP_H__,r29 out __SREG__,__tmp_reg__ - out __SP_H__,r29 */ + out __SP_L__,r28 */ if (scan_stage == 2 && vpc + 12 <= prologue_len) { @@ -691,19 +684,19 @@ avr_scan_prologue (struct frame_info *fi) unsigned char img[] = { 0x0f, 0xb6, /* in r0,0x3f */ 0xf8, 0x94, /* cli */ - 0xcd, 0xbf, /* out 0x3d,r28 ; SPL */ + 0xde, 0xbf, /* out 0x3e,r29 ; SPH */ 0x0f, 0xbe, /* out 0x3f,r0 ; SREG */ - 0xde, 0xbf /* out 0x3e,r29 ; SPH */ + 0xcd, 0xbf /* out 0x3d,r28 ; SPL */ }; unsigned char img_sig[] = { - 0xcd, 0xbf, /* out 0x3d,r28 ; SPL */ - 0xde, 0xbf /* out 0x3e,r29 ; SPH */ + 0xde, 0xbf, /* out 0x3e,r29 ; SPH */ + 0xcd, 0xbf /* out 0x3d,r28 ; SPL */ }; unsigned char img_int[] = { 0xf8, 0x94, /* cli */ - 0xcd, 0xbf, /* out 0x3d,r28 ; SPL */ + 0xde, 0xbf, /* out 0x3e,r29 ; SPH */ 0x78, 0x94, /* sei */ - 0xde, 0xbf /* out 0x3e,r29 ; SPH */ + 0xcd, 0xbf /* out 0x3d,r28 ; SPL */ }; insn = EXTRACT_INSN (&prologue[vpc]); @@ -753,8 +746,8 @@ avr_init_extra_frame_info (int fromleaf, struct frame_info *fi) if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), get_frame_base (fi), get_frame_base (fi))) { - /* We need to setup fi->frame here because run_stack_dummy gets it wrong - by assuming it's always FP. */ + /* We need to setup fi->frame here because call_function_by_hand + gets it wrong by assuming it's always FP. */ deprecated_update_frame_base_hack (fi, deprecated_read_register_dummy (get_frame_pc (fi), get_frame_base (fi), AVR_PC_REGNUM)); } @@ -1082,24 +1075,63 @@ avr_push_arguments (int nargs, struct value **args, CORE_ADDR sp, while (len > 0) { /* there's room in registers */ len -= wordsize; - regval = extract_address (val + len, wordsize); + regval = extract_unsigned_integer (val + len, wordsize); write_register (argreg--, regval); } } return sp; } +/* Not all avr devices support the BREAK insn. Those that don't should treat + it as a NOP. Thus, it should be ok. Since the avr is currently a remote + only target, this shouldn't be a problem (I hope). TRoth/2003-05-14 */ + +static const unsigned char * +avr_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr) +{ + static unsigned char avr_break_insn [] = { 0x98, 0x95 }; + *lenptr = sizeof (avr_break_insn); + return avr_break_insn; +} + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. + + Return values are always passed via registers r25:r24:... */ + +static void +avr_extract_return_value (struct type *type, struct regcache *regcache, + void *valbuf) +{ + if (TYPE_LENGTH (type) == 1) + { + ULONGEST c; + + /* For single byte return values, r25 is always cleared, so we can + ignore it. */ + regcache_cooked_read_unsigned (regcache, 24, &c); + store_unsigned_integer (valbuf, 1, c); + } + else + { + int i; + /* The MSB of the return value is always in r25, calculate which + register holds the LSB. */ + int lsb_reg = 25 - TYPE_LENGTH (type) + 1; + + for (i=0; i< TYPE_LENGTH (type); i++) + { + regcache_cooked_read (regcache, lsb_reg + i, + (bfd_byte *) valbuf + i); + } + } +} + /* Initialize the gdbarch structure for the AVR's. */ static struct gdbarch * avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { - /* FIXME: TRoth/2002-02-18: I have no idea if avr_call_dummy_words[] should - be bigger or not. Initial testing seems to show that `call my_func()` - works and backtrace from a breakpoint within the call looks correct. - Admittedly, I haven't tested with more than a very simple program. */ - static LONGEST avr_call_dummy_words[] = { 0 }; - struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; @@ -1145,47 +1177,32 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_read_pc (gdbarch, avr_read_pc); set_gdbarch_write_pc (gdbarch, avr_write_pc); - set_gdbarch_read_fp (gdbarch, avr_read_fp); + set_gdbarch_deprecated_target_read_fp (gdbarch, avr_read_fp); set_gdbarch_read_sp (gdbarch, avr_read_sp); - set_gdbarch_write_sp (gdbarch, avr_write_sp); + set_gdbarch_deprecated_dummy_write_sp (gdbarch, avr_write_sp); set_gdbarch_num_regs (gdbarch, AVR_NUM_REGS); set_gdbarch_sp_regnum (gdbarch, AVR_SP_REGNUM); - set_gdbarch_fp_regnum (gdbarch, AVR_FP_REGNUM); + set_gdbarch_deprecated_fp_regnum (gdbarch, AVR_FP_REGNUM); set_gdbarch_pc_regnum (gdbarch, AVR_PC_REGNUM); set_gdbarch_register_name (gdbarch, avr_register_name); - set_gdbarch_register_size (gdbarch, 1); - set_gdbarch_register_bytes (gdbarch, AVR_NUM_REG_BYTES); - set_gdbarch_register_byte (gdbarch, avr_register_byte); - set_gdbarch_register_raw_size (gdbarch, avr_register_raw_size); - set_gdbarch_deprecated_max_register_raw_size (gdbarch, 4); - set_gdbarch_register_virtual_size (gdbarch, avr_register_virtual_size); - set_gdbarch_deprecated_max_register_virtual_size (gdbarch, 4); - set_gdbarch_register_virtual_type (gdbarch, avr_register_virtual_type); + set_gdbarch_register_type (gdbarch, avr_register_type); + set_gdbarch_extract_return_value (gdbarch, avr_extract_return_value); set_gdbarch_print_insn (gdbarch, print_insn_avr); set_gdbarch_call_dummy_address (gdbarch, avr_call_dummy_address); - set_gdbarch_call_dummy_start_offset (gdbarch, 0); - set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); - set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0); - set_gdbarch_call_dummy_length (gdbarch, 0); - set_gdbarch_call_dummy_p (gdbarch, 1); - set_gdbarch_call_dummy_words (gdbarch, avr_call_dummy_words); - set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy); - -/* set_gdbarch_believe_pcc_promotion (gdbarch, 1); // TRoth: should this be set? */ set_gdbarch_address_to_pointer (gdbarch, avr_address_to_pointer); set_gdbarch_pointer_to_address (gdbarch, avr_pointer_to_address); - set_gdbarch_push_arguments (gdbarch, avr_push_arguments); - set_gdbarch_push_return_address (gdbarch, avr_push_return_address); + set_gdbarch_deprecated_push_arguments (gdbarch, avr_push_arguments); + set_gdbarch_deprecated_push_return_address (gdbarch, avr_push_return_address); set_gdbarch_deprecated_pop_frame (gdbarch, avr_pop_frame); set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention); - set_gdbarch_store_struct_return (gdbarch, avr_store_struct_return); + set_gdbarch_deprecated_store_struct_return (gdbarch, avr_store_struct_return); set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, avr_scan_prologue); set_gdbarch_deprecated_init_extra_frame_info (gdbarch, avr_init_extra_frame_info); @@ -1193,21 +1210,17 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_inner_than (gdbarch, core_addr_lessthan); set_gdbarch_decr_pc_after_break (gdbarch, 0); + set_gdbarch_breakpoint_from_pc (gdbarch, avr_breakpoint_from_pc); set_gdbarch_function_start_offset (gdbarch, 0); - set_gdbarch_remote_translate_xfer_address (gdbarch, - avr_remote_translate_xfer_address); + set_gdbarch_frame_args_skip (gdbarch, 0); set_gdbarch_frameless_function_invocation (gdbarch, frameless_look_for_prologue); /* ??? */ set_gdbarch_deprecated_frame_chain (gdbarch, avr_frame_chain); set_gdbarch_deprecated_frame_saved_pc (gdbarch, avr_frame_saved_pc); set_gdbarch_frame_args_address (gdbarch, avr_frame_address); set_gdbarch_frame_locals_address (gdbarch, avr_frame_address); - set_gdbarch_saved_pc_after_call (gdbarch, avr_saved_pc_after_call); - set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); - - set_gdbarch_convert_from_func_ptr_addr (gdbarch, - avr_convert_from_func_ptr_addr); + set_gdbarch_deprecated_saved_pc_after_call (gdbarch, avr_saved_pc_after_call); return gdbarch; } @@ -1236,13 +1249,11 @@ avr_io_reg_read_command (char *args, int from_tty) unsigned int val; int i, j, k, step; -/* fprintf_unfiltered (gdb_stderr, "DEBUG: avr_io_reg_read_command (\"%s\", %d)\n", */ -/* args, from_tty); */ - if (!current_target.to_query) { fprintf_unfiltered (gdb_stderr, - "ERR: info io_registers NOT supported by current target\n"); + "ERR: info io_registers NOT supported by current " + "target\n"); return; } @@ -1302,6 +1313,8 @@ avr_io_reg_read_command (char *args, int from_tty) } } +extern initialize_file_ftype _initialize_avr_tdep; /* -Wmissing-prototypes */ + void _initialize_avr_tdep (void) {