aboutsummaryrefslogtreecommitdiff
path: root/gdb/avr-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/avr-tdep.c')
-rw-r--r--gdb/avr-tdep.c151
1 files changed, 110 insertions, 41 deletions
diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
index a7ef17c..62f977d 100644
--- a/gdb/avr-tdep.c
+++ b/gdb/avr-tdep.c
@@ -359,26 +359,81 @@ avr_read_fp (void)
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,<LOCALS_SIZE>
- 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,<LOCALS_SIZE>
+ 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,<LOCALS_SIZE>
- ldi r27,<LOCALS_SIZE>/265
- ldi r30,pm_lo8(.L_foo_body)
- ldi r31,pm_hi8(.L_foo_body)
- rjmp __prologue_saves__+RRR
- .L_foo_body: */
+ out __SP_L__,r28
+ out __SREG__,__tmp_reg__
+ out __SP_H__,r29
+
+ 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(<RAM_ADDR> - <LOCALS_SIZE>)
+ ldi r29,hi8(<RAM_ADDR> - <LOCALS_SIZE>)
+ 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, <LOCALS_SIZE>
+ 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, <LOCALS_SIZE>
+ 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(<LOCALS_SIZE>)
+ ldi r27,hi8(<LOCALS_SIZE>)
+ 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)
@@ -457,10 +512,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;
@@ -490,9 +544,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;
@@ -500,15 +551,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;
@@ -606,9 +675,9 @@ avr_scan_prologue (struct frame_info *fi)
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)
{
@@ -616,19 +685,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]);