summaryrefslogtreecommitdiff
path: root/gdb/arc-tdep.c
blob: f912f896dec9c6230dcd85f9e46cc0fc4cc77b8c (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
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
/* Target dependent code for ARC processor family, for GDB, the GNU debugger.

   Copyright 2005, 2008, 2009 Free Software Foundation, Inc.

   Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)

   Authors:
      Soam Vasani          <soam.vasani@codito.com>
      Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
      Richard Stuckey      <richard.stuckey@arc.com>

   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/>.  */

/******************************************************************************/
/*                                                                            */
/* Outline:                                                                   */
/*     This module provides support for the ARC processor family's target     */
/*     dependencies.  In particular, it has knowledge of the processor ABI.   */
/*                                                                            */
/*     See                                                                    */
/*           ARCompact Instruction Set Architecture                           */
/*                   Programmer's Reference                                   */
/*                         (5115-018)                                         */
/*                                                                            */
/*     for a description of ARC processor architecture, and                   */
/*                                                                            */
/*           System V ABI Supplement                                          */
/*                   4093-004                                                 */
/*                                                                            */
/*     for a complete definition of the ABI.                                  */
/*                                                                            */
/*                                                                            */
/* Stack Frame Layout:                                                        */
/*     This shows the layout of the stack frame for the general case of a     */
/*     function call; a given function might not have a variable number of    */
/*     arguments or local variables, or might not save any registers, so it   */
/*     would not have the corresponding frame areas.  Additionally, a leaf    */
/*     function (i.e. one which calls no other functions) does not need to    */
/*     save the contents of the BLINK register (which holds its return        */
/*     address), and a function might not have a frame pointer.               */
/*                                                                            */
/*     N.B. the stack grows downward, so SP points below FP in memory; SP     */
/*          always points to the last used word on the stack, not the first   */
/*          one.                                                              */
/*                                                                            */
/*                   |                       |   |                            */
/*                   |      arg word N       |   | caller's                   */
/*                   |           :           |   | frame                      */
/*                   |      arg word 10      |   |                            */
/*                   |      arg word 9       |   |                            */
/*       old SP ---> |-----------------------| --                             */
/*                   |   var arg word 8      |   |                            */
/*                   |           :           |   |                            */
/*                   |   var arg word P+1    |   |                            */
/*                   |-----------------------|   |                            */
/*                   |                       |   |                            */
/*                   |      callee-saved     |   |                            */
/*                   |        registers      |   |                            */
/*                   |                       |   |                            */
/*                   |-----------------------|   |                            */
/*                   |      saved blink (*)  |   |                            */
/*                   |-----------------------|   | callee's                   */
/*                   |      saved FP         |   | frame                      */
/*           FP ---> |-----------------------|   |                            */
/*                   |                       |   |                            */
/*                   |         local         |   |                            */
/*                   |       variables       |   |                            */
/*                   |                       |   |                            */
/*                   |       register        |   |                            */
/*                   |      spill area       |   |                            */
/*                   |                       |   |                            */
/*                   |     outgoing args     |   |                            */
/*                   |                       |   |                            */
/*           SP ---> |-----------------------| --                             */
/*                   |                       |                                */
/*                   |         unused        |                                */
/*                   |                       |                                */
/*                               |                                            */
/*                               |                                            */
/*                               V                                            */
/*                           downwards                                        */
/*                                                                            */
/*     The list of arguments to be passed to a function is considered to be a */
/*     sequence of N words (as though all the parameters were stored in order */
/*     in memory with each parameter occupying an integral number of words).  */
/*     Words 1 .. 8 are passed in registers 0 .. 7; if the function has more  */
/*     than 8 words of arguments then words 9 .. N are passed on the stack in */
/*     the caller's frame.                                                    */
/*                                                                            */
/*     If the function has a variable number of arguments, e.g. it has a form */
/*     such as                                                                */
/*                      function(p1, p2, ...);                                */
/*                                                                            */
/*     and P words are required to hold the values of the named parameters    */
/*     (which are passed in registers 0 .. P-1), then the remaining 8 - P     */
/*     words passed in registers P .. 7 are spilled into the top of the frame */
/*     so that the anonymous parameter words occupy a continous region.       */
/*                                                                            */
/*     (*) if saved.                                                          */
/*                                                                            */
/* Usage:                                                                     */
/*     The module exports a function _initialize_arc_tdep: the call to this   */
/*     function is generated by the gdb build mechanism, so this function     */
/*     should not be explicitly called.                                       */
/*                                                                            */
/*     The operations provided by this module are registered with gdb during  */
/*     initialization; gdb then calls them via function pointers, rather than */
/*     by name (this allows gdb to handle multiple target architectures):     */
/*                                                                            */
/*          set_gdbarch_XXX (gdbarch, <function>);                            */
/*                                                                            */
/*                                                                            */
/* Build Configuration:                                                       */
/*     The ARC gdb may be built in two different configurations, according to */
/*     the nature of the target that it is to debug:                          */
/*                                                                            */
/*     1) arc-elf32:                                                          */
/*           for debugging 'bare-metal' builds of user code (i.e. built with  */
/*           newlib)                                                          */
/*                                                                            */
/*           ARC-specific modules:                                            */
/*                arc-tdep                                                    */
/*                arc-elf32-tdep                                              */
/*                arc-xiss                                                    */
/*                arc-jtag                                                    */
/*                arc-jtag-ops                                                */
/*                arc-jtag-actionpoints                                       */
/*                arc-gpio                                                    */
/*                arc-remote-fileio                                           */
/*                arc-registers                                               */
/*                arc-architecture                                            */
/*                arc-board                                                   */
/*                arc-arguments                                               */
/*                arc-memory                                                  */
/*                arc-inst-tracing                                            */
/*                                                                            */
/*     2) arc-linux-uclibc:                                                   */
/*           for deugging user mode Linux applications, via communication to  */
/*           the remote gdbserver process, running on Linux for ARC700        */
/*                                                                            */
/*           ARC-specific modules:                                            */
/*                arc-tdep                                                    */
/*                arc-linux-tdep                                              */
/*                                                                            */
/*     This module provides operations which are common to both; operations   */
/*     which are specific to one, or which have different variants in each    */
/*     configuration, are provided by the other modules.                      */
/*                                                                            */
/*                                                                            */
/* Debug Targets:                                                             */
/*     The ARC gdb supports a number of debug targets.  These are:            */
/*                                                                            */
/*         arc-elf32-gdb                                                      */
/*             built-in simulator                       'target sim'          */
/*             ARCangel 4 h/w emulator                  'target arcjtag'      */
/*             dynamically loaded xISS simulator        'target arcxiss'      */
/*             separately executing xISS simulator      'target remote'       */
/*                                                                            */
/*         arc-linux-uclibc-gdb                                               */
/*             gdbserver running on ARC Linux           'target remote'       */
/*                                                                            */
/*     It should, in theory, be possible for either debugger to connect to    */
/*     any remote target which supports the gdb Remote Serial Protocol.       */
/*     However, any such target MUST agree with the debugger on the register  */
/*     numbering scheme that is used, as this controls the order of register  */
/*     contents held in the RSP 'G' (set all registers) packet and the 'g'    */
/*     (get all registers) response packet, as well as the register numbers   */
/*     used in the 'P' (set one register) and 'p' (get one register) packets, */
/*     and in the 'T' stop reply packet.  The schemes used by each debugger   */
/*     are defined in the arc-elf32-tdep and arc-linux-tdep modules.          */
/*                                                                            */
/******************************************************************************/

/* system header files */
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <byteswap.h>

/* gdb header files */
#include "defs.h"
#include "config.h"
#include "arch-utils.h"
#include "dis-asm.h"
#include "frame.h"
#include "frame-unwind.h"
#include "inferior.h"
#include "regcache.h"
#include "reggroups.h"
#include "trad-frame.h"
#include "dwarf2-frame.h"
#include "gdbcore.h"
#include "observer.h"
#include "osabi.h"
#include "gdbcmd.h"
#include "block.h"
#include "dictionary.h"
#include "language.h"
#include "demangle.h"
#include "objfiles.h"
#include "gdb_assert.h"

/* ARC header files */

/* N.B. one and only one of ARC_ELF32_TARGET and ARC_LINUX_TARGET must be defined!  */

#ifdef ARC_ELF32_TARGET
#ifdef ARC_LINUX_TARGET
#error ARC build is not correctly configured (both flags set)
#else
#include "config/arc/tm-embed.h"
#endif
#else
#ifdef ARC_LINUX_TARGET
#include "config/arc/tm-linux.h"
#else
#error ARC build is not correctly configured (no flag set)
#endif
#endif

#include "opcode/arc.h"
#include "opcodes/arc-dis.h"
#include "opcodes/arc-ext.h"
#include "opcodes/arcompact-dis.h"
#include "arc-support.h"
#include "arc-tdep.h"


/* -------------------------------------------------------------------------- */
/*                               local types                                  */
/* -------------------------------------------------------------------------- */

typedef struct
{
    const char  *name;
    CORE_ADDR    address;
    Boolean      is_argument;
    Boolean      is_callee;
    Boolean      is_array;
    unsigned int size;
    unsigned int element_size;
} LocalVariable;


/* The frame unwind cache for the ARC.  */

typedef struct
{
    /* BLINK save location offset from previous SP (-ve value).  */
    int blink_save_offset_from_prev_sp;

    /* The stack pointer at the time this frame was created; i.e. the
       caller's stack pointer when this function was called.  It is used
       to identify this frame.  */
    CORE_ADDR prev_sp;

    /* The frame base (as held in FP).
       N.B. this is NOT the address of the lowest word in the frame!  */
    CORE_ADDR frame_base;

    /* Change in SP from previous SP (-ve value) - this is computed by scanning
       the prologue of the function: initially 0, it is updated for each
       instruction which changes SP (either explicitly by a subtraction from SP
       or implicitly by a push operation), so at each point in the prologue it
       gives the difference between the previous SP (i.e. before the function
       was called) and the current SP at that point; at the end of the prologue
       it holds the total change in SP, i.e. the size of the frame.  */
    LONGEST delta_sp;

    /* Offset of old stack pointer from frame base (+ve value).  */
    LONGEST old_sp_offset_from_fp;

    /* Is this a leaf function? */
    Boolean is_leaf;
    /* Is there a frame pointer? */
    Boolean uses_fp;

    /* Offsets for each register in the stack frame.  */
    struct trad_frame_saved_reg *saved_regs;
    unsigned int                 saved_regs_mask;
} UnwindCache;


/* -------------------------------------------------------------------------- */
/*                               local data                                   */
/* -------------------------------------------------------------------------- */

#define DEBUG_COMMAND               "arc-debug"
#define SHOW_FRAME_COMMAND          "arc-show-frame"
#define SHOW_FRAME_COMMAND_USAGE    "Usage: " SHOW_FRAME_COMMAND " [ <FRAME> ]\n"

#define NEW_LINE                     _("\n")


/* -------------------------------------------------------------------------- */
/*                               externally visible data                      */
/* -------------------------------------------------------------------------- */

/* Global debug flag.  */
Boolean arc_debug_target;


/* -------------------------------------------------------------------------- */
/*                               local macros                                 */
/* -------------------------------------------------------------------------- */

#define WORD_ALIGNED(addr)         ((addr) & ~(BYTES_IN_WORD - 1))
#define WORDS_OCCUPIED(bytes)      (((bytes) + BYTES_IN_WORD - 1) / BYTES_IN_WORD)
#define ROUND_UP_TO_WORDS(bytes)   (WORDS_OCCUPIED(bytes) * BYTES_IN_WORD)



/* Macros to be used with disassembling the prologue and update the frame info.
   The *FI macros are to update the frame info and the ACT macros are to
   actually do the action on a corresponding match.  */

#define IS_INSTRUCTION(insn_name, search_string)    !strcmp(insn_name, search_string)

#define CHECK_OPERAND_STRING_AND_ACT(target_check, search_string, action) \
    if (strstr(target_check, search_string) == target_check)              \
    {                                                                     \
        action;                                                           \
        return TRUE;                                                      \
    }


/* The frame info changes by changing the decrementing the delta_sp and setting
   the leaf function flag to be False (if this function prologue is saving blink
   then it must be going to call another function - so it can not be a leaf!);
   also the offset of the blink register save location from the previous value
   of sp is recorded.  This will eventually used to compute the address of the
   save location:

           <blink saved address> = <prev sp> + <blink offset from prev sp>

   The addition (+=) below is because the sp offset and the instruction offset
   are negative - so incrementing the sp offset by the instruction offset is
   actually making the sp offset more negative, correctly reflecting that SP
   is moving further down the downwards-growing stack.  */

#define PUSH_BLINK(offset)                                           \
    {                                                                \
        info->delta_sp += offset;                                    \
        info->blink_save_offset_from_prev_sp = (int) info->delta_sp; \
        info->is_leaf = FALSE;                                       \
    }

#define PUSH_BLINK_ACT                          \
    do {                                        \
           if (info) PUSH_BLINK(instr->_offset) \
       } while (0);


#define IS_PUSH_BLINK_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "blink", PUSH_BLINK_ACT)


/* At the point that that FP is pushed onto the stack (so saving the dynamic
   link chain pointer to the previous frame), at the address that will be the
   base of the new frame, we know the offset of SP from the previous SP - so the
   offset of the old SP from the new frame base is known (the -ve delta_sp is
   negated to give the +ve old_sp_offset_from_fp).  */
#define PUSH_FP_ACT  do {                                                       \
                            if (info)                                           \
                            {                                                   \
                                 info->delta_sp += instr->_offset;              \
                                 info->old_sp_offset_from_fp = -info->delta_sp; \
                        }} while (0);

#define IS_PUSH_FP_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp", PUSH_FP_ACT)


#define UPDATE_FP_ACT    do {                         \
                             if (info)                \
                                info->uses_fp = TRUE; \
                          } while (0);

#define IS_UPDATE_FP_FI(state)                                                    \
   if (IS_INSTRUCTION(state->instrBuffer, "mov"))                                 \
   {                                                                              \
      CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp,sp", UPDATE_FP_ACT); \
   }


#define UPDATE_STACK_SPACE(state)    do {                                                 \
                                       if (info) {                                        \
                                          /* Eat up sp,sp.  */                            \
                                          int immediate = atoi(state->operandBuffer + 6); \
                                          info->delta_sp -= immediate;                    \
                                      }} while (0);


#define IS_SUB_SP_FI(state)                                                                    \
    if (IS_INSTRUCTION(state->instrBuffer, "sub") ||                                           \
        IS_INSTRUCTION(state->instrBuffer, "sub_s"))                                           \
    {                                                                                          \
        CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "sp,sp", UPDATE_STACK_SPACE(state)) \
    }


/* -------------------------------------------------------------------------- */
/*                              forward declarations                          */
/* -------------------------------------------------------------------------- */

static CORE_ADDR scan_prologue (CORE_ADDR          entrypoint,
                                struct frame_info *next_frame,
                                UnwindCache       *info);


/* -------------------------------------------------------------------------- */
/*                               local debug functions                        */
/* -------------------------------------------------------------------------- */

/* Print information for a frame.  */

static void
printFrameInfo (const char  *message,
                UnwindCache *info,
                Boolean      addresses_known)
{
    unsigned int i;

    DEBUG("-------------------\n");
    DEBUG("%s (info = %p)\n",     message, info);
    DEBUG("prev_sp               = %lx\n", (long unsigned int) info->prev_sp);
    DEBUG("frame_base            = %lx\n", (long unsigned int) info->frame_base);
    DEBUG("blink offset          = %d\n",                      info->blink_save_offset_from_prev_sp);
    DEBUG("delta_sp              = %d\n",  (int)               info->delta_sp);
    DEBUG("old_sp_offset_from_fp = %d\n",  (int)               info->old_sp_offset_from_fp);
    DEBUG("is_leaf = %d, uses_fp = %d\n", info->is_leaf, info->uses_fp);

     for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++)
     {
        if (info->saved_regs_mask & (1 << i))
            DEBUG("saved register R%02d %s 0x%lx\n",
                  i,
                  (addresses_known) ? "address" : "offset",
                  (unsigned long) info->saved_regs[i].addr);
    }
    DEBUG("-------------------\n");
}


static const char*
ARC_Debugger_OperandType_Image (enum ARC_Debugger_OperandType value)
{
    switch (value)
    {
        case ARC_LIMM          : return "LIMM";
        case ARC_SHIMM         : return "SHIMM";
        case ARC_REGISTER      : return "REGISTER";
        case ARCOMPACT_REGISTER: return "COMPACT REGISTER";
        case ARC_UNDEFINED     : return "UNDEFINED";
    }
    return "?";
}


/* Print the instruction state returned by the disassembler.
   Used for internal debugging only.  */

static void
printInsnState (struct arcDisState state)
{
    DEBUG("---------------------------------\n");
    DEBUG("Instruction Length %d\n",          state.instructionLen);
    DEBUG("Opcode [0x%x] : Cond [%x]\n",      state._opcode, state._cond);
    DEBUG("Words 1 [%lx] : 2 [%lx]\n",        state.words[0], state.words[1]);
    DEBUG("Ea present [%x] : memload [%x]\n", state._ea_present, state._mem_load);
    DEBUG("Load Length [%d]:\n",              state._load_len);
    DEBUG("Address Writeback [%d]\n",         state._addrWriteBack);
    DEBUG("EA reg1 is [%x] offset [%x]\n",    state.ea_reg1, state._offset);
    DEBUG("EA reg2 is [%x]\n",                state.ea_reg2);
    DEBUG("Instr   buffer is %s\n",           state.instrBuffer);
    DEBUG("Operand buffer is %s\n",           state.operandBuffer);
    DEBUG("SourceType is %s\n",               ARC_Debugger_OperandType_Image(state.sourceType));
    DEBUG("Source operand is %u\n",           state.source_operand.registerNum);   /* All fields of the union have same type.  */
    DEBUG("Flow is %d\n",                     state.flow);
    DEBUG("Branch is %d\n",                   state.isBranch);
    DEBUG("---------------------------------\n");
}


/* -------------------------------------------------------------------------- */
/*                     local functions for the disassembler                   */
/* -------------------------------------------------------------------------- */

/* Wrapper for the target_read_memory function.  */

static int
read_memory_for_disassembler (bfd_vma                  memaddr,
                              bfd_byte                *myaddr,
                              unsigned int             length,
                              struct disassemble_info *info)    // unused
{
    return target_read_memory((CORE_ADDR) memaddr, (gdb_byte*) myaddr, (int) length);
}


/* This is a callback function which gets called by gdb whenever the current
   object file changes.  */

static void
set_disassembler (struct objfile *objfile)
{
    if (objfile)
    {
       /* The ARC libopcodes wants obfd so that it can find out what CPU
          extensions are defined in the file.  */
        set_gdbarch_print_insn(current_gdbarch, arcompact_get_disassembler(objfile->obfd));
//      dump_ARC_extmap();
    }
}


/* This function is supplied to gdb as the disassembler until such time as we do
   have a disassembler available.  */

static int
dummy_disassembler (bfd_vma address, disassemble_info *info)
{
    error(_("No disassembly operation yet available (no executable file loaded)"));
    return 0;
}


/* -------------------------------------------------------------------------- */
/*               local functions for decoding call chains                     */
/* -------------------------------------------------------------------------- */

/* Simple utility function to create a new frame cache structure.  */

static UnwindCache*
create_cache (struct frame_info *next_frame)
{
    UnwindCache *cache = FRAME_OBSTACK_ZALLOC (UnwindCache);

    /* Zero all fields.  */
    cache->blink_save_offset_from_prev_sp = 0;
    cache->prev_sp                        = 0;
    cache->frame_base                     = 0;
    cache->delta_sp                       = 0;
    cache->old_sp_offset_from_fp          = 0;
    cache->is_leaf                        = FALSE;
    cache->uses_fp                        = FALSE;

    /* Allocate space for saved register info.  */
    cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);

    return cache;
}


/* Compute the previous frame's stack pointer (which is also the frame's ID's
   stack address), and this frame's base pointer.  */

static void
find_previous_stack_pointer (UnwindCache       *info,
                             struct frame_info *next_frame)
{
    ENTERARGS("next_frame = %p", next_frame);

    /* If the frame has a frame pointer.  */
    if (info->uses_fp)
    {
        ULONGEST     this_base;
        unsigned int i;

        /* 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. The old contents of FP were saved in the location
           at the base of this frame, so this also gives us the address of
           the FP save location.  */
	this_base = frame_unwind_register_unsigned(next_frame, ARC_FP_REGNUM);
        info->frame_base                     = (CORE_ADDR) this_base;
        info->saved_regs[ARC_FP_REGNUM].addr = (long long) this_base;

        /* The previous SP is the current frame base + the difference between
           that frame base and the previous SP.  */
        info->prev_sp = info->frame_base + (CORE_ADDR) info->old_sp_offset_from_fp;

        for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++)
        {
            /* If this register has been saved, add the previous stack pointer
               to the offset from the previous stack pointer at which the
               register was saved, so giving the address at which it was saved.  */
            if (info->saved_regs_mask & (1 << i))
            {
                info->saved_regs[i].addr += info->prev_sp;

#ifdef DUMP_SAVED_REGISTERS
                /* This is a really useful debugging aid: we can debug a test
                   program which loads known values into the callee-saved
                   registers, then calls another function which uses those
                   registers (and hence must save them) then hits a breakpoint;
                   traversing the stack chain (e.g. with the 'where' command)
                   should then execute this code, and we should see those known
                   values being dumped, so showing that we have got the right
                   addresses for the save locations!  */
                {
                    unsigned int contents;

                    DEBUG("saved R%02d is at 0x%lx\n", i, (long unsigned int) info->saved_regs[i].addr);

                    if (target_read_memory((CORE_ADDR) info->saved_regs[i].addr,
                                           (gdb_byte*) &contents,
                                           BYTES_IN_REGISTER) == 0)
                    {
                        DEBUG("saved R%02d contents: 0x%0x\n", i, contents);
                    }
                }
#endif
            }
        }
    }
    else
    {
        ULONGEST this_sp;

        /* Get the stack pointer for this frame by getting the saved SP
           from the next frame.  */
 	this_sp = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM);

        /* The previous SP is this frame's SP plus the known difference between
           the previous SP and this frame's SP (the delta_sp is negated as it is
           a negative quantity).  */
        info->prev_sp = (CORE_ADDR) (this_sp + (ULONGEST) (-info->delta_sp));

        /* Assume that the FP is this frame's SP.  */
        info->frame_base = (CORE_ADDR) this_sp;
    }

    /* If the function owning this frame is not a leaf function.  */
    if (!info->is_leaf)
    {
        /* Usually blink is saved above the callee save registers and below the
           space created for variable arguments. The quantity

                    info->blink_save_offset_from_prev_sp

           is negative, so adding it to the the previous SP gives the address of
           a location further down the stack from that SP.  */
        info->saved_regs[ARC_BLINK_REGNUM].addr =
            (LONGEST) (info->prev_sp + info->blink_save_offset_from_prev_sp);
    }
}


/* The workhorse : frame_unwind_cache for the ARC700 target.  */

static UnwindCache *
frame_unwind_cache (struct frame_info *next_frame,
                    void             **this_prologue_cache)
{
    ENTERMSG;

    if ((*this_prologue_cache) == NULL)
    {
        CORE_ADDR    entrypoint = frame_func_unwind(next_frame, NORMAL_FRAME);
        UnwindCache *cache      = create_cache(next_frame);

        /* Return the newly-created cache.  */
        *this_prologue_cache = cache;

        /* Prologue analysis does the rest... */

        /* Currently our scan prologue does not support getting input for the
           frame unwinder.  */
        (void) scan_prologue(entrypoint, next_frame, cache);
    }

    return *this_prologue_cache;
}


/* -------------------------------------------------------------------------- */
/*               local functions for decoding function prologues              */
/* -------------------------------------------------------------------------- */

/* This function determines whether the given register, which is being saved
   by a function prologue on the stack at a known offset from the current SP,
   is a callee-saved register.  If it is, the information in the frame unwind
   cache is updated.  */

static Boolean
is_callee_saved_register (unsigned int  reg,
                          int           offset,
                          UnwindCache * info)
{
    if (ARC_ABI_FIRST_CALLEE_SAVED_REGISTER <= reg && reg <= ARC_ABI_LAST_CALLEE_SAVED_REGISTER)
    {
        DEBUG("register R%02u saved\n", reg);

        if (info)
        {
            /* We can not determine the address of the location in the stack
               frame in which the register was saved, as we do not (yet) know
               the frame or stack pointers for the frame; so the most we can do
               is to record the offset from the old SP of that location, which
               we can compute as we know the offset of SP from the old SP, and
               the offset of the location from SP (which is the offset in the
               store instruction).

               N.B. the stack grows downward, so the store offset is positive,
                    but the delta-SP is negative, so the save offset is also
                    negative.

                                             |            |
                              old sp ------> |------------|
                            /                |            |  \
                            :                |            |  :
                            :                |            |  :    -ve
                            :                |            |  : save offset
                            :                |------------|  :
                    -ve     :                |  save loc  |  /
                  delta sp  :                |------------| <--- store address
                            :            /   |            |
                            :     +ve    :   |            |
                            :    store   :   |            |
                            :    offset  :   |            |
                            \            \   |            |
                              sp' ---------> |            |
                                             |            |
                                             |            |
                                             |------------| <---- frame base
                                             |            |
                                             |            |
                                             |            |
                                             |     |      |
                                                   |
                                                   V
                                               downwards

               where sp' is the stack pointer at the current point in the code */

            info->saved_regs[reg].addr = info->delta_sp + offset;

            /* We now know that this register has been saved, so set the
               corresponding bit in the save mask.  */
            info->saved_regs_mask |= (1 << reg);

            printFrameInfo("after callee register save", info, FALSE);

            return TRUE;
        }
    }

    return FALSE;
}


/* This function determines whether the given disassembled instruction may be
   part of a function prologue.  If it is, the information in the frame unwind
   cache may be updated.  */

static Boolean
is_in_prologue (UnwindCache *info, struct arcDisState *instr)
{
    /* Might be a push or a pop */
    if (instr->_opcode == 0x3)
    {
        if (instr->_addrWriteBack != (char) 0)
        {
            /* This is a st.a instruction.  */
            if (instr->ea_reg1 == ARC_ABI_STACK_POINTER)
            {
                if (instr->_offset == -4)
                {
                    /* This is a push something at SP.  */
                    /* Is it a push of the blink?  */
                    IS_PUSH_BLINK_FI(instr);

                    /* Is it a push for fp?  */
                    IS_PUSH_FP_FI(instr);
                }
                else
                {
                    if (instr->sourceType == ARC_REGISTER )
                    {
                        /* st.a <reg>, [sp,<offset>] */

                        if (is_callee_saved_register(instr->source_operand.registerNum,
                                                     instr->_offset,
                                                     info))
                        {
                            /* This is a push onto the stack, so change delta_sp.  */
                            info->delta_sp += instr->_offset;
                            return TRUE;
                        }
                    }
                }
           }
        }
        else
        {
            if (instr->sourceType == ARC_REGISTER )
            {
                /* Is this a store of some register onto the stack using the
                   stack pointer?  */
                if (instr->ea_reg1 == ARC_ABI_STACK_POINTER)
                {
                    /* st <reg>, [sp,offset] */

                    if (is_callee_saved_register(instr->source_operand.registerNum,
                                                 instr->_offset,
                                                 info))
                        /* This is NOT a push onto the stack, so do not change delta_sp.  */
                        return TRUE;
                }

                /* Is this the store of some register on the stack using the
                   frame pointer? We check for argument registers getting saved
                   and restored.  */
                if (instr->ea_reg1 == ARC_ABI_FRAME_POINTER)
                {
                    if (IS_ARGUMENT_REGISTER(instr->source_operand.registerNum))
                    {
                        /* Saving argument registers. Don't set the bits in the
                           saved mask, just skip.  */
                        return TRUE;
                    }
                }
            }
        }
    }

    else if (instr->_opcode == 0x4)
    {
        /* A major opcode 0x4 instruction.  */
        /* We are usually interested in a mov or a sub.  */
        IS_UPDATE_FP_FI(instr);
        IS_SUB_SP_FI(instr);
    }

    else if (instr->_opcode == 0x18)
    {
        /* sub_s sp,sp,constant */
        IS_SUB_SP_FI(instr);

        /* push_s blink */
        if (strcmp(instr->instrBuffer, "push_s") == 0)
        {
            if (strcmp(instr->operandBuffer, "blink") == 0)
            {
                if (info)
                {
                    /* SP is decremented by the push_s instruction (before it
                       stores blink at the stack location addressed by SP).  */
                    PUSH_BLINK(-BYTES_IN_REGISTER)
                }
                return TRUE;
            }
        }
        else if (strcmp(instr->instrBuffer, "st_s") == 0)
        {
            unsigned int reg;
            int          offset;

            if (sscanf(instr->operandBuffer, "r%u,[sp,%d]", &reg, &offset) == 2)
            {
                /* st_s <reg>,[sp,<offset>] */

                if (is_callee_saved_register(reg, offset, info))
                    /* This is NOT a push onto the stack, so do not change delta_sp.  */
                    return TRUE;
            }
        }
    }

    return FALSE;
}


/* Scan the prologue and update the corresponding frame cache for the frame
   unwinder for unwinding frames without debug info. In such a situation GDB
   attempts to parse the prologue for this purpose. This currently would attempt
   to parse the prologue generated by our gcc 2.95 compiler (we should support
   Metaware generated binaries at some suitable point of time).

   This function is called with:
      entrypoint : the address of the functon entry point
      next_frame : the next frame to be filled in (if need be)
      info       : the existing cached info.

   Returns: the address of the first instruction after the prologue.

   This function is called by our unwinder as well as from arc_skip_prologue
   in the case that it cannot detect the end of the prologue.

   'next_frame' and 'info' are NULL if this function is called from
   arc_skip_prologue in an attempt to discover the end of the prologue.
   In this case we don't fill in the 'info' structure that is passed in.

   TODOs:
      1. Support 32 bit normal frames generated by GCC 2.95
      2. Support 16 and 32 bit mixed frames generated by GCC 2.95
      3. Support 32 bit normal variadic function frames by GCC 2.95
      4. Support 32 bit normal frames from GCC 3.4.x with variadic args
      5. Support 16 and 32 bit normal frames from GCC 3.4.x with variadic args
      6. Support 16 and 32 bit mixed frames generated by GCC 3.4.x
      7. Support Metaware generated prologues
           (The difference is in the use of thunks to identify the saving and
            restoring of callee saves: may have to do some hackery even in
            next_pc, since the call is going to create its own set of problems
            with our stack setup).

   We attempt to use the disassembler interface from the opcodes library to do
   our disassembling.

   The usual 32 bit normal gcc -O0 prologue looks like this:

   Complete Prologue for all GCC frames (Cases #1 to #6 in TODOs above):

      sub  sp, sp, limm         ; space for variadic arguments
      st.a blink, [sp,-4]       ; push blink (if not a leaf function) - decrements sp
      sub  sp, sp , limm        ; (optional space creation for callee saves)
      st   r13, [sp]            ; push of first callee saved register
      st   r14, [sp,4]          ; push of next callee saved register
      ...
      st.a fp , [sp,-4]         ; push fp (if fp has to be saved) - decrements sp
      mov  fp , sp              ; set the current frame up correctly
      sub  sp , sp , #immediate ; create space for local vars on the stack   */

/* 3 instructions before and after callee saves, and max number of saves; assume each is 4-byte inst.  */
#define MAX_PROLOGUE_LENGTH   ((6 + (ARC_ABI_LAST_CALLEE_SAVED_REGISTER - ARC_ABI_FIRST_CALLEE_SAVED_REGISTER + 1)) * 4)

static CORE_ADDR
scan_prologue (CORE_ADDR          entrypoint,
               struct frame_info *next_frame,
               UnwindCache       *info)
{
    ENTERARGS("next_frame = %p, info = %p", next_frame, info);

    {
        /* Will be set to end of prologue.  */
        CORE_ADDR               prologue_ends_pc = entrypoint;
        struct disassemble_info di;

        /* An arbitrary limit on the length of the prologue. If next_frame is
           NULL this means that there was no debug info and we are called from
           arc_skip_prologue; otherwise, if we know the frame, we can find the
           pc within the function.

           N.B. that pc will usually be after the end of the prologue, but
                it could actually be within the prologue (i.e. execution has
                halted within the prologue, e.g. at a breakpoint); in that
                case, do NOT go beyond that pc, as the instructions at the
                pc and after have not been executed yet, so have had no effect!  */
        CORE_ADDR final_pc = (next_frame) ? frame_pc_unwind(next_frame)
                                          : entrypoint + MAX_PROLOGUE_LENGTH;

        if (info)
        {
            /* Assume that the function is a leaf function until we find out
               that it is not (i.e. when we find the 'push blink' instruction
               in the prologue).  */
            info->is_leaf = TRUE;

            /* No registers known to be saved, as yet.  */
            info->saved_regs_mask = 0;
        }

        /* Initializations to use the opcodes library.  */
        arc_initialize_disassembler(&di);

        DEBUG("Prologue PC: %lx\n", (unsigned long) prologue_ends_pc);
        DEBUG("Final    PC: %lx\n", (unsigned long) final_pc);

        /* Look at each instruction in the prologue.  */
        while (prologue_ends_pc < final_pc)
        {
            struct arcDisState current_instr = arcAnalyzeInstr(prologue_ends_pc, &di);

            printInsnState(current_instr);

            /* If this instruction is in the prologue, fields in the info will be updated,
               and the saved registers mask may be updated.  */
            if (!is_in_prologue(info, &current_instr))
            {
                /* Found a instruction that is not in the prologue.  */
                DEBUG("End of Prologue reached \n");
                break;
            }

            prologue_ends_pc += current_instr.instructionLen;
        }

        /* Means we were not called from arc_skip_prologue.  */
        if (!((next_frame == NULL) && (info == NULL)))
        {
            printFrameInfo("after prologue", info, FALSE);

            find_previous_stack_pointer(info, next_frame);

            /* The PC is found in blink (the actual register or located on the stack).  */
            info->saved_regs[ARC_PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];

            printFrameInfo("after previous SP found", info, TRUE);
        }

        return prologue_ends_pc;
    }
}


/* -------------------------------------------------------------------------- */
/*              local functions for handling function return values           */
/* -------------------------------------------------------------------------- */

/* This function gets the return value of a function from the registers used to
   return it, according to the convention used by the ABI.

   Parameters:
      type     : the information for the return type of the function
      regcache : the register cache holding the register contents
      valbuf   : a buffer to be filled with the return value
*/

static void
extract_return_value (struct type     *type,
                      struct regcache *regcache,
                      gdb_byte        *valbuf)

{
    unsigned int len = TYPE_LENGTH (type);

    ENTERMSG;

    if (len <= BYTES_IN_REGISTER)
    {
        ULONGEST val;

        /* Get the return value from one register.  */
        regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_REGNUM, &val);
        store_unsigned_integer (valbuf, (int) len, val);

        DEBUG("returning 0x%08lX\n", (unsigned long) val);
    }
    else if (len <= BYTES_IN_REGISTER * 2)
    {
        ULONGEST low, high;

        /* Get the return value from two registers.  */
        regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM,  &low);
        regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, &high);

        store_unsigned_integer (valbuf,                     BYTES_IN_REGISTER,             low);
        store_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER, high);

        DEBUG("returning 0x%08lX%08lX\n",
              (unsigned long) high, (unsigned long) low);
    }
    else
        error(_("%s: type length %u too large"), __FUNCTION__, len);
}


/* This function loads the return value of a function into the registers used to
   return it, according to the convention used by the ABI.

   Parameters:
      type     : the information for the return type of the function
      regcache : the register cache holding the register contents
      valbuf   : a buffer holding the return value
*/

static void
store_return_value (struct type     *type,
                    struct regcache *regcache,
                    const  gdb_byte *valbuf)
{
    unsigned int len = TYPE_LENGTH (type);

    ENTERMSG;

    if (len <= BYTES_IN_REGISTER)
    {
        ULONGEST val;

        /* Put the return value into one register.  */
        val = extract_unsigned_integer (valbuf, (int) len);
        regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_REGNUM, val);

        DEBUG("storing 0x%08lX\n", (unsigned long) val);
    }
    else if (len <= BYTES_IN_REGISTER * 2)
    {
        ULONGEST low, high;

        /* Put the return value into  two registers.  */
        low  = extract_unsigned_integer (valbuf,                     BYTES_IN_REGISTER);
        high = extract_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER);

        regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM,  low);
        regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, high);

        DEBUG("storing 0x%08lX%08lX\n",
              (unsigned long) high, (unsigned long) low);
    }
    else
        error(_("arc_store_return_value: type length too large."));
}


/* -------------------------------------------------------------------------- */
/*                 local functions for handling the stack frame               */
/* -------------------------------------------------------------------------- */

/* This is copied from file stack.c in the gdb sources.
   It identifies a frame from information (such as frame number) given by the
   user (in the frame_exp parameter).  */

static struct frame_info*
parse_frame_specification_1 (const char *frame_exp,
                             const char *message,
                             int        *selected_frame_p)
{
    int           numargs = 0;
    struct value *args[4];
    CORE_ADDR     addrs[ARRAY_SIZE (args)];

    if (frame_exp)
    {
        while (TRUE)
        {
            char           *addr_string;
            struct cleanup *cleanup;
            const char     *p;

            /* Skip leading white space.  */
            while (isspace (*frame_exp))
                frame_exp++;

            if (*frame_exp == '\0')
                break;

            /* Parse the argument, extract it, save it.  */
            for (p = frame_exp; (*p != '\0') && !isspace (*p); p++);

            addr_string = savestring (frame_exp, (size_t) (p - frame_exp));
            frame_exp   = p;
            cleanup     = make_cleanup (xfree, addr_string);

            /* NOTE: Parse and evaluate expression, but do not use
               functions such as parse_and_eval_long or
               parse_and_eval_address to also extract the value.
               Instead value_as_long and value_as_address are used.
               This avoids problems with expressions that contain
               side-effects.  */
            if (numargs >= (int) ARRAY_SIZE (args))
                error (_("Too many args in frame specification"));

            args[numargs++] = parse_and_eval (addr_string);

            do_cleanups (cleanup);
        }
    }

    /* If no args, default to the selected frame.  */
    if (numargs == 0)
    {
        if (selected_frame_p != NULL)
            (*selected_frame_p) = 1;
        return get_selected_frame (message);
    }

    /* None of the remaining use the selected frame.  */
    if (selected_frame_p != NULL)
        (*selected_frame_p) = 0;

    /* Assume the single arg[0] is an integer, and try using that to
       select a frame relative to current.  */
    if (numargs == 1)
    {
        int                level = (int) value_as_long (args[0]);
        struct frame_info *fid   = find_relative_frame (get_current_frame (), &level);

        if (level == 0)
            /* find_relative_frame was successful.  */
            return fid;
    }

    /* Convert each value into a corresponding address.  */
    {
        int i;
        for (i = 0; i < numargs; i++)
            addrs[i] = value_as_address (args[i]);
    }

    /* Assume that the single arg[0] is an address, use that to identify
       a frame with a matching ID.  Should this also accept stack/pc or
       stack/pc/special.  */
    if (numargs == 1)
    {
        struct frame_id id = frame_id_build_wild (addrs[0]);
        struct frame_info *fid;

        /* If (s)he specifies the frame with an address, he deserves
           what (s)he gets.  Still, give the highest one that matches.
           (NOTE: cagney/2004-10-29: Why highest, or outer-most, I don't
           know).  */
        for (fid = get_current_frame ();
             fid != NULL;
             fid = get_prev_frame (fid))
        {
            if (frame_id_eq (id, get_frame_id (fid)))
            {
                while (frame_id_eq (id, frame_unwind_id (fid)))
                    fid = get_prev_frame (fid);
                return fid;
            }
        }
    }

    /* We couldn't identify the frame as an existing frame, but
       perhaps we can create one with a single argument.  */
    if (numargs == 1)
        return create_new_frame (addrs[0], 0);
    else if (numargs == 2)
        return create_new_frame (addrs[0], addrs[1]);
    else
        error (_("Too many args in frame specification"));
}


/* Return an array (and count) of the local variables and parameters declared
   in the function which owns the given frame.

   Parameters:
      frame    : the frame information for the function
      variables: a pointer to an existing array of variable information (may be NULL)
      count    : (IN/OUT) the total number of variables found
      callee   : TRUE if the function is a callee of another function

   Result:
      A pointer to an array containing one element for each parameter, and, if
      'callee' is FALSE, each local variable, of the function.  */

static LocalVariable*
find_variables (struct frame_info *frame,
                LocalVariable     *variables,
                unsigned int      *count,
                Boolean            callee)
{
    struct block *block = get_frame_block (frame, 0);
    unsigned int  vars  = *count;

    while (block)
    {
        struct dict_iterator iter;
        struct symbol       *sym;

        ALL_BLOCK_SYMBOLS (block, iter, sym)
        {
            Boolean   is_arg = (SYMBOL_CLASS(sym) == LOC_COMPUTED_ARG);
            CORE_ADDR addr;

            switch (SYMBOL_CLASS (sym))
            {
                case LOC_COMPUTED:
                case LOC_COMPUTED_ARG:
                    addr = SYMBOL_OPS (sym)->get_variable_address(sym, frame);

                    /* For callees, we are only interested in the arguments.  */
                    if ((addr != 0) && (!callee || is_arg))
                    {
                        struct type *type = SYMBOL_TYPE (sym);

                        vars++;
                        variables = xrealloc(variables, sizeof(LocalVariable) * vars);

                        if (variables)
                        {
                            LocalVariable *var = &variables[vars - 1];

                            var->name        = SYMBOL_PRINT_NAME (sym);
                            var->address     = addr;
                            var->is_callee   = callee;
                            var->is_argument = is_arg;
                            var->is_array    = (TYPE_CODE (type) == TYPE_CODE_ARRAY);
                            var->size        = SYMBOL_OPS (sym)->get_variable_size(sym, frame);

                            if (var->is_array)
                                var->element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (type));
                        }
                        else
                        {
                            *count = 0;
                            return NULL;
                        }
                    }
                    break;

                default:
                  /* Ignore symbols which are not locals.  */
                  break;
            }
        }

        /* After handling the function's top-level block, stop.  Don't continue
           to its superblock, the block of per-file symbols.  */
        if (BLOCK_FUNCTION (block))
            break;
        block = BLOCK_SUPERBLOCK (block);
    }

    *count = vars;
    return variables;
}


/* Return an array (and count) of the local variables declared in the function
   which owns the given frame, and also those declared in the function which is
   the callee (if any) of that function in the current call chain.  */

static LocalVariable*
find_local_variables (struct frame_info *frame, unsigned int *count)
{
    struct frame_info *callee = get_next_frame(frame);
    LocalVariable     *variables;

    *count = 0;

    variables = find_variables(frame, NULL, count, FALSE);

    if (callee)
        variables = find_variables(callee, variables, count, TRUE);

    return variables;
}


/* Try to add the name of a local variable or function parameter to a line of
   output, if a given address lies within the range of locations occupied by
   that data item.

   Parameters:
      line                   : the line in which any output is to be placed
      location               : the address of a location on the stack
      variables              : an array of local variables and parameters
      num_variables          : the number of elements in the array
      is_following_element   : set to TRUE if the location lies within an
                               array element, and it is not the 0th element
      elements_are_word_sized: set to TRUE if the array element is word-sized

   Returns TRUE if the given location holds a local variable or parameter
   (i.e. information has been added to the line of output).  */

static Boolean
add_local_name (char          *line,
                CORE_ADDR      location,
                LocalVariable *variables,
                unsigned int   num_variables,
                Boolean       *is_following_element,
                Boolean       *elements_are_word_sized)
{
    unsigned int i;

    *is_following_element    = FALSE;
    *elements_are_word_sized = FALSE;

    /* Look at each of the local variables / parameters in the array.  */
    for (i = 0; i < num_variables; i++)
    {
        LocalVariable *var   = &variables[i];
        int            index = -1;

        /* is the variable an array?  */
        if (var->is_array)
        {
            /* If we know the size of the array, and the size of its elements. */
            if (var->size > 0 && var->element_size > 0)
            {
                /* What is the offset of the given stack location from the start
                   of the array?  */
                int offset = (int) ((long int) location - (long int) var->address);

                /* Does that offset actually lie within the array?  */
                if (0 <= offset && offset < (int) var->size)
                {
                    /* Compute the index of the array element which contains the
                       location.  */
                    index = offset / var->element_size;
                }

                if (var->element_size == BYTES_IN_WORD)
                    *elements_are_word_sized = FALSE;
            }
        }

        /* If the variable starts in the given location, or the variable is an
           array and one of its elements contains the location. */
        if (var->address == location || index >= 0)
        {
            int n;

            /* What is the variable?  */
            if (var->is_callee)
                n = sprintf(line, _("callee parameter"));
            else if (var->is_argument)
                n = sprintf(line, _("parameter"));
            else
                n = sprintf(line, _("local variable"));

            line[n] = ' ';
            n++;
            n += sprintf(line + n, _("'%s'"),  var->name);
            line[n] = ' ';

            /* If it is an array element.  */
            if (index >= 0)
            {
                /* Add the array element index to the output.  */
                (void) sprintf(line + n, _("[%u]"), index);

                /* Is it an element which follows another element?  */
                *is_following_element = (index > 0);
            }
            else if (var->size > BYTES_IN_WORD)
            {
                /* It occupies more than one word.  */
                (void) sprintf(line + n + 1, _("(%u words)"),
                               WORDS_OCCUPIED(var->size));
            }

            return TRUE;
        }
     }

    return FALSE;
}


/* Try to identify the given frame, and output that identification.  */

static void
identify_frame (struct frame_info *frame)
{
    enum language          func_lang = language_unknown;
    char                  *func_name = NULL;
    char                  *demangled = NULL;
    struct symbol         *func;
    struct symtab_and_line sal;

    find_frame_sal (frame, &sal);
    func = get_frame_function (frame);

    /* Have we found the function owning the frame?  */
    if (func)
    {
        func_name = DEPRECATED_SYMBOL_NAME (func);
        func_lang = SYMBOL_LANGUAGE        (func);
    }
    else
    {
        struct minimal_symbol *msymbol;

        /* Try to find the symbol most closely associated with the PC
           corresponding to the frame.  */
        msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (frame));

        if (msymbol != NULL)
        {
            func_name = DEPRECATED_SYMBOL_NAME (msymbol);
            func_lang = SYMBOL_LANGUAGE        (msymbol);
        }
    }

    /* Have we found a name?  */
    if (func_name)
    {
        /* If user wants to see raw output, no problem.
           (demangle is a global flag which can be set by user command).  */
        if (demangle)
        {
            demangled = language_demangle (language_def (func_lang),
                                           func_name,
                                           DMGL_ANSI | DMGL_PARAMS);

            /* If the demangler fails, try the demangled name from the symbol
               table. That'll have parameters, but that's preferable to
               displaying a mangled name.  */
            if (demangled == NULL)
            {
                if (func == NULL)
                    func_name = _("<unknown function>");
                else
                    func_name = SYMBOL_PRINT_NAME (func);
            }
            else
                func_name = demangled;
        }
    }
    else
        func_name = _("<unknown function>");

    printf_filtered(_("Frame of function: %s"), func_name);
    if (sal.symtab)
        printf_filtered(_(" (%s:%d)"), sal.symtab->filename, sal.line);
    printf_filtered(NEW_LINE);

    if (demangled != NULL)
        xfree (demangled);
}


/* -------------------------------------------------------------------------- */
/*                       local functions called from gdb                      */
/* -------------------------------------------------------------------------- */

/*  Standard register type for the ARC platform.
    It would be builtin_type_uint32 until we consider the DSP extensions.  */

static struct type *
arc_register_type (struct gdbarch *gdbarch, int regnum)
{
    return builtin_type_uint32;
}


/* Skip the prologue for the function at pc.
   Returns the address of the first instruction after the prologue. */

static CORE_ADDR
arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
    CORE_ADDR function_addr, function_end = 0;
    char     *function_name;

   /* This is done by checking from the line information read from the DWARF,
      if possible; otherwise, we scan the function prologue to find its end.  */

    ENTERMSG;

    /* If we're in a dummy frame, don't even try to skip the prologue.  */
    if (deprecated_pc_in_call_dummy (pc))
        return pc;

    /* See what the symbol table says.  */
    if (find_pc_partial_function (pc, &function_name, &function_addr, &function_end))
    {
        /* Found a function.  */
        struct symbol *sym = lookup_symbol (function_name, NULL, VAR_DOMAIN, NULL, NULL);

        if ((sym != NULL) && SYMBOL_LANGUAGE (sym) != language_asm)
        {
            /* Don't use this trick for assembly source files.  */
            struct symtab_and_line sal = find_pc_line (function_addr, 0);

            if ((sal.line != 0) && (sal.end < function_end))
                return sal.end;
        }
    }

    /* Find the address of the first instruction after the prologue by scanning
       through it - no other information is needed, so pass NULL for the other
       parameters.  */
    return scan_prologue(pc, NULL, NULL);
}


/* Construct frame id for the normal frame.  */

static void
arc_frame_this_id (struct frame_info *next_frame,
                   void             **this_prologue_cache,
                   struct frame_id   *this_id)
{
    ENTERMSG;

    /* FIXME: to what should *this_id be set if the frame base can not be found? */

    {
        /* Find the entry point of the function which owns the frame.  */
        CORE_ADDR entrypoint = frame_func_unwind (next_frame, NORMAL_FRAME);

        /* This is meant to halt the backtrace at the entry point (_start)
           (it assumes that there is no code at a lower address).  */
        if (entrypoint > gdbarch_tdep (current_gdbarch)->lowest_pc)
        {
            UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache);
            CORE_ADDR    base = info->prev_sp;

            /* 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".  */

            if (base != 0)
            {
                /* Build the ID from the frame base address.  */
                *this_id = frame_id_build (base, entrypoint);

#if 0
                printf("*** Frame ID: %x ==> (%x %x %x)\n",
                       base,
                       this_id->stack_addr,
                       this_id->code_addr,
                       this_id->special_addr);
#endif
            }
        }
    }
}


/* Unwind and obtain the register information.  */

static void
arc_frame_prev_register (struct frame_info *next_frame,
                         void             **this_prologue_cache,
                         int                regnum,
                         int               *optimized,
                         enum lval_type    *lval,
                         CORE_ADDR         *addr,
                         int               *realnum,
                         gdb_byte          *buffer)
{
    ENTERARGS("regnum %d ", regnum);

    {
        UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache);

        /* If we are asked to unwind the PC, then we need to return blink
           instead: the saved value of PC points into this frame's function's prologue,
           not the next frame's function's resume location.  */
        if (regnum == ARC_PC_REGNUM)
            regnum = ARC_BLINK_REGNUM;

        /* SP is generally not saved to the stack, but this frame is identified
           by next_frame's stack pointer at the time of the call. The value was
           already reconstructed into prev_sp.  */
        if (regnum == ARC_SP_REGNUM)
        {
            /* This value is not an L-value, i.e. it can not be changed, because
               it is implicit in the structure of the call-chain.  */
            *lval = not_lval;

            if (buffer)
                store_unsigned_integer (buffer, BYTES_IN_REGISTER, info->prev_sp);
            return;
        }

        trad_frame_get_prev_register (next_frame,
                                      info->saved_regs,
                                      regnum,
                                      optimized,
                                      lval,
                                      addr,
                                      realnum,
                                      buffer);

        DEBUG("-*-*-*\n Regnum = %d, buffer = %p\n", regnum, buffer);
    }
}


/* This function is passed to gdb to enable it to unwind frames.  */

static const struct frame_unwind *
arc_frame_sniffer (struct frame_info *next_frame)
{
    static const struct frame_unwind arc_frame_unwind =
    {
        NORMAL_FRAME,                // type
        arc_frame_this_id,           // this_id
        arc_frame_prev_register,     // prev_register
        NULL,                        // unwind_data
        NULL,                        // sniffer
        NULL,                        // prev_pc
        NULL                         // dealloc_cache
    };

    return &arc_frame_unwind;
}


/* Get the breakpoint which is appropriate for address at which it is to be set.

   Return whatever is in the ARC-private tdep structure (this has been set up
   according to the correct target / architecture chosen).

   Fortunately, the ARC processor does not have separate instruction sets (like
   the ARM's normal 32-bit and 16-bit Thumb instructions), so the bp instruction
   to be used does not depend on the address (although the ARC does have both
   16- and 32-bit instructions, they may be freely intermixed).  */

static const unsigned char *
arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
    struct gdbarch_tdep *tdep = gdbarch_tdep       (gdbarch);
    int    end                = gdbarch_byte_order (gdbarch);

    /* Return the breakpoint instruction length.  */
    *lenptr = (int) tdep->breakpoint_size;

    /* Return the breakpoint instruction code.  */
    if (end == BFD_ENDIAN_LITTLE)
        return tdep->le_breakpoint_instruction;
    if (end == BFD_ENDIAN_BIG)
        return tdep->be_breakpoint_instruction;

    internal_error (__FILE__, __LINE__, "target endianness is not known");
}


/* Determine whether the given register is a member of the given group.

   Returns 0, 1, or -1:
      0 means the register is not in the group.
      1 means the register is in the group.
     -1 means the tdep has nothing to say about this register and group.  */

static int
arc_register_reggroup_p (struct gdbarch  *gdbarch,
                         int              regnum,
                         struct reggroup *group)
{
    struct gdbarch_tdep *tdep        = gdbarch_tdep (gdbarch);
    int                  tdep_answer = tdep->register_reggroup_p (regnum, group);

    /* If the configuration-specific tdep knows about this register.  */
    if (tdep_answer != -1)
        return tdep_answer;

    if (group == all_reggroup)
        return 1;

    if (group == save_reggroup || group == restore_reggroup)
    {
        /* Don't save/restore read-only registers.  */
	return (!gdbarch_cannot_store_register(current_gdbarch, regnum));
    }

    if (group == system_reggroup)
    {
        if (regnum == ARC_ILINK1_REGNUM ||
            regnum == ARC_ILINK2_REGNUM)
            return 1;

        return 0;
    }

    internal_error(__FILE__, __LINE__, _("bad register group"));
    return 0;
}


/* This function is used by the DWARF-2 frame sniffer.
   It is the architecture-specific register state initialization function:
   it tells gdb how to find certain registers in the DWARF-2 Call Frame Information.  */

static void
arc_dwarf2_frame_init_reg (struct gdbarch                *gdbarch,
                           int                            regnum,
                           struct dwarf2_frame_state_reg *reg,
                           struct frame_info             *info)
{
//  ENTERARGS("Regno no:%d, 0x%x", regnum, (unsigned int) regnum);

    /* Make sure that we know the number of the PC!  */
    arc_check_pc_defined(gdbarch);

    /* The return address column.  */
    if (regnum == ARC_PC_REGNUM)
        reg->how = DWARF2_FRAME_REG_RA;

    /* The call frame address.  */
    if (regnum == ARC_SP_REGNUM)
        reg->how = DWARF2_FRAME_REG_CFA;
}


/* Unwind the frame to find the previous frame's PC.  */

static CORE_ADDR
arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
    ULONGEST pc;

    /* Make sure that we know the number of the PC!  */
    arc_check_pc_defined(gdbarch);

    pc = frame_unwind_register_unsigned (next_frame, ARC_PC_REGNUM);

    DEBUG("unwind PC: 0x%08lx\n", (unsigned long) pc);

    return (CORE_ADDR) pc;
}


/* Unwind the frame to find the previous frame's SP.  */

static CORE_ADDR
arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
    ULONGEST sp;

    sp  = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM);

    DEBUG("unwind SP: 0x%08lx\n", (unsigned long) sp);

    return (CORE_ADDR) sp;
}


/* This function returns the convention used by the ABI for returning a result
   of the given type from a function; it may also be required to:

     a) set the return value (this is for the situation where the debugger user
        has issued a "return <value>" command to request immediate return from
        the current function with the given result; or

     b) get the return value ((this is for the situation where the debugger user
        has executed a "call <function>" command to execute the specified
        function in the target program, and that function has a non-void result
        which must be returned to the user.

  Parameters:
      gdbarch : gdbarch structure for the backend to use if needed
      valtype : the information for the return type of the function
      regcache: the register cache to be used for altered register values
      readbuf : if non-NULL, read the return value into this buffer
      writebuf: if non-NULL, write the return value from this buffer
 */

static enum return_value_convention
arc_return_value (struct gdbarch  *gdbarch,
                  struct type     *valtype,
                  struct regcache *regcache,
                  gdb_byte        *readbuf,
                  const gdb_byte  *writebuf)
{
    ENTERARGS("readbuf = %p, writebuf = %p", readbuf, writebuf);

    {
        /* If the return type is a struct, or a union, or would occupy more
           than two registers, the ABI uses the "struct return convention": the
           calling function passes a hidden first parameter to the callee (in R0).
           That parameter is the address at which the value being returned
           should be stored.  Otherwise, the result is returned in registers.  */
        Boolean is_struct_return = (TYPE_CODE   (valtype) == TYPE_CODE_STRUCT ||
                                    TYPE_CODE   (valtype) == TYPE_CODE_UNION  ||
                                    TYPE_LENGTH (valtype) > 2 * BYTES_IN_REGISTER);

        /* case a) */
        if (writebuf != NULL)
        {
            /* gdb should not ask us to set a struct return value: it should
               know the struct return location and write the value there
               itself.  */
            gdb_assert (!is_struct_return);
            store_return_value (valtype, regcache, writebuf);
        }

        /* case b) */
        if (readbuf != NULL)
        {
            /* gdb should not ask us to get a struct return value: it should
               know the struct return location and read the value from there
               itself.  */
            gdb_assert (!is_struct_return);
            extract_return_value (valtype, regcache, readbuf);
        }

        return (is_struct_return) ? RETURN_VALUE_STRUCT_CONVENTION
                                  : RETURN_VALUE_REGISTER_CONVENTION;
    }
}


/* Assuming that next_frame->prev 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() (!!!! WHAT IS THIS???), and the PC to match the dummy
   frame's breakpoint.  */

static struct frame_id
arc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
    return frame_id_build (arc_unwind_sp (gdbarch, next_frame),
                           frame_pc_unwind (next_frame));
}


/* Signal Trampoline Frame Unwinder.
   These unwinders allow frame unwinding to happen from within signal handlers.  */

static UnwindCache *
arc_sigtramp_frame_cache (struct frame_info *next_frame,
                          void             **this_cache)
{
    ENTERMSG;

    if (*this_cache == NULL)
    {
        struct gdbarch_tdep *tdep  = gdbarch_tdep (current_gdbarch);
        UnwindCache         *cache = create_cache(next_frame);
        gdb_byte             buf[BYTES_IN_REGISTER];

        *this_cache = cache;

        /* Get the stack pointer and use it as the frame base.  */
        frame_unwind_register (next_frame, ARC_SP_REGNUM, buf);
        cache->frame_base = (CORE_ADDR) extract_unsigned_integer (buf, BYTES_IN_REGISTER);

        /* If the ARC-private target-dependent info has a table of offsets of
           saved register contents within a O/S signal context structure.  */
        if (tdep->sc_reg_offset)
        {
            /* Find the address of the sigcontext structure.  */
            CORE_ADDR    addr = tdep->sigcontext_addr (next_frame);
            unsigned int i;

            /* For each register, if its contents have been saved within the
               sigcontext structure, determine the address of those contents.  */
            for (i = 0; i < tdep->sc_num_regs; i++)
                if (tdep->sc_reg_offset[i] != REGISTER_NOT_PRESENT)
                    cache->saved_regs[i].addr = (LONGEST) (addr + tdep->sc_reg_offset[i]);
        }
    }

    return *this_cache;
}


/* Construct id for the given frame.  */

static void
arc_sigtramp_frame_this_id (struct frame_info *next_frame,
                            void             **this_cache,
                            struct frame_id   *this_id)
{
    UnwindCache *cache;

    ENTERMSG;

    cache = arc_sigtramp_frame_cache (next_frame, this_cache);

    *this_id = frame_id_build (cache->frame_base, frame_pc_unwind (next_frame));
}


/* Retrieve the value of the register in the frame.  */

static void
arc_sigtramp_frame_prev_register (struct frame_info *next_frame,
                                  void             **this_cache,
                                  int                regnum,
                                  int               *optimizedp,
                                  enum lval_type    *lvalp,
                                  CORE_ADDR         *addrp,
                                  int               *realnump,
                                  gdb_byte          *valuep)
{
    ENTERMSG;

    {
        struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);

        /* Make sure we've initialized the cache.  */
        UnwindCache *cache = arc_sigtramp_frame_cache (next_frame, this_cache);

        /* On a signal, the PC is in ret.  */
        if (regnum == ARC_PC_REGNUM)
            regnum = tdep->pc_regnum_in_sigcontext;

        trad_frame_get_prev_register (next_frame,
                                      cache->saved_regs,
                                      regnum,
                                      optimizedp,
                                      lvalp,
                                      addrp,
                                      realnump,
                                      valuep);
    }
}


static const struct frame_unwind *
arc_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
    ENTERMSG;

    {
        struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));

        /* We don't even bother if we don't have a sigcontext_addr handler.  */
        if ((tdep->sigcontext_addr != NULL) &&
            (tdep->is_sigtramp     != NULL) &&
            tdep->is_sigtramp (next_frame))
        {
            static const struct frame_unwind arc_sigtramp_frame_unwind =
            {
                SIGTRAMP_FRAME,                   // type
                arc_sigtramp_frame_this_id,       // this_id
                arc_sigtramp_frame_prev_register, // prev_register
                NULL,                             // unwind_data
                NULL,                             // sniffer
                NULL,                             // prev_pc
                NULL                              // dealloc_cache
            };

            return &arc_sigtramp_frame_unwind;
        }

        return NULL;
    }
}


/* Allow calls to be made to functions defined in the debuggee (A.K.A dummy calls).

   Parameters:
      gdbarch      : gdbarch structure for the backend to use if needed.
      function     : the function to be called
      regcache     : the register cache to be used for altered register values
      bp_addr      : return address for the breakpoint.
      nargs        : the number of arguments to the function
      args         : the arguments to be passed to the function
      sp           : current value of SP.
      struct_return: 1 if structures are returned by the function.
      struct_addr  : hidden address for returning a struct.  */

static CORE_ADDR
arc_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)

{
    int arg_reg = ARC_ABI_FIRST_ARGUMENT_REGISTER;

    ENTERARGS("nargs = %d, struct_return = %d", nargs, struct_return);

    /* Push the return address.  */
    regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr);

    DEBUG("set BLINK = %X\n", (unsigned int) bp_addr);

    /* Are we returning a value using a structure return instead of a normal
       value return? If so, struct_addr is the address of the reserved space
       for the return structure to be written on the stack, and that address
       is passed to that function as a hidden first argument.  */

    if (struct_return)
    {
        /* Pass the return address in the first argument register.  */
        regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);

        DEBUG("struct return address 0x%08lX passed in R%d", struct_addr, arg_reg);

        arg_reg++;
    }

    /* If the function has arguments.  */
    if (nargs > 0)
    {
        Boolean      big_endian  = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG;
        unsigned int total_space = 0;
        gdb_byte    *memory_image;
        gdb_byte    *data;
        int          i;

        /* How much space do the arguments occupy in total?
           N.B. must round each argument's size up to an integral number of words.  */
        for (i = 0; i < nargs; i++)
        {
            unsigned int len   = TYPE_LENGTH (value_type (args[i]));
            unsigned int space = ROUND_UP_TO_WORDS(len);

            total_space += space;

            DEBUG("function arg[%d]: %d bytes -> %d\n", i, len, space);
        }

        /* Allocate a buffer to hold a memory image of the arguments.  */
        memory_image = XCALLOC((size_t) total_space, gdb_byte);
        if (memory_image == NULL)
        {
            /* could not do the call! */
            return 0;
        }

        /* Now copy all of the arguments into the buffer, correctly aligned.  */
        data = memory_image;
        for (i = 0; i < nargs; i++)
        {
            unsigned int len    = TYPE_LENGTH (value_type (args[i]));
            unsigned int space  = ROUND_UP_TO_WORDS(len);
            gdb_byte*    actual = data;
            unsigned int w;

            /* Parameters smaller than a word are normally aligned by gcc to the
               least significant byte, so if we have a big-endian target we put
               the data at the end of the word rather than at the start.  */
            if ((len < BYTES_IN_WORD) && big_endian)
               actual += BYTES_IN_WORD - len;

            (void) memcpy(actual, value_contents (args[i]), (size_t) len);

            DEBUG("function arg[%d] =", i);
            for (w = 0; w < space / BYTES_IN_WORD; w++)
                DEBUG(" 0x%08X", *((int*) data + w));
            DEBUG("\n");

            data += space;
        }

        /* Now load as much as possible of the memory image into registers.  */
        data = memory_image;
        while (arg_reg <= ARC_ABI_LAST_ARGUMENT_REGISTER)
        {
            ARC_RegisterContents contents = *(ARC_RegisterContents*) data;

            DEBUG("passing 0x%08X in register R%d\n", (unsigned int) contents, arg_reg);

            /* Convert to target byte order if necessary.  */
            if (HOST_AND_TARGET_ENDIANNESS_DIFFER(gdbarch))
            {
                contents = __bswap_32(contents);
                DEBUG("byte-swapped to 0x%08X\n", contents);
            }

            regcache_cooked_write_unsigned (regcache,
                                            arg_reg,
                                            (ULONGEST) contents);

            data        += BYTES_IN_REGISTER;
            total_space -= BYTES_IN_REGISTER;

            /* If all the data is now in registers.  */
            if (total_space == 0)
                break;

            arg_reg++;
        }

        /* If there is any data left, push it onto the stack (in a single write operation).  */
        if (total_space > 0)
        {
            DEBUG("passing %d bytes on stack\n", total_space);

            sp -= total_space;
            write_memory (sp, data, (int) total_space);
        }

        xfree(memory_image);
    }

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

    DEBUG("set SP = %X\n", (unsigned int) sp);

    return sp;
}


/* Align frame.  */

static CORE_ADDR
arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
    /* Align to the normal alignment on the stack).  */
    return WORD_ALIGNED(sp);
}


/* Print interesting information about the floating point processor
   (if present) or emulator.  */

static void
arc_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
                      struct frame_info *frame, const char *args)
{
    printf(_("Software FPU\n"));
}


/* Set the main_name to "_main" if required.
   This is set as an observer of inferior_created.  */

static void
arc_set_main_name (struct target_ops *objfile, int from_tty)
{
    /* Old ARC toolchains prepend an underscore to symbol names.  If there is
       an _main but no main, then we're probably debugging a binary that was
       made with the old toolchain.  */
    struct minimal_symbol *umainsym = lookup_minimal_symbol ("_main", NULL, NULL);
    struct minimal_symbol *mainsym  = lookup_minimal_symbol ("main",  NULL, NULL);

    if ((umainsym != NULL) && (mainsym == NULL))
    {
        set_main_name ("_main");
    }

    /* If we don't have any symbols, the default, i.e. "main", will get used.  */
}


/* This initialization function is called by gdb.
   See gdbarch.h for a description of its parameters.  */

static struct gdbarch*
arc_gdbarch_init (struct gdbarch_info  info,
                  struct gdbarch_list *arches)
{
    /* Allocate the ARC-private target-dependent information structure, and the
       gdb target-independent information structure.  */
    struct gdbarch_tdep *tdep    = xmalloc (sizeof (struct gdbarch_tdep));
    struct gdbarch      *gdbarch = gdbarch_alloc (&info, tdep);

    memset(tdep, 0, sizeof(*tdep));

    /* Put stuff in gdbarch. */

    /* Breakpoint manipulation.  */
    set_gdbarch_breakpoint_from_pc  (gdbarch, arc_breakpoint_from_pc);
    set_gdbarch_decr_pc_after_break (gdbarch, 0);

    info.osabi = CONFIG_OSABI;
    gdbarch_init_osabi(info, gdbarch);

    /* Characters are unsigned by default.  */
    set_gdbarch_char_signed (gdbarch, 0);

    set_gdbarch_sp_regnum        (gdbarch, ARC_SP_REGNUM);
    set_gdbarch_register_type    (gdbarch, arc_register_type);
    set_gdbarch_print_float_info (gdbarch, arc_print_float_info);

    /* Advance PC across function entry code.  */
    set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);

    /* Hook in the Dwarf-2 frame sniffer.  */
    dwarf2_frame_set_init_reg   (gdbarch, arc_dwarf2_frame_init_reg);
    frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);

    /* Signal frames.  */
    frame_unwind_append_sniffer (gdbarch, arc_sigtramp_frame_sniffer);

    /* The stack grows downward.  */
    set_gdbarch_inner_than      (gdbarch, core_addr_lessthan);
    set_gdbarch_unwind_pc       (gdbarch, arc_unwind_pc);
    set_gdbarch_unwind_sp       (gdbarch, arc_unwind_sp);
    set_gdbarch_unwind_dummy_id (gdbarch, arc_unwind_dummy_id);
    frame_unwind_append_sniffer (gdbarch, arc_frame_sniffer);
    set_gdbarch_return_value    (gdbarch, arc_return_value);

    /* Add the ARC register groups.  */
    reggroup_add (gdbarch, general_reggroup);
    reggroup_add (gdbarch, all_reggroup);
    reggroup_add (gdbarch, system_reggroup);

    set_gdbarch_register_reggroup_p (gdbarch, arc_register_reggroup_p);

    set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
    set_gdbarch_frame_align(gdbarch, arc_frame_align);

    /* Dummy Frame handling.  */
    set_gdbarch_push_dummy_call     (gdbarch, arc_push_dummy_call);
    set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);

    /* N.B. we do not want to call arcompact_get_disassembler at this point, as we do
            not as yet have an executable file, so do not know whether we want
            the disassembler for the A4 architecture (still supported by the
            opcodes library!) or the one for the ARCompact architecture; also,
            it is better to pass the arcompact_get_disassembler function a valid bfd
            structure, rather than a faked one, so that it can read the ARC-
            specific sections in the ELF file (for whatever reason...).

            So just set up a dummy disassembler at this point (gdb requires that
            *some* disassembler is defined for an architecture), and set up a
            callback which will set up the appropriate disassembler once an
            executable file has been selected for debugging.  */

#if 0
    {
        /* The arc libopcodes wants abfd so that it can find out what CPU
           extensions are there.  */
        bfd abfd;

        abfd.sections = NULL;

        set_gdbarch_print_insn(gdbarch, arcompact_get_disassembler(&abfd));
    }
#endif
    set_gdbarch_print_insn(gdbarch, dummy_disassembler);
    (void) observer_attach_new_objfile(set_disassembler);

    /* Set main_name to _main if necessary.  Ideally we'd want a hook that
       gets called when symbols are loaded, but it seems there isn't one; so
       we'll use this.  This will not work if the user does "target remote
       ..." and then "add-symbol-file ...".  */
    (void) observer_attach_inferior_created (arc_set_main_name);

    /* Initialize the target-dependent modules (if any).  */
    CONFIG_INIT_TDEP

    /* Return a pointer to the new object - indicates that a new architecture
       has been created.  */
    return gdbarch;
}


static void
arc_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
    /* Do nothing.  */
}


/* -------------------------------------------------------------------------- */
/*                     local functions implementing commands                  */
/* -------------------------------------------------------------------------- */

/* <command>  [ <frame> ]
   Display annotated stack frame.  */

static void
arc_show_stack_frame_command (char *arg, int from_tty)
{
    struct frame_info *fi;
    gdb_byte           value[MAX_REGISTER_SIZE];
    CORE_ADDR          pc, fp, sp, old_sp;
    CORE_ADDR          addr;
    enum lval_type     lval;
    int                optimized;
    int                realnum;
    int                frame_size;
    unsigned int      *frame_contents;
    LocalVariable     *variables;
    unsigned int       num_variables;

    /* Find the frame.  */
    fi = parse_frame_specification_1 (arg, _("No stack."), NULL);
    gdb_assert(fi != NULL);

    /* Find out PC, FP and SP for the frame.  */
    pc = get_frame_pc(fi);
    sp = get_frame_sp(fi);
    get_frame_register(fi, ARC_FP_REGNUM, value);
    fp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER);

    DEBUG("*** PC = %x, FP = %x, SP = %x\n", (unsigned int) pc, (unsigned int) fp, (unsigned int) sp);

    if (pc == 0)
    {
        warning(_("invalid frame"));
        return;
    }

    frame_register_unwind (fi, ARC_SP_REGNUM, &optimized, &lval, &addr, &realnum, value);
    old_sp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER);

    /* Find the local variables and parameters.  */
    variables = find_local_variables(fi, &num_variables);

    printf_filtered(NEW_LINE);
    identify_frame(fi);

    DEBUG(_("\n\n*** FRAME: 0x%x .. 0x%x\n\n"), (unsigned int) sp, (unsigned int) (old_sp - 1));

    frame_size = (int) (old_sp - sp);

    frame_contents = xmalloc((size_t) frame_size);

    if (frame_contents)
    {
        /* Read all of the frame's contents from target memory.  */
        if (target_read_memory(sp, (gdb_byte*) frame_contents, frame_size) == 0)
        {
            int          numregs       = ARC_TOTAL_REGS;
            int          i             = frame_size / BYTES_IN_WORD - 1;
            unsigned int the_same      = 0;
            unsigned int previous_word = 0;
            Boolean      first_word    = TRUE;
            Boolean      is_following_element;
            Boolean      elements_are_word_sized;

            addr = old_sp - BYTES_IN_WORD;

            printf_filtered(NEW_LINE);

            /* Traverse the frame from high address to low address, one word at a time.  */
            while (i >= 0)
            {
                unsigned int this_word = frame_contents[i];
                Boolean      print     = first_word;        /* Always print the first word. */
                char         line[256];
                int          n;

                /* Start with a blank line.  */
                (void) memset(line, (int) ' ', sizeof(line));

                /* Does FP and/or SP address this particular stack location?  */
                if (addr == sp && fp == sp)
                {
                    (void) strcpy(line + 14, _("SP/FP ===> "));
                    line[25] = ' ';
                    print = TRUE;
                }
                else if (addr == sp)
                {
                    (void) strcpy(line + 17, _("SP ===> "));
                    line[25] = ' ';
                    print = TRUE;
                }
                else if (addr == fp)
                {
                    (void) strcpy(line + 17, _("FP ===> "));
                    line[25] = ' ';
                    print = TRUE;
                }

                /* Does this stack location hold a local variable or parameter?  */
                if ((add_local_name(line + 38,
                                    addr,
                                    variables,
                                    num_variables,
                                    &is_following_element,
                                    &elements_are_word_sized)))
                {
                    /* Yes - so we want to print it (but this may be revised below!).  */
                    print = TRUE;
                }
                else
                {
                    int r;

                    /* Does this location hold a saved register?  */
                    for (r = 0; r < numregs; r++)
                    {
                        if (r != ARC_SP_REGNUM &&
                            gdbarch_register_reggroup_p (current_gdbarch, r, all_reggroup))
                        {
                            CORE_ADDR saved_addr;

                            /* Find out the location of the saved register without
                               fetching the corresponding value.  */
                            frame_register_unwind (fi, r, &optimized, &lval, &saved_addr, &realnum, NULL);

                            if (!optimized && lval == lval_memory && saved_addr == addr)
                            {
                                (void) sprintf(line + 38, _("saved register '%s'"), gdbarch_register_name(current_gdbarch, r));
                                print = TRUE;
                                break;
                            }
                        }
                    }
                }

                /* Do we think we need to print out the line?  */
                if (print)
                {
                    /* If the location is a non-zeroth word-sized array element,
                       and this word is the same as the previous word.  */
                    if (is_following_element && elements_are_word_sized && (this_word == previous_word))
                    {
                        /* No need to print it - one more word the same!  */
                        the_same++;
                        print = FALSE;
                    }
                }
                else
                {
                    /* N.B. this will not be the first word (since print is FALSE) */

                    /* This location does not hold anything "interesting",  but
                       if this word is not the same as the previous word, we
                       want to print it. */
                    if (this_word == previous_word)
                        the_same++;
                    else
                        print = TRUE;
                }

                /* OK, now we really know whether we need to print out the line.  */
                if (print)
                {
                    n = sprintf(line, _("0x%08X:"), (unsigned int) addr);
                    line[n] = ' ';

                    n = sprintf(line + 25, "%08X", this_word);
                    line[25 + n] = ' ';

                    n = (int) sizeof(line) - 1;
                    while (line[n] == ' ') n--;
                    line[n + 1] = '\0';

                    /* If we did not print the previous word because it was the
                       same as the word before, but not the same as any preceding
                       words, print it now (there is no point in outputting a
                       message which says simply "... 1 words omitted" - we might
                       just as well print out the word!  */
                    if (the_same == 1)
                        printf_filtered(_("0x%08X:              %08X\n"), (unsigned int) addr + BYTES_IN_WORD, previous_word);
                    else if (the_same != 0)
                        /* 2 or more words the same... */
                        printf_filtered(_("... %u words omitted\n"), the_same);

                    /* Now print out the line with the current word (and other information).  */
                    printf_filtered(_("%s\n"), line);

                    /* No words omitted.  */
                    the_same = 0;
                }

                first_word    = FALSE;
                previous_word = this_word;

                addr -= BYTES_IN_WORD;
                i--;
            }

            printf_filtered(NEW_LINE);
        }

        xfree(frame_contents);
    }

    xfree(variables);
}


/* -------------------------------------------------------------------------- */
/*                               externally visible functions                 */
/* -------------------------------------------------------------------------- */

/* Initialize the module. This function is called from the gdb core on start-up.  */

void
_initialize_arc_tdep (void)
{
    /* Register the ARC processor architecture with gdb, providing an
       initialization function and a dump function; 'bfd_arch_arc' is
       an enumeration value specifically denoting the ARC architecture.  */
    gdbarch_register(bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);

    /* Register ARC-specific commands with gdb.  */

    add_setshow_boolean_cmd(DEBUG_COMMAND,
                            no_class,
                            &arc_debug_target,
                            _("Set whether to print ARC debug messages.\n"),
                            _("Show whether to print ARC debug messages.\n"),
                            _("If set debug messages are printed.\n"),
                            NULL,
                            NULL,
                            &setlist,
                            &showlist);

    (void) add_cmd(SHOW_FRAME_COMMAND,
                   class_obscure,
                   arc_show_stack_frame_command,
                   _("Display the stack frame with annotation.\n"
                     SHOW_FRAME_COMMAND_USAGE
                     "<FRAME> may be the number or address of a frame.\n"),
                   &cmdlist);
}


/* Initialize the info structure to enable the disassembler to be used.  */

void
arc_initialize_disassembler (struct disassemble_info *info)
{
    /* N.B. this type cast is not strictly correct: the return types differ!  */
    init_disassemble_info(info, gdb_stdout, (fprintf_ftype) fprintf_filtered);
    info->arch             = gdbarch_bfd_arch_info(current_gdbarch)->arch;
    info->mach             = gdbarch_bfd_arch_info(current_gdbarch)->mach;
    info->endian           = gdbarch_byte_order   (current_gdbarch);
    info->read_memory_func = read_memory_for_disassembler;
}

/******************************************************************************/