summaryrefslogtreecommitdiffstats
path: root/gdb/m32r-tdep.c
blob: d96ebed3f81da94731e7adf2eeae11bd9f9c72b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
/* Target-dependent code for Renesas M32R, for GDB.

   Copyright (C) 1996-2013 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 "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "value.h"
#include "inferior.h"
#include "symfile.h"
#include "objfiles.h"
#include "osabi.h"
#include "language.h"
#include "arch-utils.h"
#include "regcache.h"
#include "trad-frame.h"
#include "dis-asm.h"

#include "gdb_assert.h"

#include "m32r-tdep.h"

/* Local functions */

extern void _initialize_m32r_tdep (void);

static CORE_ADDR
m32r_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
  /* Align to the size of an instruction (so that they can safely be
     pushed onto the stack.  */
  return sp & ~3;
}


/* Breakpoints
 
   The little endian mode of M32R is unique.  In most of architectures,
   two 16-bit instructions, A and B, are placed as the following:
  
   Big endian:
   A0 A1 B0 B1
  
   Little endian:
   A1 A0 B1 B0
  
   In M32R, they are placed like this:
  
   Big endian:
   A0 A1 B0 B1
  
   Little endian:
   B1 B0 A1 A0
  
   This is because M32R always fetches instructions in 32-bit.
  
   The following functions take care of this behavior.  */

static int
m32r_memory_insert_breakpoint (struct gdbarch *gdbarch,
			       struct bp_target_info *bp_tgt)
{
  CORE_ADDR addr = bp_tgt->placed_address;
  int val;
  gdb_byte buf[4];
  gdb_byte contents_cache[4];
  gdb_byte bp_entry[] = { 0x10, 0xf1 };	/* dpt */

  /* Save the memory contents.  */
  val = target_read_memory (addr & 0xfffffffc, contents_cache, 4);
  if (val != 0)
    return val;			/* return error */

  memcpy (bp_tgt->shadow_contents, contents_cache, 4);
  bp_tgt->placed_size = bp_tgt->shadow_len = 4;

  /* Determine appropriate breakpoint contents and size for this address.  */
  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
    {
      if ((addr & 3) == 0)
	{
	  buf[0] = bp_entry[0];
	  buf[1] = bp_entry[1];
	  buf[2] = contents_cache[2] & 0x7f;
	  buf[3] = contents_cache[3];
	}
      else
	{
	  buf[0] = contents_cache[0];
	  buf[1] = contents_cache[1];
	  buf[2] = bp_entry[0];
	  buf[3] = bp_entry[1];
	}
    }
  else				/* little-endian */
    {
      if ((addr & 3) == 0)
	{
	  buf[0] = contents_cache[0];
	  buf[1] = contents_cache[1] & 0x7f;
	  buf[2] = bp_entry[1];
	  buf[3] = bp_entry[0];
	}
      else
	{
	  buf[0] = bp_entry[1];
	  buf[1] = bp_entry[0];
	  buf[2] = contents_cache[2];
	  buf[3] = contents_cache[3];
	}
    }

  /* Write the breakpoint.  */
  val = target_write_memory (addr & 0xfffffffc, buf, 4);
  return val;
}

static int
m32r_memory_remove_breakpoint (struct gdbarch *gdbarch,
			       struct bp_target_info *bp_tgt)
{
  CORE_ADDR addr = bp_tgt->placed_address;
  int val;
  gdb_byte buf[4];
  gdb_byte *contents_cache = bp_tgt->shadow_contents;

  buf[0] = contents_cache[0];
  buf[1] = contents_cache[1];
  buf[2] = contents_cache[2];
  buf[3] = contents_cache[3];

  /* Remove parallel bit.  */
  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
    {
      if ((buf[0] & 0x80) == 0 && (buf[2] & 0x80) != 0)
	buf[2] &= 0x7f;
    }
  else				/* little-endian */
    {
      if ((buf[3] & 0x80) == 0 && (buf[1] & 0x80) != 0)
	buf[1] &= 0x7f;
    }

  /* Write contents.  */
  val = target_write_raw_memory (addr & 0xfffffffc, buf, 4);
  return val;
}

static const gdb_byte *
m32r_breakpoint_from_pc (struct gdbarch *gdbarch,
			 CORE_ADDR *pcptr, int *lenptr)
{
  static gdb_byte be_bp_entry[] = {
    0x10, 0xf1, 0x70, 0x00
  };	/* dpt -> nop */
  static gdb_byte le_bp_entry[] = {
    0x00, 0x70, 0xf1, 0x10
  };	/* dpt -> nop */
  gdb_byte *bp;

  /* Determine appropriate breakpoint.  */
  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
    {
      if ((*pcptr & 3) == 0)
	{
	  bp = be_bp_entry;
	  *lenptr = 4;
	}
      else
	{
	  bp = be_bp_entry;
	  *lenptr = 2;
	}
    }
  else
    {
      if ((*pcptr & 3) == 0)
	{
	  bp = le_bp_entry;
	  *lenptr = 4;
	}
      else
	{
	  bp = le_bp_entry + 2;
	  *lenptr = 2;
	}
    }

  return bp;
}


char *m32r_register_names[] = {
  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  "r8", "r9", "r10", "r11", "r12", "fp", "lr", "sp",
  "psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch",
  "evb"
};

static const char *
m32r_register_name (struct gdbarch *gdbarch, int reg_nr)
{
  if (reg_nr < 0)
    return NULL;
  if (reg_nr >= M32R_NUM_REGS)
    return NULL;
  return m32r_register_names[reg_nr];
}


/* Return the GDB type object for the "standard" data type
   of data in register N.  */

static struct type *
m32r_register_type (struct gdbarch *gdbarch, int reg_nr)
{
  if (reg_nr == M32R_PC_REGNUM)
    return builtin_type (gdbarch)->builtin_func_ptr;
  else if (reg_nr == M32R_SP_REGNUM || reg_nr == M32R_FP_REGNUM)
    return builtin_type (gdbarch)->builtin_data_ptr;
  else
    return builtin_type (gdbarch)->builtin_int32;
}


/* Write into appropriate registers a function return value
   of type TYPE, given in virtual format.

   Things always get returned in RET1_REGNUM, RET2_REGNUM.  */

static void
m32r_store_return_value (struct type *type, struct regcache *regcache,
			 const void *valbuf)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  CORE_ADDR regval;
  int len = TYPE_LENGTH (type);

  regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_order);
  regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval);

  if (len > 4)
    {
      regval = extract_unsigned_integer ((gdb_byte *) valbuf + 4,
					 len - 4, byte_order);
      regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
    }
}

/* This is required by skip_prologue.  The results of decoding a prologue
   should be cached because this thrashing is getting nuts.  */

static int
decode_prologue (struct gdbarch *gdbarch,
		 CORE_ADDR start_pc, CORE_ADDR scan_limit,
		 CORE_ADDR *pl_endptr, unsigned long *framelength)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  unsigned long framesize;
  int insn;
  int op1;
  CORE_ADDR after_prologue = 0;
  CORE_ADDR after_push = 0;
  CORE_ADDR after_stack_adjust = 0;
  CORE_ADDR current_pc;
  LONGEST return_value;

  framesize = 0;
  after_prologue = 0;

  for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2)
    {
      /* Check if current pc's location is readable.  */
      if (!safe_read_memory_integer (current_pc, 2, byte_order, &return_value))
	return -1;

      insn = read_memory_unsigned_integer (current_pc, 2, byte_order);

      if (insn == 0x0000)
	break;

      /* If this is a 32 bit instruction, we dont want to examine its
         immediate data as though it were an instruction.  */
      if (current_pc & 0x02)
	{
	  /* Decode this instruction further.  */
	  insn &= 0x7fff;
	}
      else
	{
	  if (insn & 0x8000)
	    {
	      if (current_pc == scan_limit)
		scan_limit += 2;	/* extend the search */

	      current_pc += 2;	/* skip the immediate data */

	      /* Check if current pc's location is readable.  */
	      if (!safe_read_memory_integer (current_pc, 2, byte_order,
					     &return_value))
		return -1;

	      if (insn == 0x8faf)	/* add3 sp, sp, xxxx */
		/* add 16 bit sign-extended offset */
		{
		  framesize +=
		    -((short) read_memory_unsigned_integer (current_pc,
							    2, byte_order));
		}
	      else
		{
		  if (((insn >> 8) == 0xe4) /* ld24 r4, xxxxxx; sub sp, r4 */
		      && safe_read_memory_integer (current_pc + 2,
						   2, byte_order,
						   &return_value)
		      && read_memory_unsigned_integer (current_pc + 2,
						       2, byte_order)
			 == 0x0f24)
		    {
		      /* Subtract 24 bit sign-extended negative-offset.  */
		      insn = read_memory_unsigned_integer (current_pc - 2,
							   4, byte_order);
		      if (insn & 0x00800000)	/* sign extend */
			insn |= 0xff000000;	/* negative */
		      else
			insn &= 0x00ffffff;	/* positive */
		      framesize += insn;
		    }
		}
	      after_push = current_pc + 2;
	      continue;
	    }
	}
      op1 = insn & 0xf000;	/* Isolate just the first nibble.  */

      if ((insn & 0xf0ff) == 0x207f)
	{			/* st reg, @-sp */
	  int regno;
	  framesize += 4;
	  regno = ((insn >> 8) & 0xf);
	  after_prologue = 0;
	  continue;
	}
      if ((insn >> 8) == 0x4f)	/* addi sp, xx */
	/* Add 8 bit sign-extended offset.  */
	{
	  int stack_adjust = (signed char) (insn & 0xff);

	  /* there are probably two of these stack adjustments:
	     1) A negative one in the prologue, and
	     2) A positive one in the epilogue.
	     We are only interested in the first one.  */

	  if (stack_adjust < 0)
	    {
	      framesize -= stack_adjust;
	      after_prologue = 0;
	      /* A frameless function may have no "mv fp, sp".
	         In that case, this is the end of the prologue.  */
	      after_stack_adjust = current_pc + 2;
	    }
	  continue;
	}
      if (insn == 0x1d8f)
	{			/* mv fp, sp */
	  after_prologue = current_pc + 2;
	  break;		/* end of stack adjustments */
	}

      /* Nop looks like a branch, continue explicitly.  */
      if (insn == 0x7000)
	{
	  after_prologue = current_pc + 2;
	  continue;		/* nop occurs between pushes.  */
	}
      /* End of prolog if any of these are trap instructions.  */
      if ((insn & 0xfff0) == 0x10f0)
	{
	  after_prologue = current_pc;
	  break;
	}
      /* End of prolog if any of these are branch instructions.  */
      if ((op1 == 0x7000) || (op1 == 0xb000) || (op1 == 0xf000))
	{
	  after_prologue = current_pc;
	  continue;
	}
      /* Some of the branch instructions are mixed with other types.  */
      if (op1 == 0x1000)
	{
	  int subop = insn & 0x0ff0;
	  if ((subop == 0x0ec0) || (subop == 0x0fc0))
	    {
	      after_prologue = current_pc;
	      continue;		/* jmp , jl */
	    }
	}
    }

  if (framelength)
    *framelength = framesize;

  if (current_pc >= scan_limit)
    {
      if (pl_endptr)
	{
	  if (after_stack_adjust != 0)
	    /* We did not find a "mv fp,sp", but we DID find
	       a stack_adjust.  Is it safe to use that as the
	       end of the prologue?  I just don't know.  */
	    {
	      *pl_endptr = after_stack_adjust;
	    }
	  else if (after_push != 0)
	    /* We did not find a "mv fp,sp", but we DID find
	       a push.  Is it safe to use that as the
	       end of the prologue?  I just don't know.  */
	    {
	      *pl_endptr = after_push;
	    }
	  else
	    /* We reached the end of the loop without finding the end
	       of the prologue.  No way to win -- we should report
	       failure.  The way we do that is to return the original
	       start_pc.  GDB will set a breakpoint at the start of
	       the function (etc.)  */
	    *pl_endptr = start_pc;
	}
      return 0;
    }

  if (after_prologue == 0)
    after_prologue = current_pc;

  if (pl_endptr)
    *pl_endptr = after_prologue;

  return 0;
}				/*  decode_prologue */

/* Function: skip_prologue
   Find end of function prologue.  */

#define DEFAULT_SEARCH_LIMIT 128

static CORE_ADDR
m32r_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  CORE_ADDR func_addr, func_end;
  struct symtab_and_line sal;
  LONGEST return_value;

  /* See what the symbol table says.  */

  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
    {
      sal = find_pc_line (func_addr, 0);

      if (sal.line != 0 && sal.end <= func_end)
	{
	  func_end = sal.end;
	}
      else
	/* Either there's no line info, or the line after the prologue is after
	   the end of the function.  In this case, there probably isn't a
	   prologue.  */
	{
	  func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT);
	}
    }
  else
    func_end = pc + DEFAULT_SEARCH_LIMIT;

  /* If pc's location is not readable, just quit.  */
  if (!safe_read_memory_integer (pc, 4, byte_order, &return_value))
    return pc;

  /* Find the end of prologue.  */
  if (decode_prologue (gdbarch, pc, func_end, &sal.end, NULL) < 0)
    return pc;

  return sal.end;
}

struct m32r_unwind_cache
{
  /* The previous frame's inner most stack address.  Used as this
     frame ID's stack_addr.  */
  CORE_ADDR prev_sp;
  /* The frame's base, optionally used by the high-level debug info.  */
  CORE_ADDR base;
  int size;
  /* How far the SP and r13 (FP) have been offset from the start of
     the stack frame (as defined by the previous frame's stack
     pointer).  */
  LONGEST sp_offset;
  LONGEST r13_offset;
  int uses_frame;
  /* Table indicating the location of each and every register.  */
  struct trad_frame_saved_reg *saved_regs;
};

/* Put here the code to store, into fi->saved_regs, the addresses of
   the saved registers of frame described by FRAME_INFO.  This
   includes special registers such as pc and fp saved in special ways
   in the stack frame.  sp is even more special: the address we return
   for it IS the sp for the next frame.  */

static struct m32r_unwind_cache *
m32r_frame_unwind_cache (struct frame_info *this_frame,
			 void **this_prologue_cache)
{
  CORE_ADDR pc, scan_limit;
  ULONGEST prev_sp;
  ULONGEST this_base;
  unsigned long op;
  int i;
  struct m32r_unwind_cache *info;


  if ((*this_prologue_cache))
    return (*this_prologue_cache);

  info = FRAME_OBSTACK_ZALLOC (struct m32r_unwind_cache);
  (*this_prologue_cache) = info;
  info->saved_regs = trad_frame_alloc_saved_regs (this_frame);

  info->size = 0;
  info->sp_offset = 0;
  info->uses_frame = 0;

  scan_limit = get_frame_pc (this_frame);
  for (pc = get_frame_func (this_frame);
       pc > 0 && pc < scan_limit; pc += 2)
    {
      if ((pc & 2) == 0)
	{
	  op = get_frame_memory_unsigned (this_frame, pc, 4);
	  if ((op & 0x80000000) == 0x80000000)
	    {
	      /* 32-bit instruction */
	      if ((op & 0xffff0000) == 0x8faf0000)
		{
		  /* add3 sp,sp,xxxx */
		  short n = op & 0xffff;
		  info->sp_offset += n;
		}
	      else if (((op >> 8) == 0xe4)
		       && get_frame_memory_unsigned (this_frame, pc + 2,
						     2) == 0x0f24)
		{
		  /* ld24 r4, xxxxxx; sub sp, r4 */
		  unsigned long n = op & 0xffffff;
		  info->sp_offset += n;
		  pc += 2;	/* skip sub instruction */
		}

	      if (pc == scan_limit)
		scan_limit += 2;	/* extend the search */
	      pc += 2;		/* skip the immediate data */
	      continue;
	    }
	}

      /* 16-bit instructions */
      op = get_frame_memory_unsigned (this_frame, pc, 2) & 0x7fff;
      if ((op & 0xf0ff) == 0x207f)
	{
	  /* st rn, @-sp */
	  int regno = ((op >> 8) & 0xf);
	  info->sp_offset -= 4;
	  info->saved_regs[regno].addr = info->sp_offset;
	}
      else if ((op & 0xff00) == 0x4f00)
	{
	  /* addi sp, xx */
	  int n = (signed char) (op & 0xff);
	  info->sp_offset += n;
	}
      else if (op == 0x1d8f)
	{
	  /* mv fp, sp */
	  info->uses_frame = 1;
	  info->r13_offset = info->sp_offset;
	  break;		/* end of stack adjustments */
	}
      else if ((op & 0xfff0) == 0x10f0)
	{
	  /* End of prologue if this is a trap instruction.  */
	  break;		/* End of stack adjustments.  */
	}
    }

  info->size = -info->sp_offset;

  /* Compute the previous frame's stack pointer (which is also the
     frame's ID's stack address), and this frame's base pointer.  */
  if (info->uses_frame)
    {
      /* The SP was moved to the FP.  This indicates that a new frame
         was created.  Get THIS frame's FP value by unwinding it from
         the next frame.  */
      this_base = get_frame_register_unsigned (this_frame, M32R_FP_REGNUM);
      /* The FP points at the last saved register.  Adjust the FP back
         to before the first saved register giving the SP.  */
      prev_sp = this_base + info->size;
    }
  else
    {
      /* Assume that the FP is this frame's SP but with that pushed
         stack space added back.  */
      this_base = get_frame_register_unsigned (this_frame, M32R_SP_REGNUM);
      prev_sp = this_base + info->size;
    }

  /* Convert that SP/BASE into real addresses.  */
  info->prev_sp = prev_sp;
  info->base = this_base;

  /* Adjust all the saved registers so that they contain addresses and
     not offsets.  */
  for (i = 0; i < gdbarch_num_regs (get_frame_arch (this_frame)) - 1; i++)
    if (trad_frame_addr_p (info->saved_regs, i))
      info->saved_regs[i].addr = (info->prev_sp + info->saved_regs[i].addr);

  /* The call instruction moves the caller's PC in the callee's LR.
     Since this is an unwind, do the reverse.  Copy the location of LR
     into PC (the address / regnum) so that a request for PC will be
     converted into a request for the LR.  */
  info->saved_regs[M32R_PC_REGNUM] = info->saved_regs[LR_REGNUM];

  /* The previous frame's SP needed to be computed.  Save the computed
     value.  */
  trad_frame_set_value (info->saved_regs, M32R_SP_REGNUM, prev_sp);

  return info;
}

static CORE_ADDR
m32r_read_pc (struct regcache *regcache)
{
  ULONGEST pc;
  regcache_cooked_read_unsigned (regcache, M32R_PC_REGNUM, &pc);
  return pc;
}

static CORE_ADDR
m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  return frame_unwind_register_unsigned (next_frame, M32R_SP_REGNUM);
}


static CORE_ADDR
m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
		      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
		      struct value **args, CORE_ADDR sp, int struct_return,
		      CORE_ADDR struct_addr)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  int stack_offset, stack_alloc;
  int argreg = ARG1_REGNUM;
  int argnum;
  struct type *type;
  enum type_code typecode;
  CORE_ADDR regval;
  gdb_byte *val;
  gdb_byte valbuf[MAX_REGISTER_SIZE];
  int len;

  /* First force sp to a 4-byte alignment.  */
  sp = sp & ~3;

  /* Set the return address.  For the m32r, the return breakpoint is
     always at BP_ADDR.  */
  regcache_cooked_write_unsigned (regcache, LR_REGNUM, bp_addr);

  /* If STRUCT_RETURN is true, then the struct return address (in
     STRUCT_ADDR) will consume the first argument-passing register.
     Both adjust the register count and store that value.  */
  if (struct_return)
    {
      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
      argreg++;
    }

  /* Now make sure there's space on the stack.  */
  for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
    stack_alloc += ((TYPE_LENGTH (value_type (args[argnum])) + 3) & ~3);
  sp -= stack_alloc;		/* Make room on stack for args.  */

  for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
    {
      type = value_type (args[argnum]);
      typecode = TYPE_CODE (type);
      len = TYPE_LENGTH (type);

      memset (valbuf, 0, sizeof (valbuf));

      /* Passes structures that do not fit in 2 registers by reference.  */
      if (len > 8
	  && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
	{
	  store_unsigned_integer (valbuf, 4, byte_order,
				  value_address (args[argnum]));
	  typecode = TYPE_CODE_PTR;
	  len = 4;
	  val = valbuf;
	}
      else if (len < 4)
	{
	  /* Value gets right-justified in the register or stack word.  */
	  memcpy (valbuf + (register_size (gdbarch, argreg) - len),
		  (gdb_byte *) value_contents (args[argnum]), len);
	  val = valbuf;
	}
      else
	val = (gdb_byte *) value_contents (args[argnum]);

      while (len > 0)
	{
	  if (argreg > ARGN_REGNUM)
	    {
	      /* Must go on the stack.  */
	      write_memory (sp + stack_offset, val, 4);
	      stack_offset += 4;
	    }
	  else if (argreg <= ARGN_REGNUM)
	    {
	      /* There's room in a register.  */
	      regval =
		extract_unsigned_integer (val,
					  register_size (gdbarch, argreg),
					  byte_order);
	      regcache_cooked_write_unsigned (regcache, argreg++, regval);
	    }

	  /* Store the value 4 bytes at a time.  This means that things
	     larger than 4 bytes may go partly in registers and partly
	     on the stack.  */
	  len -= register_size (gdbarch, argreg);
	  val += register_size (gdbarch, argreg);
	}
    }

  /* Finally, update the SP register.  */
  regcache_cooked_write_unsigned (regcache, M32R_SP_REGNUM, sp);

  return sp;
}


/* Given a return value in `regbuf' with a type `valtype', 
   extract and copy its value into `valbuf'.  */

static void
m32r_extract_return_value (struct type *type, struct regcache *regcache,
			   void *dst)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  bfd_byte *valbuf = dst;
  int len = TYPE_LENGTH (type);
  ULONGEST tmp;

  /* By using store_unsigned_integer we avoid having to do
     anything special for small big-endian values.  */
  regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp);
  store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), byte_order, tmp);

  /* Ignore return values more than 8 bytes in size because the m32r
     returns anything more than 8 bytes in the stack.  */
  if (len > 4)
    {
      regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp);
      store_unsigned_integer (valbuf + len - 4, 4, byte_order, tmp);
    }
}

static enum return_value_convention
m32r_return_value (struct gdbarch *gdbarch, struct value *function,
		   struct type *valtype, struct regcache *regcache,
		   gdb_byte *readbuf, const gdb_byte *writebuf)
{
  if (TYPE_LENGTH (valtype) > 8)
    return RETURN_VALUE_STRUCT_CONVENTION;
  else
    {
      if (readbuf != NULL)
	m32r_extract_return_value (valtype, regcache, readbuf);
      if (writebuf != NULL)
	m32r_store_return_value (valtype, regcache, writebuf);
      return RETURN_VALUE_REGISTER_CONVENTION;
    }
}



static CORE_ADDR
m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  return frame_unwind_register_unsigned (next_frame, M32R_PC_REGNUM);
}

/* Given a GDB frame, determine the address of the calling function's
   frame.  This will be used to create a new GDB frame struct.  */

static void
m32r_frame_this_id (struct frame_info *this_frame,
		    void **this_prologue_cache, struct frame_id *this_id)
{
  struct m32r_unwind_cache *info
    = m32r_frame_unwind_cache (this_frame, this_prologue_cache);
  CORE_ADDR base;
  CORE_ADDR func;
  struct minimal_symbol *msym_stack;
  struct frame_id id;

  /* The FUNC is easy.  */
  func = get_frame_func (this_frame);

  /* Check if the stack is empty.  */
  msym_stack = lookup_minimal_symbol ("_stack", NULL, NULL);
  if (msym_stack && info->base == SYMBOL_VALUE_ADDRESS (msym_stack))
    return;

  /* Hopefully the prologue analysis either correctly determined the
     frame's base (which is the SP from the previous frame), or set
     that base to "NULL".  */
  base = info->prev_sp;
  if (base == 0)
    return;

  id = frame_id_build (base, func);
  (*this_id) = id;
}

static struct value *
m32r_frame_prev_register (struct frame_info *this_frame,
			  void **this_prologue_cache, int regnum)
{
  struct m32r_unwind_cache *info
    = m32r_frame_unwind_cache (this_frame, this_prologue_cache);
  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
}

static const struct frame_unwind m32r_frame_unwind = {
  NORMAL_FRAME,
  default_frame_unwind_stop_reason,
  m32r_frame_this_id,
  m32r_frame_prev_register,
  NULL,
  default_frame_sniffer
};

static CORE_ADDR
m32r_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
  struct m32r_unwind_cache *info
    = m32r_frame_unwind_cache (this_frame, this_cache);
  return info->base;
}

static const struct frame_base m32r_frame_base = {
  &m32r_frame_unwind,
  m32r_frame_base_address,
  m32r_frame_base_address,
  m32r_frame_base_address
};

/* Assuming THIS_FRAME is a dummy, return the frame ID of that dummy
   frame.  The frame ID's base needs to match the TOS value saved by
   save_dummy_frame_tos(), and the PC match the dummy frame's breakpoint.  */

static struct frame_id
m32r_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
  CORE_ADDR sp = get_frame_register_unsigned (this_frame, M32R_SP_REGNUM);
  return frame_id_build (sp, get_frame_pc (this_frame));
}


static gdbarch_init_ftype m32r_gdbarch_init;

static struct gdbarch *
m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
  struct gdbarch *gdbarch;
  struct gdbarch_tdep *tdep;

  /* If there is already a candidate, use it.  */
  arches = gdbarch_list_lookup_by_info (arches, &info);
  if (arches != NULL)
    return arches->gdbarch;

  /* Allocate space for the new architecture.  */
  tdep = XMALLOC (struct gdbarch_tdep);
  gdbarch = gdbarch_alloc (&info, tdep);

  set_gdbarch_read_pc (gdbarch, m32r_read_pc);
  set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp);

  set_gdbarch_num_regs (gdbarch, M32R_NUM_REGS);
  set_gdbarch_pc_regnum (gdbarch, M32R_PC_REGNUM);
  set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM);
  set_gdbarch_register_name (gdbarch, m32r_register_name);
  set_gdbarch_register_type (gdbarch, m32r_register_type);

  set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call);
  set_gdbarch_return_value (gdbarch, m32r_return_value);

  set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue);
  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
  set_gdbarch_breakpoint_from_pc (gdbarch, m32r_breakpoint_from_pc);
  set_gdbarch_memory_insert_breakpoint (gdbarch,
					m32r_memory_insert_breakpoint);
  set_gdbarch_memory_remove_breakpoint (gdbarch,
					m32r_memory_remove_breakpoint);

  set_gdbarch_frame_align (gdbarch, m32r_frame_align);

  frame_base_set_default (gdbarch, &m32r_frame_base);

  /* Methods for saving / extracting a dummy frame's ID.  The ID's
     stack address must match the SP value returned by
     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
  set_gdbarch_dummy_id (gdbarch, m32r_dummy_id);

  /* Return the unwound PC value.  */
  set_gdbarch_unwind_pc (gdbarch, m32r_unwind_pc);

  set_gdbarch_print_insn (gdbarch, print_insn_m32r);

  /* Hook in ABI-specific overrides, if they have been registered.  */
  gdbarch_init_osabi (info, gdbarch);

  /* Hook in the default unwinders.  */
  frame_unwind_append_unwinder (gdbarch, &m32r_frame_unwind);

  /* Support simple overlay manager.  */
  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);

  return gdbarch;
}

void
_initialize_m32r_tdep (void)
{
  register_gdbarch_init (bfd_arch_m32r, m32r_gdbarch_init);
}
OpenPOWER on IntegriCloud