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 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652
|
;;; -*- Mode: Lisp; Log: code.log; Package: DI -*-
;;;
;;; **********************************************************************
;;; This code was written as part of the CMU Common Lisp project at
;;; Carnegie Mellon University, and has been placed in the public domain.
;;;
(ext:file-comment
"$Header: /home/pvaneynd/fakeroot/cvs2.cons.org/src/code/debug-int.lisp,v 1.88 1998/02/14 21:09:48 dtc Exp $")
;;;
;;; **********************************************************************
;;;
;;; This file contains the implementation of the programmer's interface
;;; to writing debugging tools.
;;;
;;; Written by Bill Chiles and Rob Maclachlan.
;;;
;;; X86 support by Douglas Crosher 1996,1997,1998.
(in-package "DEBUG-INTERNALS")
;;; The compiler's debug-source structure is almost exactly what we want, so
;;; just get these symbols and export them.
;;;
(import '(c::debug-source-from c::debug-source-name c::debug-source-created
c::debug-source-compiled c::debug-source-start-positions
c::make-debug-source c::debug-source c::debug-source-p))
(export '(debug-variable-name debug-variable-package debug-variable-symbol
debug-variable-id debug-variable-value debug-variable-validity
debug-variable-valid-value debug-variable debug-variable-p
top-frame frame-down frame-up flush-frames-above frame-debug-function
frame-code-location eval-in-frame return-from-frame frame-catches
frame-number frame frame-p
do-debug-function-blocks debug-function-lambda-list
debug-variable-info-available do-debug-function-variables
debug-function-symbol-variables ambiguous-debug-variables
preprocess-for-eval function-debug-function debug-function-function
debug-function-kind debug-function-name debug-function
debug-function-p debug-function-start-location
do-debug-block-locations debug-block-successors debug-block
debug-block-p debug-block-elsewhere-p
make-breakpoint activate-breakpoint deactivate-breakpoint
breakpoint-active-p breakpoint-hook-function breakpoint-info
breakpoint-kind breakpoint-what breakpoint breakpoint-p
delete-breakpoint function-end-cookie-valid-p
code-location-debug-function code-location-debug-block
code-location-top-level-form-offset code-location-form-number
code-location-debug-source code-location-kind
code-location code-location-p code-location-unknown-p code-location=
debug-source-from debug-source-name debug-source-created
debug-source-compiled debug-source-root-number
debug-source-start-positions form-number-translations
source-path-context debug-source debug-source-p
debug-condition no-debug-info no-debug-function-returns
no-debug-blocks lambda-list-unavailable
debug-error unhandled-condition invalid-control-stack-pointer
unknown-code-location unknown-debug-variable invalid-value
ambiguous-variable-name frame-function-mismatch
set-breakpoint-for-editor set-location-breakpoint-for-editor
delete-breakpoint-for-editor
*debugging-interpreter*))
;;;; Conditions.
;;; The interface to building debugging tools signals conditions that prevent
;;; it from adhering to its contract. These are serious-conditions because the
;;; program using the interface must handle them before it can correctly
;;; continue execution. These debugging conditions are not errors since it is
;;; no fault of the programmers that the conditions occur. The interface does
;;; not provide for programs to detect these situations other than calling a
;;; routine that detects them and signals a condition. For example,
;;; programmers call A which may fail to return successfully due to a lack of
;;; debug information, and there is no B the they could have called to realize
;;; A would fail. It is not an error to have called A, but it is an error for
;;; the program to then ignore the signal generated by A since it cannot
;;; continue without A's correctly returning a value or performing some
;;; operation.
;;;
;;; Use DEBUG-SIGNAL to signal these conditions.
;;;
(define-condition debug-condition (serious-condition)
()
(:documentation
"All debug-conditions inherit from this type. These are serious conditions
that must be handled, but they are not programmer errors."))
(define-condition no-debug-info (debug-condition)
()
(:documentation "There is absolutely no debugging information available.")
(:report (lambda (condition stream)
(declare (ignore condition))
(fresh-line stream)
(write-line "No debugging information available." stream))))
(define-condition no-debug-function-returns (debug-condition)
((debug-function :reader no-debug-function-returns-debug-function
:initarg :debug-function))
(:documentation
"The system could not return values from a frame with debug-function since
it lacked information about returning values.")
(:report (lambda (condition stream)
(let ((fun (debug-function-function
(no-debug-function-returns-debug-function condition))))
(format stream
"~&Cannot return values from ~:[frame~;~:*~S~] since ~
the debug information lacks details about returning ~
values here."
fun)))))
(define-condition no-debug-blocks (debug-condition)
((debug-function :reader no-debug-blocks-debug-function
:initarg :debug-function))
(:documentation "The debug-function has no debug-block information.")
(:report (lambda (condition stream)
(format stream "~&~S has no debug-block information."
(no-debug-blocks-debug-function condition)))))
(define-condition no-debug-variables (debug-condition)
((debug-function :reader no-debug-variables-debug-function
:initarg :debug-function))
(:documentation "The debug-function has no debug-variable information.")
(:report (lambda (condition stream)
(format stream "~&~S has no debug-variable information."
(no-debug-variables-debug-function condition)))))
(define-condition lambda-list-unavailable (debug-condition)
((debug-function :reader lambda-list-unavailable-debug-function
:initarg :debug-function))
(:documentation
"The debug-function has no lambda-list since argument debug-variables are
unavailable.")
(:report (lambda (condition stream)
(format stream "~&~S has no lambda-list information available."
(lambda-list-unavailable-debug-function condition)))))
(define-condition invalid-value (debug-condition)
((debug-variable :reader invalid-value-debug-variable
:initarg :debug-variable)
(frame :reader invalid-value-frame :initarg :frame))
(:report (lambda (condition stream)
(format stream "~&~S has :invalid or :unknown value in ~S."
(invalid-value-debug-variable condition)
(invalid-value-frame condition)))))
(define-condition ambiguous-variable-name (debug-condition)
((name :reader ambiguous-variable-name-name :initarg :name)
(frame :reader ambiguous-variable-name-frame :initarg :frame))
(:report (lambda (condition stream)
(format stream "~&~S names more than one valid variable in ~S."
(ambiguous-variable-name-name condition)
(ambiguous-variable-name-frame condition)))))
;;;; Errors and DEBUG-SIGNAL.
;;; The debug-internals code tries to signal all programmer errors as subtypes
;;; of debug-error. There are calls to ERROR signalling simple-errors, but
;;; these dummy checks in the code and shouldn't come up.
;;;
;;; While under development, this code also signals errors in code branches
;;; that remain unimplemented.
;;;
(define-condition debug-error (error) ()
(:documentation
"All programmer errors from using the interface for building debugging
tools inherit from this type."))
(define-condition unhandled-condition (debug-error)
((condition :reader unhandled-condition-condition :initarg :condition))
(:report (lambda (condition stream)
(format stream "~&Unhandled debug-condition:~%~A"
(unhandled-condition-condition condition)))))
(define-condition unknown-code-location (debug-error)
((code-location :reader unknown-code-location-code-location
:initarg :code-location))
(:report (lambda (condition stream)
(format stream "~&Invalid use of an unknown code-location -- ~S."
(unknown-code-location-code-location condition)))))
(define-condition unknown-debug-variable (debug-error)
((debug-variable :reader unknown-debug-variable-debug-variable
:initarg :debug-variable)
(debug-function :reader unknown-debug-variable-debug-function
:initarg :debug-function))
(:report (lambda (condition stream)
(format stream "~&~S not in ~S."
(unknown-debug-variable-debug-variable condition)
(unknown-debug-variable-debug-function condition)))))
(define-condition invalid-control-stack-pointer (debug-error)
()
(:report (lambda (condition stream)
(declare (ignore condition))
(fresh-line stream)
(write-string "Invalid control stack pointer." stream))))
(define-condition frame-function-mismatch (debug-error)
((code-location :reader frame-function-mismatch-code-location
:initarg :code-location)
(frame :reader frame-function-mismatch-frame :initarg :frame)
(form :reader frame-function-mismatch-form :initarg :form))
(:report (lambda (condition stream)
(format stream
"~&Form was preprocessed for ~S,~% but called on ~S:~% ~S"
(frame-function-mismatch-code-location condition)
(frame-function-mismatch-frame condition)
(frame-function-mismatch-form condition)))))
;;; DEBUG-SIGNAL -- Internal.
;;;
;;; This signals debug-conditions. If they go unhandled, then signal an
;;; unhandled-condition error.
;;;
;;; ??? Get SIGNAL in the right package!
;;;
(defmacro debug-signal (datum &rest arguments)
`(let ((condition (make-condition ,datum ,@arguments)))
(signal condition)
(error 'unhandled-condition :condition condition)))
;;;; Structures.
;;; Most of these structures model information stored in internal data
;;; structures created by the compiler. Whenever comments preface an object or
;;; type with "compiler", they refer to the internal compiler thing, not to the
;;; object or type with the same name in the "DI" package.
;;;
;;;
;;; Debug-variables
;;;
;;; These exist for caching data stored in packed binary form in compiler
;;; debug-functions. Debug-functions store these.
;;;
(defstruct (debug-variable (:print-function print-debug-variable)
(:constructor nil))
;;
;; String name of variable.
(name nil :type simple-string)
;;
;; String name of package. Nil when variable's name is uninterned.
(package nil :type (or null simple-string))
;;
;; Unique integer identification relative to other variables with the same
;; name and package.
(id 0 :type c::index)
;;
;; Whether the variable always has a valid value.
(alive-p nil :type c::boolean))
(defun print-debug-variable (obj str n)
(declare (ignore n))
(format str "#<Debug-Variable ~A:~A:~A>"
(debug-variable-package obj)
(debug-variable-name obj)
(debug-variable-id obj)))
(setf (documentation 'debug-variable-name 'function)
"Returns the name of the debug-variable. The name is the name of the symbol
used as an identifier when writing the code.")
(setf (documentation 'debug-variable-package 'function)
"Returns the package name of the debug-variable. This is the package name of
the symbol used as an identifier when writing the code.")
(setf (documentation 'debug-variable-id 'function)
"Returns the integer that makes debug-variable's name and package name unique
with respect to other debug-variable's in the same function.")
(defstruct (compiled-debug-variable
(:include debug-variable)
(:constructor make-compiled-debug-variable
(name package id alive-p sc-offset save-sc-offset)))
;;
;; Storage class and offset. (unexported).
(sc-offset nil :type c::sc-offset)
;;
;; Storage class and offset when saved somewhere.
(save-sc-offset nil :type (or c::sc-offset null)))
(defstruct (interpreted-debug-variable
(:include debug-variable
(alive-p t))
(:constructor make-interpreted-debug-variable
(name package ir1-var)))
;;
;; This is the IR1 structure that holds information about interpreted vars.
(ir1-var nil :type c::lambda-var))
;;;
;;; Frames
;;;
;;; These represents call-frames on the stack.
;;;
(defstruct (frame (:constructor nil))
;;
;; Next frame up. Null when top frame.
(up nil :type (or frame null))
;;
;; Previous frame down. Nil when the bottom frame. Before computing the
;; next frame down, this slot holds the frame pointer to the control stack
;; for the given frame. This lets us get the next frame down and the
;; return-pc for that frame.
(%down :unparsed :type (or frame (member nil :unparsed)))
;;
;; Debug-function for function whose call this frame represents.
(debug-function nil :type debug-function)
;;
;; Code-location to continue upon return to frame.
(code-location nil :type code-location)
;;
;; A-list of catch-tags to code-locations.
(%catches :unparsed :type (or list (member :unparsed)))
;;
;; Pointer to frame on control stack. (unexported)
;; When is an interpreted-frame, this is an index into the interpreter's
;; stack.
pointer
;;
;; This is the frame's number for prompt printing. Top is zero.
(number 0 :type index))
(setf (documentation 'frame-up 'function)
"Returns the frame immediately above frame on the stack. When frame is
the top of the stack, this returns nil.")
(setf (documentation 'frame-debug-function 'function)
"Returns the debug-function for the function whose call frame represents.")
(setf (documentation 'frame-code-location 'function)
"Returns the code-location where the frame's debug-function will continue
running when program execution returns to this frame. If someone
interrupted this frame, the result could be an unknown code-location.")
(defstruct (compiled-frame
(:include frame)
(:print-function print-compiled-frame)
(:constructor make-compiled-frame
(pointer up debug-function code-location number
#+gengc saved-state-chain
&optional escaped)))
;;
;; Indicates whether someone interrupted frame. (unexported).
;; If escaped, this is a pointer to the state that was saved when we were
;; interrupted. On the non-gengc system, this is a sigcontext pointer.
;; On the gengc system, this is a state pointer from saved-state-chain.
escaped
;;
;; List of saps to saved states. Each time we unwind past an exception,
;; we pop the next entry off this list. When we get to the end of the
;; list, there is nothing else on the stack.
#+gengc (saved-state-chain nil :type list))
(defun print-compiled-frame (obj str n)
(declare (ignore n))
(format str "#<Compiled-Frame ~S~:[~;, interrupted~]>"
(debug-function-name (frame-debug-function obj))
(compiled-frame-escaped obj)))
(defstruct (interpreted-frame
(:include frame)
(:print-function print-interpreted-frame)
(:constructor make-interpreted-frame
(pointer up debug-function code-location number
real-frame closure)))
;;
;; This points to the compiled-frame for EVAL:INTERNAL-APPLY-LOOP.
(real-frame nil :type compiled-frame)
;;
;; This is the closed over data used by the interpreter.
(closure nil :type simple-vector))
(defun print-interpreted-frame (obj str n)
(declare (ignore n))
(format str "#<Interpreted-Frame ~S>"
(debug-function-name (frame-debug-function obj))))
;;;
;;; Debug-functions
;;;
;;; These exist for caching data stored in packed binary form in compiler
;;; debug-functions. *compiled-debug-functions* maps a c::debug-function to a
;;; debug-function. There should only be one debug-function in existence for
;;; any function; that is, all code-locations and other objects that reference
;;; debug-functions point to unique objects. This is due to the overhead in
;;; cached information.
;;;
(defstruct (debug-function (:print-function print-debug-function))
;;
;; Some representation of the function arguments. See
;; DEBUG-FUNCTION-LAMBDA-LIST.
;; NOTE: must parse vars before parsing arg list stuff.
(%lambda-list :unparsed)
;;
;; Cached debug-variable information. (unexported).
;; These are sorted by their name.
(debug-vars :unparsed :type (or simple-vector null (member :unparsed)))
;;
;; Cached debug-block information. This is nil when we have tried to parse
;; the packed binary info, but none is available.
(blocks :unparsed :type (or simple-vector null (member :unparsed)))
;;
;; The actual function if available.
(%function :unparsed :type (or null function (member :unparsed))))
(defun print-debug-function (obj str n)
(declare (ignore n))
(format str "#<~A-Debug-Function ~S>"
(etypecase obj
(compiled-debug-function "Compiled")
(interpreted-debug-function "Interpreted")
(bogus-debug-function "Bogus"))
(debug-function-name obj)))
(defstruct (compiled-debug-function
(:include debug-function)
(:constructor %make-compiled-debug-function
(compiler-debug-fun component)))
;;
;; Compiler's dumped debug-function information. (unexported).
(compiler-debug-fun nil :type c::compiled-debug-function)
;;
;; Code object. (unexported).
component
;;
;; The :function-start breakpoint (if any) used to facilitate function
;; end breakpoints.
(end-starter nil :type (or null breakpoint)))
;;; This maps c::compiled-debug-functions to compiled-debug-functions, so we
;;; can get at cached stuff and not duplicate compiled-debug-function
;;; structures.
;;;
(defvar *compiled-debug-functions* (make-hash-table :test #'eq))
;;; MAKE-COMPILED-DEBUG-FUNCTION -- Internal.
;;;
;;; Makes a compiled-debug-function for a c::compiler-debug-function and its
;;; component. This maps the latter to the former in
;;; *compiled-debug-functions*. If there already is a compiled-debug-function,
;;; then this returns it from *compiled-debug-functions*.
;;;
(defun make-compiled-debug-function (compiler-debug-fun component)
(or (gethash compiler-debug-fun *compiled-debug-functions*)
(setf (gethash compiler-debug-fun *compiled-debug-functions*)
(%make-compiled-debug-function compiler-debug-fun component))))
(defstruct (interpreted-debug-function
(:include debug-function)
(:constructor %make-interpreted-debug-function (ir1-lambda)))
;;
;; This is the ir1 lambda this debug-function represents.
(ir1-lambda nil :type c::clambda))
(defstruct (bogus-debug-function
(:include debug-function)
(:constructor make-bogus-debug-function
(%name &aux (%lambda-list nil) (debug-vars nil)
(blocks nil) (%function nil))))
%name)
(defvar *ir1-lambda-debug-function* (make-hash-table :test #'eq))
(defun make-interpreted-debug-function (ir1-lambda)
(let ((home-lambda (c::lambda-home ir1-lambda)))
(or (gethash home-lambda *ir1-lambda-debug-function*)
(setf (gethash home-lambda *ir1-lambda-debug-function*)
(%make-interpreted-debug-function home-lambda)))))
;;;
;;; Debug-blocks.
;;;
;;; These exist for caching data stored in packed binary form in compiler
;;; debug-blocks.
;;;
(defstruct (debug-block (:print-function print-debug-block))
;;
;; Code-locations where execution continues after this block.
(successors nil :type list)
;;
;; This indicates whether the block is a special glob of code shared by
;; various functions and tucked away elsewhere in a component. This kind of
;; block has no start code-location. In an interpreted-debug-block, this is
;; always nil. This slot is in all debug-blocks since it is an exported
;; interface.
(elsewhere-p nil :type c::boolean))
(defun print-debug-block (obj str n)
(declare (ignore n))
(format str "#<~A-Debug-Block ~S>"
(etypecase obj
(compiled-debug-block "Compiled")
(interpreted-debug-block "Interpreted"))
(debug-block-function-name obj)))
(setf (documentation 'debug-block-successors 'function)
"Returns the list of possible code-locations where execution may continue
when the basic-block represented by debug-block completes its execution.")
(setf (documentation 'debug-block-elsewhere-p 'function)
"Returns whether debug-block represents elsewhere code.")
(defstruct (compiled-debug-block (:include debug-block)
(:constructor
make-compiled-debug-block
(code-locations successors elsewhere-p)))
;;
;; Code-location information for the block.
(code-locations nil :type simple-vector))
(defstruct (interpreted-debug-block (:include debug-block
(elsewhere-p nil))
(:constructor %make-interpreted-debug-block
(ir1-block)))
;;
;; This is the IR1 block this debug-block represents.
(ir1-block nil :type c::cblock)
;;
;; Code-location information for the block.
(locations :unparsed :type (or (member :unparsed) simple-vector)))
(defvar *ir1-block-debug-block* (make-hash-table :test #'eq))
;;; MAKE-INTERPRETED-DEBUG-BLOCK -- Internal.
;;;
;;; This makes a debug-block for the interpreter's ir1-block. If we have it in
;;; the cache, return it. If we need to make it, then first make debug-blocks
;;; for all the ir1-blocks in ir1-block's home lambda; this makes sure all the
;;; successors of ir1-block have debug-blocks. We need this to fill in the
;;; resulting debug-block's successors list with debug-blocks, not ir1-blocks.
;;; After making all the possible debug-blocks we'll need to reference, go back
;;; over the list of new debug-blocks and fill in their successor slots with
;;; lists of debug-blocks. Then look up our argument ir1-block to find its
;;; debug-block since we know we have it now.
;;;
(defun make-interpreted-debug-block (ir1-block)
(check-type ir1-block c::cblock)
(let ((res (gethash ir1-block *ir1-block-debug-block*)))
(or res
(let ((lambda (c::block-home-lambda ir1-block)))
(c::do-blocks (block (c::block-component ir1-block))
(when (eq lambda (c::block-home-lambda block))
(push (setf (gethash block *ir1-block-debug-block*)
(%make-interpreted-debug-block block))
res)))
(dolist (block res)
(let* ((successors nil)
(cblock (interpreted-debug-block-ir1-block block))
(succ (c::block-succ cblock))
(valid-succ
(if (and succ
(eq (car succ)
(c::component-tail
(c::block-component cblock))))
()
succ)))
(dolist (sblock valid-succ)
(let ((dblock (gethash sblock *ir1-block-debug-block*)))
(when dblock
(push dblock successors))))
(setf (debug-block-successors block) (nreverse successors))))
(gethash ir1-block *ir1-block-debug-block*)))))
;;;
;;; Breakpoints.
;;;
;;; This is an internal structure that manages information about a breakpoint
;;; locations. See *component-breakpoint-offsets*.
;;;
(defstruct (breakpoint-data (:print-function print-breakpoint-data)
(:constructor make-breakpoint-data
(component offset)))
;;
;; This is the component in which the breakpoint lies.
component
;;
;; This is the byte offset into the component.
(offset nil :type c::index)
;;
;; The original instruction replaced by the breakpoint.
(instruction nil :type (or null (unsigned-byte 32)))
;;
;; A list of user breakpoints at this location.
(breakpoints nil :type list))
;;;
(defun print-breakpoint-data (obj str n)
(declare (ignore n))
(format str "#<Breakpoint-Data ~S at ~S>"
(debug-function-name
(debug-function-from-pc (breakpoint-data-component obj)
(breakpoint-data-offset obj)))
(breakpoint-data-offset obj)))
(defstruct (breakpoint (:print-function print-breakpoint)
(:constructor %make-breakpoint
(hook-function what kind %info)))
;;
;; This is the function invoked when execution encounters the breakpoint. It
;; takes a frame, the breakpoint, and optionally a list of values. Values
;; are supplied for :function-end breakpoints as values to return for the
;; function containing the breakpoint. :function-end breakpoint
;; hook-functions also take a cookie argument. See cookie-fun slot.
(hook-function nil :type function)
;;
;; Code-location or debug-function.
(what nil :type (or code-location debug-function))
;;
;; :code-location, :function-start, or :function-end for that kind of
;; breakpoint. :unknown-return-partner if this is the partner of a
;; :code-location breakpoint at an :unknown-return code-location.
(kind nil :type (member :code-location :function-start :function-end
:unknown-return-partner))
;;
;; Status helps the user and the implementation.
(status :inactive :type (member :active :inactive :deleted))
;;
;; This is a backpointer to a breakpoint-data.
(internal-data nil :type (or null breakpoint-data))
;;
;; With code-locations whose type is :unknown-return, there are really
;; two breakpoints: one at the multiple-value entry point, and one at
;; the single-value entry point. This slot holds the breakpoint for the
;; other one, or NIL if this isn't at an :unknown-return code location.
(unknown-return-partner nil :type (or null breakpoint))
;;
;; :function-end breakpoints use a breakpoint at the :function-start to
;; establish the end breakpoint upon function entry. We do this by frobbing
;; the LRA to jump to a special piece of code that breaks and provides the
;; return values for the returnee. This slot points to the start breakpoint,
;; so we can activate, deactivate, and delete it.
(start-helper nil :type (or null breakpoint))
;;
;; This is a hook users supply to get a dynamically unique cookie for
;; identifying :function-end breakpoint executions. That is, if there is one
;; :function-end breakpoint, but there may be multiple pending calls of its
;; function on the stack. This function takes the cookie, and the
;; hook-function takes the cookie too.
(cookie-fun nil :type (or null function))
;;
;; This slot users can set with whatever information they find useful.
%info)
;;;
(defun print-breakpoint (obj str n)
(declare (ignore n))
(let ((what (breakpoint-what obj)))
(format str "#<Breakpoint ~S~:[~;~:*~S~]>"
(etypecase what
(code-location what)
(debug-function (debug-function-name what)))
(etypecase what
(code-location nil)
(debug-function (breakpoint-kind obj))))))
(setf (documentation 'breakpoint-hook-function 'function)
"Returns the breakpoint's function the system calls when execution encounters
the breakpoint, and it is active. This is SETF'able.")
(setf (documentation 'breakpoint-what 'function)
"Returns the breakpoint's what specification.")
(setf (documentation 'breakpoint-kind 'function)
"Returns the breakpoint's kind specification.")
;;;
;;; Code-locations.
;;;
(defstruct (code-location (:print-function print-code-location)
(:constructor nil))
;;
;; This is the debug-function containing code-location.
(debug-function nil :type debug-function)
;;
;; This is initially :unsure. Upon first trying to access an :unparsed slot,
;; if the data is unavailable, then this becomes t, and the code-location is
;; unknown. If the data is available, this becomes nil, a known location.
;; We can't use a separate type code-location for this since we must return
;; code-locations before we can tell whether they're known or unknown. For
;; example, when parsing the stack, we don't want to unpack all the variables
;; and blocks just to make frames.
(%unknown-p :unsure :type (member t nil :unsure))
;;
;; This is the debug-block containing code-location.
;; Possibly toss this out and just find it in the blocks cache in
;; debug-function.
(%debug-block :unparsed :type (or debug-block (member :unparsed)))
;;
;; This is the number of forms processed by the compiler or loader before
;; the top-level form containing this code-location.
(%tlf-offset :unparsed :type (or c::index (member :unparsed)))
;;
;; This is the depth-first number of the node that begins code-location
;; within its top-level form.
(%form-number :unparsed :type (or c::index (member :unparsed))))
(defun print-code-location (obj str n)
(declare (ignore n))
(format str "#<~A ~S>"
(ecase (code-location-unknown-p obj)
((nil) (etypecase obj
(compiled-code-location "Compiled-Code-Location")
(interpreted-code-location "Interpreted-Code-Location")))
((t) "Unknown-Code-Location"))
(debug-function-name (code-location-debug-function obj))))
(setf (documentation 'code-location-debug-function 'function)
"Returns the debug-function representing information about the function
corresponding to the code-location.")
(defstruct (compiled-code-location
(:include code-location)
(:constructor make-known-code-location
(pc debug-function %tlf-offset %form-number
%live-set kind &aux (%unknown-p nil)))
(:constructor make-compiled-code-location (pc debug-function)))
;;
;; This is an index into debug-function's component slot.
(pc nil :type c::index)
;;
;; This is a bit-vector indexed by a variable's position in
;; DEBUG-FUNCTION-DEBUG-VARS indicating whether the variable has a valid
;; value at this code-location. (unexported).
(%live-set :unparsed :type (or simple-bit-vector (member :unparsed)))
;;
;; (unexported)
;; To see c::location-kind, do "(kernel:type-expand 'c::location-kind)".
(kind :unparsed :type (or (member :unparsed) c::location-kind)))
(defstruct (interpreted-code-location
(:include code-location
(%unknown-p nil))
(:constructor make-interpreted-code-location
(ir1-node debug-function)))
;;
;; This is an index into debug-function's component slot.
(ir1-node nil :type c::node))
;;;
;;; Debug-sources
;;;
(proclaim '(inline debug-source-root-number))
;;;
(defun debug-source-root-number (debug-source)
"Returns the number of top-level forms processed by the compiler before
compiling this source. If this source is uncompiled, this is zero. This
may be zero even if the source is compiled since the first form in the first
file compiled in one compilation, for example, must have a root number of
zero -- the compiler saw no other top-level forms before it."
(c::debug-source-source-root debug-source))
(setf (documentation 'c::debug-source-from 'function)
"Returns an indication of the type of source. The following are the possible
values:
:file from a file (obtained by COMPILE-FILE if compiled).
:lisp from Lisp (obtained by COMPILE if compiled).
:stream from a non-file stream.")
(setf (documentation 'c::debug-source-name 'function)
"Returns the actual source in some sense represented by debug-source, which
is related to DEBUG-SOURCE-FROM:
:file the pathname of the file.
:lisp a lambda-expression.
:stream some descriptive string that's otherwise useless.")
(setf (documentation 'c::debug-source-created 'function)
"Returns the universal time someone created the source. This may be nil if
it is unavailable.")
(setf (documentation 'c::debug-source-compiled 'function)
"Returns the time someone compiled the source. This is nil if the source
is uncompiled.")
(setf (documentation 'c::debug-source-start-positions 'function)
"This function returns the file position of each top-level form as an array
if debug-source is from a :file. If DEBUG-SOURCE-FROM is :lisp or :stream,
this returns nil.")
(setf (documentation 'c::debug-source-p 'function)
"Returns whether object is a debug-source.")
;;;; Frames.
;;; This is used in FIND-ESCAPE-FRAME and with the bogus components and LRAs
;;; used for :function-end breakpoints. When a components debug-info slot is
;;; :bogus-lra, then the real-lra-slot contains the real component to continue
;;; executing, as opposed to the bogus component which appeared in some frame's
;;; LRA location.
;;;
(defconstant real-lra-slot vm:code-constants-offset)
;;; These are magically converted by the compiler.
;;;
(defun kernel:current-sp () (kernel:current-sp))
(defun kernel:current-fp () (kernel:current-fp))
(defun kernel:stack-ref (s n) (kernel:stack-ref s n))
(defun kernel:%set-stack-ref (s n value) (kernel:%set-stack-ref s n value))
(defun kernel:function-code-header (fun) (kernel:function-code-header fun))
#-gengc (defun kernel:lra-code-header (lra) (kernel:lra-code-header lra))
(defun kernel:make-lisp-obj (value) (kernel:make-lisp-obj value))
(defun kernel:get-lisp-obj-address (thing) (kernel:get-lisp-obj-address thing))
(defun kernel:function-word-offset (fun) (kernel:function-word-offset fun))
;;;
(defsetf kernel:stack-ref kernel:%set-stack-ref)
(declaim (inline cstack-pointer-valid-p))
(defun cstack-pointer-valid-p (x)
(declare (type system:system-area-pointer x))
#-:x86
(and (system:sap< x (kernel:current-sp))
(system:sap<= #-gengc (alien:alien-sap
(alien:extern-alien "control_stack" (* t)))
#+gengc (kernel:mutator-control-stack-base)
x)
(zerop (logand (system:sap-int x) #b11)))
#+:x86 ;; stack grows to low address values
(and (system:sap>= x (kernel:current-sp))
(system:sap> (alien:alien-sap
(alien:extern-alien "control_stack_end" (* t)))
x)
(zerop (logand (system:sap-int x) #b11))))
#+(or gengc x86)
(alien:def-alien-routine component-ptr-from-pc (system:system-area-pointer)
(pc system:system-area-pointer))
#+(or gengc x86)
(defun component-from-component-ptr (component-ptr)
(declare (type system:system-area-pointer component-ptr))
(kernel:make-lisp-obj
(logior (system:sap-int component-ptr)
vm:other-pointer-type)))
;;;; X86 support.
#+x86
(progn
(defun compute-lra-data-from-pc (pc)
(declare (type system-area-pointer pc))
(let ((component-ptr (component-ptr-from-pc pc)))
(unless (sap= component-ptr (int-sap #x0))
(let* ((code (component-from-component-ptr component-ptr))
(code-header-len (* (kernel:get-header-data code) vm:word-bytes))
(pc-offset (- (sap-int pc)
(- (kernel:get-lisp-obj-address code)
vm:other-pointer-type)
code-header-len)))
; (format t "c-lra-fpc ~a ~a ~a~%" pc code pc-offset)
(values pc-offset code)))))
(defconstant vm::nargs-offset #.vm::ecx-offset)
;;; Check for a valid return address - it could be any valid C/Lisp
;;; address.
;;;
;;; XX Could be a little smarter.
(declaim (inline ra-pointer-valid-p))
(defun ra-pointer-valid-p (ra)
(declare (type system:system-area-pointer ra))
(and
;; Not the first page which is unmapped.
(>= (sys:sap-int ra) 4096)
;; Not a Lisp stack pointer.
(or (sys:sap< ra (kernel:current-sp))
(sys:sap>= ra (alien:alien-sap
(alien:extern-alien "control_stack_end" (* t)))))))
;;; Try to find a valid previous stack. This is complex on the x86 as
;;; it can jump between C and Lisp frames. To help find a valid frame
;;; it searches backwards.
;;;
;;; XX Should probably check if it has reached the bottom of the
;;; stack.
;;;
;;; XX Should handle interrupted frames, both Lisp and C. A present it
;;; manages to find a fp trail, see linux hack below.
;;;
(defun x86-call-context (fp &key (depth 8))
(declare (type system-area-pointer fp)
(fixnum depth))
; (format t "*CC ~s ~s~%" fp depth)
(cond
((not (cstack-pointer-valid-p fp))
(format t "Debug invalid fp ~s~%" fp)
nil)
(t
;; Check the two possible frame pointers.
(let ((lisp-ocfp (sap-ref-sap fp (- (* (1+ vm::ocfp-save-offset) 4))))
(lisp-ra (sap-ref-sap fp (- (* (1+ vm::return-pc-save-offset) 4))))
(c-ocfp (sap-ref-sap fp (* 0 vm:word-bytes)))
(c-ra (sap-ref-sap fp (* 1 vm:word-bytes))))
(cond ((and (sap> lisp-ocfp fp) (cstack-pointer-valid-p lisp-ocfp)
(ra-pointer-valid-p lisp-ra)
(sap> c-ocfp fp) (cstack-pointer-valid-p c-ocfp)
(ra-pointer-valid-p c-ra))
; (format t "*C Both valid ~s ~s ~s ~s~%"
; lisp-ocfp lisp-ra c-ocfp c-ra)
;; Look forward another step to check their validity.
(let ((lisp-path-fp (x86-call-context lisp-ocfp
:depth (- depth 1)))
(c-path-fp (x86-call-context c-ocfp :depth (- depth 1))))
(cond ((and lisp-path-fp c-path-fp)
;; Both still seem valid - choose the smallest.
(format t "Debug: Both still valid ~s ~s ~s ~s~%"
lisp-ocfp lisp-ra c-ocfp c-ra)
(if (sap< lisp-ocfp c-ocfp)
(values lisp-ra lisp-ocfp)
(values c-ra c-ocfp)))
(lisp-path-fp
;; The lisp convention is looking good.
; (format t "*C lisp-ocfp ~s ~s~%" lisp-ocfp lisp-ra)
(values lisp-ra lisp-ocfp))
(c-path-fp
;; The C convention is looking good.
; (format t "*C c-ocfp ~s ~s~%" c-ocfp c-ra)
(values c-ra c-ocfp))
(t
;; Neither seems right?
; (format t "Debug: no valid2 fp found ~s ~s~%"
; lisp-ocfp c-ocfp)
nil))))
((and (sap> lisp-ocfp fp) (cstack-pointer-valid-p lisp-ocfp)
(ra-pointer-valid-p lisp-ra))
;; The lisp convention is looking good.
; (format t "*C lisp-ocfp ~s ~s~%" lisp-ocfp lisp-ra)
(values lisp-ra lisp-ocfp))
((and (sap> c-ocfp fp) (cstack-pointer-valid-p c-ocfp)
#-linux (ra-pointer-valid-p c-ra))
;; The C convention is looking good.
; (format t "*C c-ocfp ~s ~s~%" c-ocfp c-ra)
(values c-ra c-ocfp))
(t
; (format t "Debug: no valid fp found ~s ~s~%" lisp-ocfp c-ocfp)
nil))))))
) ; end progn x86
;;; DESCRIPTOR-SAP -- internal
;;;
;;; Convert the descriptor into a SAP. The bits all stay the same, we just
;;; change our notion of what we think they are.
;;;
(declaim (inline descriptor-sap))
(defun descriptor-sap (x)
(system:int-sap (kernel:get-lisp-obj-address x)))
;;; TOP-FRAME -- Public.
;;;
(defun top-frame ()
"Returns the top frame of the control stack as it was before calling this
function."
(multiple-value-bind (fp pc)
(kernel:%caller-frame-and-pc)
(possibly-an-interpreted-frame
(compute-calling-frame (descriptor-sap fp)
#-gengc pc #+gengc (descriptor-sap pc)
nil)
nil)))
;;; FLUSH-FRAMES-ABOVE -- public.
;;;
(defun flush-frames-above (frame)
"Flush all of the frames above FRAME, and renumber all the frames below
FRAME."
(setf (frame-up frame) nil)
(do ((number 0 (1+ number))
(frame frame (frame-%down frame)))
((not (frame-p frame)))
(setf (frame-number frame) number)))
;;; FRAME-DOWN -- Public.
;;;
;;; We have to access the old-fp and return-pc out of frame and pass them to
;;; COMPUTE-CALLING-FRAME.
;;;
(defun frame-down (frame)
"Returns the frame immediately below frame on the stack. When frame is
the bottom of the stack, this returns nil."
(let ((down (frame-%down frame)))
(if (eq down :unparsed)
(let* ((real (frame-real-frame frame))
(debug-fun (frame-debug-function real)))
(setf (frame-%down frame)
(etypecase debug-fun
(compiled-debug-function
(let ((c-d-f (compiled-debug-function-compiler-debug-fun
debug-fun)))
(possibly-an-interpreted-frame
(compute-calling-frame
(descriptor-sap
(get-context-value
real vm::ocfp-save-offset
(c::compiled-debug-function-old-fp c-d-f)))
#-gengc
(get-context-value
real vm::lra-save-offset
(c::compiled-debug-function-return-pc c-d-f))
#+gengc
(descriptor-sap
(get-context-value
real vm::ra-save-offset
(c::compiled-debug-function-return-pc c-d-f)))
frame)
frame)))
(bogus-debug-function
(let ((fp (frame-pointer real)))
(when (cstack-pointer-valid-p fp)
#+x86
(multiple-value-bind (ra ofp) (x86-call-context fp)
(compute-calling-frame ofp ra frame))
#-x86
(compute-calling-frame
#-alpha
(system:sap-ref-sap fp (* vm::ocfp-save-offset
vm:word-bytes))
#+alpha
(kernel::int-sap
(system:sap-ref-32 fp (* vm::ocfp-save-offset
vm:word-bytes)))
#-gengc
(kernel:stack-ref fp vm::lra-save-offset)
#+gengc
(system:sap-ref-sap fp (* vm::ra-save-offset
vm:word-bytes))
frame)))))))
down)))
;;; GET-CONTEXT-VALUE -- Internal.
;;;
;;; Get the old FP or return PC out of frame. Stack-slot is the standard save
;;; location offset on the stack. Loc is the saved sc-offset describing the
;;; main location.
;;;
#-x86
(defun get-context-value (frame stack-slot loc)
(declare (type compiled-frame frame) (type unsigned-byte stack-slot)
(type c::sc-offset loc))
(let ((pointer (frame-pointer frame))
(escaped (compiled-frame-escaped frame)))
(if escaped
(sub-access-debug-var-slot pointer loc escaped)
(kernel:stack-ref pointer stack-slot))))
#+x86
(defun get-context-value (frame stack-slot loc)
(declare (type compiled-frame frame) (type unsigned-byte stack-slot)
(type c::sc-offset loc))
(let ((pointer (frame-pointer frame))
(escaped (compiled-frame-escaped frame)))
(if escaped
(sub-access-debug-var-slot pointer loc escaped)
(ecase stack-slot
(#.vm::ocfp-save-offset
(kernel:stack-ref pointer stack-slot))
(#.vm::lra-save-offset
(sap-ref-sap pointer (- (* (1+ stack-slot) 4))))))))
;;;
#-x86
(defun (setf get-context-value) (value frame stack-slot loc)
(declare (type compiled-frame frame) (type unsigned-byte stack-slot)
(type c::sc-offset loc))
(let ((pointer (frame-pointer frame))
(escaped (compiled-frame-escaped frame)))
(if escaped
(sub-set-debug-var-slot pointer loc value escaped)
(setf (kernel:stack-ref pointer stack-slot) value))))
#+x86
(defun (setf get-context-value) (value frame stack-slot loc)
(declare (type compiled-frame frame) (type unsigned-byte stack-slot)
(type c::sc-offset loc))
(let ((pointer (frame-pointer frame))
(escaped (compiled-frame-escaped frame)))
(if escaped
(sub-set-debug-var-slot pointer loc value escaped)
(ecase stack-slot
(#.vm::ocfp-save-offset
(setf (kernel:stack-ref pointer stack-slot) value))
(#.vm::lra-save-offset
(setf (sap-ref-sap pointer (- (* (1+ stack-slot) 4))) value))))))
(defvar *debugging-interpreter* nil
"When set, the debugger foregoes making interpreted-frames, so you can
debug the functions that manifest the interpreter.")
;;; POSSIBLY-AN-INTERPRETED-FRAME -- Internal.
;;;
;;; This takes a newly computed frame, frame, and the frame above it on the
;;; stack, up-frame, which is possibly nil. Frame is nil when we hit the
;;; bottom of the control stack. When frame represents a call to
;;; EVAL::INTERNAL-APPLY-LOOP, we make an interpreted frame to replace frame.
;;; The interpreted frame points to frame.
;;;
(defun possibly-an-interpreted-frame (frame up-frame)
(if (or (not frame)
(not (eq (debug-function-name (frame-debug-function frame))
'eval::internal-apply-loop))
*debugging-interpreter*
(compiled-frame-escaped frame))
frame
(flet ((get-var (name location)
(let ((vars (di:ambiguous-debug-variables
(di:frame-debug-function frame) name)))
(when (or (null vars) (> (length vars) 1))
(error "Zero or more than one ~A variable in ~
EVAL::INTERNAL-APPLY-LOOP?"
(string-downcase name)))
(if (eq (debug-variable-validity (car vars) location)
:valid)
(car vars)))))
(let* ((code-loc (frame-code-location frame))
(ptr-var (get-var "FRAME-PTR" code-loc))
(node-var (get-var "NODE" code-loc))
(closure-var (get-var "CLOSURE" code-loc)))
(if (and ptr-var node-var closure-var)
(let* ((node (debug-variable-value node-var frame))
(d-fun (make-interpreted-debug-function
(c::block-home-lambda (c::node-block node)))))
(make-interpreted-frame
(debug-variable-value ptr-var frame)
up-frame
d-fun
(make-interpreted-code-location node d-fun)
(frame-number frame)
frame
(debug-variable-value closure-var frame)))
frame)))))
;;; COMPUTE-CALLING-FRAME -- Internal.
;;;
;;; This returns a frame for the one existing in time immediately prior to the
;;; frame referenced by current-fp. This is current-fp's caller or the next
;;; frame down the control stack. If there is no down frame, this returns nil
;;; for the bottom of the stack. Up-frame is the up link for the resulting
;;; frame object, and it is nil when we call this to get the top of the stack.
;;;
;;; The current frame contains the pointer to the temporally previous frame we
;;; want, and the current frame contains the pc at which we will continue
;;; executing upon returning to that previous frame.
;;;
;;; Note: Sometimes LRA is actually a fixnum. This happens when lisp calls
;;; into C. In this case, the code object is stored on the stack after the
;;; LRA, and the LRA is the word offset.
;;;
#-(or gengc x86)
(defun compute-calling-frame (caller lra up-frame)
(declare (type system:system-area-pointer caller))
(when (cstack-pointer-valid-p caller)
(multiple-value-bind
(code pc-offset escaped)
(if lra
(multiple-value-bind
(word-offset code)
(if (ext:fixnump lra)
(let ((fp (frame-pointer up-frame)))
(values lra
(kernel:stack-ref fp (1+ vm::lra-save-offset))))
(values (kernel:get-header-data lra)
(kernel:lra-code-header lra)))
(if code
(values code
(* (1+ (- word-offset (kernel:get-header-data code)))
vm:word-bytes)
nil)
(values :foreign-function
0
nil)))
(find-escaped-frame caller))
(if (and (kernel:code-component-p code)
(eq (kernel:%code-debug-info code) :bogus-lra))
(let ((real-lra (kernel:code-header-ref code real-lra-slot)))
(compute-calling-frame caller real-lra up-frame))
(let ((d-fun (case code
(:undefined-function
(make-bogus-debug-function
"The Undefined Function"))
(:foreign-function
(make-bogus-debug-function
"Foreign function call land"))
((nil)
(make-bogus-debug-function
"Bogus stack frame"))
(t
(debug-function-from-pc code pc-offset)))))
(make-compiled-frame caller up-frame d-fun
(code-location-from-pc d-fun pc-offset
escaped)
(if up-frame (1+ (frame-number up-frame)) 0)
escaped))))))
#+x86
(defun compute-calling-frame (caller ra up-frame)
(declare (type system:system-area-pointer caller ra))
; (format t "ccf: ~a ~a ~a~%" caller ra up-frame)
(when (cstack-pointer-valid-p caller)
; (format t "ccf2~%")
;; First check for an escaped frame.
(multiple-value-bind
(code pc-offset escaped)
(find-escaped-frame caller)
(cond (code
;; If it's escaped it may be a function end breakpoint
;; trap.
; (format t "ccf2: escaped ~s ~s~%" code pc-offset)
(when (and (kernel:code-component-p code)
(eq (kernel:%code-debug-info code) :bogus-lra))
;; If :bogus-lra grab the real lra.
(setq pc-offset (kernel:code-header-ref
code (1+ real-lra-slot)))
(setq code (kernel:code-header-ref code real-lra-slot))
; (format t "ccf3 :bogus-lra ~s ~s~%" code pc-offset)
(assert code)))
(t
;; Not escaped
(multiple-value-setq (pc-offset code)
(compute-lra-data-from-pc ra))
; (format t "ccf4 ~s ~s~%" code pc-offset)
(unless code
(setf code :foreign-function
pc-offset 0
escaped nil))))
(let ((d-fun (case code
(:undefined-function
(make-bogus-debug-function
"The Undefined Function"))
(:foreign-function
(make-bogus-debug-function
"Foreign function call land"))
((nil)
(make-bogus-debug-function
"Bogus stack frame"))
(t
(debug-function-from-pc code pc-offset)))))
(make-compiled-frame caller up-frame d-fun
(code-location-from-pc d-fun pc-offset
escaped)
(if up-frame (1+ (frame-number up-frame)) 0)
escaped)))))
#-(or gengc x86)
(defun find-escaped-frame (frame-pointer)
(declare (type system:system-area-pointer frame-pointer))
(dotimes (index lisp::*free-interrupt-context-index* (values nil 0 nil))
(alien:with-alien
((lisp-interrupt-contexts (array (* unix:sigcontext) nil) :extern))
(let ((scp (alien:deref lisp-interrupt-contexts index)))
(when (= (system:sap-int frame-pointer)
(vm:sigcontext-register scp vm::cfp-offset))
(system:without-gcing
(let ((code (code-object-from-bits
(vm:sigcontext-register scp vm::code-offset))))
(when (symbolp code)
(return (values code 0 scp)))
(let* ((code-header-len (* (kernel:get-header-data code)
vm:word-bytes))
(pc-offset
(- (system:sap-int
(vm:sigcontext-program-counter scp))
(- (kernel:get-lisp-obj-address code)
vm:other-pointer-type)
code-header-len)))
;; Check to see if we were executing in a branch delay slot.
#+(or pmax sgi) ; pmax only
(when (logbitp 31 (alien:slot scp 'mips::sc-cause))
(incf pc-offset vm:word-bytes))
(unless (<= 0 pc-offset
(* (kernel:code-header-ref code
vm:code-code-size-slot)
vm:word-bytes))
;; We were in an assembly routine. Therefore, use the LRA as
;; the pc.
(setf pc-offset
(- (vm:sigcontext-register scp vm::lra-offset)
(kernel:get-lisp-obj-address code)
code-header-len)))
(return
(if (eq (kernel:%code-debug-info code) :bogus-lra)
(let ((real-lra (kernel:code-header-ref code
real-lra-slot)))
(values (kernel:lra-code-header real-lra)
(kernel:get-header-data real-lra)
nil))
(values code pc-offset scp)))))))))))
#+x86
(defun find-escaped-frame (frame-pointer)
(declare (type system:system-area-pointer frame-pointer))
(dotimes (index lisp::*free-interrupt-context-index* (values nil 0 nil))
(alien:with-alien
((lisp-interrupt-contexts (array (* unix:sigcontext) nil) :extern))
(let ((scp (alien:deref lisp-interrupt-contexts index)))
(when (= (system:sap-int frame-pointer)
(vm:sigcontext-register scp vm::cfp-offset))
(system:without-gcing
(let* ((component-ptr
(component-ptr-from-pc (vm:sigcontext-program-counter scp)))
(code (if (sap= component-ptr (int-sap #x0))
nil
(component-from-component-ptr component-ptr))))
(when (null code)
(return (values code 0 scp)))
(let* ((code-header-len (* (kernel:get-header-data code)
vm:word-bytes))
(pc-offset
(- (system:sap-int
(vm:sigcontext-program-counter scp))
(- (kernel:get-lisp-obj-address code)
vm:other-pointer-type)
code-header-len)))
(unless (<= 0 pc-offset
(* (kernel:code-header-ref code
vm:code-code-size-slot)
vm:word-bytes))
;; We were in an assembly routine. Therefore, use the LRA as
;; the pc.
(format t "** pc-offset ~s not in code obj ~s?~%"
pc-offset code))
(return
(values code pc-offset scp))))))))))
;;; CODE-OBJECT-FROM-BITS -- internal.
;;;
;;; Find the code object corresponding to the object represented by bits and
;;; return it. We assume bogus functions correspond to the
;;; undefined-function.
;;;
#-gengc
(defun code-object-from-bits (bits)
(declare (type (unsigned-byte 32) bits))
(let ((object (kernel:make-lisp-obj bits)))
(if (functionp object)
(or (kernel:function-code-header object)
:undefined-function)
(let ((lowtag (kernel:get-lowtag object)))
(if (= lowtag vm:other-pointer-type)
(let ((type (kernel:get-type object)))
(cond ((= type vm:code-header-type)
object)
((= type vm:return-pc-header-type)
(kernel:lra-code-header object))
(t
nil))))))))
;;; *SAVED-STATE-CHAIN* -- maintained by the C code as a list of saps, each
;;; sap pointing to a saved exception state.
;;;
#+gengc
(declaim (special kernel::*saved-state-chain*))
#+gengc
(defun lookup-trace-table-entry (component pc)
(declare (type code-component component)
(type unsigned-byte pc))
(let ((tt (system:sap+ (kernel:code-instructions component)
(kernel:code-header-ref
component
vm:code-trace-table-offset-slot)))
(end (system:sap+ (kernel:code-instructions component)
(* (kernel:%code-code-size component)
vm:word-bytes))))
(iterate repeat ((sap tt) (offset 0) (state vm:trace-table-normal))
(cond ((> offset pc)
state)
((system:sap< sap end)
(let ((entry (system:sap-ref-16 tt 0)))
(repeat (system:sap+ sap 2)
(+ offset
(ldb (byte c::tt-bits-per-offset
c::tt-bits-per-state)
entry))
(ldb (byte c::tt-bits-per-state 0) entry))))
(t
vm:trace-table-normal)))))
;;; EXTRACT-INFO-FROM-STATE -- internal.
;;;
;;; Examine the interrupt state and figure out where we were when the interrupt
;;; hit. Return three values, the debug-function, the pc-offset, and the
;;; control-frame-pointer.
;;;
;;; First, we check to see what component the PC is in the middle of. There
;;; are a couple interesting cases:
;;;
;;; - no component:
;;; we were either in one of the C trampoline routines:
;;; - call_into_lisp
;;; - call_into_c
;;; - undefined_tramp
;;; - closure_tramp
;;; - function_end_breakpoint
;;; arn't ever actually in it, because we copy it into a bogus-lra
;;; component before every actually using it.
;;; or someone jumped someplace strange, in which case we can't do anything.
;;; - component w/ :ASSEMBLER-ROUTINE for debug-info:
;;; we are in an assembly routine. RA will point back into the regular
;;; component. In order to find the CFP we need to check the trace table:
;;; - normal: CFP will hold the correct stack pointer.
;;; - call-site: OCFP will hold the correct stack pointer.
;;; - prologue & epilogue: not used
;;; - component w/ :BOGUS-LRA for debug-info:
;;; we are in the middle of a function-end-breakpoint.
;;; - regular component:
;;; check the trace table:
;;; - normal: everything fine: PC & CFP hold the info we want.
;;; - call-site: same as normal, except use OCFP for the frame pointer.
;;; - prologue: this frame hasn't been initialized. Use the caller, who
;;; can be found by looking at RA and OCFP.
;;; - epilogue: we are in a world of hurt, because we have trashed the
;;; current frame and can't reliably find the caller.
;;;
#+gengc
(defun extract-info-from-state (state)
(declare (type (alien:alien (* unix:sigcontext)) state)
(values debug-function unsigned-byte system:system-area-pointer))
(let* ((pc (vm:sigcontext-program-counter state))
(component-ptr (component-ptr-from-pc pc)))
(if (zerop (system:sap-int component-ptr))
;; We were in one of the trampoline routines or off in the ether.
;; ### Need to figure out which one, and do something better.
(values (make-bogus-debug-function "Trampoline routine")
0
(system:int-sap 0))
;; We have a real component.
(let* ((component (component-from-component-ptr component-ptr))
(pc-offset (- (sap- pc component-ptr)
(* (kernel:get-header-data component)
vm:word-bytes))))
(case (kernel:%code-debug-info component)
(:assembler-routine
(ecase (lookup-trace-table-entry component pc-offset)
(#.vm:trace-table-normal
;; ### Need to do something real.
(values (make-bogus-debug-function "Assembler routine.")
0
(system:int-sap
(vm:sigcontext-register state vm::cfp-offset))))
(#.vm:trace-table-call-site
;; ### Need to do something real.
(values (make-bogus-debug-function "Assembler routine.")
0
(system:int-sap
(vm:sigcontext-register state vm::ocfp-offset))))
(#.vm:trace-table-function-prologue
(values (make-bogus-debug-function
"Function-Prologue in an assembler routine?")
0
(system:int-sap 0)))
(#.vm:trace-table-function-epilogue
(values (make-bogus-debug-function
"Function-Epilogue in an assembler routine?")
0
(system:int-sap 0)))))
(:bogus-lra
(values (make-bogus-debug-function "Function-end breakpoing")
0
(system:int-sap 0)))
(t
(ecase (lookup-trace-table-entry component pc-offset)
(#.vm:trace-table-normal
(values (debug-function-from-pc component pc-offset)
pc-offset
(system:int-sap
(vm:sigcontext-register state vm::cfp-offset))))
(#.vm:trace-table-call-site
(values (debug-function-from-pc component pc-offset)
pc-offset
(system:int-sap
(vm:sigcontext-register state vm::ocfp-offset))))
(#.vm:trace-table-function-prologue
#+nil ;; ### Need to do something real.
(let* ((ra (system:int-sap
(vm:sigcontext-register state vm::ra-offset)))
(caller-ptr (component-ptr-from-pc ra)))
...)
(values (make-bogus-debug-function
"Interrupted function prologue")
0
(system:int-sap 0)))
(#.vm:trace-table-function-epilogue
(values (make-bogus-debug-function
"Interrupted function epiloge.")
0
(system:int-sap 0))))))))))
;;; COMPUTE-CALLING-FRAME -- GenGC version.
;;;
;;; Compute the frame that called us. The information we have available is
;;; the old control-frame-pointer and the return-address.
;;;
;;; On the gengc system, there are fewer special cases that compute-calling-
;;; frame needs to take into account.
;;;
#+gengc
(defun compute-calling-frame (ocfp ra up-frame)
(declare (type system:system-area-pointer ocfp ra))
(flet ((make-frame (dfun pc-offset &optional (cfp ocfp) state
(chain (if up-frame
(compiled-frame-saved-state-chain
(frame-real-frame up-frame))
kernel::*saved-state-chain*)))
(make-compiled-frame
cfp up-frame dfun
(code-location-from-pc dfun pc-offset nil)
(if up-frame (1+ (frame-number up-frame)) 0)
chain state)))
(cond
((zerop (system:sap-int ocfp))
;; If the ocfp is NULL, then we are the first stack frame after an
;; exception (or at the start).
(let ((saved-state-chain (if up-frame
(compiled-frame-saved-state-chain
(frame-real-frame up-frame))
kernel::*saved-state-chain*)))
(when saved-state-chain
;; Well, there are more saved states.
(let ((state
(locally
(declare (optimize (inhibit-warnings 3)))
(alien:sap-alien (car saved-state-chain)
(* unix:sigcontext)))))
(multiple-value-bind
(dfun pc-offset cfp)
(extract-info-from-state state)
(make-frame dfun pc-offset cfp state
(cdr saved-state-chain)))))))
((cstack-pointer-valid-p ocfp)
;; The ocfp is valid. Find the code component that ra points into.
(let ((component-ptr (component-ptr-from-pc ra)))
(if (zerop (system:sap-int component-ptr))
;; There isn't a component. We must have been called from C.
(make-frame (make-bogus-debug-function "Foreign function land") 0)
;; There is a component. Figure out what it is.
(let ((component (component-from-component-ptr component-ptr)))
;; ### Should check to see if it is a bogus lra.
(let* ((pc-offset
(- (sap- ra component-ptr)
(* (kernel:get-header-data component)
vm:word-bytes))))
(make-frame (debug-function-from-pc component pc-offset)
pc-offset))))))
(t
;; ocfp isn't NULL and isn't valid: we can't tell anything about the
;; caller. This shouldn't happen, and if it does, do something sane.
(make-frame (make-bogus-debug-function "Bogus stack frame") 0)))))
;;;
;;; Frame utilities.
;;;
;;; DEBUG-FUNCTION-FROM-PC -- Internal.
;;;
;;; This returns a compiled-debug-function for code and pc. We fetch the
;;; c::debug-info and run down its function-map to get a
;;; c::compiled-debug-function from the pc. The result only needs to reference
;;; the component, for function constants, and the c::compiled-debug-function.
;;;
(defun debug-function-from-pc (component pc)
(let ((info (kernel:%code-debug-info component)))
(cond
((not info)
(debug-signal 'no-debug-info))
((eq info :bogus-lra)
(make-bogus-debug-function "Function End Breakpoint"))
(t
(let* ((function-map (get-debug-info-function-map info))
(len (length function-map)))
(declare (simple-vector function-map))
(if (= len 1)
(make-compiled-debug-function (svref function-map 0) component)
(let ((i 1)
(elsewhere-p
(>= pc (c::compiled-debug-function-elsewhere-pc
(svref function-map 0)))))
(declare (type c::index i))
(loop
(when (or (= i len)
(< pc (if elsewhere-p
(c::compiled-debug-function-elsewhere-pc
(svref function-map (1+ i)))
(svref function-map i))))
(return (make-compiled-debug-function
(svref function-map (1- i))
component)))
(incf i 2)))))))))
;;; CODE-LOCATION-FROM-PC -- Internal.
;;;
;;; This returns a code-location for the compiled-debug-function, debug-fun,
;;; and the pc into its code vector. If we stopped at a breakpoint, find
;;; the code-location for that breakpoint. Otherwise, make an :unsure code
;;; location, so it can be filled in when we figure out what is going on.
;;;
(defun code-location-from-pc (debug-fun pc escaped)
(or (and (compiled-debug-function-p debug-fun)
escaped
(let ((data (breakpoint-data
(compiled-debug-function-component debug-fun)
pc nil)))
(when (and data (breakpoint-data-breakpoints data))
(let ((what (breakpoint-what
(first (breakpoint-data-breakpoints data)))))
(when (compiled-code-location-p what)
what)))))
(make-compiled-code-location pc debug-fun)))
;;; FRAME-CATCHES -- Public.
;;;
(defun frame-catches (frame)
"Returns an a-list mapping catch tags to code-locations. These are
code-locations at which execution would continue with frame as the top
frame if someone threw to the corresponding tag."
(let ((catch
#-gengc (descriptor-sap lisp::*current-catch-block*)
#+gengc (kernel:mutator-current-catch-block))
(res nil)
(fp (frame-pointer (frame-real-frame frame))))
(loop
(when (zerop (sap-int catch)) (return (nreverse res)))
(when (sap= fp
#-alpha
(system:sap-ref-sap catch
(* vm:catch-block-current-cont-slot
vm:word-bytes))
#+alpha
(kernel::int-sap
(system:sap-ref-32 catch
(* vm:catch-block-current-cont-slot
vm:word-bytes))))
(let* (#-(or gengc x86)
(lra (kernel:stack-ref catch vm:catch-block-entry-pc-slot))
#+(or gengc x86)
(ra (system:sap-ref-sap
catch (* vm:catch-block-entry-pc-slot vm:word-bytes)))
#-x86
(component
(kernel:stack-ref catch vm:catch-block-current-code-slot))
#+x86
(component (component-from-component-ptr
(component-ptr-from-pc ra)))
(offset
#-(or gengc x86)
(* (- (1+ (kernel:get-header-data lra))
(kernel:get-header-data component))
vm:word-bytes)
#+gengc
(+ (- (system:sap-int ra)
(kernel:get-lisp-obj-address component)
(kernel:get-header-data component))
vm:other-pointer-type)
#+x86
(- (system:sap-int ra)
(- (kernel:get-lisp-obj-address component)
vm:other-pointer-type)
(* (kernel:get-header-data component) vm:word-bytes))))
(push (cons #-x86
(kernel:stack-ref catch vm:catch-block-tag-slot)
#+x86
(kernel:make-lisp-obj
(system:sap-ref-32 catch (* vm:catch-block-tag-slot
vm:word-bytes)))
(make-compiled-code-location
offset (frame-debug-function frame)))
res)))
(setf catch
#-alpha
(system:sap-ref-sap catch
(* vm:catch-block-previous-catch-slot
vm:word-bytes))
#+alpha
(kernel::int-sap
(system:sap-ref-32 catch
(* vm:catch-block-previous-catch-slot
vm:word-bytes)))))))
;;; FRAME-REAL-FRAME -- Internal.
;;;
;;; If an interpreted frame, return the real frame, otherwise frame.
;;;
(defun frame-real-frame (frame)
(etypecase frame
(compiled-frame frame)
(interpreted-frame (interpreted-frame-real-frame frame))))
;;;; Debug-functions.
;;; DO-DEBUG-FUNCTION-BLOCKS -- Public.
;;;
(defmacro do-debug-function-blocks ((block-var debug-function &optional result)
&body body)
"Executes the forms in a context with block-var bound to each debug-block in
debug-function successively. Result is an optional form to execute for
return values, and DO-DEBUG-FUNCTION-BLOCKS returns nil if there is no
result form. This signals a no-debug-blocks condition when the
debug-function lacks debug-block information."
(let ((blocks (gensym))
(i (gensym)))
`(let ((,blocks (debug-function-debug-blocks ,debug-function)))
(declare (simple-vector ,blocks))
(dotimes (,i (length ,blocks) ,result)
(let ((,block-var (svref ,blocks ,i)))
,@body)))))
;;; DO-DEBUG-FUNCTION-VARIABLES -- Public.
;;;
(defmacro do-debug-function-variables ((var debug-function &optional result)
&body body)
"Executes body in a context with var bound to each debug-variable in
debug-function. This returns the value of executing result (defaults to
nil). This may iterate over only some of debug-function's variables or none
depending on debug policy; for example, possibly the compilation only
preserved argument information."
(let ((vars (gensym))
(i (gensym)))
`(let ((,vars (debug-function-debug-variables ,debug-function)))
(declare (type (or null simple-vector) ,vars))
(if ,vars
(dotimes (,i (length ,vars) ,result)
(let ((,var (svref ,vars ,i)))
,@body))
,result))))
;;; DEBUG-FUNCTION-FUNCTION -- Public.
;;;
(defun debug-function-function (debug-function)
"Returns the Common Lisp function associated with the debug-function. This
returns nil if the function is unavailable or is non-existent as a user
callable function object."
(let ((cached-value (debug-function-%function debug-function)))
(if (eq cached-value :unparsed)
(setf (debug-function-%function debug-function)
(etypecase debug-function
(compiled-debug-function
(let ((component
(compiled-debug-function-component debug-function))
(start-pc
(c::compiled-debug-function-start-pc
(compiled-debug-function-compiler-debug-fun
debug-function))))
(do ((entry (kernel:%code-entry-points component)
(kernel:%function-next entry)))
((null entry) nil)
(when (= start-pc
(c::compiled-debug-function-start-pc
(compiled-debug-function-compiler-debug-fun
(function-debug-function entry))))
(return entry)))))
(interpreted-debug-function
(c::lambda-eval-info-function
(c::leaf-info
(interpreted-debug-function-ir1-lambda debug-function))))
(bogus-debug-function nil)))
cached-value)))
;;; DEBUG-FUNCTION-NAME -- Public.
;;;
(defun debug-function-name (debug-function)
"Returns the name of the function represented by debug-function. This may
be a string or a cons; do not assume it is a symbol."
(etypecase debug-function
(compiled-debug-function
(c::compiled-debug-function-name
(compiled-debug-function-compiler-debug-fun debug-function)))
(interpreted-debug-function
(c::lambda-name (interpreted-debug-function-ir1-lambda debug-function)))
(bogus-debug-function
(bogus-debug-function-%name debug-function))))
;;; FUNCTION-DEBUG-FUNCTION -- Public.
;;;
(defun function-debug-function (fun)
"Returns a debug-function that represents debug information for function."
(case (get-type fun)
(#.vm:closure-header-type
(function-debug-function (%closure-function fun)))
(#.vm:funcallable-instance-header-type
(cond ((eval:interpreted-function-p fun)
(make-interpreted-debug-function
(or (eval::interpreted-function-definition fun)
(eval::convert-interpreted-fun fun))))
(t
(function-debug-function (funcallable-instance-function fun)))))
((#.vm:function-header-type #.vm:closure-function-header-type)
(let* ((name (kernel:%function-name fun))
(component (kernel:function-code-header fun))
(res (find-if
#'(lambda (x)
(and (c::compiled-debug-function-p x)
(eq (c::compiled-debug-function-name x) name)
(eq (c::compiled-debug-function-kind x) nil)))
(get-debug-info-function-map
(kernel:%code-debug-info component)))))
(if res
(make-compiled-debug-function res component)
;; This used to be the non-interpreted branch, but William wrote it
;; to return the debug-fun of fun's XEP instead of fun's debug-fun.
;; The above code does this more correctly, but it doesn't get or
;; eliminate all appropriate cases. It mostly works, and probably
;; works for all named functions anyway.
(debug-function-from-pc component
(* (- (kernel:function-word-offset fun)
(kernel:get-header-data component))
vm:word-bytes)))))))
;;; DEBUG-FUNCTION-KIND -- Public.
;;;
(defun debug-function-kind (debug-function)
"Returns the kind of the function which is one of :optional, :external,
:top-level, :cleanup, nil."
(etypecase debug-function
(compiled-debug-function
(c::compiled-debug-function-kind
(compiled-debug-function-compiler-debug-fun debug-function)))
(interpreted-debug-function
(c::lambda-kind (interpreted-debug-function-ir1-lambda debug-function)))
(bogus-debug-function
nil)))
;;; DEBUG-VARIABLE-INFO-AVAILABLE -- Public.
;;;
(defun debug-variable-info-available (debug-function)
"Returns whether there is any variable information for debug-function."
(not (not (debug-function-debug-variables debug-function))))
;;; DEBUG-FUNCTION-SYMBOL-VARIABLES -- Public.
;;;
(defun debug-function-symbol-variables (debug-function symbol)
"Returns a list of debug-variables in debug-function having the same name
and package as symbol. If symbol is uninterned, then this returns a list of
debug-variables without package names and with the same name as symbol. The
result of this function is limited to the availability of variable
information in debug-function; for example, possibly debug-function only
knows about its arguments."
(let ((vars (ambiguous-debug-variables debug-function (symbol-name symbol)))
(package (if (symbol-package symbol)
(package-name (symbol-package symbol)))))
(delete-if (if (stringp package)
#'(lambda (var)
(let ((p (debug-variable-package var)))
(or (not (stringp p))
(string/= p package))))
#'(lambda (var)
(stringp (debug-variable-package var))))
vars)))
;;; AMBIGUOUS-DEBUG-VARIABLES -- Public.
;;;
(defun ambiguous-debug-variables (debug-function name-prefix-string)
"Returns a list of debug-variables in debug-function whose names contain
name-prefix-string as an intial substring. The result of this function is
limited to the availability of variable information in debug-function; for
example, possibly debug-function only knows about its arguments."
(declare (simple-string name-prefix-string))
(let ((variables (debug-function-debug-variables debug-function)))
(declare (type (or null simple-vector) variables))
(if variables
(let* ((len (length variables))
(prefix-len (length name-prefix-string))
(pos (find-variable name-prefix-string variables len))
(res nil))
(when pos
;; Find names from pos to variable's len that contain prefix.
(do ((i pos (1+ i)))
((= i len))
(let* ((var (svref variables i))
(name (debug-variable-name var))
(name-len (length name)))
(declare (simple-string name))
(when (/= (or (string/= name-prefix-string name
:end1 prefix-len :end2 name-len)
prefix-len)
prefix-len)
(return))
(push var res)))
(setq res (nreverse res)))
res))))
;;; FIND-VARIABLE -- Internal.
;;;
;;; This returns a position in variables for one containing name as an initial
;;; substring. End is the length of variables if supplied.
;;;
(defun find-variable (name variables &optional end)
(declare (simple-vector variables)
(simple-string name))
(let ((name-len (length name)))
(position name variables
:test #'(lambda (x y)
(let* ((y (debug-variable-name y))
(y-len (length y)))
(declare (simple-string y))
(and (>= y-len name-len)
(string= x y :end1 name-len :end2 name-len))))
:end (or end (length variables)))))
;;; DEBUG-FUNCTION-LAMBDA-LIST -- Public.
;;;
(defun debug-function-lambda-list (debug-function)
"Returns a list representing the lambda-list for debug-function. The list
has the following structure:
(required-var1 required-var2
...
(:optional var3 suppliedp-var4)
(:optional var5)
...
(:rest var6) (:rest var7)
...
(:keyword keyword-symbol var8 suppliedp-var9)
(:keyword keyword-symbol var10)
...
)
Each VARi is a debug-variable; however it may be the symbol :deleted it
is unreferenced in debug-function. This signals a lambda-list-unavaliable
condition when there is no argument list information."
(etypecase debug-function
(compiled-debug-function
(compiled-debug-function-lambda-list debug-function))
(interpreted-debug-function
(interpreted-debug-function-lambda-list debug-function))
(bogus-debug-function
nil)))
;;; INTERPRETED-DEBUG-FUNCTION-LAMBDA-LIST -- Internal.
;;;
;;; The hard part is when the lambda-list is unparsed. If it is unparsed,
;;; and all the arguments are required, this is still pretty easy; just
;;; whip the appropriate debug-variables into a list. Otherwise, we have
;;; to pick out the funny arguments including any suppliedp variables. In
;;; this situation, the ir1-lambda is an external entry point that takes
;;; arguments users really pass in. It looks at those and computes defaults
;;; and suppliedp variables, ultimately passing everything defined as a
;;; a parameter to the real function as final arguments. If this has to
;;; compute the lambda list, it caches it in debug-function.
;;;
(defun interpreted-debug-function-lambda-list (debug-function)
(let ((lambda-list (debug-function-%lambda-list debug-function))
(debug-vars (debug-function-debug-variables debug-function))
(ir1-lambda (interpreted-debug-function-ir1-lambda debug-function))
(res nil))
(if (eq lambda-list :unparsed)
(flet ((frob (v debug-vars)
(if (c::lambda-var-refs v)
(find v debug-vars
:key #'interpreted-debug-variable-ir1-var)
:deleted)))
(let ((xep-args (c::lambda-optional-dispatch ir1-lambda)))
(if (and xep-args
(eq (c::optional-dispatch-main-entry xep-args) ir1-lambda))
;;
;; There are rest, optional, keyword, and suppliedp vars.
(let ((final-args (c::lambda-vars ir1-lambda)))
(dolist (xep-arg (c::optional-dispatch-arglist xep-args))
(let ((info (c::lambda-var-arg-info xep-arg))
(final-arg (pop final-args)))
(cond (info
(case (c::arg-info-kind info)
(:required
(push (frob final-arg debug-vars) res))
(:keyword
(push (list :keyword
(c::arg-info-keyword info)
(frob final-arg debug-vars))
res))
(:rest
(push (list :rest (frob final-arg debug-vars))
res))
(:optional
(push (list :optional
(frob final-arg debug-vars))
res)))
(when (c::arg-info-supplied-p info)
(nconc
(car res)
(list (frob (pop final-args) debug-vars)))))
(t
(push (frob final-arg debug-vars) res)))))
(setf (debug-function-%lambda-list debug-function)
(nreverse res)))
;;
;; All required args, so return them in a list.
(dolist (v (c::lambda-vars ir1-lambda)
(setf (debug-function-%lambda-list debug-function)
(nreverse res)))
(push (frob v debug-vars) res)))))
;;
;; Everything's unparsed and cached, so return it.
lambda-list)))
;;; COMPILED-DEBUG-FUNCTION-LAMBDA-LIST -- Internal.
;;;
;;; If this has to compute the lambda list, it caches it in debug-function.
;;;
(defun compiled-debug-function-lambda-list (debug-function)
(let ((lambda-list (debug-function-%lambda-list debug-function)))
(cond ((eq lambda-list :unparsed)
(multiple-value-bind
(args argsp)
(parse-compiled-debug-function-lambda-list debug-function)
(setf (debug-function-%lambda-list debug-function) args)
(if argsp
args
(debug-signal 'lambda-list-unavailable
:debug-function debug-function))))
(lambda-list)
((bogus-debug-function-p debug-function)
nil)
((c::compiled-debug-function-arguments
(compiled-debug-function-compiler-debug-fun
debug-function))
;; If the packed information is there (whether empty or not) as
;; opposed to being nil, then returned our cached value (nil).
nil)
(t
;; Our cached value is nil, and the packed lambda-list information
;; is nil, so we don't have anything available.
(debug-signal 'lambda-list-unavailable
:debug-function debug-function)))))
;;; PARSE-COMPILED-DEBUG-FUNCTION-LAMBDA-LIST -- Internal.
;;;
;;; COMPILED-DEBUG-FUNCTION-LAMBDA-LIST calls this when a
;;; compiled-debug-function has no lambda-list information cached. It returns
;;; the lambda-list as the first value and whether there was any argument
;;; information as the second value. Therefore, nil and t means there were no
;;; arguments, but nil and nil means there was no argument information.
;;;
(defun parse-compiled-debug-function-lambda-list (debug-function)
(let ((args (c::compiled-debug-function-arguments
(compiled-debug-function-compiler-debug-fun
debug-function))))
(cond
((not args)
(values nil nil))
((eq args :minimal)
(values (coerce (debug-function-debug-variables debug-function) 'list)
t))
(t
(let ((vars (debug-function-debug-variables debug-function))
(i 0)
(len (length args))
(res nil)
(optionalp nil))
(declare (type (or null simple-vector) vars))
(loop
(when (>= i len) (return))
(let ((ele (aref args i)))
(cond
((symbolp ele)
(case ele
(c::deleted
;; Deleted required arg at beginning of args array.
(push :deleted res))
(c::optional-args
(setf optionalp t))
(c::supplied-p
;; supplied-p var immediately following keyword or optional.
;; Stick the extra var in the result element representing
;; the keyword or optional, which is the previous one.
(nconc (car res)
(list (compiled-debug-function-lambda-list-var
args (incf i) vars))))
(c::rest-arg
(push (list :rest
(compiled-debug-function-lambda-list-var
args (incf i) vars))
res))
(c::more-arg
;; Just ignore the fact that the next two args are the
;; more arg context and count, and act like they are
;; regular arguments.
nil)
(t
;; Keyword arg.
(push (list :keyword
ele
(compiled-debug-function-lambda-list-var
args (incf i) vars))
res))))
(optionalp
;; We saw an optional marker, so the following non-symbols are
;; indexes indicating optional variables.
(push (list :optional (svref vars ele)) res))
(t
;; Required arg at beginning of args array.
(push (svref vars ele) res))))
(incf i))
(values (nreverse res) t))))))
;;; COMPILED-DEBUG-FUNCTION-LAMBDA-LIST-VAR -- Internal
;;;
;;; Used in COMPILED-DEBUG-FUNCTION-LAMBDA-LIST.
;;;
(defun compiled-debug-function-lambda-list-var (args i vars)
(declare (type (simple-array * (*)) args)
(simple-vector vars))
(let ((ele (aref args i)))
(cond ((not (symbolp ele)) (svref vars ele))
((eq ele 'c::deleted) :deleted)
(t (error "Malformed arguments description.")))))
;;; COMPILED-DEBUG-FUNCTION-DEBUG-INFO -- Internal.
;;;
(defun compiled-debug-function-debug-info (debug-fun)
(kernel:%code-debug-info (compiled-debug-function-component debug-fun)))
;;;; Unpacking variable and basic block data.
(defvar *parsing-buffer*
(make-array 20 :adjustable t :fill-pointer t))
(defvar *other-parsing-buffer*
(make-array 20 :adjustable t :fill-pointer t))
;;;
;;; WITH-PARSING-BUFFER -- Internal.
;;;
;;; PARSE-DEBUG-BLOCKS, PARSE-DEBUG-VARIABLES and UNCOMPACT-FUNCTION-MAP use
;;; this to unpack binary encoded information. It returns the values returned
;;; by the last form in body.
;;;
;;; This binds buffer-var to *parsing-buffer*, makes sure it starts at element
;;; zero, and makes sure if we unwind, we nil out any set elements for GC
;;; purposes.
;;;
;;; This also binds other-var to *other-parsing-buffer* when it is supplied,
;;; making sure it starts at element zero and that we nil out any elements if
;;; we unwind.
;;;
;;; This defines the local macro RESULT that takes a buffer, copies its
;;; elements to a resulting simple-vector, nil's out elements, and restarts
;;; the buffer at element zero. RESULT returns the simple-vector.
;;;
(eval-when (compile eval)
(defmacro with-parsing-buffer ((buffer-var &optional other-var) &body body)
(let ((len (gensym))
(res (gensym)))
`(unwind-protect
(let ((,buffer-var *parsing-buffer*)
,@(if other-var `((,other-var *other-parsing-buffer*))))
(setf (fill-pointer ,buffer-var) 0)
,@(if other-var `((setf (fill-pointer ,other-var) 0)))
(macrolet ((result (buf)
`(let* ((,',len (length ,buf))
(,',res (make-array ,',len)))
(replace ,',res ,buf :end1 ,',len :end2 ,',len)
(fill ,buf nil :end ,',len)
(setf (fill-pointer ,buf) 0)
,',res)))
,@body))
(fill *parsing-buffer* nil)
,@(if other-var `((fill *other-parsing-buffer* nil))))))
) ;eval-when
;;; DEBUG-FUNCTION-DEBUG-BLOCKS -- Internal.
;;;
;;; The argument is a debug internals structure. This returns the debug-blocks
;;; for debug-function, regardless of whether we have unpacked them yet. It
;;; signals a no-debug-blocks condition if it can't return the blocks.
;;;
(defun debug-function-debug-blocks (debug-function)
(let ((blocks (debug-function-blocks debug-function)))
(cond ((eq blocks :unparsed)
(setf (debug-function-blocks debug-function)
(parse-debug-blocks debug-function))
(unless (debug-function-blocks debug-function)
(debug-signal 'no-debug-blocks
:debug-function debug-function))
(debug-function-blocks debug-function))
(blocks)
(t
(debug-signal 'no-debug-blocks
:debug-function debug-function)))))
;;; PARSE-DEBUG-BLOCKS -- Internal.
;;;
;;; This returns a simple-vector of debug-blocks or nil. Nil indicates there
;;; was no basic block information.
;;;
(defun parse-debug-blocks (debug-function)
(etypecase debug-function
(compiled-debug-function
(parse-compiled-debug-blocks debug-function))
(bogus-debug-function
(debug-signal 'no-debug-blocks :debug-function debug-function))
(interpreted-debug-function
(parse-interpreted-debug-blocks debug-function))))
;;; PARSE-COMPILED-DEBUG-BLOCKS -- Internal.
;;;
;;; This does some of the work of PARSE-DEBUG-BLOCKS.
;;;
(defun parse-compiled-debug-blocks (debug-function)
(let* ((debug-fun (compiled-debug-function-compiler-debug-fun debug-function))
(var-count (length (debug-function-debug-variables debug-function)))
(blocks (c::compiled-debug-function-blocks debug-fun))
;; 8 is a hard-wired constant in the compiler for the element size of
;; the packed binary representation of the blocks data.
(live-set-len (ceiling var-count 8))
(tlf-number (c::compiled-debug-function-tlf-number debug-fun)))
(unless blocks (return-from parse-compiled-debug-blocks nil))
(macrolet ((aref+ (a i) `(prog1 (aref ,a ,i) (incf ,i))))
(with-parsing-buffer (blocks-buffer locations-buffer)
(let ((i 0)
(len (length blocks))
(last-pc 0))
(loop
(when (>= i len) (return))
(let ((succ-and-flags (aref+ blocks i))
(successors nil))
(declare (type (unsigned-byte 8) succ-and-flags)
(list successors))
(dotimes (k (ldb c::compiled-debug-block-nsucc-byte
succ-and-flags))
(push (c::read-var-integer blocks i) successors))
(let* ((locations
(dotimes (k (c::read-var-integer blocks i)
(result locations-buffer))
(let ((kind (svref c::compiled-code-location-kinds
(aref+ blocks i)))
(pc (+ last-pc (c::read-var-integer blocks i)))
(tlf-offset (or tlf-number
(c::read-var-integer blocks i)))
(form-number (c::read-var-integer blocks i))
(live-set (c::read-packed-bit-vector
live-set-len blocks i)))
(vector-push-extend (make-known-code-location
pc debug-function tlf-offset
form-number live-set kind)
locations-buffer)
(setf last-pc pc))))
(block (make-compiled-debug-block
locations successors
(not (zerop (logand
c::compiled-debug-block-elsewhere-p
succ-and-flags))))))
(vector-push-extend block blocks-buffer)
(dotimes (k (length locations))
(setf (code-location-%debug-block (svref locations k))
block))))))
(let ((res (result blocks-buffer)))
(declare (simple-vector res))
(dotimes (i (length res))
(let* ((block (svref res i))
(succs nil))
(dolist (ele (debug-block-successors block))
(push (svref res ele) succs))
(setf (debug-block-successors block) succs)))
res)))))
;;; PARSE-INTERPRETED-DEBUG-BLOCKS -- Internal.
;;;
;;; This does some of the work of PARSE-DEBUG-BLOCKS.
;;;
(defun parse-interpreted-debug-blocks (debug-function)
(let ((ir1-lambda (interpreted-debug-function-ir1-lambda debug-function)))
(with-parsing-buffer (buffer)
(c::do-blocks (block (c::block-component
(c::node-block (c::lambda-bind ir1-lambda))))
(when (eq ir1-lambda (c::block-home-lambda block))
(vector-push-extend (make-interpreted-debug-block block) buffer)))
(result buffer))))
;;; DEBUG-FUNCTION-DEBUG-VARIABLES -- Internal.
;;;
;;; The argument is a debug internals structure. This returns nil if there is
;;; no variable information. It returns an empty simple-vector if there were
;;; no locals in the function. Otherwise it returns a simple-vector of
;;; debug-variables.
;;;
(defun debug-function-debug-variables (debug-function)
(let ((vars (debug-function-debug-vars debug-function)))
(if (eq vars :unparsed)
(setf (debug-function-debug-vars debug-function)
(etypecase debug-function
(compiled-debug-function
(parse-compiled-debug-variables debug-function))
(bogus-debug-function nil)
(interpreted-debug-function
(parse-interpreted-debug-variables debug-function))))
vars)))
;;; PARSE-INTERPRETED-DEBUG-VARIABLES -- Internal.
;;;
;;; This grabs all the variables from debug-fun's ir1-lambda, from the IR1
;;; lambda vars, and all of it's LET's. Each LET is an IR1 lambda. For each
;;; variable, we make an interpreted-debug-variable. We then SORT all the
;;; variables by name. Then we go through, and for any duplicated names we
;;; distinguish the interpreted-debug-variables by setting their id slots to a
;;; distinct number.
;;;
(defun parse-interpreted-debug-variables (debug-fun)
(let* ((ir1-lambda (interpreted-debug-function-ir1-lambda debug-fun))
(vars (flet ((frob (ir1-lambda buf)
(dolist (v (c::lambda-vars ir1-lambda))
(vector-push-extend
(let* ((id (c::leaf-name v))
(pkg (symbol-package id)))
(make-interpreted-debug-variable
(symbol-name id)
(when pkg (package-name pkg))
v))
buf))))
(with-parsing-buffer (buf)
(frob ir1-lambda buf)
(dolist (let-lambda (c::lambda-lets ir1-lambda))
(frob let-lambda buf))
(result buf)))))
(declare (simple-vector vars))
(sort vars #'string< :key #'debug-variable-name)
(let ((len (length vars)))
(when (> len 1)
(let ((i 0)
(j 1))
(block PUNT
(loop
(let* ((var-i (svref vars i))
(var-j (svref vars j))
(name (debug-variable-name var-i)))
(when (string= name (debug-variable-name var-j))
(let ((count 1))
(loop
(setf (debug-variable-id var-j) count)
(when (= (incf j) len) (return-from PUNT))
(setf var-j (svref vars j))
(when (string/= name (debug-variable-name var-j))
(return))
(incf count))))
(setf i j)
(incf j)
(when (= j len) (return))))))))
vars))
;;; ASSIGN-MINIMAL-VAR-NAMES -- Internal.
;;;
;;; Vars is the parsed variables for a minimal debug function. We need to
;;; assign names of the form ARG-NNN. We must pad with leading zeros, since
;;; the arguments must be in alphabetical order.
;;;
(defun assign-minimal-var-names (vars)
(declare (simple-vector vars))
(let* ((len (length vars))
(width (length (format nil "~D" (1- len)))))
(dotimes (i len)
(setf (compiled-debug-variable-name (svref vars i))
(format nil "ARG-~V,'0D" width i)))))
;;; PARSE-COMPILED-DEBUG-VARIABLES -- Internal.
;;;
;;; This parses the packed binary representation of debug-variables from
;;; debug-function's c::compiled-debug-function.
;;;
(defun parse-compiled-debug-variables (debug-function)
(let* ((debug-fun (compiled-debug-function-compiler-debug-fun debug-function))
(packed-vars (c::compiled-debug-function-variables debug-fun))
(default-package (c::compiled-debug-info-package
(compiled-debug-function-debug-info debug-function)))
(args-minimal (eq (c::compiled-debug-function-arguments debug-fun)
:minimal)))
(unless packed-vars
(return-from parse-compiled-debug-variables nil))
(when (zerop (length packed-vars))
;; Return a simple-vector not whatever packed-vars may be.
(return-from parse-compiled-debug-variables '#()))
(let ((i 0)
(len (length packed-vars)))
(with-parsing-buffer (buffer)
(loop
;; The routines in the "C" package are macros that advance the
;; index.
(let* ((flags (prog1 (aref packed-vars i) (incf i)))
(minimal (logtest c::compiled-debug-variable-minimal-p flags))
(deleted (logtest c::compiled-debug-variable-deleted-p flags))
(name (if minimal "" (c::read-var-string packed-vars i)))
(package (cond
(minimal default-package)
((logtest c::compiled-debug-variable-packaged
flags)
(c::read-var-string packed-vars i))
((logtest c::compiled-debug-variable-uninterned
flags)
nil)
(t
default-package)))
(id (if (logtest c::compiled-debug-variable-id-p flags)
(c::read-var-integer packed-vars i)
0))
(sc-offset
(if deleted 0 (c::read-var-integer packed-vars i)))
(save-sc-offset
(if (logtest c::compiled-debug-variable-save-loc-p flags)
(c::read-var-integer packed-vars i)
nil)))
(assert (not (and args-minimal (not minimal))))
(vector-push-extend
(make-compiled-debug-variable
name package id
(logtest c::compiled-debug-variable-environment-live flags)
sc-offset save-sc-offset)
buffer))
(when (>= i len) (return)))
(let ((res (result buffer)))
(when args-minimal
(assign-minimal-var-names res))
res)))))
;;;; Unpacking minimal debug functions.
(eval-when (compile eval)
;;; MAKE-UNCOMPACTED-DEBUG-FUN -- Internal.
;;;
;;; Sleazoid "macro" to keep our indentation sane in UNCOMPACT-FUNCTION-MAP.
;;;
(defmacro make-uncompacted-debug-fun ()
'(c::make-compiled-debug-function
:name
(let ((base (ecase (ldb c::minimal-debug-function-name-style-byte
options)
(#.c::minimal-debug-function-name-symbol
(intern (c::read-var-string map i)
(c::compiled-debug-info-package info)))
(#.c::minimal-debug-function-name-packaged
(let ((pkg (c::read-var-string map i)))
(intern (c::read-var-string map i) pkg)))
(#.c::minimal-debug-function-name-uninterned
(make-symbol (c::read-var-string map i)))
(#.c::minimal-debug-function-name-component
(c::compiled-debug-info-name info)))))
(if (logtest flags c::minimal-debug-function-setf-bit)
`(setf ,base)
base))
:kind (svref c::minimal-debug-function-kinds
(ldb c::minimal-debug-function-kind-byte options))
:variables
(when vars-p
(let ((len (c::read-var-integer map i)))
(prog1 (subseq map i (+ i len))
(incf i len))))
:arguments (when vars-p :minimal)
:returns
(ecase (ldb c::minimal-debug-function-returns-byte options)
(#.c::minimal-debug-function-returns-standard
:standard)
(#.c::minimal-debug-function-returns-fixed
:fixed)
(#.c::minimal-debug-function-returns-specified
(with-parsing-buffer (buf)
(dotimes (idx (c::read-var-integer map i))
(vector-push-extend (c::read-var-integer map i) buf))
(result buf))))
:return-pc (c::read-var-integer map i)
:old-fp (c::read-var-integer map i)
:nfp (when (logtest flags c::minimal-debug-function-nfp-bit)
(c::read-var-integer map i))
:start-pc
(progn
(setq code-start-pc (+ code-start-pc (c::read-var-integer map i)))
(+ code-start-pc (c::read-var-integer map i)))
:elsewhere-pc
(setq elsewhere-pc (+ elsewhere-pc (c::read-var-integer map i)))))
) ;EVAL-WHEN (compile eval)
;;; UNCOMPACT-FUNCTION-MAP -- Internal
;;;
;;; Return a normal function map derived from a minimal debug info function
;;; map. This involves looping parsing minimal-debug-functions and then
;;; building a vector out of them.
;;;
(defun uncompact-function-map (info)
(declare (type c::compiled-debug-info info))
(let* ((map (c::compiled-debug-info-function-map info))
(i 0)
(len (length map))
(code-start-pc 0)
(elsewhere-pc 0))
(declare (type (simple-array (unsigned-byte 8) (*)) map))
(ext:collect ((res))
(loop
(when (= i len) (return))
(let* ((options (prog1 (aref map i) (incf i)))
(flags (prog1 (aref map i) (incf i)))
(vars-p (logtest flags c::minimal-debug-function-variables-bit))
(dfun (make-uncompacted-debug-fun)))
(res code-start-pc)
(res dfun)))
(coerce (cdr (res)) 'simple-vector))))
;;; This variable maps minimal debug-info function maps to an unpacked version
;;; thereof.
;;;
(defvar *uncompacted-function-maps* (make-hash-table :test #'eq))
;;; GET-DEBUG-INFO-FUNCTION-MAP -- Internal
;;;
;;; Return a function-map for a given compiled-debug-info object. If the
;;; info is minimal, and has not been parsed, then parse it.
;;;
(defun get-debug-info-function-map (info)
(declare (type c::compiled-debug-info info))
(let ((map (c::compiled-debug-info-function-map info)))
(if (simple-vector-p map)
map
(or (gethash map *uncompacted-function-maps*)
(setf (gethash map *uncompacted-function-maps*)
(uncompact-function-map info))))))
;;;; Code-locations.
;;; CODE-LOCATION-UNKNOWN-P -- Public.
;;;
;;; If we're sure of whether code-location is known, return t or nil. If we're
;;; :unsure, then try to fill in the code-location's slots. This determines
;;; whether there is any debug-block information, and if code-location is
;;; known.
;;;
;;; ??? IF this conses closures every time it's called, then break off the
;;; :unsure part to get the HANDLER-CASE into another function.
;;;
(defun code-location-unknown-p (basic-code-location)
"Returns whether basic-code-location is unknown. It returns nil when the
code-location is known."
(ecase (code-location-%unknown-p basic-code-location)
((t) t)
((nil) nil)
(:unsure
(setf (code-location-%unknown-p basic-code-location)
(handler-case (not (fill-in-code-location basic-code-location))
(no-debug-blocks () t))))))
;;; CODE-LOCATION-DEBUG-BLOCK -- Public.
;;;
(defun code-location-debug-block (basic-code-location)
"Returns the debug-block containing code-location if it is available. Some
debug policies inhibit debug-block information, and if none is available,
then this signals a no-debug-blocks condition."
(let ((block (code-location-%debug-block basic-code-location)))
(if (eq block :unparsed)
(etypecase basic-code-location
(compiled-code-location
(compute-compiled-code-location-debug-block basic-code-location))
(interpreted-code-location
(setf (code-location-%debug-block basic-code-location)
(make-interpreted-debug-block
(c::node-block
(interpreted-code-location-ir1-node basic-code-location))))))
block)))
;;; COMPUTE-COMPILED-CODE-LOCATION-DEBUG-BLOCK -- Internal.
;;;
;;; This stores and returns basic-code-location's debug-block. It determines
;;; the correct one using the code-location's pc. This uses
;;; DEBUG-FUNCTION-DEBUG-BLOCKS to return the cached block information or
;;; signal a 'no-debug-blocks condition. The blocks are sorted by their first
;;; code-location's pc, in ascending order. Therefore, as soon as we find a
;;; block that starts with a pc greater than basic-code-location's pc, we know
;;; the previous block contains the pc. If we get to the last block, then the
;;; code-location is either in the second to last block or the last block, and
;;; we have to be careful in determining this since the last block could be
;;; random code at the end of the function. We have to check for the last
;;; block being random code first to see how to compare the code-location's pc.
;;;
(defun compute-compiled-code-location-debug-block (basic-code-location)
(let* ((pc (compiled-code-location-pc basic-code-location))
(debug-function (code-location-debug-function
basic-code-location))
(blocks (debug-function-debug-blocks debug-function))
(len (length blocks)))
(declare (simple-vector blocks))
(setf (code-location-%debug-block basic-code-location)
(if (= len 1)
(svref blocks 0)
(do ((i 1 (1+ i))
(end (1- len)))
((= i end)
(let ((last (svref blocks end)))
(cond
((debug-block-elsewhere-p last)
(if (< pc
(c::compiled-debug-function-elsewhere-pc
(compiled-debug-function-compiler-debug-fun
debug-function)))
(svref blocks (1- end))
last))
((< pc
(compiled-code-location-pc
(svref (compiled-debug-block-code-locations last)
0)))
(svref blocks (1- end)))
(t last))))
(declare (type c::index i end))
(when (< pc
(compiled-code-location-pc
(svref (compiled-debug-block-code-locations
(svref blocks i))
0)))
(return (svref blocks (1- i)))))))))
;;; CODE-LOCATION-DEBUG-SOURCE -- Public.
;;;
(defun code-location-debug-source (code-location)
"Returns the code-location's debug-source."
(etypecase code-location
(compiled-code-location
(let* ((info (compiled-debug-function-debug-info
(code-location-debug-function code-location)))
(sources (c::compiled-debug-info-source info))
(len (length sources)))
(declare (list sources))
(when (zerop len)
(debug-signal 'no-debug-blocks :debug-function
(code-location-debug-function code-location)))
(if (= len 1)
(car sources)
(do ((prev sources src)
(src (cdr sources) (cdr src))
(offset (code-location-top-level-form-offset code-location)))
((null src) (car prev))
(when (< offset (c::debug-source-source-root (car src)))
(return (car prev)))))))
(interpreted-code-location
(first
(let ((c::*lexical-environment* (c::make-null-environment)))
(c::debug-source-for-info
(c::component-source-info
(c::block-component
(c::node-block
(interpreted-code-location-ir1-node code-location))))))))))
;;; CODE-LOCATION-TOP-LEVEL-FORM-OFFSET -- Public.
;;;
(defun code-location-top-level-form-offset (code-location)
"Returns the number of top-level forms before the one containing
code-location as seen by the compiler in some compilation unit. A
compilation unit is not necessarily a single file, see the section on
debug-sources."
(when (code-location-unknown-p code-location)
(error 'unknown-code-location :code-location code-location))
(let ((tlf-offset (code-location-%tlf-offset code-location)))
(cond ((eq tlf-offset :unparsed)
(etypecase code-location
(compiled-code-location
(unless (fill-in-code-location code-location)
;; This check should be unnecessary. We're missing debug info
;; the compiler should have dumped.
(error "Unknown code location? It should be known."))
(code-location-%tlf-offset code-location))
(interpreted-code-location
(setf (code-location-%tlf-offset code-location)
(c::source-path-tlf-number
(c::node-source-path
(interpreted-code-location-ir1-node code-location)))))))
(t tlf-offset))))
;;; CODE-LOCATION-FORM-NUMBER -- Public.
;;;
(defun code-location-form-number (code-location)
"Returns the number of the form corresponding to code-location. The form
number is derived by a walking the subforms of a top-level form in
depth-first order."
(when (code-location-unknown-p code-location)
(error 'unknown-code-location :code-location code-location))
(let ((form-num (code-location-%form-number code-location)))
(cond ((eq form-num :unparsed)
(etypecase code-location
(compiled-code-location
(unless (fill-in-code-location code-location)
;; This check should be unnecessary. We're missing debug info
;; the compiler should have dumped.
(error "Unknown code location? It should be known."))
(code-location-%form-number code-location))
(interpreted-code-location
(setf (code-location-%form-number code-location)
(c::source-path-form-number
(c::node-source-path
(interpreted-code-location-ir1-node code-location)))))))
(t form-num))))
;;; CODE-LOCATION-KIND -- Public
;;;
(defun code-location-kind (code-location)
"Return the kind of CODE-LOCATION, one of:
:interpreted, :unknown-return, :known-return, :internal-error,
:non-local-exit, :block-start, :call-site, :single-value-return,
:non-local-entry"
(when (code-location-unknown-p code-location)
(error 'unknown-code-location :code-location code-location))
(etypecase code-location
(compiled-code-location
(let ((kind (compiled-code-location-kind code-location)))
(cond ((not (eq kind :unparsed)) kind)
((not (fill-in-code-location code-location))
;; This check should be unnecessary. We're missing
;; debug info the compiler should have dumped.
(error "Unknown code location? It should be known."))
(t
(compiled-code-location-kind code-location)))))
(interpreted-code-location
:interpreted)))
;;; COMPILED-CODE-LOCATION-LIVE-SET -- Internal.
;;;
;;; This returns the code-location's live-set if it is available. If there
;;; is no debug-block information, this returns nil.
;;;
(defun compiled-code-location-live-set (code-location)
(if (code-location-unknown-p code-location)
nil
(let ((live-set (compiled-code-location-%live-set code-location)))
(cond ((eq live-set :unparsed)
(unless (fill-in-code-location code-location)
;; This check should be unnecessary. We're missing debug info
;; the compiler should have dumped.
(error "Unknown code location? It should be known."))
(compiled-code-location-%live-set code-location))
(t live-set)))))
;;; CODE-LOCATION= -- Public.
;;;
(defun code-location= (obj1 obj2)
"Returns whether obj1 and obj2 are the same place in the code."
(etypecase obj1
(compiled-code-location
(etypecase obj2
(compiled-code-location
(and (eq (code-location-debug-function obj1)
(code-location-debug-function obj2))
(sub-compiled-code-location= obj1 obj2)))
(interpreted-code-location
nil)))
(interpreted-code-location
(etypecase obj2
(compiled-code-location
nil)
(interpreted-code-location
(eq (interpreted-code-location-ir1-node obj1)
(interpreted-code-location-ir1-node obj2)))))))
;;;
(defun sub-compiled-code-location= (obj1 obj2)
(= (compiled-code-location-pc obj1)
(compiled-code-location-pc obj2)))
;;; FILL-IN-CODE-LOCATION -- Internal.
;;;
;;; This fills in location's :unparsed slots. It returns t or nil depending on
;;; whether the code-location was known in its debug-function's debug-block
;;; information. This may signal a no-debug-blocks condition due to
;;; DEBUG-FUNCTION-DEBUG-BLOCKS, and it assumes the %unknown-p slot is already
;;; set or going to be set.
;;;
(defun fill-in-code-location (code-location)
(declare (type compiled-code-location code-location))
(let* ((debug-function (code-location-debug-function code-location))
(blocks (debug-function-debug-blocks debug-function)))
(declare (simple-vector blocks))
(dotimes (i (length blocks) nil)
(let* ((block (svref blocks i))
(locations (compiled-debug-block-code-locations block)))
(declare (simple-vector locations))
(dotimes (j (length locations))
(let ((loc (svref locations j)))
(when (sub-compiled-code-location= code-location loc)
(setf (code-location-%debug-block code-location) block)
(setf (code-location-%tlf-offset code-location)
(code-location-%tlf-offset loc))
(setf (code-location-%form-number code-location)
(code-location-%form-number loc))
(setf (compiled-code-location-%live-set code-location)
(compiled-code-location-%live-set loc))
(setf (compiled-code-location-kind code-location)
(compiled-code-location-kind loc))
(return-from fill-in-code-location t))))))))
;;;; Debug-blocks.
;;; DO-DEBUG-BLOCK-LOCATIONS -- Public.
;;;
(defmacro do-debug-block-locations ((code-var debug-block &optional return)
&body body)
"Executes forms in a context with code-var bound to each code-location in
debug-block. This returns the value of executing result (defaults to nil)."
(let ((code-locations (gensym))
(i (gensym)))
`(let ((,code-locations (debug-block-code-locations ,debug-block)))
(declare (simple-vector ,code-locations))
(dotimes (,i (length ,code-locations) ,return)
(let ((,code-var (svref ,code-locations ,i)))
,@body)))))
;;; DEBUG-BLOCK-FUNCTION-NAME -- Internal.
;;;
(defun debug-block-function-name (debug-block)
"Returns the name of the function represented by debug-function. This may
be a string or a cons; do not assume it is a symbol."
(etypecase debug-block
(compiled-debug-block
(let ((code-locs (compiled-debug-block-code-locations debug-block)))
(declare (simple-vector code-locs))
(if (zerop (length code-locs))
"??? Can't get name of debug-block's function."
(debug-function-name
(code-location-debug-function (svref code-locs 0))))))
(interpreted-debug-block
(c::lambda-name (c::block-home-lambda
(interpreted-debug-block-ir1-block debug-block))))))
;;; DEBUG-BLOCK-CODE-LOCATIONS -- Internal.
;;;
(defun debug-block-code-locations (debug-block)
(etypecase debug-block
(compiled-debug-block
(compiled-debug-block-code-locations debug-block))
(interpreted-debug-block
(interpreted-debug-block-code-locations debug-block))))
;;; INTERPRETED-DEBUG-BLOCK-CODE-LOCATIONS -- Internal.
;;;
(defun interpreted-debug-block-code-locations (debug-block)
(let ((code-locs (interpreted-debug-block-locations debug-block)))
(if (eq code-locs :unparsed)
(with-parsing-buffer (buf)
(c::do-nodes (node cont (interpreted-debug-block-ir1-block
debug-block))
(vector-push-extend (make-interpreted-code-location
node
(make-interpreted-debug-function
(c::block-home-lambda (c::node-block node))))
buf))
(setf (interpreted-debug-block-locations debug-block)
(result buf)))
code-locs)))
;;;; Variables.
;;; DEBUG-VARIABLE-SYMBOL -- Public.
;;;
(defun debug-variable-symbol (debug-var)
"Returns the symbol from interning DEBUG-VARIABLE-NAME in the package named
by DEBUG-VARIABLE-PACKAGE."
(let ((package (debug-variable-package debug-var)))
(if package
(intern (debug-variable-name debug-var) package)
(make-symbol (debug-variable-name debug-var)))))
;;; DEBUG-VARIABLE-VALID-VALUE -- Public.
;;;
(defun debug-variable-valid-value (debug-var frame)
"Returns the value stored for debug-variable in frame. If the value is not
:valid, then this signals an invalid-value error."
(unless (eq (debug-variable-validity debug-var (frame-code-location frame))
:valid)
(error 'invalid-value :debug-variable debug-var :frame frame))
(debug-variable-value debug-var frame))
;;; DEBUG-VARIABLE-VALUE -- Public.
;;;
(defun debug-variable-value (debug-var frame)
"Returns the value stored for debug-variable in frame. The value may be
invalid. This is SETF'able."
(etypecase debug-var
(compiled-debug-variable
(check-type frame compiled-frame)
(let ((res (access-compiled-debug-var-slot debug-var frame)))
(if (indirect-value-cell-p res)
(c:value-cell-ref res)
res)))
(interpreted-debug-variable
(check-type frame interpreted-frame)
(eval::leaf-value-lambda-var
(interpreted-code-location-ir1-node (frame-code-location frame))
(interpreted-debug-variable-ir1-var debug-var)
(frame-pointer frame)
(interpreted-frame-closure frame)))))
;;; ACCESS-COMPILED-DEBUG-VAR-SLOT -- Internal.
;;;
;;; This returns what is stored for the variable represented by debug-var
;;; relative to the frame. This may be an indirect value cell if the
;;; variable is both closed over and set.
;;;
(defun access-compiled-debug-var-slot (debug-var frame)
(let ((escaped (compiled-frame-escaped frame)))
(if escaped
(sub-access-debug-var-slot
(frame-pointer frame)
(compiled-debug-variable-sc-offset debug-var)
escaped)
(sub-access-debug-var-slot
(frame-pointer frame)
(or (compiled-debug-variable-save-sc-offset debug-var)
(compiled-debug-variable-sc-offset debug-var))))))
;;; SUB-ACCESS-DEBUG-VAR-SLOT -- Internal.
;;;
#-x86
(defun sub-access-debug-var-slot (fp sc-offset &optional escaped)
(macrolet ((with-escaped-value ((var) &body forms)
`(if escaped
(let ((,var (vm:sigcontext-register
escaped
(c:sc-offset-offset sc-offset))))
,@forms)
:invalid-value-for-unescaped-register-storage))
(escaped-float-value (format)
`(if escaped
(vm:sigcontext-float-register
escaped
(c:sc-offset-offset sc-offset)
',format)
:invalid-value-for-unescaped-register-storage))
(with-nfp ((var) &body body)
`(let ((,var (if escaped
(system:int-sap
(vm:sigcontext-register escaped
vm::nfp-offset))
#-alpha
(system:sap-ref-sap fp (* vm::nfp-save-offset
vm:word-bytes))
#+alpha
(alpha::make-number-stack-pointer
(system:sap-ref-32 fp (* vm::nfp-save-offset
vm:word-bytes))))))
,@body)))
(ecase (c:sc-offset-scn sc-offset)
((#.vm:any-reg-sc-number
#.vm:descriptor-reg-sc-number
#+rt #.vm:word-pointer-reg-sc-number)
(system:without-gcing
(with-escaped-value (val)
(kernel:make-lisp-obj val))))
(#.vm:base-char-reg-sc-number
(with-escaped-value (val)
(code-char val)))
(#.vm:sap-reg-sc-number
(with-escaped-value (val)
(system:int-sap val)))
(#.vm:signed-reg-sc-number
(with-escaped-value (val)
(if (logbitp (1- vm:word-bits) val)
(logior val (ash -1 vm:word-bits))
val)))
(#.vm:unsigned-reg-sc-number
(with-escaped-value (val)
val))
#+nil ; PVE
(#.vm:non-descriptor-reg-sc-number
(error "Local non-descriptor register access?"))
#+nil ; PVE
(#.vm:interior-reg-sc-number
(error "Local interior register access?"))
(#.vm:single-reg-sc-number
(escaped-float-value single-float))
(#.vm:double-reg-sc-number
(escaped-float-value double-float))
#+complex-float
(#.vm:complex-single-reg-sc-number
(if escaped
(complex
(vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) 'single-float)
(vm:sigcontext-float-register
escaped (1+ (c:sc-offset-offset sc-offset)) 'single-float))
:invalid-value-for-unescaped-register-storage))
#+complex-float
(#.vm:complex-double-reg-sc-number
(if escaped
(complex
(vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) 'double-float)
(vm:sigcontext-float-register
escaped (+ (c:sc-offset-offset sc-offset) #+sparc 2 #-sparc 1)
'double-float))
:invalid-value-for-unescaped-register-storage))
(#.vm:single-stack-sc-number
(with-nfp (nfp)
(system:sap-ref-single nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))))
(#.vm:double-stack-sc-number
(with-nfp (nfp)
(system:sap-ref-double nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))))
#+complex-float
(#.vm:complex-single-stack-sc-number
(with-nfp (nfp)
(complex
(system:sap-ref-single nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(system:sap-ref-single nfp (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))))
#+complex-float
(#.vm:complex-double-stack-sc-number
(with-nfp (nfp)
(complex
(system:sap-ref-double nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(system:sap-ref-double nfp (* (+ (c:sc-offset-offset sc-offset) 2)
vm:word-bytes)))))
(#.vm:control-stack-sc-number
(kernel:stack-ref fp (c:sc-offset-offset sc-offset)))
(#.vm:base-char-stack-sc-number
(with-nfp (nfp)
(code-char (system:sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes)))))
(#.vm:unsigned-stack-sc-number
(with-nfp (nfp)
(system:sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))))
(#.vm:signed-stack-sc-number
(with-nfp (nfp)
(system:signed-sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))))
(#.vm:sap-stack-sc-number
(with-nfp (nfp)
(system:sap-ref-sap nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes)))))))
#+x86
(defun sub-access-debug-var-slot (fp sc-offset &optional escaped)
(declare (type system:system-area-pointer fp))
(macrolet ((with-escaped-value ((var) &body forms)
`(if escaped
(let ((,var (vm:sigcontext-register
escaped (c:sc-offset-offset sc-offset))))
,@forms)
:invalid-value-for-unescaped-register-storage))
(escaped-float-value (format)
`(if escaped
(vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) ',format)
:invalid-value-for-unescaped-register-storage))
#+complex-float
(escaped-complex-float-value (format)
`(if escaped
(complex
(vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) ',format)
(vm:sigcontext-float-register
escaped (1+ (c:sc-offset-offset sc-offset)) ',format))
:invalid-value-for-unescaped-register-storage))
;; The debug variable locations are not always valid, and
;; on the x86 locations can contain raw values. To
;; prevent later problems from invalid objects, they are
;; filtered here.
(make-valid-lisp-obj (val)
`(if (or
;; Fixnum
(zerop (logand ,val 3))
;; Character
(and (zerop (logand ,val #xffff0000)) ; Top bits zero
(= (logand ,val #xff) vm:base-char-type)) ; Char tag
;; Unbound marker.
(= ,val vm:unbound-marker-type)
;; Pointer
(and (logand ,val 1)
;; Check that the pointer is valid. XX Should do
;; a better job.
(< (lisp::read-only-space-start) ,val #x11000000)))
(kernel:make-lisp-obj ,val)
:invalid-object)))
(ecase (c:sc-offset-scn sc-offset)
((#.vm:any-reg-sc-number #.vm:descriptor-reg-sc-number)
(system:without-gcing
(with-escaped-value (val)
(make-valid-lisp-obj val))))
(#.vm:base-char-reg-sc-number
(with-escaped-value (val)
(code-char val)))
(#.vm:sap-reg-sc-number
(with-escaped-value (val)
(system:int-sap val)))
(#.vm:signed-reg-sc-number
(with-escaped-value (val)
(if (logbitp (1- vm:word-bits) val)
(logior val (ash -1 vm:word-bits))
val)))
(#.vm:unsigned-reg-sc-number
(with-escaped-value (val)
val))
#+nil ; PVE
(#.vm:non-descriptor-reg-sc-number
(error "Local non-descriptor register access?"))
#+nil ; PVE
(#.vm:interior-reg-sc-number
(error "Local interior register access?"))
(#.vm:single-reg-sc-number
(escaped-float-value single-float))
(#.vm:double-reg-sc-number
(escaped-float-value double-float))
#+complex-float
(#.vm:complex-single-reg-sc-number
(escaped-complex-float-value single-float))
#+complex-float
(#.vm:complex-double-reg-sc-number
(escaped-complex-float-value double-float))
(#.vm:single-stack-sc-number
(system:sap-ref-single fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes))))
(#.vm:double-stack-sc-number
(system:sap-ref-double fp (- (* (+ (c:sc-offset-offset sc-offset) 2)
vm:word-bytes))))
#+complex-float
(#.vm:complex-single-stack-sc-number
(complex
(system:sap-ref-single fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))
(system:sap-ref-single fp (- (* (+ (c:sc-offset-offset sc-offset) 2)
vm:word-bytes)))))
#+complex-float
(#.vm:complex-double-stack-sc-number
(complex
(system:sap-ref-double fp (- (* (+ (c:sc-offset-offset sc-offset) 2)
vm:word-bytes)))
(system:sap-ref-double fp (- (* (+ (c:sc-offset-offset sc-offset) 4)
vm:word-bytes)))))
(#.vm:control-stack-sc-number
(kernel:stack-ref fp (c:sc-offset-offset sc-offset)))
(#.vm:base-char-stack-sc-number
(code-char
(system:sap-ref-32 fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))))
(#.vm:unsigned-stack-sc-number
(system:sap-ref-32 fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes))))
(#.vm:signed-stack-sc-number
(system:signed-sap-ref-32 fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes))))
(#.vm:sap-stack-sc-number
(system:sap-ref-sap fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))))))
;;; %SET-DEBUG-VARIABLE-VALUE -- Internal.
;;;
;;; This stores value as the value of debug-var in frame. In the
;;; compiled-debug-variable case, access the current value to determine if it
;;; is an indirect value cell. This occurs when the variable is both closed
;;; over and set. For interpreted-debug-variables just call
;;; EVAL::SET-LEAF-VALUE-LAMBDA-VAR with the right interpreter objects.
;;;
(defun %set-debug-variable-value (debug-var frame value)
(etypecase debug-var
(compiled-debug-variable
(check-type frame compiled-frame)
(let ((current-value (access-compiled-debug-var-slot debug-var frame)))
(if (indirect-value-cell-p current-value)
(c:value-cell-set current-value value)
(set-compiled-debug-variable-slot debug-var frame value))))
(interpreted-debug-variable
(check-type frame interpreted-frame)
(eval::set-leaf-value-lambda-var
(interpreted-code-location-ir1-node (frame-code-location frame))
(interpreted-debug-variable-ir1-var debug-var)
(frame-pointer frame)
(interpreted-frame-closure frame)
value)))
value)
;;;
(defsetf debug-variable-value %set-debug-variable-value)
;;; SET-COMPILED-DEBUG-VARIABLE-SLOT -- Internal.
;;;
;;; This stores value for the variable represented by debug-var relative to the
;;; frame. This assumes the location directly contains the variable's value;
;;; that is, there is no indirect value cell currently there in case the
;;; variable is both closed over and set.
;;;
(defun set-compiled-debug-variable-slot (debug-var frame value)
(let ((escaped (compiled-frame-escaped frame)))
(if escaped
(sub-set-debug-var-slot (frame-pointer frame)
(compiled-debug-variable-sc-offset debug-var)
value escaped)
(sub-set-debug-var-slot
(frame-pointer frame)
(or (compiled-debug-variable-save-sc-offset debug-var)
(compiled-debug-variable-sc-offset debug-var))
value))))
;;; SUB-SET-DEBUG-VAR-SLOT -- Internal.
;;;
#-x86
(defun sub-set-debug-var-slot (fp sc-offset value &optional escaped)
(macrolet ((set-escaped-value (val)
`(if escaped
(setf (vm:sigcontext-register
escaped
(c:sc-offset-offset sc-offset))
,val)
value))
(set-escaped-float-value (format val)
`(if escaped
(setf (vm:sigcontext-float-register
escaped
(c:sc-offset-offset sc-offset)
',format)
,val)
value))
(with-nfp ((var) &body body)
`(let ((,var (if escaped
(system:int-sap
(vm:sigcontext-register escaped
vm::nfp-offset))
#-alpha
(system:sap-ref-sap fp
(* vm::nfp-save-offset
vm:word-bytes))
#+alpha
(alpha::make-number-stack-pointer
(system:sap-ref-32 fp
(* vm::nfp-save-offset
vm:word-bytes))))))
,@body)))
(ecase (c:sc-offset-scn sc-offset)
((#.vm:any-reg-sc-number
#.vm:descriptor-reg-sc-number
#+rt #.vm:word-pointer-reg-sc-number)
(system:without-gcing
(set-escaped-value
(kernel:get-lisp-obj-address value))))
(#.vm:base-char-reg-sc-number
(set-escaped-value (char-code value)))
(#.vm:sap-reg-sc-number
(set-escaped-value (system:sap-int value)))
(#.vm:signed-reg-sc-number
(set-escaped-value (logand value (1- (ash 1 vm:word-bits)))))
(#.vm:unsigned-reg-sc-number
(set-escaped-value value))
#+nil ; PVE
(#.vm:non-descriptor-reg-sc-number
(error "Local non-descriptor register access?"))
#+nil ; PVE
(#.vm:interior-reg-sc-number
(error "Local interior register access?"))
(#.vm:single-reg-sc-number
(set-escaped-float-value single-float value))
(#.vm:double-reg-sc-number
(set-escaped-float-value double-float value))
#+complex-float
(#.vm:single-reg-sc-number
(when escaped
(setf (vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) 'single-float)
(realpart value))
(setf (vm:sigcontext-float-register
escaped (1+ (c:sc-offset-offset sc-offset))
'single-float)
(imagpart value)))
value)
#+complex-float
(#.vm:double-reg-sc-number
(when escaped
(setf (vm:sigcontext-float-register
escaped (c:sc-offset-offset sc-offset) 'double-float)
(realpart value))
(setf (vm:sigcontext-float-register
escaped
(+ (c:sc-offset-offset sc-offset) #+sparc 2 #-sparc 1)
'double-float)
(imagpart value)))
value)
(#.vm:single-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-single nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(the single-float value))))
(#.vm:double-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-double nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(the double-float value))))
#+complex-float
(#.vm:complex-single-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-single
nfp (* (c:sc-offset-offset sc-offset) vm:word-bytes))
(the single-float (realpart value)))
(setf (system:sap-ref-single
nfp (* (1+ (c:sc-offset-offset sc-offset)) vm:word-bytes))
(the single-float (realpart value)))))
#+complex-float
(#.vm:complex-double-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-double
nfp (* (c:sc-offset-offset sc-offset) vm:word-bytes))
(the double-float (realpart value)))
(setf (system:sap-ref-double
nfp (* (+ (c:sc-offset-offset sc-offset) 2) vm:word-bytes))
(the double-float (realpart value)))))
(#.vm:control-stack-sc-number
(setf (kernel:stack-ref fp (c:sc-offset-offset sc-offset)) value))
(#.vm:base-char-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(char-code (the character value)))))
(#.vm:unsigned-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(the (unsigned-byte 32) value))))
(#.vm:signed-stack-sc-number
(with-nfp (nfp)
(setf (system:signed-sap-ref-32 nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(the (signed-byte 32) value))))
(#.vm:sap-stack-sc-number
(with-nfp (nfp)
(setf (system:sap-ref-sap nfp (* (c:sc-offset-offset sc-offset)
vm:word-bytes))
(the system:system-area-pointer value)))))))
#+x86
(defun sub-set-debug-var-slot (fp sc-offset value &optional escaped)
(macrolet ((set-escaped-value (val)
`(if escaped
(setf (vm:sigcontext-register
escaped
(c:sc-offset-offset sc-offset))
,val)
value)))
(ecase (c:sc-offset-scn sc-offset)
((#.vm:any-reg-sc-number #.vm:descriptor-reg-sc-number)
(system:without-gcing
(set-escaped-value
(kernel:get-lisp-obj-address value))))
(#.vm:base-char-reg-sc-number
(set-escaped-value (char-code value)))
(#.vm:sap-reg-sc-number
(set-escaped-value (system:sap-int value)))
(#.vm:signed-reg-sc-number
(set-escaped-value (logand value (1- (ash 1 vm:word-bits)))))
(#.vm:unsigned-reg-sc-number
(set-escaped-value value))
#+nil ; PVE
(#.vm:non-descriptor-reg-sc-number
(error "Local non-descriptor register access?"))
#+nil ; PVE
(#.vm:interior-reg-sc-number
(error "Local interior register access?"))
(#.vm:single-reg-sc-number
#+nil ;; don't have escaped floats.
(set-escaped-float-value single-float value))
(#.vm:double-reg-sc-number
#+nil ;; don't have escaped floats -- still in npx?
(set-escaped-float-value double-float value))
(#.vm:single-stack-sc-number
(setf (system:sap-ref-single
fp (- (* (1+ (c:sc-offset-offset sc-offset)) vm:word-bytes)))
(the single-float value)))
(#.vm:double-stack-sc-number
(setf (system:sap-ref-double
fp (- (* (+ (c:sc-offset-offset sc-offset) 2) vm:word-bytes)))
(the double-float value)))
#+complex-float
(#.vm:complex-single-stack-sc-number
(setf (system:sap-ref-single
fp (- (* (1+ (c:sc-offset-offset sc-offset)) vm:word-bytes)))
(realpart (the (complex single-float) value)))
(setf (system:sap-ref-single
fp (- (* (+ (c:sc-offset-offset sc-offset) 2) vm:word-bytes)))
(imagpart (the (complex single-float) value))))
#+complex-float
(#.vm:complex-double-stack-sc-number
(setf (system:sap-ref-double
fp (- (* (+ (c:sc-offset-offset sc-offset) 2) vm:word-bytes)))
(realpart (the (complex double-float) value)))
(setf (system:sap-ref-double
fp (- (* (+ (c:sc-offset-offset sc-offset) 4) vm:word-bytes)))
(imagpart (the (complex double-float) value))))
(#.vm:control-stack-sc-number
(setf (kernel:stack-ref fp (c:sc-offset-offset sc-offset)) value))
(#.vm:base-char-stack-sc-number
(setf (system:sap-ref-32 fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))
(char-code (the character value))))
(#.vm:unsigned-stack-sc-number
(setf (system:sap-ref-32 fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))
(the (unsigned-byte 32) value)))
(#.vm:signed-stack-sc-number
(setf (system:signed-sap-ref-32
fp (- (* (1+ (c:sc-offset-offset sc-offset)) vm:word-bytes)))
(the (signed-byte 32) value)))
(#.vm:sap-stack-sc-number
(setf (system:sap-ref-sap fp (- (* (1+ (c:sc-offset-offset sc-offset))
vm:word-bytes)))
(the system:system-area-pointer value))))))
(defsetf debug-variable-value %set-debug-variable-value)
;;; INDIRECT-VALUE-CELL-P -- Internal.
;;;
;;; The method for setting and accessing compiled-debug-variable values use
;;; this to determine if the value stored is the actual value or an indirection
;;; cell.
;;;
(defun indirect-value-cell-p (x)
(and (= (kernel:get-lowtag x) vm:other-pointer-type)
(= (kernel:get-type x) vm:value-cell-header-type)))
;;; DEBUG-VARIABLE-VALIDITY -- Public.
;;;
;;; If the variable is always alive, then it is valid. If the code-location is
;;; unknown, then the variable's validity is :unknown. Once we've called
;;; CODE-LOCATION-UNKNOWN-P, we know the live-set information has been cached
;;; in the code-location.
;;;
(defun debug-variable-validity (debug-var basic-code-loc)
"Returns three values reflecting the validity of debug-variable's value
at basic-code-location:
:valid The value is known to be available.
:invalid The value is known to be unavailable.
:unknown The value's availability is unknown."
(etypecase debug-var
(compiled-debug-variable
(compiled-debug-variable-validity debug-var basic-code-loc))
(interpreted-debug-variable
(check-type basic-code-loc interpreted-code-location)
(let ((validp (rassoc (interpreted-debug-variable-ir1-var debug-var)
(c::lexenv-variables
(c::node-lexenv
(interpreted-code-location-ir1-node
basic-code-loc))))))
(if validp :valid :invalid)))))
;;; COMPILED-DEBUG-VARIABLE-VALIDITY -- Internal.
;;;
;;; This is the method for DEBUG-VARIABLE-VALIDITY for compiled-debug-variables.
;;; For safety, make sure basic-code-loc is what we think.
;;;
(defun compiled-debug-variable-validity (debug-var basic-code-loc)
(check-type basic-code-loc compiled-code-location)
(cond ((debug-variable-alive-p debug-var)
(let ((debug-fun (code-location-debug-function basic-code-loc)))
(if (>= (compiled-code-location-pc basic-code-loc)
(c::compiled-debug-function-start-pc
(compiled-debug-function-compiler-debug-fun debug-fun)))
:valid
:invalid)))
((code-location-unknown-p basic-code-loc) :unknown)
(t
(let ((pos (position debug-var
(debug-function-debug-variables
(code-location-debug-function basic-code-loc)))))
(unless pos
(error 'unknown-debug-variable
:debug-variable debug-var
:debug-function
(code-location-debug-function basic-code-loc)))
;; There must be live-set info since basic-code-loc is known.
(if (zerop (sbit (compiled-code-location-live-set basic-code-loc)
pos))
:invalid
:valid)))))
;;;; Sources.
;;; Written by Rob Maclachlan.
;;; Documented by Bill Chiles.
;;;
;;; This code produces and uses what we call source-paths. A source-path is a
;;; list whose first element is a form number as returned by
;;; CODE-LOCATION-FORM-NUMBER and whose last element is a top-level-form number
;;; as returned by CODE-LOCATION-TOP-LEVEL-FORM-NUMBER. The elements from the
;;; last to the first, exclusively, are the numbered subforms into which to
;;; descend. For example:
;;; (defun foo (x)
;;; (let ((a (aref x 3)))
;;; (cons a 3)))
;;; The call to AREF in this example is form number 5. Assuming this DEFUN is
;;; the 11'th top-level-form, the source-path for the AREF call is as follows:
;;; (5 1 0 1 3 11)
;;; Given the DEFUN, 3 gets you the LET, 1 gets you the bindings, 0 gets the
;;; first binding, and 1 gets the AREF form.
;;;
;;; Temporary buffer used to build form-number => source-path translation in
;;; FORM-NUMBER-TRANSLATIONS.
;;;
(defvar *form-number-temp* (make-array 10 :fill-pointer 0 :adjustable t))
;;; Table used to detect CAR circularities in FORM-NUMBER-TRANSLATIONS.
;;;
(defvar *form-number-circularity-table* (make-hash-table :test #'eq))
;;; FORM-NUMBER-TRANSLATIONS -- Public.
;;;
;;; The vector elements are in the same format as the compiler's
;;; NODE-SOUCE-PATH; that is, the first element is the form number and the last
;;; is the top-level-form number.
;;;
(defun form-number-translations (form tlf-number)
"This returns a table mapping form numbers to source-paths. A source-path
indicates a descent into the top-level-form form, going directly to the
subform corressponding to the form number."
(clrhash *form-number-circularity-table*)
(setf (fill-pointer *form-number-temp*) 0)
(sub-translate-form-numbers form (list tlf-number))
(coerce *form-number-temp* 'simple-vector))
;;;
(defun sub-translate-form-numbers (form path)
(unless (gethash form *form-number-circularity-table*)
(setf (gethash form *form-number-circularity-table*) t)
(vector-push-extend (cons (fill-pointer *form-number-temp*) path)
*form-number-temp*)
(let ((pos 0)
(subform form)
(trail form))
(declare (fixnum pos))
(macrolet ((frob ()
'(progn
(when (atom subform) (return))
(let ((fm (car subform)))
(when (consp fm)
(sub-translate-form-numbers fm (cons pos path)))
(incf pos))
(setq subform (cdr subform))
(when (eq subform trail) (return)))))
(loop
(frob)
(frob)
(setq trail (cdr trail)))))))
;;; SOURCE-PATH-CONTEXT -- Public.
;;;
(defun source-path-context (form path context)
"Form is a top-level form, and path is a source-path into it. This returns
the form indicated by the source-path. Context is the number of enclosing
forms to return instead of directly returning the source-path form. When
context is non-zero, the form returned contains a marker, #:****HERE****,
immediately before the form indicated by path."
(declare (type unsigned-byte context))
;;
;; Get to the form indicated by path or the enclosing form indicated by
;; context and path.
(let ((path (reverse (butlast (cdr path)))))
(dotimes (i (- (length path) context))
(let ((index (first path)))
(unless (and (listp form) (< index (length form)))
(error "Source path no longer exists."))
(setq form (elt form index))
(setq path (rest path))))
;;
;; Recursively rebuild the source form resulting from the above descent,
;; copying the beginning of each subform up to the next subform we descend
;; into according to path. At the bottom of the recursion, we return the
;; form indicated by path preceded by our marker, and this gets spliced
;; into the resulting list structure on the way back up.
(labels ((frob (form path level)
(if (or (zerop level) (null path))
(if (zerop context)
form
`(#:***here*** ,form))
(let ((n (first path)))
(unless (and (listp form) (< n (length form)))
(error "Source path no longer exists."))
(let ((res (frob (elt form n) (rest path) (1- level))))
(nconc (subseq form 0 n)
(cons res (nthcdr (1+ n) form))))))))
(frob form path context))))
;;;; PREPROCESS-FOR-EVAL and EVAL-IN-FRAME.
;;; PREPROCESS-FOR-EVAL -- Public.
;;;
;;; Create a SYMBOL-MACROLET for each variable valid at the location which
;;; accesses that variable from the frame argument.
;;;
(defun preprocess-for-eval (form loc)
"Return a function of one argument that evaluates form in the lexical
context of the basic-code-location loc. PREPROCESS-FOR-EVAL signals a
no-debug-variables condition when the loc's debug-function has no
debug-variable information available. The returned function takes the frame
to get values from as its argument, and it returns the values of form.
The returned function signals the following conditions: invalid-value,
ambiguous-variable-name, and frame-function-mismatch"
(declare (type code-location loc))
(let ((n-frame (gensym))
(fun (code-location-debug-function loc)))
(unless (debug-variable-info-available fun)
(debug-signal 'no-debug-variables :debug-function fun))
(ext:collect ((binds)
(specs))
(do-debug-function-variables (var fun)
(let ((validity (debug-variable-validity var loc)))
(unless (eq validity :invalid)
(let* ((sym (debug-variable-symbol var))
(found (assoc sym (binds))))
(if found
(setf (second found) :ambiguous)
(binds (list sym validity var)))))))
(dolist (bind (binds))
(let ((name (first bind))
(var (third bind)))
(ecase (second bind)
(:valid
(specs `(,name (debug-variable-value ',var ,n-frame))))
(:unknown
(specs `(,name (debug-signal 'invalid-value :debug-variable ',var
:frame ,n-frame))))
(:ambiguous
(specs `(,name (debug-signal 'ambiguous-variable-name :name ',name
:frame ,n-frame)))))))
(let ((res (coerce `(lambda (,n-frame)
(declare (ignorable ,n-frame))
(symbol-macrolet ,(specs) ,form))
'function)))
#'(lambda (frame)
;; This prevents these functions from use in any location other
;; than a function return location, so maybe this should only
;; check whether frame's debug-function is the same as loc's.
(unless (code-location= (frame-code-location frame) loc)
(debug-signal 'frame-function-mismatch
:code-location loc :form form :frame frame))
(funcall res frame))))))
;;; EVAL-IN-FRAME -- Public.
;;;
(defun eval-in-frame (frame form)
(declare (type frame frame))
"Evaluate Form in the lexical context of Frame's current code location,
returning the results of the evaluation."
(funcall (preprocess-for-eval form (frame-code-location frame)) frame))
;;;; Breakpoints.
;;;
;;; User visible interface.
;;;
(defun make-breakpoint (hook-function what
&key (kind :code-location) info function-end-cookie)
"This creates and returns a breakpoint. When program execution encounters
the breakpoint, the system calls hook-function. Hook-function takes the
current frame for the function in which the program is running and the
breakpoint object.
What and kind determine where in a function the system invokes
hook-function. What is either a code-location or a debug-function. Kind is
one of :code-location, :function-start, or :function-end. Since the starts
and ends of functions may not have code-locations representing them,
designate these places by supplying what as a debug-function and kind
indicating the :function-start or :function-end. When what is a
debug-function and kind is :function-end, then hook-function must take two
additional arguments, a list of values returned by the function and a
function-end-cookie.
Info is information supplied by and used by the user.
Function-end-cookie is a function. To implement :function-end breakpoints,
the system uses starter breakpoints to establish the :function-end breakpoint
for each invocation of the function. Upon each entry, the system creates a
unique cookie to identify the invocation, and when the user supplies a
function for this argument, the system invokes it on the frame and the
cookie. The system later invokes the :function-end breakpoint hook on the
same cookie. The user may save the cookie for comparison in the hook
function.
This signals an error if what is an unknown code-location."
(etypecase what
(code-location
(when (code-location-unknown-p what)
(error "Cannot make a breakpoint at an unknown code location -- ~S."
what))
(assert (eq kind :code-location))
(let ((bpt (%make-breakpoint hook-function what kind info)))
(etypecase what
(interpreted-code-location
(error "Breakpoints in interpreted code are currently unsupported."))
(compiled-code-location
;; This slot is filled in due to calling CODE-LOCATION-UNKNOWN-P.
(when (eq (compiled-code-location-kind what) :unknown-return)
(let ((other-bpt (%make-breakpoint hook-function what
:unknown-return-partner
info)))
(setf (breakpoint-unknown-return-partner bpt) other-bpt)
(setf (breakpoint-unknown-return-partner other-bpt) bpt)))))
bpt))
(compiled-debug-function
(ecase kind
(:function-start
(%make-breakpoint hook-function what kind info))
(:function-end
(unless (eq (c::compiled-debug-function-returns
(compiled-debug-function-compiler-debug-fun what))
:standard)
(error ":FUNCTION-END breakpoints are currently unsupported ~
for the known return convention."))
(let* ((bpt (%make-breakpoint hook-function what kind info))
(starter (compiled-debug-function-end-starter what)))
(unless starter
(setf starter (%make-breakpoint #'list what :function-start nil))
(setf (breakpoint-hook-function starter)
(function-end-starter-hook starter what))
(setf (compiled-debug-function-end-starter what) starter))
(setf (breakpoint-start-helper bpt) starter)
(push bpt (breakpoint-%info starter))
(setf (breakpoint-cookie-fun bpt) function-end-cookie)
bpt))))
(interpreted-debug-function
(error ":function-end breakpoints are currently unsupported ~
for interpreted-debug-functions."))))
;;; These are unique objects created upon entry into a function by a
;;; :function-end breakpoint's starter hook. These are only created when users
;;; supply :function-end-cookie to MAKE-BREAKPOINT. Also, the :function-end
;;; breakpoint's hook is called on the same cookie when it is created.
;;;
(defstruct (function-end-cookie
(:print-function (lambda (obj str n)
(declare (ignore obj n))
(write-string "#<Function-End-Cookie>" str)))
(:constructor make-function-end-cookie (bogus-lra debug-fun)))
;; This is a pointer to the bogus-lra created for :function-end bpts.
bogus-lra
;; This is the debug-function associated with the cookie.
debug-fun)
;;; This maps bogus-lra-components to cookies, so
;;; HANDLE-FUNCTION-END-BREAKPOINT can find the appropriate cookie for the
;;; breakpoint hook.
;;;
(defvar *function-end-cookies* (make-hash-table :test #'eq))
;;; FUNCTION-END-STARTER-HOOK -- Internal.
;;;
;;; This returns a hook function for the start helper breakpoint associated
;;; with a :function-end breakpoint. The returned function makes a fake LRA
;;; that all returns go through, and this piece of fake code actually breaks.
;;; Upon return from the break, the code provides the returnee with any values.
;;; Since the returned function effectively activates fun-end-bpt on each entry
;;; to debug-fun's function, we must establish breakpoint-data about
;;; fun-end-bpt.
;;;
(defun function-end-starter-hook (starter-bpt debug-fun)
(declare (type breakpoint starter-bpt)
(type compiled-debug-function debug-fun))
#'(lambda (frame breakpoint)
(declare (ignore breakpoint)
(type frame frame))
(let ((lra-sc-offset
(c::compiled-debug-function-return-pc
(compiled-debug-function-compiler-debug-fun debug-fun))))
(multiple-value-bind (lra component offset)
(make-bogus-lra
(get-context-value frame
#-gengc vm::lra-save-offset
#+gengc vm::ra-save-offset
lra-sc-offset))
(setf (get-context-value frame
#-gengc vm::lra-save-offset
#+gengc vm::ra-save-offset
lra-sc-offset)
lra)
(let ((end-bpts (breakpoint-%info starter-bpt)))
(let ((data (breakpoint-data component offset)))
(setf (breakpoint-data-breakpoints data) end-bpts)
(dolist (bpt end-bpts)
(setf (breakpoint-internal-data bpt) data)))
(let ((cookie (make-function-end-cookie lra debug-fun)))
(setf (gethash component *function-end-cookies*) cookie)
(dolist (bpt end-bpts)
(let ((fun (breakpoint-cookie-fun bpt)))
(when fun (funcall fun frame cookie))))))))))
;;; FUNCTION-END-COOKIE-VALID-P -- Public.
;;;
(defun function-end-cookie-valid-p (frame cookie)
"This takes a function-end-cookie and a frame, and it returns whether the
cookie is still valid. A cookie becomes invalid when the frame that
established the cookie has exited. Sometimes cookie holders are unaware
of cookie invalidation because their :function-end breakpoint hooks didn't
run due to THROW'ing. This takes a frame as an efficiency hack since the
user probably has a frame object in hand when using this routine, and it
saves repeated parsing of the stack and consing when asking whether a
series of cookies is valid."
(let ((lra (function-end-cookie-bogus-lra cookie))
(lra-sc-offset (c::compiled-debug-function-return-pc
(compiled-debug-function-compiler-debug-fun
(function-end-cookie-debug-fun cookie)))))
(do ((frame frame (frame-down frame)))
((not frame) nil)
(when (and (compiled-frame-p frame)
(eq lra
(get-context-value frame
#-gengc vm::lra-save-offset
#+gengc vm::ra-save-offset
lra-sc-offset)))
(return t)))))
;;;
;;; ACTIVATE-BREAKPOINT.
;;;
;;; ACTIVATE-BREAKPOINT -- Public.
;;;
(defun activate-breakpoint (breakpoint)
"This causes the system to invoke the breakpoint's hook-function until the
next call to DEACTIVATE-BREAKPOINT or DELETE-BREAKPOINT. The system invokes
breakpoint hook functions in the opposite order that you activate them."
(when (eq (breakpoint-status breakpoint) :deleted)
(error "Cannot activate a deleted breakpoint -- ~S." breakpoint))
(unless (eq (breakpoint-status breakpoint) :active)
(ecase (breakpoint-kind breakpoint)
(:code-location
(let ((loc (breakpoint-what breakpoint)))
(etypecase loc
(interpreted-code-location
(error "Breakpoints in interpreted code are currently unsupported."))
(compiled-code-location
(activate-compiled-code-location-breakpoint breakpoint)
(let ((other (breakpoint-unknown-return-partner breakpoint)))
(when other
(activate-compiled-code-location-breakpoint other)))))))
(:function-start
(etypecase (breakpoint-what breakpoint)
(compiled-debug-function
(activate-compiled-function-start-breakpoint breakpoint))
(interpreted-debug-function
(error "I don't know how you made this, but they're unsupported -- ~S"
(breakpoint-what breakpoint)))))
(:function-end
(etypecase (breakpoint-what breakpoint)
(compiled-debug-function
(let ((starter (breakpoint-start-helper breakpoint)))
(unless (eq (breakpoint-status starter) :active)
;; May already be active by some other :function-end breakpoint.
(activate-compiled-function-start-breakpoint starter)))
(setf (breakpoint-status breakpoint) :active))
(interpreted-debug-function
(error "I don't know how you made this, but they're unsupported -- ~S"
(breakpoint-what breakpoint)))))))
breakpoint)
;;; ACTIVATE-COMPILED-CODE-LOCATION-BREAKPOINT -- Internal.
;;;
(defun activate-compiled-code-location-breakpoint (breakpoint)
(declare (type breakpoint breakpoint))
(let ((loc (breakpoint-what breakpoint)))
(declare (type compiled-code-location loc))
(sub-activate-breakpoint
breakpoint
(breakpoint-data (compiled-debug-function-component
(code-location-debug-function loc))
(+ (compiled-code-location-pc loc)
(if (or (eq (breakpoint-kind breakpoint)
:unknown-return-partner)
(eq (compiled-code-location-kind loc)
:single-value-return))
vm:single-value-return-byte-offset
0))))))
;;; ACTIVATE-COMPILED-FUNCTION-START-BREAKPOINT -- Internal.
;;;
(defun activate-compiled-function-start-breakpoint (breakpoint)
(declare (type breakpoint breakpoint))
(let ((debug-fun (breakpoint-what breakpoint)))
(sub-activate-breakpoint
breakpoint
(breakpoint-data (compiled-debug-function-component debug-fun)
(c::compiled-debug-function-start-pc
(compiled-debug-function-compiler-debug-fun
debug-fun))))))
;;; SUB-ACTIVATE-BREAKPOINT -- Internal.
;;;
(defun sub-activate-breakpoint (breakpoint data)
(declare (type breakpoint breakpoint)
(type breakpoint-data data))
(setf (breakpoint-status breakpoint) :active)
(system:without-interrupts
(unless (breakpoint-data-breakpoints data)
(setf (breakpoint-data-instruction data)
(system:without-gcing
(breakpoint-install (kernel:get-lisp-obj-address
(breakpoint-data-component data))
(breakpoint-data-offset data)))))
(setf (breakpoint-data-breakpoints data)
(append (breakpoint-data-breakpoints data) (list breakpoint)))
(setf (breakpoint-internal-data breakpoint) data)))
;;;
;;; DEACTIVATE-BREAKPOINT.
;;;
;;; DEACTIVATE-BREAKPOINT -- Public.
;;;
(defun deactivate-breakpoint (breakpoint)
"This stops the system from invoking the breakpoint's hook-function."
(when (eq (breakpoint-status breakpoint) :active)
(system:without-interrupts
(let ((loc (breakpoint-what breakpoint)))
(etypecase loc
((or interpreted-code-location interpreted-debug-function)
(error
"Breakpoints in interpreted code are currently unsupported."))
((or compiled-code-location compiled-debug-function)
(deactivate-compiled-breakpoint breakpoint)
(let ((other (breakpoint-unknown-return-partner breakpoint)))
(when other
(deactivate-compiled-breakpoint other))))))))
breakpoint)
(defun deactivate-compiled-breakpoint (breakpoint)
(if (eq (breakpoint-kind breakpoint) :function-end)
(let ((starter (breakpoint-start-helper breakpoint)))
(unless (find-if #'(lambda (bpt)
(and (not (eq bpt breakpoint))
(eq (breakpoint-status bpt) :active)))
(breakpoint-%info starter))
(deactivate-compiled-breakpoint starter)))
(let* ((data (breakpoint-internal-data breakpoint))
(bpts (delete breakpoint (breakpoint-data-breakpoints data))))
(setf (breakpoint-internal-data breakpoint) nil)
(setf (breakpoint-data-breakpoints data) bpts)
(unless bpts
(system:without-gcing
(breakpoint-remove (kernel:get-lisp-obj-address
(breakpoint-data-component data))
(breakpoint-data-offset data)
(breakpoint-data-instruction data)))
(delete-breakpoint-data data))))
(setf (breakpoint-status breakpoint) :inactive)
breakpoint)
;;;
;;; BREAKPOINT-INFO.
;;;
;;; BREAKPOINT-INFO -- Public.
;;;
(defun breakpoint-info (breakpoint)
"This returns the user maintained info associated with breakpoint. This
is SETF'able."
(breakpoint-%info breakpoint))
;;;
(defun %set-breakpoint-info (breakpoint value)
(setf (breakpoint-%info breakpoint) value)
(let ((other (breakpoint-unknown-return-partner breakpoint)))
(when other
(setf (breakpoint-%info other) value))))
;;;
(defsetf breakpoint-info %set-breakpoint-info)
;;;
;;; BREAKPOINT-ACTIVE-P and DELETE-BREAKPOINT.
;;;
;;; BREAKPOINT-ACTIVE-P -- Public.
;;;
(defun breakpoint-active-p (breakpoint)
"This returns whether breakpoint is currently active."
(ecase (breakpoint-status breakpoint)
(:active t)
((:inactive :deleted) nil)))
;;; DELETE-BREAKPOINT -- Public.
;;;
(defun delete-breakpoint (breakpoint)
"This frees system storage and removes computational overhead associated with
breakpoint. After calling this, breakpoint is completely impotent and can
never become active again."
(let ((status (breakpoint-status breakpoint)))
(unless (eq status :deleted)
(when (eq status :active)
(deactivate-breakpoint breakpoint))
(setf (breakpoint-status breakpoint) :deleted)
(let ((other (breakpoint-unknown-return-partner breakpoint)))
(when other
(setf (breakpoint-status other) :deleted)))
(when (eq (breakpoint-kind breakpoint) :function-end)
(let* ((starter (breakpoint-start-helper breakpoint))
(breakpoints (delete breakpoint
(the list (breakpoint-info starter)))))
(setf (breakpoint-info starter) breakpoints)
(unless breakpoints
(delete-breakpoint starter)
(setf (compiled-debug-function-end-starter
(breakpoint-what breakpoint))
nil))))))
breakpoint)
;;;
;;; C call out stubs.
;;;
;;; BREAKPOINT-INSTALL -- Internal.
;;;
;;; This actually installs the break instruction in the component. It returns
;;; the overwritten bits. You must call this in a context in which GC is
;;; disabled, so Lisp doesn't move objects around that C is pointing to.
;;;
(alien:def-alien-routine "breakpoint_install" c-call:unsigned-long
(code-obj c-call:unsigned-long)
(pc-offset c-call:int))
;;; BREAKPOINT-REMOVE -- Internal.
;;;
;;; This removes the break instruction and replaces the original instruction.
;;; You must call this in a context in which GC is disabled, so Lisp doesn't
;;; move objects around that C is pointing to.
;;;
(alien:def-alien-routine "breakpoint_remove" c-call:void
(code-obj c-call:unsigned-long)
(pc-offset c-call:int)
(old-inst c-call:unsigned-long))
(alien:def-alien-routine "breakpoint_do_displaced_inst" c-call:void
(scp (* unix:sigcontext))
(orig-inst c-call:unsigned-long))
;;;
;;; Breakpoint handlers (layer between C and exported interface).
;;;
;;; This maps components to a mapping of offsets to breakpoint-datas.
;;;
(defvar *component-breakpoint-offsets* (make-hash-table :test #'eq))
;;; BREAKPOINT-DATA -- Internal.
;;;
;;; This returns the breakpoint-data associated with component cross offset.
;;; If none exists, this makes one, installs it, and returns it.
;;;
(defun breakpoint-data (component offset &optional (create t))
(flet ((install-breakpoint-data ()
(when create
(let ((data (make-breakpoint-data component offset)))
(push (cons offset data)
(gethash component *component-breakpoint-offsets*))
data))))
(let ((offsets (gethash component *component-breakpoint-offsets*)))
(if offsets
(let ((data (assoc offset offsets)))
(if data
(cdr data)
(install-breakpoint-data)))
(install-breakpoint-data)))))
;;; DELETE-BREAKPOINT-DATA -- Internal.
;;;
;;; We use this when there are no longer any active breakpoints corresponding
;;; to data.
;;;
(defun delete-breakpoint-data (data)
(let* ((component (breakpoint-data-component data))
(offsets (delete (breakpoint-data-offset data)
(gethash component *component-breakpoint-offsets*)
:key #'car)))
(if offsets
(setf (gethash component *component-breakpoint-offsets*) offsets)
(remhash component *component-breakpoint-offsets*)))
(ext:undefined-value))
;;; HANDLE-BREAKPOINT -- Internal Interface.
;;;
;;; The C handler for interrupts calls this when it has a debugging-tool break
;;; instruction. This does NOT handle all breaks; for example, it does not
;;; handle breaks for internal errors.
;;;
(defun handle-breakpoint (offset component signal-context)
(let ((data (breakpoint-data component offset nil)))
(unless data
(error "Unknown breakpoint in ~S at offset ~S."
(debug-function-name (debug-function-from-pc component offset))
offset))
(let ((breakpoints (breakpoint-data-breakpoints data)))
(if (or (null breakpoints)
(eq (breakpoint-kind (car breakpoints)) :function-end))
(handle-function-end-breakpoint-aux breakpoints data signal-context)
(handle-breakpoint-aux breakpoints data
offset component signal-context)))))
;;; This holds breakpoint-datas while invoking the breakpoint hooks associated
;;; with that particular component and location. While they are executing, if
;;; we hit the location again, we ignore the breakpoint to avoid infinite
;;; recursion. Function-end breakpoints must work differently since the
;;; breakpoint-data is unique for each invocation.
;;;
(defvar *executing-breakpoint-hooks* nil)
;;; HANDLE-BREAKPOINT-AUX -- Internal.
;;;
;;; This handles code-location and debug-function :function-start breakpoints.
;;;
(defun handle-breakpoint-aux (breakpoints data offset component signal-context)
(unless breakpoints
(error "Breakpoint that nobody wants?"))
(unless (member data *executing-breakpoint-hooks*)
(let ((*executing-breakpoint-hooks* (cons data
*executing-breakpoint-hooks*)))
(invoke-breakpoint-hooks breakpoints component offset)))
;; At this point breakpoints may not hold the same list as
;; BREAKPOINT-DATA-BREAKPOINTS since invoking hooks may have allowed a
;; breakpoint deactivation. In fact, if all breakpoints were deactivated
;; then data is invalid since it was deleted and so the correct one must be
;; looked up if it is to be used. If there are no more breakpoints active
;; at this location, then the normal instruction has been put back, and we
;; do not need to do-displaced-inst.
(let ((data (breakpoint-data component offset nil)))
(when (and data (breakpoint-data-breakpoints data))
;; There breakpoint is still active, so we need to execute the displaced
;; instruction and leave the breakpoint instruction behind. The best
;; way to do this is different on each machine, so we just leave it up
;; to the C code.
(breakpoint-do-displaced-inst signal-context
(breakpoint-data-instruction data))
; Under HPUX we can't sigreturn so bp-do-disp-i has to return.
#-(or hpux irix x86)
(error "BREAKPOINT-DO-DISPLACED-INST returned?"))))
(defun invoke-breakpoint-hooks (breakpoints component offset)
(let* ((debug-fun (debug-function-from-pc component offset))
(frame (do ((f (top-frame) (frame-down f)))
((eq debug-fun (frame-debug-function f)) f))))
(dolist (bpt breakpoints)
(funcall (breakpoint-hook-function bpt)
frame
;; If this is an :unknown-return-partner, then pass the
;; hook function the original breakpoint, so that users
;; arn't forced to confront the fact that some breakpoints
;; really are two.
(if (eq (breakpoint-kind bpt) :unknown-return-partner)
(breakpoint-unknown-return-partner bpt)
bpt)))))
;;; HANDLE-FUNCTION-END-BREAKPOINT -- Internal Interface
;;;
(defun handle-function-end-breakpoint (offset component sigcontext)
(let ((data (breakpoint-data component offset nil)))
(unless data
(error "Unknown breakpoint in ~S at offset ~S."
(debug-function-name (debug-function-from-pc component offset))
offset))
(let ((breakpoints (breakpoint-data-breakpoints data)))
(when breakpoints
(assert (eq (breakpoint-kind (car breakpoints)) :function-end))
(handle-function-end-breakpoint-aux breakpoints data sigcontext)))))
;;; HANDLE-FUNCTION-END-BREAKPOINT-AUX -- Internal.
;;;
;;; Either HANDLE-BREAKPOINT calls this for :function-end breakpoints [old C
;;; code] or HANDLE-FUNCTION-END-BREAKPOINT calls this directly [new C code].
;;;
(defun handle-function-end-breakpoint-aux (breakpoints data signal-context)
(delete-breakpoint-data data)
(let* ((scp
(locally
(declare (optimize (ext:inhibit-warnings 3)))
(alien:sap-alien signal-context (* unix:sigcontext))))
(frame (do ((cfp (vm:sigcontext-register scp vm::cfp-offset))
(f (top-frame) (frame-down f)))
((= cfp (system:sap-int (frame-pointer f))) f)
(declare (type (unsigned-byte #.vm:word-bits) cfp))))
(component (breakpoint-data-component data))
(cookie (gethash component *function-end-cookies*)))
(remhash component *function-end-cookies*)
(dolist (bpt breakpoints)
(funcall (breakpoint-hook-function bpt)
frame bpt
(get-function-end-breakpoint-values scp)
cookie))))
(defun get-function-end-breakpoint-values (scp)
(let ((ocfp (system:int-sap (vm:sigcontext-register scp
#-x86 vm::ocfp-offset
#+x86 vm::ebx-offset)))
(nargs (kernel:make-lisp-obj
(vm:sigcontext-register scp vm::nargs-offset)))
(reg-arg-offsets '#.vm::register-arg-offsets)
(results nil))
(system:without-gcing
(dotimes (arg-num nargs)
(push (if reg-arg-offsets
(kernel:make-lisp-obj
(vm:sigcontext-register scp (pop reg-arg-offsets)))
(kernel:stack-ref ocfp arg-num))
results)))
(nreverse results)))
;;;
;;; MAKE-BOGUS-LRA (used for :function-end breakpoints)
;;;
(defconstant bogus-lra-constants #-x86 2 #+x86 3)
(defconstant known-return-p-slot (+ vm:code-constants-offset #-x86 1 #+x86 2))
;;; MAKE-BOGUS-LRA -- Interface.
;;;
(defun make-bogus-lra (real-lra &optional known-return-p)
"Make a bogus LRA object that signals a breakpoint trap when returned to. If
the breakpoint trap handler returns, REAL-LRA is returned to. Three values
are returned: the bogus LRA object, the code component it is part of, and
the PC offset for the trap instruction."
(system:without-gcing
(let* ((src-start (system:foreign-symbol-address
"function_end_breakpoint_guts"))
(src-end (system:foreign-symbol-address
"function_end_breakpoint_end"))
(trap-loc (system:foreign-symbol-address
"function_end_breakpoint_trap"))
(length (system:sap- src-end src-start))
(code-object
(system:%primitive
#-(and x86 gencgc) c:allocate-code-object
#+(and x86 gencgc) c::allocate-dynamic-code-object
(1+ bogus-lra-constants)
length))
(dst-start (kernel:code-instructions code-object)))
(declare (type system:system-area-pointer
src-start src-end dst-start trap-loc)
(type kernel:index length))
(setf (kernel:%code-debug-info code-object) :bogus-lra)
(setf (kernel:code-header-ref code-object vm:code-trace-table-offset-slot)
length)
#-x86
(setf (kernel:code-header-ref code-object real-lra-slot) real-lra)
#+x86
(multiple-value-bind (offset code)
(compute-lra-data-from-pc real-lra)
(setf (kernel:code-header-ref code-object real-lra-slot) code)
(setf (kernel:code-header-ref code-object (1+ real-lra-slot)) offset))
(setf (kernel:code-header-ref code-object known-return-p-slot)
known-return-p)
(kernel:system-area-copy src-start 0 dst-start 0 (* length vm:byte-bits))
(vm:sanctify-for-execution code-object)
#+x86
(values dst-start code-object (system:sap- trap-loc src-start))
#-x86
(let ((new-lra (kernel:make-lisp-obj (+ (system:sap-int dst-start)
vm:other-pointer-type))))
(kernel:set-header-data
new-lra
(logandc2 (+ vm:code-constants-offset bogus-lra-constants 1)
1))
(vm:sanctify-for-execution code-object)
(values new-lra code-object (system:sap- trap-loc src-start))))))
;;;; Editor support.
;;; This holds breakpoints in the slave set on behalf of the editor.
;;;
;(defvar *editor-breakpoints* (make-hash-table :test #'equal))
;;;
;;; Setting breakpoints.
;;;
;;; SET-BREAKPOINT-FOR-EDITOR -- Internal Interface.
;;;
(defun set-breakpoint-for-editor (package name-str path)
"The editor calls this remotely in the slave to set breakpoints. Package is
the string name of a package or nil, and name-str is a string representing a
function name (for example, \"foo\" or \"(setf foo)\"). After finding
package, this READs name-str with *package* bound appropriately. Path is
either a modified source-path or a symbol (:function-start or
:function-end). If it is a modified source-path, it has no top-level-form
offset or form-number component, and it is in descent order from the root of
the top-level form."
(let* ((name (let ((*package* (if package
(lisp::package-or-lose package)
*package*)))
(read-from-string name-str)))
(debug-fun (function-debug-function (fdefinition name))))
(etypecase path
(symbol
(let* ((bpt (di:make-breakpoint
#'(lambda (frame bpt)
(declare (ignore frame bpt))
(break "Editor installed breakpoint."))
debug-fun :kind path))
(remote-bpt (wire:make-remote-object bpt)))
(activate-breakpoint bpt)
;;(push remote-bpt (gethash name *editor-breakpoints*))
remote-bpt))
(cons
(etypecase debug-fun
(compiled-debug-function
(compiled-debug-function-set-breakpoint-for-editor
debug-fun #|name|# path))
(interpreted-debug-function
(error
"We don't currently support breakpoints in interpreted code.")))))))
(defun compiled-debug-function-set-breakpoint-for-editor (debug-fun #|name|# path)
(let* ((source-paths (generate-component-source-paths
(compiled-debug-function-component debug-fun)))
(matches nil)
(matching-length 0))
(declare (simple-vector source-paths)
(list matches)
(fixnum matching-length))
;; Build a list of paths that match path up to matching-length
;; elements.
(macrolet ((maybe-store-match (path matched-len)
`(cond ((> ,matched-len matching-length)
(setf matches (list ,path))
(setf matching-length ,matched-len))
((= ,matched-len matching-length)
(cons ,path matches)))))
(dotimes (i (length source-paths))
(declare (fixnum i))
(let ((sp (svref source-paths i)))
;; Remember, first element of sp is a code-location.
(do ((path-ptr path (cdr path-ptr))
(sp-ptr (cdr sp) (cdr sp-ptr))
(count 0 (1+ count)))
((or (null path-ptr) (null sp-ptr))
(when (null sp-ptr)
(maybe-store-match sp count)))
(declare (list sp-ptr path-ptr)
(fixnum count))
(unless (= (the fixnum (car path-ptr)) (the fixnum (car sp-ptr)))
(maybe-store-match sp count))))))
;; If there's just one, set it; otherwise, return the conflict set.
(cond ((and (= (length matches) 1) (equal path (cdar matches)))
(let* ((bpt (make-breakpoint
#'(lambda (frame bpt)
(declare (ignore frame bpt))
(break "Editor installed breakpoint."))
(wire:remote-object-value (caar matches))))
(remote-bpt (wire:make-remote-object bpt)))
(activate-breakpoint bpt)
;;(push remote-bpt (gethash name *editor-breakpoints*))
remote-bpt))
(t matches))))
;;; This maps components to vectors of modified source-paths. We assume users
;;; will set multiple breakpoints in a given function which entails computing
;;; this data repeatedly. Possibly the GC hook should free this cache. The
;;; source-paths are modified in the following ways:
;;; 1] The form number element (first) is clobbered with the code-location
;;; corresponding to the source-path.
;;; 2] The top-level-form offset element (last) is thrown away.
;;; 3] Everything after the first element is reversed, so the modified
;;; source-path actually portrays a descent into the form.
;;;
(defvar *component-source-locations* (make-hash-table :test #'eq))
;;; GENERATE-COMPONENT-SOURCE-PATHS -- Internal.
;;;
;;; This returns a vector of modified source-paths, one for every code-location
;;; in component. The source-paths are modified as described for
;;; *component-source-locations*.
;;;
(defun generate-component-source-paths (component)
(or (gethash component *component-source-locations*)
(setf (gethash component *component-source-locations*)
(sub-generate-component-source-paths component))))
;;; This maps source-infos to hashtables that map top-level-form offsets to
;;; modified form-number translations (as returned by
;;; FORM-NUMBER-TRANSLATIONS). These are modified as described for
;;; *component-source-locations*.
;;;
(defvar *source-info-offset-translations* (make-hash-table :test #'eq))
;;; This is a hacking space for SUB-GENERATE-COMPONENT-SOURCE-PATHS. We use
;;; this because we throw away many source-paths we accumulate in this buffer
;;; since they are not associated with code-locations.
;;;
(defvar *source-paths-buffer* (make-array 50 :fill-pointer t :adjustable t))
;;; SUB-GENERATE-COMPONENT-SOURCE-PATHS -- Internal.
;;;
;;; We iterate over the code-locations in component, fetching their
;;; source-infos and using the *source-info-offset-translations* cache. This
;;; computation often repeatedly sees the same source-info/tlf-offset pair, so
;;; we see many source-paths from one form-number-translation table. Because
;;; of this, when we add a form-number-translations table to this cache, we add
;;; all the source-paths in it to the result immediately. Then later if we see
;;; the same (not EQ though) source-info/tlf-offset form-number-translations,
;;; we can simply check if one of the source-paths is already in the result,
;;; and if it is, then all of them already are. We keep the cache around
;;; between invocations since we expect multiple breakpoints to be set in the
;;; same function, and this is why we must check if a form-number-translations
;;; has been added to the result; just its presence in the cache does not mean
;;; it is in the result vector.
;;;
(defun sub-generate-component-source-paths (component)
(let ((info (kernel:%code-debug-info component)))
(unless info (debug-signal 'no-debug-info))
(let* ((function-map (get-debug-info-function-map info))
(result *source-paths-buffer*))
(declare (simple-vector function-map)
(vector result))
(setf (fill-pointer result) 0)
(flet ((copy-stuff (form-num-trans result)
(declare (simple-vector form-num-trans)
(vector result))
(dotimes (i (length form-num-trans))
(declare (fixnum i))
(vector-push-extend (svref form-num-trans i) result)))
(convert-paths (form-num-trans)
(declare (simple-vector form-num-trans))
(dotimes (i (length form-num-trans) form-num-trans)
(declare (fixnum i))
(let* ((source-path (svref form-num-trans i)))
(declare (list source-path))
;; Make the first cons point to the reversal of everything
;; else, but throw away what was the last element before the
;; reversal.
(setf (cdr source-path)
;; Must copy the rest of the list, so REVERSE, but
;; the first cons cell of each list is unique.
(cdr (reverse (cdr source-path))))))))
;; Get all possible source-paths, modifying any new additions to the
;; cache.
(do ((i 0 (+ i 2))
(len (length function-map)))
((>= i len))
(declare (type c::index i))
(let ((d-fun (make-compiled-debug-function (svref function-map i)
component)))
(do-debug-function-blocks (d-block d-fun)
(do-debug-block-locations (loc d-block)
(let* ((d-source (code-location-debug-source loc))
(translations (gethash d-source
*source-info-offset-translations*))
(tlf-offset (code-location-top-level-form-offset loc))
(loc-num (code-location-form-number loc)))
(cond
(translations
(let ((form-num-trans (gethash tlf-offset translations)))
(declare (type (or simple-vector null) form-num-trans))
(cond
((not form-num-trans)
(let ((form-num-trans (get-form-number-translations
d-source tlf-offset)))
(declare (simple-vector form-num-trans))
(setf (gethash tlf-offset translations) form-num-trans)
(copy-stuff (convert-paths form-num-trans) result)
(setf (car (svref form-num-trans loc-num))
(wire:make-remote-object loc))))
;; If one of these source-paths is in our result, then
;; they all are.
((find (svref form-num-trans 0) result :test #'eq)
(setf (car (svref form-num-trans loc-num))
(wire:make-remote-object loc)))
;; Otherwise, store these source-paths in the result.
(t
(copy-stuff form-num-trans result)
(setf (car (svref form-num-trans loc-num))
(wire:make-remote-object loc))))))
(t
(let ((translations (make-hash-table :test #'eq))
(form-num-trans (get-form-number-translations
d-source tlf-offset)))
(declare (simple-vector form-num-trans))
(setf (gethash d-source *source-info-offset-translations*)
translations)
(setf (gethash tlf-offset translations) form-num-trans)
(copy-stuff (convert-paths form-num-trans) result)
(setf (car (svref form-num-trans loc-num))
(wire:make-remote-object loc)))))))))))
;; Copy source-paths with code-locations from the result buffer to a
;; real result vector.
(let* ((count (count-if #'(lambda (x) (wire:remote-object-p (car x)))
result))
(the-real-thing (make-array count))
(i -1))
(declare (simple-vector the-real-thing)
(fixnum i count))
(dotimes (j count)
(loop (when (wire:remote-object-p (car (aref result (incf i))))
(return)))
(setf (svref the-real-thing j) (aref result i)))
the-real-thing))))
;;; GET-FORM-NUMBER-TRANSLATIONS -- Internal.
;;;
;;; This returns a vector of form-number translations to source-paths for
;;; d-source and the top-level-form indicated by the top-level-form offset.
;;;
(defun get-form-number-translations (d-source tlf-offset)
(let ((name (debug-source-name d-source)))
(ecase (debug-source-from d-source)
(:file
(cond
((not (probe-file name))
(format t "~%Cannot set breakpoints for editor when source file no ~
longer exists:~% ~A."
(namestring name)))
(t
(let* ((local-tlf-offset (- tlf-offset
(debug-source-root-number d-source)))
(char-offset
(aref (or (debug-source-start-positions d-source)
(error "Cannot set breakpoints for editor when ~
there is no start positions map."))
local-tlf-offset)))
(with-open-file (f name)
(cond
((= (debug-source-created d-source) (file-write-date name))
(file-position f char-offset))
(t
(format t
"~%While setting a breakpoint for the editor, noticed ~
source file has been modified since compilation:~% ~A~@
Using form offset instead of character position.~%"
(namestring name))
(dotimes (i local-tlf-offset) (read f))))
(form-number-translations (read f) tlf-offset))))))
((:lisp :stream)
(form-number-translations (svref name tlf-offset) tlf-offset)))))
;;; SET-LOCATION-BREAKPOINT-FOR-EDITOR -- Internal Interface.
;;;
(defun set-location-breakpoint-for-editor (remote-obj-loc)
"The editor calls this in the slave with a remote-object representing a
code-location to set a breakpoint."
(let ((loc (wire:remote-object-value remote-obj-loc)))
(etypecase loc
(interpreted-code-location
(error "Breakpoints in interpreted code are currently unsupported."))
(compiled-code-location
(let* ((bpt (make-breakpoint #'(lambda (frame bpt)
(declare (ignore frame bpt))
(break "Editor installed breakpoint."))
loc))
(remote-bpt (wire:make-remote-object bpt)))
(activate-breakpoint bpt)
;;(push remote-bpt (gethash name *editor-breakpoints*))
remote-bpt)))))
;;;
;;; Deleting breakpoints.
;;;
;;; DELETE-BREAKPOINT-FOR-EDITOR -- Internal Interface.
;;;
(defun delete-breakpoint-for-editor (remote-obj-bpt)
"The editor calls this remotely in the slave to delete a breakpoint."
(delete-breakpoint (wire:remote-object-value remote-obj-bpt))
(wire:forget-remote-translation remote-obj-bpt))
;;;; Miscellaneous
;;; This appears here because it cannot go with the debug-function interface
;;; since DO-DEBUG-BLOCK-LOCATIONS isn't defined until after the debug-function
;;; routines.
;;;
;;; DEBUG-FUNCTION-START-LOCATION -- Public.
;;;
(defun debug-function-start-location (debug-fun)
"This returns a code-location before the body of a function and after all
the arguments are in place. If this cannot determine that location due to
a lack of debug information, it returns nil."
(etypecase debug-fun
(compiled-debug-function
(code-location-from-pc debug-fun
(c::compiled-debug-function-start-pc
(compiled-debug-function-compiler-debug-fun
debug-fun))
nil))
(interpreted-debug-function
;; Return the first location if there are any, otherwise nil.
(handler-case (do-debug-function-blocks (block debug-fun nil)
(do-debug-block-locations (loc block nil)
(return-from debug-function-start-location loc)))
(no-debug-blocks (condx)
(declare (ignore condx))
nil)))))
(defun print-code-locations (function)
(let ((debug-fun (function-debug-function function)))
(do-debug-function-blocks (block debug-fun)
(do-debug-block-locations (loc block)
(fill-in-code-location loc)
(format t "~S code location at ~D"
(compiled-code-location-kind loc)
(compiled-code-location-pc loc))
(debug::print-code-location-source-form loc 0)
(terpri)))))
|