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
|
/*--------------------------------------------------------------------*/
/*--- Reading of syms & debug info from ELF .so/executable files. ---*/
/*--- readelf.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2017 Julian Seward
jseward@acm.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
The GNU General Public License is contained in the file COPYING.
*/
#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_vkiscnums.h"
#include "pub_core_debuglog.h"
#include "pub_core_debuginfo.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcprint.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcfile.h"
#include "pub_core_libcproc.h"
#include "pub_core_machine.h" /* VG_ELF_CLASS */
#include "pub_core_options.h"
#include "pub_core_oset.h"
#include "pub_core_pathscan.h" /* find_executable */
#include "pub_core_syscall.h"
#include "pub_core_tooliface.h" /* VG_(needs) */
#include "pub_core_xarray.h"
#include "pub_core_libcproc.h"
#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
#include "priv_image.h"
#include "priv_d3basics.h"
#include "priv_tytypes.h"
#include "priv_storage.h"
#include "priv_readelf.h" /* self */
#include "priv_readdwarf.h" /* 'cos ELF contains DWARF */
#include "priv_readdwarf3.h"
#include "priv_readexidx.h"
#include "config.h"
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
#include <elf.h>
#if defined(VGO_solaris)
#include <sys/link.h> /* ElfXX_Dyn, DT_* */
#endif
/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
#if !defined(HAVE_ELF32_CHDR)
typedef struct {
Elf32_Word ch_type;
Elf32_Word ch_size;
Elf32_Word ch_addralign;
} Elf32_Chdr;
#endif
#if !defined(HAVE_ELF64_CHDR)
typedef struct {
Elf64_Word ch_type;
Elf64_Word ch_reserved;
Elf64_Xword ch_size;
Elf64_Xword ch_addralign;
} Elf64_Chdr;
#endif
#if !defined(SHF_COMPRESSED)
#define SHF_COMPRESSED (1 << 11)
#endif
#if !defined(ELFCOMPRESS_ZLIB)
#define ELFCOMPRESS_ZLIB 1
#endif
#define SIZE_OF_ZLIB_HEADER 12
/*------------------------------------------------------------*/
/*--- 32/64-bit parameterisation ---*/
/*------------------------------------------------------------*/
/* For all the ELF macros and types which specify '32' or '64',
select the correct variant for this platform and give it
an 'XX' name. Then use the 'XX' variant consistently in
the rest of this file.
*/
#if VG_WORDSIZE == 4
# define ElfXX_Ehdr Elf32_Ehdr
# define ElfXX_Shdr Elf32_Shdr
# define ElfXX_Phdr Elf32_Phdr
# define ElfXX_Nhdr Elf32_Nhdr
# define ElfXX_Sym Elf32_Sym
# define ElfXX_Off Elf32_Off
# define ElfXX_Word Elf32_Word
# define ElfXX_Addr Elf32_Addr
# define ElfXX_Dyn Elf32_Dyn
# define ELFXX_ST_BIND ELF32_ST_BIND
# define ELFXX_ST_TYPE ELF32_ST_TYPE
# define ElfXX_Chdr Elf32_Chdr
#elif VG_WORDSIZE == 8
# define ElfXX_Ehdr Elf64_Ehdr
# define ElfXX_Shdr Elf64_Shdr
# define ElfXX_Phdr Elf64_Phdr
# define ElfXX_Nhdr Elf64_Nhdr
# define ElfXX_Sym Elf64_Sym
# define ElfXX_Off Elf64_Off
# define ElfXX_Word Elf64_Word
# define ElfXX_Addr Elf64_Addr
# define ElfXX_Dyn Elf64_Dyn
# define ELFXX_ST_BIND ELF64_ST_BIND
# define ELFXX_ST_TYPE ELF64_ST_TYPE
# define ElfXX_Chdr Elf64_Chdr
#else
# error "VG_WORDSIZE should be 4 or 8"
#endif
/*------------------------------------------------------------*/
/*--- ---*/
/*--- Read symbol table and line info from ELF files. ---*/
/*--- ---*/
/*------------------------------------------------------------*/
/* readelf.c parses ELF files and acquires symbol table info from
them. It calls onwards to readdwarf.c to read DWARF2/3 line number
and call frame info found. */
/* Identify an ELF object file by peering at the first few bytes of
it. */
Bool ML_(is_elf_object_file)( const void* image, SizeT n_image, Bool rel_ok )
{
const ElfXX_Ehdr* ehdr = image;
Int ok = 1;
if (n_image < sizeof(ElfXX_Ehdr))
return False;
ok &= (ehdr->e_ident[EI_MAG0] == 0x7F
&& ehdr->e_ident[EI_MAG1] == 'E'
&& ehdr->e_ident[EI_MAG2] == 'L'
&& ehdr->e_ident[EI_MAG3] == 'F');
ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS
&& ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX
&& ehdr->e_ident[EI_VERSION] == EV_CURRENT);
ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
|| (rel_ok && ehdr->e_type == ET_REL));
ok &= (ehdr->e_machine == VG_ELF_MACHINE);
ok &= (ehdr->e_version == EV_CURRENT);
ok &= (ehdr->e_shstrndx != SHN_UNDEF);
ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0);
ok &= ((ehdr->e_phoff != 0 && ehdr->e_phnum != 0)
|| ehdr->e_type == ET_REL);
return ok ? True : False;
}
/* The same thing, but operating on a DiImage instead. */
static Bool is_elf_object_file_by_DiImage( DiImage* img, Bool rel_ok )
{
/* Be sure this doesn't make the frame too big. */
vg_assert(sizeof(ElfXX_Ehdr) <= 512);
ElfXX_Ehdr ehdr;
if (!ML_(img_valid)(img, 0, sizeof(ehdr)))
return False;
ML_(img_get)(&ehdr, img, 0, sizeof(ehdr));
return ML_(is_elf_object_file)( &ehdr, sizeof(ehdr), rel_ok );
}
/* Show a raw ELF symbol, given its in-image address and name. */
static
void show_raw_elf_symbol ( DiImage* strtab_img,
Int i,
const ElfXX_Sym* sym,
DiOffT sym_name_ioff, Addr sym_svma,
Bool ppc64_linux_format )
{
const HChar* space = ppc64_linux_format ? " " : "";
VG_(printf)("raw symbol [%4d]: ", i);
switch (ELFXX_ST_BIND(sym->st_info)) {
case STB_LOCAL: VG_(printf)("LOC "); break;
case STB_GLOBAL: VG_(printf)("GLO "); break;
case STB_WEAK: VG_(printf)("WEA "); break;
case STB_LOPROC: VG_(printf)("lop "); break;
case STB_HIPROC: VG_(printf)("hip "); break;
default: VG_(printf)("??? "); break;
}
switch (ELFXX_ST_TYPE(sym->st_info)) {
case STT_NOTYPE: VG_(printf)("NOT "); break;
case STT_OBJECT: VG_(printf)("OBJ "); break;
case STT_FUNC: VG_(printf)("FUN "); break;
case STT_SECTION: VG_(printf)("SEC "); break;
case STT_FILE: VG_(printf)("FIL "); break;
case STT_LOPROC: VG_(printf)("lop "); break;
case STT_HIPROC: VG_(printf)("hip "); break;
default: VG_(printf)("??? "); break;
}
HChar* sym_name = NULL;
if (sym->st_name)
sym_name = ML_(img_strdup)(strtab_img, "di.sres.1", sym_name_ioff);
VG_(printf)(": svma %#010lx, %ssz %4llu %s\n",
sym_svma, space, (ULong)(sym->st_size + 0UL),
(sym_name ? sym_name : "NONAME") );
if (sym_name)
ML_(dinfo_free)(sym_name);
}
/* Decide whether SYM is something we should collect, and if so, copy
relevant info to the _OUT arguments. For {x86,amd64,ppc32}-linux
this is straightforward - the name, address, size are copied out
unchanged.
There is a bit of a kludge re data symbols (see KLUDGED BSS CHECK
below): we assume that the .bss is mapped immediately after .data,
and so accept any data symbol which exists in the range [start of
.data, size of .data + size of .bss). I don't know if this is
really correct/justifiable, or not.
For ppc64be-linux it's more complex. If the symbol is seen to be in
the .opd section, it is taken to be a function descriptor, and so
a dereference is attempted, in order to get hold of the real entry
point address. Also as part of the dereference, there is an attempt
to calculate the TOC pointer (R2 value) associated with the symbol.
To support the ppc64be-linux pre-"dotless" ABI (prior to gcc 4.0.0),
if the symbol is seen to be outside the .opd section and its name
starts with a dot, an .opd deference is not attempted, and no TOC
pointer is calculated, but the leading dot is removed from the
name.
As a result, on ppc64be-linux, the caller of this function may have
to piece together the real size, address, name of the symbol from
multiple calls to this function. Ugly and confusing.
*/
static
Bool get_elf_symbol_info (
/* INPUTS */
struct _DebugInfo* di, /* containing DebugInfo */
const ElfXX_Sym* sym, /* ELF symbol */
DiOffT sym_name_ioff, /* name, may be absent (DiOffT_INVALID) */
const DiSlice* escn_strtab, /* holds the name */
Addr sym_svma, /* address as stated in the object file */
Bool symtab_in_debug, /* symbol table is in the debug file */
const DiSlice* escn_opd, /* the .opd (ppc64be-linux only) */
PtrdiffT opd_bias, /* for biasing AVMAs found in .opd */
/* OUTPUTS */
DiOffT* sym_name_out_ioff, /* name (in strtab) we should record */
SymAVMAs* sym_avmas_out, /* sym avmas we should record */
Int* sym_size_out, /* symbol size */
Bool* from_opd_out, /* ppc64be-linux only: did we deref an
.opd entry? */
Bool* is_text_out, /* is this a text symbol? */
Bool* is_ifunc_out, /* is this a STT_GNU_IFUNC function ?*/
Bool* is_global_out /* is this a global symbol ?*/
)
{
Bool plausible;
# if defined(VGP_ppc64be_linux)
Bool is_in_opd;
# endif
Bool in_text, in_data, in_sdata, in_rodata, in_bss, in_sbss;
Addr text_svma, data_svma, sdata_svma, rodata_svma, bss_svma, sbss_svma;
PtrdiffT text_bias, data_bias, sdata_bias, rodata_bias, bss_bias, sbss_bias;
# if defined(VGPV_arm_linux_android) \
|| defined(VGPV_x86_linux_android) \
|| defined(VGPV_mips32_linux_android) \
|| defined(VGPV_arm64_linux_android)
Addr available_size = 0;
#define COMPUTE_AVAILABLE_SIZE(segsvma, segsize) \
available_size = segsvma + segsize - sym_svma
#else
#define COMPUTE_AVAILABLE_SIZE(segsvma, segsize)
#endif
/* Set defaults */
*sym_name_out_ioff = sym_name_ioff;
(*sym_avmas_out).main = sym_svma; /* we will bias this shortly */
*is_text_out = True;
SET_TOCPTR_AVMA(*sym_avmas_out, 0); /* default to unknown/inapplicable */
SET_LOCAL_EP_AVMA(*sym_avmas_out, 0); /* default to unknown/inapplicable */
*from_opd_out = False;
*is_ifunc_out = False;
*is_global_out = False;
/* Get the symbol size, but restrict it to fit in a signed 32 bit
int. Also, deal with the stupid case of negative size by making
the size be 1. Note that sym->st_size has type UWord,
effectively. */
{ Word size_tmp = (Word)sym->st_size;
Word max_Int = (1LL << 31) - 1;
if (size_tmp < 0) size_tmp = 1;
if (size_tmp > max_Int) size_tmp = max_Int;
*sym_size_out = (Int)size_tmp;
}
/* After this point refer only to *sym_size_out and not to
sym->st_size. */
/* Figure out if we're interested in the symbol. Firstly, is it of
the right flavour? */
plausible
= (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL
|| ELFXX_ST_BIND(sym->st_info) == STB_LOCAL
|| ELFXX_ST_BIND(sym->st_info) == STB_WEAK
)
&&
(ELFXX_ST_TYPE(sym->st_info) == STT_FUNC
|| ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT
# ifdef STT_GNU_IFUNC
|| ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC
# endif
);
/* Work out the svma and bias for each section as it will appear in
addresses in the symbol table. */
if (symtab_in_debug) {
text_svma = di->text_debug_svma;
text_bias = di->text_debug_bias;
data_svma = di->data_debug_svma;
data_bias = di->data_debug_bias;
sdata_svma = di->sdata_debug_svma;
sdata_bias = di->sdata_debug_bias;
rodata_svma = di->rodata_debug_svma;
rodata_bias = di->rodata_debug_bias;
bss_svma = di->bss_debug_svma;
bss_bias = di->bss_debug_bias;
sbss_svma = di->sbss_debug_svma;
sbss_bias = di->sbss_debug_bias;
} else {
text_svma = di->text_svma;
text_bias = di->text_bias;
data_svma = di->data_svma;
data_bias = di->data_bias;
sdata_svma = di->sdata_svma;
sdata_bias = di->sdata_bias;
rodata_svma = di->rodata_svma;
rodata_bias = di->rodata_bias;
bss_svma = di->bss_svma;
bss_bias = di->bss_bias;
sbss_svma = di->sbss_svma;
sbss_bias = di->sbss_bias;
}
/* Now bias (*sym_avmas_out).main accordingly by figuring out exactly which
section the symbol is from and bias accordingly. Screws up if
the previously deduced section svma address ranges are wrong. */
if (di->text_present
&& di->text_size > 0
&& sym_svma >= text_svma
&& sym_svma < text_svma + di->text_size) {
*is_text_out = True;
(*sym_avmas_out).main += text_bias;
COMPUTE_AVAILABLE_SIZE(text_svma, di->text_size);
} else
if (di->data_present
&& di->data_size > 0
&& sym_svma >= data_svma
&& sym_svma < data_svma + di->data_size) {
*is_text_out = False;
(*sym_avmas_out).main += data_bias;
COMPUTE_AVAILABLE_SIZE(data_svma, di->data_size);
} else
if (di->sdata_present
&& di->sdata_size > 0
&& sym_svma >= sdata_svma
&& sym_svma < sdata_svma + di->sdata_size) {
*is_text_out = False;
(*sym_avmas_out).main += sdata_bias;
COMPUTE_AVAILABLE_SIZE(sdata_svma, di->sdata_size);
} else
if (di->rodata_present
&& di->rodata_size > 0
&& sym_svma >= rodata_svma
&& sym_svma < rodata_svma + di->rodata_size) {
*is_text_out = False;
(*sym_avmas_out).main += rodata_bias;
COMPUTE_AVAILABLE_SIZE(rodata_svma, di->rodata_size);
} else
if (di->bss_present
&& di->bss_size > 0
&& sym_svma >= bss_svma
&& sym_svma < bss_svma + di->bss_size) {
*is_text_out = False;
(*sym_avmas_out).main += bss_bias;
COMPUTE_AVAILABLE_SIZE(bss_svma, di->bss_size);
} else
if (di->sbss_present
&& di->sbss_size > 0
&& sym_svma >= sbss_svma
&& sym_svma < sbss_svma + di->sbss_size) {
*is_text_out = False;
(*sym_avmas_out).main += sbss_bias;
COMPUTE_AVAILABLE_SIZE(sbss_svma, di->sbss_size);
} else {
/* Assume it's in .text. Is this a good idea? */
*is_text_out = True;
(*sym_avmas_out).main += text_bias;
}
# ifdef STT_GNU_IFUNC
/* Check for indirect functions. */
if (*is_text_out
&& ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) {
*is_ifunc_out = True;
}
# endif
if (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL
|| ELFXX_ST_BIND(sym->st_info) == STB_WEAK) {
*is_global_out = True;
}
# if defined(VGP_ppc64be_linux)
/* Allow STT_NOTYPE in the very special case where we're running on
ppc64be-linux and the symbol is one which the .opd-chasing hack
below will chase. */
if (!plausible
&& *is_text_out
&& ELFXX_ST_TYPE(sym->st_info) == STT_NOTYPE
&& *sym_size_out > 0
&& di->opd_present
&& di->opd_size > 0
&& (*sym_avmas_out).main >= di->opd_avma
&& (*sym_avmas_out).main < di->opd_avma + di->opd_size)
plausible = True;
# endif
if (!plausible)
return False;
/* Ignore if nameless. */
if (sym_name_ioff == DiOffT_INVALID
|| /* VG_(strlen)(sym_name) == 0 */
/* equivalent but cheaper ... */
ML_(img_get_UChar)(escn_strtab->img, sym_name_ioff) == '\0') {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.1", sym_name_ioff);
TRACE_SYMTAB(" ignore -- nameless: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* Ignore if zero-sized. Except on Android:
On Android 2.3.5, some of the symbols that Memcheck needs to
intercept (for noise reduction purposes) have zero size, due to
lack of .size directives in handwritten assembly sources. So we
can't reject them out of hand -- instead give them a bogusly
large size and let canonicaliseSymtab trim them so they don't
overlap any following symbols. At least the following symbols
are known to be affected:
in /system/lib/libc.so: strlen strcmp strcpy memcmp memcpy
in /system/bin/linker: __dl_strcmp __dl_strlen
*/
if (*sym_size_out == 0) {
# if defined(VGPV_arm_linux_android) \
|| defined(VGPV_x86_linux_android) \
|| defined(VGPV_mips32_linux_android) \
|| defined(VGPV_arm64_linux_android)
*sym_size_out = available_size ? available_size : 2048;
# else
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.2", sym_name_ioff);
TRACE_SYMTAB(" ignore -- size=0: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
# endif
}
/* This seems to significantly reduce the number of junk
symbols, and particularly reduces the number of
overlapping address ranges. Don't ask me why ... */
if ((Int)sym->st_value == 0) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.3", sym_name_ioff);
TRACE_SYMTAB( " ignore -- valu=0: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* If it's apparently in a GOT or PLT, it's really a reference to a
symbol defined elsewhere, so ignore it. */
if (di->got_present
&& di->got_size > 0
&& (*sym_avmas_out).main >= di->got_avma
&& (*sym_avmas_out).main < di->got_avma + di->got_size) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.4", sym_name_ioff);
TRACE_SYMTAB(" ignore -- in GOT: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
if (di->plt_present
&& di->plt_size > 0
&& (*sym_avmas_out).main >= di->plt_avma
&& (*sym_avmas_out).main < di->plt_avma + di->plt_size) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.5", sym_name_ioff);
TRACE_SYMTAB(" ignore -- in PLT: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* ppc64be-linux nasty hack: if the symbol is in an .opd section,
then really what we have is the address of a function
descriptor. So use the first word of that as the function's
text.
See thread starting at
http://gcc.gnu.org/ml/gcc-patches/2004-08/msg00557.html
*/
# if defined(VGP_ppc64be_linux)
/* Host and guest may have different Endianness, used by BE only */
is_in_opd = False;
# endif
if (di->opd_present
&& di->opd_size > 0
&& (*sym_avmas_out).main >= di->opd_avma
&& (*sym_avmas_out).main < di->opd_avma + di->opd_size) {
# if !defined(VGP_ppc64be_linux)
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.6", sym_name_ioff);
TRACE_SYMTAB(" ignore -- in OPD: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
# else
Int offset_in_opd;
Bool details = 1||False;
if (details)
TRACE_SYMTAB("opdXXX: opd_bias %p, sym_svma_out %p\n",
(void*)(opd_bias), (void*)(*sym_avmas_out).main);
if (!VG_IS_8_ALIGNED((*sym_avmas_out).main)) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.6a", sym_name_ioff);
TRACE_SYMTAB(" ignore -- not 8-aligned: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* (*sym_avmas_out).main is a avma pointing into the .opd section. We
know the vma of the opd section start, so we can figure out
how far into the opd section this is. */
offset_in_opd = (Addr)(*sym_avmas_out).main - (Addr)(di->opd_avma);
if (offset_in_opd < 0 || offset_in_opd >= di->opd_size) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.6a", sym_name_ioff);
TRACE_SYMTAB(" ignore -- invalid OPD offset: %s\n", sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* Now we want to know what's at that offset in the .opd
section. We can't look in the running image since it won't
necessarily have been mapped. But we can consult the oimage.
opd_img is the start address of the .opd in the oimage.
Hence: */
ULong fn_descr[2]; /* is actually 3 words, but we need only 2 */
if (!ML_(img_valid)(escn_opd->img, escn_opd->ioff + offset_in_opd,
sizeof(fn_descr))) {
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.6b", sym_name_ioff);
TRACE_SYMTAB(" ignore -- invalid OPD fn_descr offset: %s\n",
sym_name);
if (sym_name) ML_(dinfo_free)(sym_name);
}
return False;
}
/* This can't fail now, because we just checked the offset
above. */
ML_(img_get)(&fn_descr[0], escn_opd->img,
escn_opd->ioff + offset_in_opd, sizeof(fn_descr));
if (details)
TRACE_SYMTAB("opdXXY: offset %d, fn_descr %p\n",
offset_in_opd, fn_descr);
if (details)
TRACE_SYMTAB("opdXXZ: *fn_descr %p\n", (void*)(fn_descr[0]));
/* opd_bias is the what we have to add to SVMAs found in .opd to
get plausible .text AVMAs for the entry point, and .data
AVMAs (presumably) for the TOC locations. We use the caller
supplied value (which is di->text_bias) for both of these.
Not sure why that is correct - it seems to work, and sounds
OK for fn_descr[0], but surely we need to use the data bias
and not the text bias for fn_descr[1] ? Oh Well.
*/
(*sym_avmas_out).main = fn_descr[0] + opd_bias;
SET_TOCPTR_AVMA(*sym_avmas_out, fn_descr[1] + opd_bias);
*from_opd_out = True;
is_in_opd = True;
/* Do a final sanity check: if the symbol falls outside the
DebugInfo's mapped range, ignore it. Since (*sym_avmas_out).main has
been updated, that can be achieved simply by falling through
to the test below. */
# endif /* ppc64-linux nasty hack */
}
/* Here's yet another ppc64-linux hack. Get rid of leading dot if
the symbol is outside .opd. */
# if defined(VGP_ppc64be_linux)
if (di->opd_size > 0
&& !is_in_opd
&& *sym_name_out_ioff != DiOffT_INVALID
&& ML_(img_get_UChar)(escn_strtab->img, *sym_name_out_ioff) == '.') {
vg_assert(!(*from_opd_out));
(*sym_name_out_ioff)++;
}
# endif
/* If no part of the symbol falls within the mapped range,
ignore it. */
in_text
= di->text_present
&& di->text_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->text_avma
|| (*sym_avmas_out).main >= di->text_avma + di->text_size);
in_data
= di->data_present
&& di->data_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->data_avma
|| (*sym_avmas_out).main >= di->data_avma + di->data_size);
in_sdata
= di->sdata_present
&& di->sdata_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->sdata_avma
|| (*sym_avmas_out).main >= di->sdata_avma + di->sdata_size);
in_rodata
= di->rodata_present
&& di->rodata_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->rodata_avma
|| (*sym_avmas_out).main >= di->rodata_avma + di->rodata_size);
in_bss
= di->bss_present
&& di->bss_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->bss_avma
|| (*sym_avmas_out).main >= di->bss_avma + di->bss_size);
in_sbss
= di->sbss_present
&& di->sbss_size > 0
&& !((*sym_avmas_out).main + *sym_size_out <= di->sbss_avma
|| (*sym_avmas_out).main >= di->sbss_avma + di->sbss_size);
if (*is_text_out) {
/* This used to reject any symbol falling outside the text
segment ("if (!in_text) ..."). Now it is relaxed slightly,
to reject only symbols which fall outside the area mapped
r-x. This is in accordance with r7427. See
"Comment_Regarding_Text_Range_Checks" in storage.c for
background. */
Bool in_rx;
vg_assert(di->fsm.have_rx_map);
/* This could actually wrap around and cause
ML_(find_rx_mapping) to assert. But that seems so unlikely,
let's wait for it to happen before fixing it. */
in_rx = (ML_(find_rx_mapping)(
di,
(*sym_avmas_out).main,
(*sym_avmas_out).main + *sym_size_out - 1) != NULL);
if (in_text)
vg_assert(in_rx);
if (!in_rx) {
TRACE_SYMTAB(
"ignore -- %#lx .. %#lx outside .text svma range %#lx .. %#lx\n",
(*sym_avmas_out).main, (*sym_avmas_out).main + *sym_size_out - 1,
di->text_avma,
di->text_avma + di->text_size - 1);
return False;
}
} else {
if (!(in_data || in_sdata || in_rodata || in_bss || in_sbss)) {
TRACE_SYMTAB(
"ignore -- %#lx .. %#lx outside .data / .sdata / .rodata "
"/ .bss / .sbss svma ranges\n",
(*sym_avmas_out).main, (*sym_avmas_out).main + *sym_size_out - 1);
return False;
}
}
# if defined(VGP_ppc64be_linux)
if (di->opd_present && di->opd_size > 0) {
vg_assert((*sym_avmas_out).main + *sym_size_out <= di->opd_avma
|| (*sym_avmas_out).main >= di->opd_avma + di->opd_size);
}
#endif
# if defined(VGP_ppc64le_linux)
/* PPC64 LE ABI uses three bits in the st_other field to indicate the number
* of instructions between the function's global and local entry points. An
* offset of 0 indicates that there is one entry point. The value must be:
*
* 0 - one entry point, local and global are the same
* 1 - reserved
* 2 - local entry point is one instruction after the global entry point
* 3 - local entry point is two instructions after the global entry point
* 4 - local entry point is four instructions after the global entry point
* 5 - local entry point is eight instructions after the global entry point
* 6 - local entry point is sixteen instructions after the global entry point
* 7 - reserved
*
* Extract the three bit field from the other field is done by:
* (other_field & STO_PPC64_LOCAL_MASK) >> STO_PPC_LOCAL_BIT
*
* where the #define values are given in include/elf/powerpc.h file for
* the PPC binutils.
*
* conversion of the three bit field to bytes is given by
*
* ((1 << bit_field) >> 2) << 2
*/
#define STO_PPC64_LOCAL_BIT 5
#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
{
unsigned int bit_field, dist_to_local_entry;
/* extract the other filed */
bit_field = (sym->st_other & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT;
if ((bit_field > 0) && (bit_field < 7)) {
/* store the local entry point address */
dist_to_local_entry = ((1 << bit_field) >> 2) << 2;
SET_LOCAL_EP_AVMA(*sym_avmas_out,
(*sym_avmas_out).main + dist_to_local_entry);
if (TRACE_SYMTAB_ENABLED) {
HChar* sym_name = ML_(img_strdup)(escn_strtab->img,
"di.gesi.5", sym_name_ioff);
VG_(printf)("Local entry point: %s at %#010x\n",
sym_name,
(unsigned int)GET_LOCAL_EP_AVMA(*sym_avmas_out));
}
}
}
# endif
/* Acquire! */
return True;
}
/* Read an ELF symbol table (normal or dynamic). This one is for the
"normal" case ({x86,amd64,ppc32,arm,mips32,mips64, ppc64le}-linux). */
static
__attribute__((unused)) /* not referred to on all targets */
void read_elf_symtab__normal(
struct _DebugInfo* di, const HChar* tab_name,
DiSlice* escn_symtab,
DiSlice* escn_strtab,
DiSlice* escn_opd, /* ppc64be-linux only */
Bool symtab_in_debug
)
{
if (escn_strtab->img == NULL || escn_symtab->img == NULL) {
HChar buf[VG_(strlen)(tab_name) + 40];
VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
ML_(symerr)(di, False, buf);
return;
}
TRACE_SYMTAB("\n--- Reading (ELF, standard) %s (%llu entries) ---\n",
tab_name, escn_symtab->szB/sizeof(ElfXX_Sym) );
/* Perhaps should start at i = 1; ELF docs suggest that entry
0 always denotes 'unknown symbol'. */
Word i;
for (i = 1; i < (Word)(escn_symtab->szB/sizeof(ElfXX_Sym)); i++) {
ElfXX_Sym sym;
ML_(img_get)(&sym, escn_symtab->img,
escn_symtab->ioff + i * sizeof(ElfXX_Sym), sizeof(sym));
DiOffT sym_name = escn_strtab->ioff + sym.st_name;
Addr sym_svma = sym.st_value;
if (di->trace_symtab)
show_raw_elf_symbol(escn_strtab->img, i,
&sym, sym_name, sym_svma, False);
SymAVMAs sym_avmas_really;
Int sym_size = 0;
Bool from_opd = False, is_text = False, is_ifunc = False;
Bool is_global = False;
DiOffT sym_name_really = DiOffT_INVALID;
sym_avmas_really.main = 0;
SET_TOCPTR_AVMA(sym_avmas_really, 0);
SET_LOCAL_EP_AVMA(sym_avmas_really, 0);
if (get_elf_symbol_info(di, &sym, sym_name, escn_strtab,
sym_svma, symtab_in_debug,
escn_opd, di->text_bias,
&sym_name_really,
&sym_avmas_really,
&sym_size,
&from_opd, &is_text, &is_ifunc, &is_global)) {
DiSym disym;
VG_(memset)(&disym, 0, sizeof(disym));
HChar* cstr = ML_(img_strdup)(escn_strtab->img,
"di.res__n.1", sym_name_really);
disym.avmas = sym_avmas_really;
disym.pri_name = ML_(addStr) ( di, cstr, -1 );
disym.sec_names = NULL;
disym.size = sym_size;
disym.isText = is_text;
disym.isIFunc = is_ifunc;
disym.isGlobal = is_global;
ML_(dinfo_free)(cstr);
vg_assert(disym.pri_name);
vg_assert(GET_TOCPTR_AVMA(disym.avmas) == 0);
/* has no role except on ppc64be-linux */
ML_(addSym) ( di, &disym );
if (TRACE_SYMTAB_ENABLED) {
TRACE_SYMTAB(" rec(%c) [%4ld]: "
" val %#010lx, sz %4d %s\n",
is_text ? 't' : 'd',
i,
disym.avmas.main,
(Int)disym.size,
disym.pri_name
);
if (GET_LOCAL_EP_AVMA(disym.avmas) != 0) {
TRACE_SYMTAB(" local entry point %#010lx\n",
GET_LOCAL_EP_AVMA(disym.avmas));
}
}
}
}
}
/* Read an ELF symbol table (normal or dynamic). This one is for
ppc64be-linux, which requires special treatment. */
typedef
struct {
Addr addr;
DiOffT name;
/* We have to store also the DiImage* so as to give context for
|name|. This is not part of the key (in terms of lookup) but
there's no easy other way to do this. Ugly. */
DiImage* img;
}
TempSymKey;
typedef
struct {
TempSymKey key;
Addr tocptr;
Int size;
Bool from_opd;
Bool is_text;
Bool is_ifunc;
Bool is_global;
}
TempSym;
static Word cmp_TempSymKey ( const TempSymKey* key1, const TempSym* elem2 )
{
/* Stay sane ... */
vg_assert(key1->img == elem2->key.img);
vg_assert(key1->img != NULL);
if (key1->addr < elem2->key.addr) return -1;
if (key1->addr > elem2->key.addr) return 1;
vg_assert(key1->name != DiOffT_INVALID);
vg_assert(elem2->key.name != DiOffT_INVALID);
return (Word)ML_(img_strcmp)(key1->img, key1->name, elem2->key.name);
}
static
__attribute__((unused)) /* not referred to on all targets */
void read_elf_symtab__ppc64be_linux(
struct _DebugInfo* di, const HChar* tab_name,
DiSlice* escn_symtab,
DiSlice* escn_strtab,
DiSlice* escn_opd, /* ppc64be-linux only */
Bool symtab_in_debug
)
{
Word i;
Int old_size;
Bool modify_size, modify_tocptr;
OSet *oset;
TempSymKey key;
TempSym *elem;
TempSym *prev;
if (escn_strtab->img == NULL || escn_symtab->img == NULL) {
HChar buf[VG_(strlen)(tab_name) + 40];
VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
ML_(symerr)(di, False, buf);
return;
}
TRACE_SYMTAB("\n--- Reading (ELF, ppc64be-linux) %s (%llu entries) ---\n",
tab_name, escn_symtab->szB/sizeof(ElfXX_Sym) );
oset = VG_(OSetGen_Create)( offsetof(TempSym,key),
(OSetCmp_t)cmp_TempSymKey,
ML_(dinfo_zalloc), "di.respl.1",
ML_(dinfo_free) );
/* Perhaps should start at i = 1; ELF docs suggest that entry
0 always denotes 'unknown symbol'. */
for (i = 1; i < (Word)(escn_symtab->szB/sizeof(ElfXX_Sym)); i++) {
ElfXX_Sym sym;
ML_(img_get)(&sym, escn_symtab->img,
escn_symtab->ioff + i * sizeof(ElfXX_Sym), sizeof(sym));
DiOffT sym_name = escn_strtab->ioff + sym.st_name;
Addr sym_svma = sym.st_value;
if (di->trace_symtab)
show_raw_elf_symbol(escn_strtab->img, i,
&sym, sym_name, sym_svma, True);
SymAVMAs sym_avmas_really;
Int sym_size = 0;
Bool from_opd = False, is_text = False, is_ifunc = False;
Bool is_global = False;
DiOffT sym_name_really = DiOffT_INVALID;
DiSym disym;
VG_(memset)(&disym, 0, sizeof(disym));
sym_avmas_really.main = 0;
SET_TOCPTR_AVMA(sym_avmas_really, 0);
SET_LOCAL_EP_AVMA(sym_avmas_really, 0);
if (get_elf_symbol_info(di, &sym, sym_name, escn_strtab,
sym_svma, symtab_in_debug,
escn_opd, di->text_bias,
&sym_name_really,
&sym_avmas_really,
&sym_size,
&from_opd, &is_text, &is_ifunc, &is_global)) {
/* Check if we've seen this (name,addr) key before. */
key.addr = sym_avmas_really.main;
key.name = sym_name_really;
key.img = escn_strtab->img;
prev = VG_(OSetGen_Lookup)( oset, &key );
if (prev) {
/* Seen it before. Fold in whatever new info we can. */
modify_size = False;
modify_tocptr = False;
old_size = 0;
if (prev->from_opd && !from_opd
&& (prev->size == 24 || prev->size == 16)
&& sym_size != prev->size) {
/* Existing one is an opd-redirect, with a bogus size,
so the only useful new fact we have is the real size
of the symbol. */
modify_size = True;
old_size = prev->size;
prev->size = sym_size;
}
else
if (!prev->from_opd && from_opd
&& (sym_size == 24 || sym_size == 16)) {
/* Existing one is non-opd, new one is opd. What we
can acquire from the new one is the TOC ptr to be
used. Since the existing sym is non-toc, it
shouldn't currently have an known TOC ptr. */
vg_assert(prev->tocptr == 0);
modify_tocptr = True;
prev->tocptr = GET_TOCPTR_AVMA(sym_avmas_really);
}
else {
/* ignore. can we do better here? */
}
/* Only one or the other is possible (I think) */
vg_assert(!(modify_size && modify_tocptr));
if (modify_size && di->trace_symtab) {
VG_(printf)(" modify (old sz %4d) "
" val %#010lx, toc %#010lx, sz %4d %llu\n",
old_size,
prev->key.addr,
prev->tocptr,
prev->size,
prev->key.name
);
}
if (modify_tocptr && di->trace_symtab) {
VG_(printf)(" modify (upd tocptr) "
" val %#010lx, toc %#010lx, sz %4d %llu\n",
prev->key.addr,
prev->tocptr,
prev->size,
prev->key.name
);
}
} else {
/* A new (name,addr) key. Add and continue. */
elem = VG_(OSetGen_AllocNode)(oset, sizeof(TempSym));
elem->key = key;
elem->tocptr = GET_TOCPTR_AVMA(sym_avmas_really);
elem->size = sym_size;
elem->from_opd = from_opd;
elem->is_text = is_text;
elem->is_ifunc = is_ifunc;
elem->is_global = is_global;
VG_(OSetGen_Insert)(oset, elem);
if (di->trace_symtab) {
HChar* str = ML_(img_strdup)(escn_strtab->img, "di.respl.2",
elem->key.name);
VG_(printf)(" to-oset [%4ld]: "
" val %#010lx, toc %#010lx, sz %4d %s\n",
i,
elem->key.addr,
elem->tocptr,
(Int) elem->size,
str
);
if (str) ML_(dinfo_free)(str);
}
}
}
}
/* All the syms that matter are in the oset. Now pull them out,
build a "standard" symbol table, and nuke the oset. */
i = 0;
VG_(OSetGen_ResetIter)( oset );
while ( (elem = VG_(OSetGen_Next)(oset)) ) {
DiSym disym;
VG_(memset)(&disym, 0, sizeof(disym));
HChar* cstr = ML_(img_strdup)(escn_strtab->img,
"di.res__ppc64.1", elem->key.name);
disym.avmas.main = elem->key.addr;
SET_TOCPTR_AVMA(disym.avmas, elem->tocptr);
SET_LOCAL_EP_AVMA(disym.avmas, 0); // ppc64be does not use local_ep.
disym.pri_name = ML_(addStr) ( di, cstr, -1 );
disym.sec_names = NULL;
disym.size = elem->size;
disym.isText = elem->is_text;
disym.isIFunc = elem->is_ifunc;
disym.isGlobal = elem->is_global;
ML_(dinfo_free)(cstr);
vg_assert(disym.pri_name != NULL);
ML_(addSym) ( di, &disym );
if (di->trace_symtab) {
VG_(printf)(" rec(%c%c%c) [%4ld]: "
" val %#010lx, toc %#010lx, sz %4d %s\n",
disym.isText ? 't' : 'd',
disym.isIFunc ? 'i' : '-',
disym.isGlobal ? 'g' : 'l',
i,
disym.avmas.main,
GET_TOCPTR_AVMA(disym.avmas),
(Int) disym.size,
disym.pri_name
);
}
i++;
}
VG_(OSetGen_Destroy)( oset );
}
#if defined(VGO_freebsd)
/**
* read_and_set_osrel
*
* "osrel" is in an Elf note. It has values such as 1201000 for FreeBSD 12.1
* Some of the behaviour related to SIGSEGV and SIGBUS signals depends on the
* kernel reading this value.
*
* However in the case of Valgrind, the host is strictly statically linked and
* does not contain the NT_FREEBSD_ABI_TAG note. And even if it did, we want to
* override the value with that of the guest.
*
* At some later date we might want to look at the value of "fctl0" (note with the
* NT_FREEBSD_FEATURE_CTL type). This seems to be related to Address Space Layout
* Randomization. No hurry at the moment.
*
* See /usr/src/sys/kern/imgact_elf.c for details on how the kernel reads these
* notes.
*/
static
void read_and_set_osrel(DiImage* img)
{
if (is_elf_object_file_by_DiImage(img, False)) {
Word i;
ElfXX_Ehdr ehdr;
ML_(img_get)(&ehdr, img, 0, sizeof(ehdr));
/* only set osrel for executable files, not for subsequent shared libraries */
if (ehdr.e_type != ET_EXEC) {
return;
}
/* Skip the phdrs when we have to search the shdrs. In separate
.debug files the phdrs might not be valid (they are a copy of
the main ELF file) and might trigger assertions when getting
image notes based on them. */
for (i = 0; i < ehdr.e_phnum; i++) {
ElfXX_Phdr phdr;
ML_(img_get)(&phdr, img,
ehdr.e_phoff + i * ehdr.e_phentsize, sizeof(phdr));
if (phdr.p_type == PT_NOTE) {
ElfXX_Off note_ioff = phdr.p_offset;
while (note_ioff < phdr.p_offset + phdr.p_filesz) {
ElfXX_Nhdr note[2];
ML_(img_get)(note, img, (DiOffT)note_ioff, sizeof(note));
DiOffT name_ioff = note_ioff + sizeof(ElfXX_Nhdr);
//DiOffT desc_ioff = name_ioff + ((note[0].n_namesz + 3) & ~3);
if (ML_(img_strcmp_c)(img, name_ioff, "FreeBSD") == 0
&& note[0].n_type == VKI_NT_FREEBSD_ABI_TAG) {
u_int32_t osrel = note[1].n_type;
int name[4];
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_OSREL;
name[3] = VG_(getpid)();
SizeT newlen = sizeof(osrel);
Int error = VG_(sysctl)(name, 4, NULL, NULL, &osrel, newlen);
if (error == -1) {
VG_(message)(Vg_DebugMsg, "Warning: failed to set osrel for current process with value %u\n", osrel);
} else {
if (VG_(clo_verbosity) > 1) {
VG_(message)(Vg_DebugMsg, "Set osrel for current process with value %u\n", osrel);
}
}
}
note_ioff = note_ioff + sizeof(ElfXX_Nhdr)
+ ((note[0].n_namesz + 3) & ~3)
+ ((note[0].n_descsz + 3) & ~3);
}
}
}
}
}
#endif
/*
* Look for a build-id in an ELF image. The build-id specification
* can be found here:
*
* http://fedoraproject.org/wiki/RolandMcGrath/BuildID
*
* Returned string must be freed by the caller.
*/
static
HChar* find_buildid(DiImage* img, Bool rel_ok, Bool search_shdrs)
{
HChar* buildid = NULL;
# ifdef NT_GNU_BUILD_ID
if (is_elf_object_file_by_DiImage(img, rel_ok)) {
Word i;
ElfXX_Ehdr ehdr;
ML_(img_get)(&ehdr, img, 0, sizeof(ehdr));
/* Skip the phdrs when we have to search the shdrs. In separate
.debug files the phdrs might not be valid (they are a copy of
the main ELF file) and might trigger assertions when getting
image notes based on them. */
for (i = 0; !search_shdrs && i < ehdr.e_phnum; i++) {
ElfXX_Phdr phdr;
ML_(img_get)(&phdr, img,
ehdr.e_phoff + i * ehdr.e_phentsize, sizeof(phdr));
if (phdr.p_type == PT_NOTE) {
ElfXX_Off note_ioff = phdr.p_offset;
while (note_ioff < phdr.p_offset + phdr.p_filesz) {
ElfXX_Nhdr note;
ML_(img_get)(¬e, img, (DiOffT)note_ioff, sizeof(note));
DiOffT name_ioff = note_ioff + sizeof(ElfXX_Nhdr);
DiOffT desc_ioff = name_ioff + ((note.n_namesz + 3) & ~3);
if (ML_(img_strcmp_c)(img, name_ioff, ELF_NOTE_GNU) == 0
&& note.n_type == NT_GNU_BUILD_ID) {
buildid = ML_(dinfo_zalloc)("di.fbi.1",
note.n_descsz * 2 + 1);
Word j;
for (j = 0; j < note.n_descsz; j++) {
UChar desc_j = ML_(img_get_UChar)(img, desc_ioff + j);
VG_(sprintf)(buildid + VG_(strlen)(buildid),
"%02x", (UInt)desc_j);
}
}
note_ioff = note_ioff + sizeof(ElfXX_Nhdr)
+ ((note.n_namesz + 3) & ~3)
+ ((note.n_descsz + 3) & ~3);
}
}
}
/* Normally we would only search shdrs for ET_REL files, but when
we search for a separate .debug file phdrs might not be there
(they are never loaded) or have been corrupted, so try again
against shdrs. */
if (buildid || (!rel_ok && !search_shdrs))
return buildid;
for (i = 0; i < ehdr.e_shnum; i++) {
ElfXX_Shdr shdr;
ML_(img_get)(&shdr, img,
ehdr.e_shoff + i * ehdr.e_shentsize, sizeof(shdr));
if (shdr.sh_type == SHT_NOTE) {
ElfXX_Off note_ioff = shdr.sh_offset;
while (note_ioff < shdr.sh_offset + shdr.sh_size) {
ElfXX_Nhdr note;
ML_(img_get)(¬e, img, (DiOffT)note_ioff, sizeof(note));
DiOffT name_ioff = note_ioff + sizeof(ElfXX_Nhdr);
DiOffT desc_ioff = name_ioff + ((note.n_namesz + 3) & ~3);
if (ML_(img_strcmp_c)(img, name_ioff, ELF_NOTE_GNU) == 0
&& note.n_type == NT_GNU_BUILD_ID) {
buildid = ML_(dinfo_zalloc)("di.fbi.2",
note.n_descsz * 2 + 1);
Word j;
for (j = 0; j < note.n_descsz; j++) {
UChar desc_j = ML_(img_get_UChar)(img, desc_ioff + j);
VG_(sprintf)(buildid + VG_(strlen)(buildid),
"%02x", (UInt)desc_j);
}
}
note_ioff = note_ioff + sizeof(ElfXX_Nhdr)
+ ((note.n_namesz + 3) & ~3)
+ ((note.n_descsz + 3) & ~3);
}
}
}
}
# endif /* def NT_GNU_BUILD_ID */
return buildid;
}
/* Try and open a separate debug file, ignoring any where the CRC does
not match the value from the main object file. Returned DiImage
must be discarded by the caller.
If |serverAddr| is NULL, |name| is expected to be a fully qualified
(absolute) path to the file in the local filesystem. If
|serverAddr| is non-NULL, it is expected to be an IPv4 and port
spec of the form "d.d.d.d:d" or "d.d.d.d", and |name| is expected
to be a plain filename (no path components at all).
*/
static
DiImage* open_debug_file( const HChar* name, const HChar* buildid, UInt crc,
Bool rel_ok, const HChar* serverAddr )
{
DiImage* dimg
= serverAddr ? ML_(img_from_di_server)(name, serverAddr)
: ML_(img_from_local_file)(name);
if (dimg == NULL)
return NULL;
if (VG_(clo_verbosity) > 1) {
if (serverAddr)
VG_(message)(Vg_DebugMsg, " Considering %s on server %s ..\n",
name, serverAddr);
else
VG_(message)(Vg_DebugMsg, " Considering %s ..\n", name);
}
/* We will always check the crc if we have one (altfiles don't have one)
for now because we might be opening the main file again by any other
name, and that obviously also has the same buildid. More efficient
would be an fstat bases check or a check that the file actually
contains .debug* sections. */
if (buildid && crc == 0) {
HChar* debug_buildid = find_buildid(dimg, rel_ok, True);
if (debug_buildid == NULL || VG_(strcmp)(buildid, debug_buildid) != 0) {
ML_(img_done)(dimg);
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_DebugMsg,
" .. build-id mismatch (found %s wanted %s)\n",
(debug_buildid ? debug_buildid : "(null)"), buildid);
ML_(dinfo_free)(debug_buildid);
return NULL;
}
ML_(dinfo_free)(debug_buildid);
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_DebugMsg, " .. build-id is valid\n");
} else {
UInt calccrc = ML_(img_calc_gnu_debuglink_crc32)(dimg);
if (calccrc != crc) {
ML_(img_done)(dimg);
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_DebugMsg,
" .. CRC mismatch (computed %08x wanted %08x)\n", calccrc, crc);
return NULL;
}
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_DebugMsg, " .. CRC is valid\n");
}
return dimg;
}
#if defined(VGO_linux)
/* Return the path of the debuginfod-find executable. */
static
const HChar* debuginfod_find_path( void )
{
static const HChar* path = (const HChar*) -1;
if (path == (const HChar*) -1) {
if (VG_(getenv)("DEBUGINFOD_URLS") == NULL
|| VG_(strcmp)("", VG_(getenv("DEBUGINFOD_URLS"))) == 0)
path = NULL;
else
path = VG_(find_executable)("debuginfod-find");
}
return path;
}
/* Try to find a separate debug file with |buildid| via debuginfod. If found,
return its DiImage. Searches for a local debuginfod-find executable and
runs it in a child process in order to download the debug file. */
static
DiImage* find_debug_file_debuginfod( const HChar* objpath,
HChar** debugpath,
const HChar* buildid,
const UInt crc, Bool rel_ok )
{
# define BUF_SIZE 4096
Int out_fds[2], err_fds[2]; /* pipe fds */
DiImage* dimg = NULL; /* the img we found */
HChar buf[BUF_SIZE]; /* executable output buffer */
const HChar* path; /* executable path */
SizeT len; /* number of bytes read int buf */
Int ret; /* result of read call */
if (buildid == NULL)
return NULL;
if ((path = debuginfod_find_path()) == NULL)
return NULL;
if (VG_(pipe)(out_fds) != 0
|| VG_(pipe)(err_fds) != 0)
return NULL;
if (VG_(clo_verbosity) > 1)
VG_(umsg)("Downloading debug info for %s...\n", objpath);
/* Run debuginfod-find to query servers for the debuginfo. */
Int pid = VG_(fork)();
if (pid == 0) {
const HChar *argv[4] = { path, "debuginfo", buildid, (HChar*)0 };
/* Redirect stdout and stderr */
SysRes res = VG_(dup2)(out_fds[1], 1);
if (sr_Res(res) < 0)
VG_(exit)(1);
res = VG_(dup2)(err_fds[1], 2);
if (sr_Res(res) < 0)
VG_(exit)(1);
/* Disable extra stderr output since it does not play well with umesg */
VG_(env_unsetenv)(VG_(client_envp), "DEBUGINFOD_VERBOSE", NULL);
VG_(env_unsetenv)(VG_(client_envp), "DEBUGINFOD_PROGRESS", NULL);
VG_(close)(out_fds[0]);
VG_(close)(err_fds[0]);
VG_(execv)(argv[0], argv);
/* If we are still alive here, execv failed. */
VG_(exit)(1);
}
VG_(close)(out_fds[1]);
VG_(close)(err_fds[1]);
if (pid < 0) {
if (VG_(clo_verbosity) > 1)
VG_(umsg)("Server Error\n");
goto out;
}
VG_(waitpid)(pid, NULL, 0);
/* Set dimg if download was successful. */
len = 0;
ret = -1;
while (len >= 0 && len < BUF_SIZE) {
ret = VG_(read)(out_fds[0], buf + len, BUF_SIZE - len);
if (ret <= 0)
break;
len += ret;
}
if (ret >= 0 && len > 0
&& buf[0] == '/' && buf[len-1] == '\n') {
/* Remove newline from filename before trying to open debug file */
buf[len-1] = '\0';
dimg = open_debug_file(buf, buildid, crc, rel_ok, NULL);
if (dimg != NULL) {
/* Success */
if (*debugpath)
ML_(dinfo_free)(*debugpath);
*debugpath = ML_(dinfo_strdup)("di.fdfd.1", buf);
if (VG_(clo_verbosity) > 1)
VG_(umsg)("Successfully downloaded debug file for %s\n",
objpath);
goto out;
}
}
/* Download failed so try to print error message. */
HChar* nl;
if (VG_(read)(err_fds[0], buf, BUF_SIZE) > 0
&& (nl = VG_(strchr)(buf, '\n'))) {
*nl = '\0';
if (VG_(clo_verbosity) > 1)
VG_(umsg)("%s\n", buf);
} else
if (VG_(clo_verbosity) > 1)
VG_(umsg)("Server Error\n");
out:
VG_(close)(out_fds[0]);
VG_(close)(err_fds[0]);
return dimg;
}
#endif
/* Try to find a separate debug file for a given object file. If
found, return its DiImage, which should be freed by the caller. If
|buildid| is non-NULL, then a debug object matching it is
acceptable. If |buildid| is NULL or doesn't specify a findable
debug object, then we look in various places to find a file with
the specified CRC. And if that doesn't work out then we give
up. */
static
DiImage* find_debug_file( struct _DebugInfo* di,
const HChar* objpath, const HChar* buildid,
const HChar* debugname, UInt crc, Bool rel_ok )
{
const HChar* extrapath = VG_(clo_extra_debuginfo_path);
const HChar* serverpath = VG_(clo_debuginfo_server);
DiImage* dimg = NULL; /* the img that we found */
HChar* debugpath = NULL; /* where we found it */
if (buildid != NULL) {
debugpath = ML_(dinfo_zalloc)("di.fdf.1",
VG_(strlen)(buildid) + 33);
VG_(sprintf)(debugpath, "/usr/lib/debug/.build-id/%c%c/%s.debug",
buildid[0], buildid[1], buildid + 2);
dimg = open_debug_file(debugpath, buildid, 0, rel_ok, NULL);
if (!dimg) {
ML_(dinfo_free)(debugpath);
debugpath = NULL;
}
}
if (dimg == NULL && debugname != NULL) {
HChar *objdir = ML_(dinfo_strdup)("di.fdf.2", objpath);
HChar *usrmerge_objdir;
HChar *objdirptr;
if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
*objdirptr = '\0';
if ((objdirptr = VG_(strstr)(objdir, "usr")) != NULL)
usrmerge_objdir = objdirptr + VG_(strlen)("usr");
else
usrmerge_objdir = NULL;
debugpath = ML_(dinfo_zalloc)(
"di.fdf.3",
VG_(strlen)(objdir) + VG_(strlen)(debugname) + 64
+ (extrapath ? VG_(strlen)(extrapath) : 0)
+ (serverpath ? VG_(strlen)(serverpath) : 0));
# define TRY_OBJDIR(format, ...) \
do { \
VG_(sprintf)(debugpath, format, __VA_ARGS__); \
dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL); \
if (dimg != NULL) goto dimg_ok; \
} while (0);
# define TRY_OBJDIR_USRMERGE_OBJDIR(format) \
do { \
TRY_OBJDIR(format, objdir, debugname); \
if (usrmerge_objdir != NULL) { \
TRY_OBJDIR(format, usrmerge_objdir, debugname); \
} \
} while (0)
if (debugname[0] == '/') {
TRY_OBJDIR("%s", debugname);
}
TRY_OBJDIR_USRMERGE_OBJDIR("%s/%s");
TRY_OBJDIR_USRMERGE_OBJDIR("%s/.debug/%s");
TRY_OBJDIR_USRMERGE_OBJDIR("/usr/lib/debug%s/%s");
if (extrapath) {
TRY_OBJDIR("%s%s/%s", extrapath, objdir, debugname);
if (usrmerge_objdir != NULL)
TRY_OBJDIR("%s%s/%s", extrapath, usrmerge_objdir, debugname);
}
# undef TRY_OBJDIR
# undef TRY_OBJDIRS
if (serverpath) {
/* When looking on the debuginfo server, always just pass the
basename. */
const HChar* basename = debugname;
if (VG_(strstr)(basename, "/") != NULL) {
basename = VG_(strrchr)(basename, '/') + 1;
}
VG_(sprintf)(debugpath, "%s on %s", basename, serverpath);
dimg = open_debug_file(basename, buildid, crc, rel_ok, serverpath);
if (dimg) goto dimg_ok;
}
dimg_ok:
ML_(dinfo_free)(objdir);
}
# if defined(VGO_linux)
if (VG_(clo_enable_debuginfod) && dimg == NULL)
dimg = find_debug_file_debuginfod(objpath, &debugpath, buildid, crc, rel_ok);
# endif
if (dimg != NULL) {
vg_assert(debugpath);
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ Found a debuginfo file: %s\n", debugpath);
/* Only set once, we might be called again for opening the altfile. */
if (di->fsm.dbgname == NULL)
di->fsm.dbgname = ML_(dinfo_strdup)("di.fdf.4", debugpath);
}
if (debugpath)
ML_(dinfo_free)(debugpath);
return dimg;
}
/* Try to find a separate debug file for a given object file, in a
hacky and dangerous way: check only the --extra-debuginfo-path and
the --debuginfo-server. And don't do a consistency check. */
static
DiImage* find_debug_file_ad_hoc( const DebugInfo* di,
const HChar* objpath )
{
const HChar* extrapath = VG_(clo_extra_debuginfo_path);
const HChar* serverpath = VG_(clo_debuginfo_server);
DiImage* dimg = NULL; /* the img that we found */
HChar* debugpath = NULL; /* where we found it */
HChar *objdir = ML_(dinfo_strdup)("di.fdfah.1", objpath);
HChar *objdirptr;
if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
*objdirptr = '\0';
debugpath = ML_(dinfo_zalloc)(
"di.fdfah.3",
VG_(strlen)(objdir) + 64
+ (extrapath ? VG_(strlen)(extrapath) : 0)
+ (serverpath ? VG_(strlen)(serverpath) : 0));
if (extrapath) {
VG_(sprintf)(debugpath, "%s/%s", extrapath, objpath);
dimg = ML_(img_from_local_file)(debugpath);
if (dimg != NULL) {
if (VG_(clo_verbosity) > 1) {
VG_(message)(Vg_DebugMsg, " Using (POSSIBLY MISMATCHED) %s\n",
debugpath);
}
goto dimg_ok;
}
}
if (serverpath) {
/* When looking on the debuginfo server, always just pass the
basename. */
const HChar* basename = objpath;
if (VG_(strstr)(basename, "/") != NULL) {
basename = VG_(strrchr)(basename, '/') + 1;
}
VG_(sprintf)(debugpath, "%s on %s", basename, serverpath);
dimg = ML_(img_from_di_server)(basename, serverpath);
if (dimg != NULL) {
if (VG_(clo_verbosity) > 1) {
VG_(message)(Vg_DebugMsg, " Using (POSSIBLY MISMATCHED) %s\n",
debugpath);
}
goto dimg_ok;
}
}
dimg_ok:
ML_(dinfo_free)(objdir);
if (dimg != NULL) {
vg_assert(debugpath);
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ Found an ad_hoc debuginfo file: %s\n", debugpath);
}
if (debugpath)
ML_(dinfo_free)(debugpath);
return dimg;
}
static DiOffT INDEX_BIS ( DiOffT base, UWord idx, UWord scale ) {
// This is a bit stupid. Really, idx and scale ought to be
// 64-bit quantities, always.
return base + (DiOffT)idx * (DiOffT)scale;
}
/* Find the file offset corresponding to SVMA by using the program
headers. This is taken from binutils-2.17/binutils/readelf.c
offset_from_vma(). */
static
Word file_offset_from_svma ( /*OUT*/Bool* ok,
Addr svma,
DiImage* img,
DiOffT phdr_ioff,
Word phdr_nent,
Word phdr_ent_szB )
{
Word i;
for (i = 0; i < phdr_nent; i++) {
ElfXX_Phdr seg;
ML_(img_get)(&seg, img,
INDEX_BIS(phdr_ioff, i, phdr_ent_szB), sizeof(seg));
if (seg.p_type != PT_LOAD)
continue;
if (svma >= (seg.p_vaddr & -seg.p_align)
&& svma + 1 <= seg.p_vaddr + seg.p_filesz) {
*ok = True;
return svma - seg.p_vaddr + seg.p_offset;
}
}
*ok = False;
return 0;
}
/* Check if section is compressed and modify DiSlice if it is.
Returns False in case of unsupported compression type.
*/
static Bool check_compression(ElfXX_Shdr* h, DiSlice* s) {
if (h->sh_flags & SHF_COMPRESSED) {
ElfXX_Chdr chdr;
ML_(img_get)(&chdr, s->img, s->ioff, sizeof(ElfXX_Chdr));
if (chdr.ch_type != ELFCOMPRESS_ZLIB)
return False;
s->ioff = ML_(img_mark_compressed_part)(s->img,
s->ioff + sizeof(ElfXX_Chdr),
s->szB - sizeof(ElfXX_Chdr),
(SizeT)chdr.ch_size);
s->szB = chdr.ch_size;
} else if (h->sh_size > SIZE_OF_ZLIB_HEADER) {
/* Read the zlib header. In this case, it should be "ZLIB"
followed by the uncompressed section size, 8 bytes in BE order. */
UChar tmp[SIZE_OF_ZLIB_HEADER];
ML_(img_get)(tmp, s->img, s->ioff, SIZE_OF_ZLIB_HEADER);
if (VG_(memcmp)(tmp, "ZLIB", 4) == 0) {
SizeT size;
# if (VG_WORDSIZE == 8)
size = tmp[4]; size <<= 8;
size += tmp[5]; size <<= 8;
size += tmp[6]; size <<= 8;
size += tmp[7]; size <<= 8;
# else
vg_assert((tmp[4] == 0) && (tmp[5] == 0) && (tmp[6] == 0)
&& (tmp[7] == 0));
size = 0;
# endif
size += tmp[8]; size <<= 8;
size += tmp[9]; size <<= 8;
size += tmp[10]; size <<= 8;
size += tmp[11];
s->ioff = ML_(img_mark_compressed_part)(s->img,
s->ioff + SIZE_OF_ZLIB_HEADER,
s->szB - SIZE_OF_ZLIB_HEADER,
size);
s->szB = size;
}
}
return True;
}
/* Helper function to get the readlink path. Returns a copy of path if the
file wasn't a symbolic link. Returns NULL on error. Unless NULL is
returned the result needs to be released with dinfo_free.
*/
static HChar* readlink_path (const HChar *path)
{
SizeT bufsiz = VG_(strlen)(path);
HChar *buf = ML_(dinfo_strdup)("readlink_path.strdup", path);
UInt tries = 6;
while (tries > 0) {
SysRes res;
#if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
(UWord)path, (UWord)buf, bufsiz);
#elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
#elif defined(VGO_solaris)
res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
(UWord)buf, bufsiz);
#else
# error Unknown OS
#endif
if (sr_isError(res)) {
if (sr_Err(res) == VKI_EINVAL)
return buf; // It wasn't a symbolic link, return the strdup result.
ML_(dinfo_free)(buf);
return NULL;
}
SSizeT r = sr_Res(res);
if (r < 0) break;
if (r == bufsiz) { // buffer too small; increase and retry
bufsiz *= 2 + 16;
buf = ML_(dinfo_realloc)("readlink_path.realloc", buf, bufsiz);
tries--;
continue;
}
buf[r] = '\0';
break;
}
if (tries == 0) { // We tried, but weird long path?
ML_(dinfo_free)(buf);
return NULL;
}
if (buf[0] == '/')
return buf;
/* Relative path, add link dir. */
HChar *linkdirptr;
SizeT linkdir_len = VG_(strlen)(path);
if ((linkdirptr = VG_(strrchr)(path, '/')) != NULL)
linkdir_len -= VG_(strlen)(linkdirptr + 1);
SizeT buflen = VG_(strlen)(buf);
SizeT needed = linkdir_len + buflen + 1;
if (bufsiz < needed)
buf = ML_(dinfo_realloc)("readlink_path.linkdir", buf, needed);
VG_(memmove)(buf + linkdir_len, buf, buflen);
VG_(memcpy)(buf, path, linkdir_len);
buf[needed - 1] = '\0';
return buf;
}
#define FINDX_MIMG(_sec_name, _sec_escn, _post_fx) \
do { \
ElfXX_Shdr a_shdr; \
ML_(img_get)(&a_shdr, mimg, \
INDEX_BIS(shdr_mioff, i, shdr_ment_szB), \
sizeof(a_shdr)); \
if (0 == ML_(img_strcmp_c)(mimg, shdr_strtab_mioff \
+ a_shdr.sh_name, _sec_name)) { \
Bool nobits; \
_sec_escn.img = mimg; \
_sec_escn.ioff = (DiOffT)a_shdr.sh_offset; \
_sec_escn.szB = a_shdr.sh_size; \
if (!check_compression(&a_shdr, &_sec_escn)) { \
ML_(symerr)(di, True, " Compression type is unsupported"); \
goto out; \
} \
nobits = a_shdr.sh_type == SHT_NOBITS; \
vg_assert(_sec_escn.img != NULL); \
vg_assert(_sec_escn.ioff != DiOffT_INVALID); \
TRACE_SYMTAB( "%-18s: ioff %llu .. %llu\n", \
_sec_name, (ULong)a_shdr.sh_offset, \
((ULong)a_shdr.sh_offset) + a_shdr.sh_size - 1); \
/* SHT_NOBITS sections have zero size in the file. */ \
if (!nobits && \
a_shdr.sh_offset + \
a_shdr.sh_size > ML_(img_real_size)(mimg)) { \
ML_(symerr)(di, True, \
" section beyond image end?!"); \
goto out; \
} \
_post_fx; \
} \
} while (0);
/* Version with no post-effects */
#define FIND_MIMG(_sec_name, _sec_escn) \
FINDX_MIMG(_sec_name, _sec_escn, /**/)
/* The central function for reading ELF debug info. For the
object/exe specified by the DebugInfo, find ELF sections, then read
the symbols, line number info, file name info, CFA (stack-unwind
info) and anything else we want, into the tables within the
supplied DebugInfo.
*/
Bool ML_(read_elf_object) ( struct _DebugInfo* di )
{
/* This function is long and complex. That, and the presence of
nested scopes, means it's not always easy to see which parts are
in loops/conditionals and which aren't. To make it easier to
follow, points executed exactly once -- that is, those which are
the top level of the function -- are marked TOPLEVEL.
*/
/* Consistent terminology for local variable names, without which
it's almost unfollowably complex:
In which file?
in the main ELF file *_m*
in the debuginfo file *_d*
in the alt debuginfo file *_a*
What kind of thing?
_{m,d,a}img a DiImage*
_{m,d,a}ioff an offset in the image (DiOffT)
_{m,d,a}nent "number of entries"
_{m,d,a}ent_szB "size in bytes of an entry"
ehdr_{m,d,a} ELF header
phdr Program header
shdr Section header
a_X a temporary X
_escn an DiSlice (elf section info) variable
szB size in bytes
*/
/* TOPLEVEL */
Bool ok;
Word i, j;
Bool dynbss_present = False;
Bool sdynbss_present = False;
Bool retval = False;
/* Image for the main ELF file we're working with. */
DiImage* mimg = NULL;
/* ELF header offset for the main file. Should be zero since the
ELF header is at start of file. */
DiOffT ehdr_mioff = 0;
/* Program header table image addr, # entries, entry size */
DiOffT phdr_mioff = 0;
UWord phdr_mnent = 0;
UWord phdr_ment_szB = 0;
/* Section header image addr, # entries, entry size. Also the
associated string table. */
DiOffT shdr_mioff = 0;
UWord shdr_mnent = 0;
UWord shdr_ment_szB = 0;
DiOffT shdr_strtab_mioff = 0;
/* SVMAs covered by rx and rw segments and corresponding biases.
Normally each object would provide just one rx and one rw area,
but various ELF mangling tools create objects with multiple
such entries, hence the generality. */
typedef
struct {
Addr svma_base;
Addr svma_limit;
PtrdiffT bias;
Bool exec;
}
RangeAndBias;
XArray* /* of RangeAndBias */ svma_ranges = NULL;
# if defined(SOLARIS_PT_SUNDWTRACE_THRP)
Addr dtrace_data_vaddr = 0;
# endif
vg_assert(di);
vg_assert(di->fsm.have_rx_map == True);
vg_assert(di->have_dinfo == False);
vg_assert(di->fsm.filename);
vg_assert(!di->symtab);
vg_assert(!di->loctab);
vg_assert(!di->inltab);
vg_assert(!di->cfsi_base);
vg_assert(!di->cfsi_m_ix);
vg_assert(!di->cfsi_rd);
vg_assert(!di->cfsi_exprs);
vg_assert(!di->strpool);
vg_assert(!di->fndnpool);
vg_assert(!di->soname);
{
Bool has_nonempty_rx = False;
Bool has_nonempty_rw = False;
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
if (!map->rx && !map->rw)
continue;
if (map->rx && map->size > 0)
has_nonempty_rx = True;
if (map->rw && map->size > 0)
has_nonempty_rw = True;
/* If this doesn't hold true, it means that m_syswrap/m_aspacemgr
managed to do a mapping where the start isn't page aligned.
Which sounds pretty bogus to me. */
vg_assert(VG_IS_PAGE_ALIGNED(map->avma));
}
vg_assert(has_nonempty_rx);
vg_assert(di->fsm.rw_map_count == 0 || has_nonempty_rw);
}
/* ----------------------------------------------------------
At this point, there is very little information in the
DebugInfo. We only know that something that looks like an ELF
file has been mapped rx-ishly and rw-ishly as recorded in the
di->fsm.maps array items. First we examine the file's ELF
Program Header, and, by comparing that against the di->fsm.maps
info, try to figure out the AVMAs for the sections we care
about, that should have been mapped: text, data, sdata, bss,
got, plt, and toc.
---------------------------------------------------------- */
if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir))
VG_(message)(Vg_DebugMsg, "Reading syms from %s\n",
di->fsm.filename );
/* Connect to the primary object image, so that we can read symbols
and line number info out of it. It will be disconnected
immediately thereafter; it is only connected transiently. */
mimg = ML_(img_from_local_file)(di->fsm.filename);
if (mimg == NULL) {
VG_(message)(Vg_UserMsg, "warning: connection to image %s failed\n",
di->fsm.filename );
VG_(message)(Vg_UserMsg, " no symbols or debug info loaded\n" );
return False;
}
/* Ok, the object image is available. Now verify that it is a
valid ELF .so or executable image. */
ok = is_elf_object_file_by_DiImage(mimg, False);
if (!ok) {
ML_(symerr)(di, True, "Invalid ELF Header");
goto out;
}
/* Find where the program and section header tables are, and give
up if either is missing or outside the image (bogus). */
ElfXX_Ehdr ehdr_m;
vg_assert(ehdr_mioff == 0); // ensured by its initialisation
ok = ML_(img_valid)(mimg, ehdr_mioff, sizeof(ehdr_m));
vg_assert(ok); // ML_(is_elf_object_file) should ensure this
ML_(img_get)(&ehdr_m, mimg, ehdr_mioff, sizeof(ehdr_m));
phdr_mioff = ehdr_mioff + ehdr_m.e_phoff;
phdr_mnent = ehdr_m.e_phnum;
phdr_ment_szB = ehdr_m.e_phentsize;
shdr_mioff = ehdr_mioff + ehdr_m.e_shoff;
shdr_mnent = ehdr_m.e_shnum;
shdr_ment_szB = ehdr_m.e_shentsize;
TRACE_SYMTAB("------ Basic facts about the object ------\n");
TRACE_SYMTAB("object: n_oimage %llu\n",
(ULong)ML_(img_size)(mimg));
TRACE_SYMTAB("phdr: ioff %llu nent %lu ent_szB %lu\n",
phdr_mioff, phdr_mnent, phdr_ment_szB);
TRACE_SYMTAB("shdr: ioff %llu nent %lu ent_szB %lu\n",
shdr_mioff, shdr_mnent, shdr_ment_szB);
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
if (map->rx)
TRACE_SYMTAB("rx_map: avma %#lx size %lu foff %lld\n",
map->avma, map->size, (Long)map->foff);
}
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
if (map->rw)
TRACE_SYMTAB("rw_map: avma %#lx size %lu foff %lld\n",
map->avma, map->size, (Long)map->foff);
}
if (phdr_mnent == 0
|| !ML_(img_valid)(mimg, phdr_mioff, phdr_mnent * phdr_ment_szB)) {
ML_(symerr)(di, True, "Missing or invalid ELF Program Header Table");
goto out;
}
if (shdr_mnent == 0
|| !ML_(img_valid)(mimg, shdr_mioff, shdr_mnent * shdr_ment_szB)) {
ML_(symerr)(di, True, "Missing or invalid ELF Section Header Table");
goto out;
}
/* Also find the section header's string table, and validate. */
/* checked previously by is_elf_object_file: */
vg_assert(ehdr_m.e_shstrndx != SHN_UNDEF);
// shdr_mioff is the offset of the section header table
// and we need the ehdr_m.e_shstrndx'th entry
{ ElfXX_Shdr a_shdr;
ML_(img_get)(&a_shdr, mimg,
INDEX_BIS(shdr_mioff, ehdr_m.e_shstrndx, shdr_ment_szB),
sizeof(a_shdr));
shdr_strtab_mioff
= ehdr_mioff /* isn't this always zero? */ + a_shdr.sh_offset;
if (!ML_(img_valid)(mimg, shdr_strtab_mioff,
1/*bogus, but we don't know the real size*/ )) {
ML_(symerr)(di, True, "Invalid ELF Section Header String Table");
goto out;
}
}
TRACE_SYMTAB("shdr: string table at %llu\n", shdr_strtab_mioff);
svma_ranges = VG_(newXA)(ML_(dinfo_zalloc), "di.relfdi.1",
ML_(dinfo_free), sizeof(RangeAndBias));
/* TOPLEVEL */
/* Look through the program header table, and:
- copy information from suitable PT_LOAD entries into svma_ranges
- find (or fake up) the .soname for this object.
*/
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ Examining the program headers ------\n");
vg_assert(di->soname == NULL);
{
/* TOPLEVEL */
ElfXX_Addr prev_svma = 0;
for (i = 0; i < phdr_mnent; i++) {
ElfXX_Phdr a_phdr;
ML_(img_get)(&a_phdr, mimg,
INDEX_BIS(phdr_mioff, i, phdr_ment_szB),
sizeof(a_phdr));
/* Make sure the PT_LOADable entries are in order and
non-overlapping. This in turn means the address ranges
slurped into svma_ranges are in order and
non-overlapping. */
if (a_phdr.p_type == PT_LOAD) {
TRACE_SYMTAB("PT_LOAD[%ld]: p_vaddr %#lx (prev %#lx)\n",
i, (UWord)a_phdr.p_vaddr, (UWord)prev_svma);
TRACE_SYMTAB("PT_LOAD[%ld]: p_offset %lu, p_filesz %lu,"
" perms %c%c%c\n",
i, (UWord)a_phdr.p_offset, (UWord)a_phdr.p_filesz,
a_phdr.p_flags & PF_R ? 'r' : '-',
a_phdr.p_flags & PF_W ? 'w' : '-',
a_phdr.p_flags & PF_X ? 'x' : '-');
if (a_phdr.p_vaddr < prev_svma) {
ML_(symerr)(di, True,
"ELF Program Headers are not in ascending order");
goto out;
}
prev_svma = a_phdr.p_vaddr;
if (a_phdr.p_memsz > 0) {
Bool loaded = False;
for (j = 0; j < VG_(sizeXA)(di->fsm.maps); j++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, j);
Bool offset_checks = a_phdr.p_offset >= map->foff
&& a_phdr.p_offset < map->foff + map->size
&& a_phdr.p_offset + a_phdr.p_filesz <= map->foff + map->size;
#if defined(VGO_freebsd)
/*
* One special case where we can't get an accurate value
* for the offset - the RW segment of the tool itself.
* See aspacemgr-linux.c parse_procselfmaps()
*/
if (map->ignore_foff) {
offset_checks = True;
}
#endif
if ( (map->rx || map->rw || map->ro)
&& map->size > 0 /* stay sane */
&& offset_checks) {
RangeAndBias item;
item.svma_base = a_phdr.p_vaddr;
item.svma_limit = a_phdr.p_vaddr + a_phdr.p_memsz;
item.bias = map->avma - map->foff
+ a_phdr.p_offset - a_phdr.p_vaddr;
if (map->rw
&& (a_phdr.p_flags & (PF_R | PF_W))
== (PF_R | PF_W)) {
item.exec = False;
VG_(addToXA)(svma_ranges, &item);
TRACE_SYMTAB(
"PT_LOAD[%ld]: acquired as rw, bias 0x%lx\n",
i, (UWord)item.bias);
loaded = True;
}
if (map->rx
&& (a_phdr.p_flags & (PF_R | PF_X))
== (PF_R | PF_X)) {
item.exec = True;
VG_(addToXA)(svma_ranges, &item);
TRACE_SYMTAB(
"PT_LOAD[%ld]: acquired as rx, bias 0x%lx\n",
i, (UWord)item.bias);
loaded = True;
}
if (map->ro
&& (a_phdr.p_flags & (PF_R | PF_W | PF_X))
== PF_R) {
item.exec = False;
VG_(addToXA)(svma_ranges, &item);
TRACE_SYMTAB(
"PT_LOAD[%ld]: acquired as ro, bias 0x%lx\n",
i, (UWord)item.bias);
loaded = True;
}
}
}
if (!loaded) {
# if defined(SOLARIS_PT_SUNDWTRACE_THRP)
if ((a_phdr.p_memsz == VKI_PT_SUNWDTRACE_SIZE)
&& ((a_phdr.p_flags & (PF_R | PF_W | PF_X)) == PF_R)) {
TRACE_SYMTAB("PT_LOAD[%ld]: ignore dtrace_data program "
"header\n", i);
dtrace_data_vaddr = a_phdr.p_vaddr;
continue;
}
# endif /* SOLARIS_PT_SUNDWTRACE_THRP */
ML_(symerr)(di, False,
"ELF section outside all mapped regions");
/* This problem might be solved by further memory mappings.
Avoid the vg_assert(!di->soname) at the beginning of this
function if DYNAMIC section has been already processed. */
if (di->soname) {
ML_(dinfo_free)(di->soname);
di->soname = NULL;
}
goto out;
}
}
}
/* Try to get the soname. If there isn't one, use "NONE".
The seginfo needs to have some kind of soname in order to
facilitate writing redirect functions, since all redirect
specifications require a soname (pattern). */
if (a_phdr.p_type == PT_DYNAMIC && di->soname == NULL) {
Word stroff = -1;
DiOffT strtab_mioff = DiOffT_INVALID;
for (j = 0; True/*exit check is in the loop*/; j++) {
ElfXX_Dyn t_dyn_m; /* dyn_img[j] */
ML_(img_get)(&t_dyn_m, mimg,
INDEX_BIS(ehdr_mioff + a_phdr.p_offset,
j, sizeof(ElfXX_Dyn)),
sizeof(t_dyn_m));
if (t_dyn_m.d_tag == DT_NULL)
break;
switch (t_dyn_m.d_tag) {
case DT_SONAME: {
stroff = t_dyn_m.d_un.d_val;
break;
}
case DT_STRTAB: {
Bool ok2 = False;
Word offset = file_offset_from_svma(
&ok2, t_dyn_m.d_un.d_ptr, mimg,
phdr_mioff, phdr_mnent, phdr_ment_szB
);
if (ok2 && strtab_mioff == DiOffT_INVALID) {
// Check for obviously bogus offsets.
if (!ML_(img_valid)(mimg, offset, 1)) {
ML_(symerr)(di, True, "Invalid DT_STRTAB offset");
goto out;
}
strtab_mioff = ehdr_mioff + offset;
vg_assert(ehdr_mioff == 0); // should always be
}
break;
}
default:
break;
}
}
if (stroff != -1 && strtab_mioff != DiOffT_INVALID) {
di->soname = ML_(img_strdup)(mimg, "di.redi.1",
strtab_mioff + stroff);
TRACE_SYMTAB("Found soname = %s\n", di->soname);
}
}
} /* for (i = 0; i < phdr_Mnent; i++) ... */
/* TOPLEVEL */
} /* examine the program headers (local scope) */
/* TOPLEVEL */
/* If, after looking at all the program headers, we still didn't
find a soname, add a fake one. */
if (di->soname == NULL) {
TRACE_SYMTAB("No soname found; using (fake) \"NONE\"\n");
di->soname = ML_(dinfo_strdup)("di.redi.2", "NONE");
}
vg_assert(VG_(sizeXA)(svma_ranges) != 0);
/* Now read the section table. */
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ Examining the section headers ------\n");
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
if (map->rx)
TRACE_SYMTAB("rx: at %#lx are mapped foffsets %lld .. %lld\n",
map->avma, (Long)map->foff, (Long)(map->foff + map->size - 1) );
}
TRACE_SYMTAB("rx: contains these svma regions:\n");
for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) {
const RangeAndBias* reg = VG_(indexXA)(svma_ranges, i);
if (reg->exec)
TRACE_SYMTAB(" svmas %#lx .. %#lx with bias %#lx\n",
reg->svma_base, reg->svma_limit - 1, (UWord)reg->bias );
}
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
if (map->rw) {
TRACE_SYMTAB("rw: at %#lx are mapped foffsets %lld .. %lld\n",
map->avma, (Long)map->foff, (Long)(map->foff + map->size - 1) );
}
}
TRACE_SYMTAB("rw: contains these svma regions:\n");
for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) {
const RangeAndBias* reg = VG_(indexXA)(svma_ranges, i);
if (!reg->exec)
TRACE_SYMTAB(" svmas %#lx .. %#lx with bias %#lx\n",
reg->svma_base, reg->svma_limit - 1, (UWord)reg->bias );
}
/* TOPLEVEL */
/* Iterate over section headers */
for (i = 0; i < shdr_mnent; i++) {
ElfXX_Shdr a_shdr;
ML_(img_get)(&a_shdr, mimg,
INDEX_BIS(shdr_mioff, i, shdr_ment_szB), sizeof(a_shdr));
DiOffT name_mioff = shdr_strtab_mioff + a_shdr.sh_name;
HChar* name = ML_(img_strdup)(mimg, "di.redi_name.2", name_mioff);
Addr svma = a_shdr.sh_addr;
OffT foff = a_shdr.sh_offset;
UWord size = a_shdr.sh_size; /* Do not change this to be signed. */
UInt alyn = a_shdr.sh_addralign;
Bool nobits = a_shdr.sh_type == SHT_NOBITS;
/* Look through our collection of info obtained from the PT_LOAD
headers, and make 'inrx' and 'inrw1' point to the first entry
in each that intersects 'avma'. If in each case none is found,
leave the relevant pointer at NULL. */
RangeAndBias* inrx = NULL;
RangeAndBias* inrw1 = NULL;
/* Depending on the link editor there may be two RW PT_LOAD headers
* If so this will point to the seond one */
RangeAndBias* inrw2 = NULL;
/* used to switch between inrw1 and inrw2 */
RangeAndBias* inrw;
for (j = 0; j < VG_(sizeXA)(svma_ranges); j++) {
RangeAndBias* rng = VG_(indexXA)(svma_ranges, j);
if (svma >= rng->svma_base && svma < rng->svma_limit) {
if (!inrx && rng->exec) {
inrx = rng;
} else if (!inrw1 && !rng->exec) {
inrw1 = rng;
} else if (!inrw2 && !rng->exec) {
inrw2 = rng;
}
}
}
TRACE_SYMTAB(" [sec %2ld] %s %s %s al%4u foff %6lld .. %6lld "
" svma %p name \"%s\"\n",
i, inrx ? "rx" : " ", inrw1 ? "rw" : " ", inrw2 ? "rw" : " ",
alyn, (Long) foff, (size == 0) ? (Long)foff : (Long)(foff+size-1),
(void *) svma, name);
/* Check for sane-sized segments. SHT_NOBITS sections have zero
size in the file and their offsets are just conceptual. */
if (!nobits &&
(foff >= ML_(img_size)(mimg) || foff + size > ML_(img_size)(mimg))) {
ML_(symerr)(di, True, "ELF Section extends beyond image end");
goto out;
}
/* Check for a sane alignment value. */
if (alyn > 0 && -1 == VG_(log2)(alyn)) {
ML_(symerr)(di, True, "ELF Section contains invalid "
".sh_addralign value");
goto out;
}
/* Ignore zero sized sections. */
if (size == 0) {
TRACE_SYMTAB("zero sized section \"%s\", ignoring\n", name);
ML_(dinfo_free)(name);
continue;
}
# define BAD(_secname) \
do { ML_(symerr)(di, True, \
"Can't make sense of " _secname \
" section mapping"); \
/* make sure we don't assert if we find */ \
/* ourselves back in this routine later, */ \
/* with the same di */ \
di->soname = NULL; \
goto out; \
} while (0)
/* Find avma-s for: .text .data .sdata .rodata .bss .sbss .plt .got .opd
and .eh_frame */
/* In inrw2 is non-NULL then it will be used for .data .got.plt .bss */
/* Accept .text where mapped as rx (code), even if zero-sized */
if (0 == VG_(strcmp)(name, ".text")) {
if (inrx && !di->text_present) {
di->text_present = True;
di->text_svma = svma;
di->text_avma = svma + inrx->bias;
di->text_size = size;
di->text_bias = inrx->bias;
di->text_debug_svma = svma;
di->text_debug_bias = inrx->bias;
TRACE_SYMTAB("acquiring .text svma = %#lx .. %#lx\n",
di->text_svma,
di->text_svma + di->text_size - 1);
TRACE_SYMTAB("acquiring .text avma = %#lx .. %#lx\n",
di->text_avma,
di->text_avma + di->text_size - 1);
TRACE_SYMTAB("acquiring .text bias = %#lx\n", (UWord)di->text_bias);
} else {
BAD(".text");
}
}
/* Accept .data where mapped as rw (data), even if zero-sized */
if (0 == VG_(strcmp)(name, ".data")) {
if (inrw2) {
inrw = inrw2;
} else {
inrw = inrw1;
}
# if defined(SOLARIS_PT_SUNDWTRACE_THRP)
if ((size == VKI_PT_SUNWDTRACE_SIZE) && (svma == dtrace_data_vaddr)) {
TRACE_SYMTAB("ignoring .data section for dtrace_data "
"%#lx .. %#lx\n", svma, svma + size - 1);
} else
# endif /* SOLARIS_PT_SUNDWTRACE_THRP */
if (inrw && !di->data_present) {
di->data_present = True;
di->data_svma = svma;
di->data_avma = svma + inrw->bias;
di->data_size = size;
di->data_bias = inrw->bias;
di->data_debug_svma = svma;
di->data_debug_bias = inrw->bias;
TRACE_SYMTAB("acquiring .data svma = %#lx .. %#lx\n",
di->data_svma,
di->data_svma + di->data_size - 1);
TRACE_SYMTAB("acquiring .data avma = %#lx .. %#lx\n",
di->data_avma,
di->data_avma + di->data_size - 1);
TRACE_SYMTAB("acquiring .data bias = %#lx\n", (UWord)di->data_bias);
} else {
BAD(".data");
}
}
/* Accept .sdata where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".sdata")) {
if (inrw1 && !di->sdata_present) {
di->sdata_present = True;
di->sdata_svma = svma;
di->sdata_avma = svma + inrw1->bias;
di->sdata_size = size;
di->sdata_bias = inrw1->bias;
di->sdata_debug_svma = svma;
di->sdata_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sdata svma = %#lx .. %#lx\n",
di->sdata_svma,
di->sdata_svma + di->sdata_size - 1);
TRACE_SYMTAB("acquiring .sdata avma = %#lx .. %#lx\n",
di->sdata_avma,
di->sdata_avma + di->sdata_size - 1);
TRACE_SYMTAB("acquiring .sdata bias = %#lx\n",
(UWord)di->sdata_bias);
} else {
BAD(".sdata");
}
}
/* Accept .rodata where mapped as rx or rw (data), even if zero-sized */
/* Also accept .rodata.<subr_name>, and aggregate adjacent after alignment. */
if (0 == VG_(strncmp)(name, ".rodata", 7)) {
if ((inrx||inrw1) && !di->rodata_present) { /* first .rodata* */
di->rodata_svma = svma;
di->rodata_avma = svma;
di->rodata_size = size;
di->rodata_debug_svma = svma;
} else if ((inrx||inrw1) && di->rodata_present) { /* not first .rodata* */
Addr tmp = VG_ROUNDUP(di->rodata_size + di->rodata_svma, alyn);
if (svma == tmp) { /* adjacent to previous .rodata* */
di->rodata_size = size + tmp - di->rodata_svma;
} else {
/* is OK, but we cannot handle multiple .rodata* */
TRACE_SYMTAB("%s section avma = %#lx .. %#lx is not contiguous, not merged\n",
name,
di->rodata_avma,
di->rodata_avma + di->rodata_size - 1);
goto out_rodata;
}
}
if (inrx) {
di->rodata_avma += inrx->bias;
di->rodata_bias = inrx->bias;
di->rodata_debug_bias = inrx->bias;
} else if (inrw1) {
di->rodata_avma += inrw1->bias;
di->rodata_bias = inrw1->bias;
di->rodata_debug_bias = inrw1->bias;
} else {
BAD(".rodata"); /* should not happen? */
}
di->rodata_present = True;
TRACE_SYMTAB("acquiring .rodata svma = %#lx .. %#lx\n",
di->rodata_svma,
di->rodata_svma + di->rodata_size - 1);
TRACE_SYMTAB("acquiring .rodata avma = %#lx .. %#lx\n",
di->rodata_avma,
di->rodata_avma + di->rodata_size - 1);
TRACE_SYMTAB("acquiring .rodata bias = %#lx\n",
(UWord)di->rodata_bias);
}
out_rodata:
if (0 == VG_(strcmp)(name, ".dynbss")) {
if (inrw1 && !di->bss_present) {
dynbss_present = True;
di->bss_present = True;
di->bss_svma = svma;
di->bss_avma = svma + inrw1->bias;
di->bss_size = size;
di->bss_bias = inrw1->bias;
di->bss_debug_svma = svma;
di->bss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .dynbss svma = %#lx .. %#lx\n",
di->bss_svma,
di->bss_svma + di->bss_size - 1);
TRACE_SYMTAB("acquiring .dynbss avma = %#lx .. %#lx\n",
di->bss_avma,
di->bss_avma + di->bss_size - 1);
TRACE_SYMTAB("acquiring .dynbss bias = %#lx\n",
(UWord)di->bss_bias);
}
}
/* Accept .bss where mapped as rw (data), even if zero-sized */
if (0 == VG_(strcmp)(name, ".bss")) {
if (inrw2) {
inrw = inrw2;
} else {
inrw = inrw1;
}
if (inrw && dynbss_present) {
vg_assert(di->bss_present);
dynbss_present = False;
vg_assert(di->bss_svma + di->bss_size == svma);
di->bss_size += size;
TRACE_SYMTAB("acquiring .bss svma = %#lx .. %#lx\n",
svma, svma + size - 1);
TRACE_SYMTAB("acquiring .bss avma = %#lx .. %#lx\n",
svma + inrw->bias, svma + inrw->bias + size - 1);
TRACE_SYMTAB("acquiring .bss bias = %#lx\n",
(UWord)di->bss_bias);
} else
if (inrw && !di->bss_present) {
di->bss_present = True;
di->bss_svma = svma;
di->bss_avma = svma + inrw->bias;
di->bss_size = size;
di->bss_bias = inrw->bias;
di->bss_debug_svma = svma;
di->bss_debug_bias = inrw->bias;
TRACE_SYMTAB("acquiring .bss svma = %#lx .. %#lx\n",
di->bss_svma,
di->bss_svma + di->bss_size - 1);
TRACE_SYMTAB("acquiring .bss avma = %#lx .. %#lx\n",
di->bss_avma,
di->bss_avma + di->bss_size - 1);
TRACE_SYMTAB("acquiring .bss bias = %#lx\n",
(UWord)di->bss_bias);
} else
/* Now one from the wtf?! department ... */
if (inrx && (!inrw) && !di->bss_present) {
/* File contains a .bss, but it got mapped as rx only.
This is very strange. For now, just pretend we didn't
see it :-) */
di->bss_present = False;
di->bss_svma = 0;
di->bss_avma = 0;
di->bss_size = 0;
di->bss_bias = 0;
di->bss_debug_svma = 0;
di->bss_debug_bias = 0;
if (!VG_(clo_xml)) {
VG_(message)(Vg_UserMsg,
"Warning: the following file's .bss is "
"mapped r-x only - ignoring .bss syms\n");
VG_(message)(Vg_UserMsg, " %s\n", di->fsm.filename
? di->fsm.filename
: "(null?!)" );
}
} else
if ((!inrw) && (!inrx) && !di->bss_present) {
/* File contains a .bss, but it didn't get mapped. Ignore. */
di->bss_present = False;
di->bss_svma = 0;
di->bss_avma = 0;
di->bss_size = 0;
di->bss_bias = 0;
} else {
BAD(".bss");
}
}
if (0 == VG_(strcmp)(name, ".sdynbss")) {
if (inrw1 && !di->sbss_present) {
sdynbss_present = True;
di->sbss_present = True;
di->sbss_svma = svma;
di->sbss_avma = svma + inrw1->bias;
di->sbss_size = size;
di->sbss_bias = inrw1->bias;
di->sbss_debug_svma = svma;
di->sbss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sdynbss svma = %#lx .. %#lx\n",
di->sbss_svma,
di->sbss_svma + di->sbss_size - 1);
TRACE_SYMTAB("acquiring .sdynbss avma = %#lx .. %#lx\n",
di->sbss_avma,
di->sbss_avma + di->sbss_size - 1);
TRACE_SYMTAB("acquiring .sdynbss bias = %#lx\n",
(UWord)di->sbss_bias);
}
}
/* Accept .sbss where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".sbss")) {
if (inrw1 && sdynbss_present) {
vg_assert(di->sbss_present);
sdynbss_present = False;
vg_assert(di->sbss_svma + di->sbss_size == svma);
di->sbss_size += size;
TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n",
svma, svma + size - 1);
TRACE_SYMTAB("acquiring .sbss avma = %#lx .. %#lx\n",
svma + inrw1->bias, svma + inrw1->bias + size - 1);
TRACE_SYMTAB("acquiring .sbss bias = %#lx\n", (UWord)di->sbss_bias);
} else
if (inrw1 && !di->sbss_present) {
di->sbss_present = True;
di->sbss_svma = svma;
di->sbss_avma = svma + inrw1->bias;
di->sbss_size = size;
di->sbss_bias = inrw1->bias;
di->sbss_debug_svma = svma;
di->sbss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n",
di->sbss_svma,
di->sbss_svma + di->sbss_size - 1);
TRACE_SYMTAB("acquiring .sbss avma = %#lx .. %#lx\n",
di->sbss_avma,
di->sbss_avma + di->sbss_size - 1);
TRACE_SYMTAB("acquiring .sbss bias = %#lx\n", (UWord)di->sbss_bias);
} else {
BAD(".sbss");
}
}
/* Accept .got where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".got")) {
if (inrw1 && !di->got_present) {
di->got_present = True;
di->got_avma = svma + inrw1->bias;
di->got_size = size;
TRACE_SYMTAB("acquiring .got avma = %#lx\n", di->got_avma);
} else {
BAD(".got");
}
}
/* Accept .got.plt where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".got.plt")) {
if (inrw2) {
inrw = inrw2;
} else {
inrw = inrw1;
}
if (inrw && !di->gotplt_present) {
di->gotplt_present = True;
di->gotplt_avma = svma + inrw->bias;
di->gotplt_size = size;
TRACE_SYMTAB("acquiring .got.plt avma = %#lx\n", di->gotplt_avma);
} else if (size != 0) {
BAD(".got.plt");
}
}
/* PLT is different on different platforms, it seems. */
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
|| defined(VGP_arm_linux) || defined (VGP_s390x_linux) \
|| defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
|| defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \
|| defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \
|| defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) \
|| defined(VGP_arm64_freebsd)
/* Accept .plt where mapped as rx (code) */
if (0 == VG_(strcmp)(name, ".plt")) {
if (inrx && !di->plt_present) {
di->plt_present = True;
di->plt_avma = svma + inrx->bias;
di->plt_size = size;
TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma);
} else {
BAD(".plt");
}
}
# elif defined(VGP_ppc32_linux)
/* Accept .plt where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".plt")) {
if (inrw1 && !di->plt_present) {
di->plt_present = True;
di->plt_avma = svma + inrw1->bias;
di->plt_size = size;
TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma);
} else {
BAD(".plt");
}
}
# elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
/* Accept .plt where mapped as rw (data), or unmapped */
if (0 == VG_(strcmp)(name, ".plt")) {
if (inrw1 && !di->plt_present) {
di->plt_present = True;
di->plt_avma = svma + inrw1->bias;
di->plt_size = size;
TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma);
} else
if ((!inrw1) && (!inrx) && size > 0 && !di->plt_present) {
/* File contains a .plt, but it didn't get mapped.
Presumably it is not required on this platform. At
least don't reject the situation as invalid. */
di->plt_present = True;
di->plt_avma = 0;
di->plt_size = 0;
} else {
BAD(".plt");
}
}
# else
# error "Unsupported platform"
# endif
/* Accept .opd where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".opd")) {
if (inrw1 && !di->opd_present) {
di->opd_present = True;
di->opd_avma = svma + inrw1->bias;
di->opd_size = size;
TRACE_SYMTAB("acquiring .opd avma = %#lx\n", di->opd_avma);
} else {
BAD(".opd");
}
}
/* Accept .eh_frame where mapped as rx (code). This seems to be
the common case. However, if that doesn't pan out, try for
rw (data) instead. We can handle up to N_EHFRAME_SECTS per
ELF object. */
if (0 == VG_(strcmp)(name, ".eh_frame")) {
if (inrx && di->n_ehframe < N_EHFRAME_SECTS) {
di->ehframe_avma[di->n_ehframe] = svma + inrx->bias;
di->ehframe_size[di->n_ehframe] = size;
TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n",
di->ehframe_avma[di->n_ehframe]);
di->n_ehframe++;
} else
if (inrw1 && di->n_ehframe < N_EHFRAME_SECTS) {
di->ehframe_avma[di->n_ehframe] = svma + inrw1->bias;
di->ehframe_size[di->n_ehframe] = size;
TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n",
di->ehframe_avma[di->n_ehframe]);
di->n_ehframe++;
} else {
BAD(".eh_frame");
}
}
/* Accept .ARM.exidx where mapped as rx (code). */
/* FIXME: make sure the entire section is mapped in, not just
the first address. */
if (0 == VG_(strcmp)(name, ".ARM.exidx")) {
if (inrx && !di->exidx_present) {
di->exidx_present = True;
di->exidx_svma = svma;
di->exidx_avma = svma + inrx->bias;
di->exidx_size = size;
di->exidx_bias = inrx->bias;
TRACE_SYMTAB("acquiring .exidx svma = %#lx .. %#lx\n",
di->exidx_svma,
di->exidx_svma + di->exidx_size - 1);
TRACE_SYMTAB("acquiring .exidx avma = %#lx .. %#lx\n",
di->exidx_avma,
di->exidx_avma + di->exidx_size - 1);
TRACE_SYMTAB("acquiring .exidx bias = %#lx\n",
(UWord)di->exidx_bias);
} else {
BAD(".ARM.exidx");
}
}
/* Accept .ARM.extab where mapped as rx (code). */
/* FIXME: make sure the entire section is mapped in, not just
the first address. */
if (0 == VG_(strcmp)(name, ".ARM.extab")) {
if (inrx && !di->extab_present) {
di->extab_present = True;
di->extab_svma = svma;
di->extab_avma = svma + inrx->bias;
di->extab_size = size;
di->extab_bias = inrx->bias;
TRACE_SYMTAB("acquiring .extab svma = %#lx .. %#lx\n",
di->extab_svma,
di->extab_svma + di->extab_size - 1);
TRACE_SYMTAB("acquiring .extab avma = %#lx .. %#lx\n",
di->extab_avma,
di->extab_avma + di->extab_size - 1);
TRACE_SYMTAB("acquiring .extab bias = %#lx\n",
(UWord)di->extab_bias);
} else {
BAD(".ARM.extab");
}
}
ML_(dinfo_free)(name);
# undef BAD
} /* iterate over the section headers */
/* TOPLEVEL */
if (0) VG_(printf)("YYYY text_: avma %#lx size %lu bias %#lx\n",
di->text_avma, di->text_size, (UWord)di->text_bias);
if (VG_(clo_verbosity) > 2 || VG_(clo_trace_redir))
VG_(message)(Vg_DebugMsg, " svma %#010lx, avma %#010lx\n",
di->text_avma - di->text_bias,
di->text_avma );
/* TOPLEVEL */
/* Find interesting sections, read the symbol table(s), read any
debug information. Each section is located either in the main,
debug or alt-debug files, but only in one. For each section,
|section_escn| records which of |mimg|, |dimg| or |aimg| we
found it in, along with the section's image offset and its size.
The triples (section_img, section_ioff, section_szB) are
consistent, in that they are always either (NULL,
DiOffT_INVALID, 0), or refer to the same image, and are all
assigned together. */
{
/* TOPLEVEL */
DiSlice strtab_escn = DiSlice_INVALID; // .strtab
DiSlice symtab_escn = DiSlice_INVALID; // .symtab
DiSlice dynstr_escn = DiSlice_INVALID; // .dynstr
DiSlice dynsym_escn = DiSlice_INVALID; // .dynsym
# if defined(VGO_solaris)
DiSlice ldynsym_escn = DiSlice_INVALID; // .SUNW_ldynsym
# endif
DiSlice opd_escn = DiSlice_INVALID; // .opd (dwarf2,
// ppc64be-linux)
DiSlice ehframe_escn[N_EHFRAME_SECTS]; // .eh_frame (dwarf2)
for (i = 0; i < N_EHFRAME_SECTS; i++)
ehframe_escn[i] = DiSlice_INVALID;
/* Find all interesting sections */
UInt ehframe_mix = 0;
/* What FIND does: it finds the section called _SEC_NAME. The
size of it is assigned to _SEC_SIZE. The address of the
section in the transiently loaded oimage is assigned to
_SEC_IMG. If the section is found, _POST_FX is executed
after _SEC_NAME and _SEC_SIZE have been assigned to.
Even for sections which are marked loadable, the client's
ld.so may not have loaded them yet, so there is no guarantee
that we can safely prod around in any such area). Because
the entire object file is transiently mapped aboard for
inspection, it's always safe to inspect that area. */
/* TOPLEVEL */
/* Iterate over section headers (again) */
for (i = 0; i < ehdr_m.e_shnum; i++) {
/* NAME ElfSec */
FIND_MIMG( ".dynsym", dynsym_escn)
FIND_MIMG( ".dynstr", dynstr_escn)
FIND_MIMG( ".symtab", symtab_escn)
FIND_MIMG( ".strtab", strtab_escn)
# if defined(VGO_solaris)
FIND_MIMG( ".SUNW_ldynsym", ldynsym_escn)
# endif
FIND_MIMG( ".opd", opd_escn)
FINDX_MIMG( ".eh_frame", ehframe_escn[ehframe_mix],
do { ehframe_mix++; vg_assert(ehframe_mix <= N_EHFRAME_SECTS);
} while (0)
)
/* Comment_on_EH_FRAME_MULTIPLE_INSTANCES: w.r.t. .eh_frame
multi-instance kludgery, how are we assured that the order
in which we fill in ehframe_escn[] is consistent with the
order in which we previously filled in di->ehframe_avma[]
and di->ehframe_size[] ? By the fact that in both cases,
these arrays were filled in by iterating over the section
headers top-to-bottom. So both loops (this one and the
previous one) encounter the .eh_frame entries in the same
order and so fill in these arrays in a consistent order.
*/
} /* Iterate over section headers (again) */
/* Check some sizes */
vg_assert((dynsym_escn.szB % sizeof(ElfXX_Sym)) == 0);
vg_assert((symtab_escn.szB % sizeof(ElfXX_Sym)) == 0);
# if defined(VGO_solaris)
vg_assert((ldynsym_escn.szB % sizeof(ElfXX_Sym)) == 0);
# endif
/* Read symbols */
{
void (*read_elf_symtab)(struct _DebugInfo*, const HChar*,
DiSlice*, DiSlice*, DiSlice*, Bool);
# if defined(VGP_ppc64be_linux)
read_elf_symtab = read_elf_symtab__ppc64be_linux;
# else
read_elf_symtab = read_elf_symtab__normal;
# endif
if (symtab_escn.img != NULL)
read_elf_symtab(di, "symbol table",
&symtab_escn, &strtab_escn, &opd_escn,
False);
read_elf_symtab(di, "dynamic symbol table",
&dynsym_escn, &dynstr_escn, &opd_escn,
False);
# if defined(VGO_solaris)
read_elf_symtab(di, "local dynamic symbol table",
&ldynsym_escn, &dynstr_escn, &opd_escn,
False);
# endif
}
/* TOPLEVEL */
/* Read .eh_frame and .debug_frame (call-frame-info) if any. Do
the .eh_frame section(s) first. */
/* i->n_ehframe is unsigned and cannot be negative */
vg_assert(di->n_ehframe <= N_EHFRAME_SECTS);
for (i = 0; i < di->n_ehframe; i++) {
/* see Comment_on_EH_FRAME_MULTIPLE_INSTANCES above for why
this next assertion should hold. */
vg_assert(ML_(sli_is_valid)(ehframe_escn[i]));
vg_assert(ehframe_escn[i].szB == di->ehframe_size[i]);
ML_(read_callframe_info_dwarf3)( di,
ehframe_escn[i],
di->ehframe_avma[i],
True/*is_ehframe*/ );
}
}
retval = True;
out:
/* Last, but not least, detach from the image. */
if (mimg) ML_(img_done)(mimg);
if (svma_ranges) VG_(deleteXA)(svma_ranges);
return retval;
}
static void find_rodata(Word i, Word shnum, DiImage* dimg, struct _DebugInfo* di, DiOffT shdr_dioff,
UWord shdr_dent_szB, DiOffT shdr_strtab_dioff, PtrdiffT rw_dbias)
{
ElfXX_Shdr a_shdr;
ElfXX_Shdr a_extra_shdr;
ML_(img_get)(&a_shdr, dimg,
INDEX_BIS(shdr_dioff, i, shdr_dent_szB),
sizeof(a_shdr));
if (di->rodata_present &&
0 == ML_(img_strcmp_c)(dimg, shdr_strtab_dioff
+ a_shdr.sh_name, ".rodata")) {
Word sh_size = a_shdr.sh_size;
Word j;
Word next_addr = a_shdr.sh_addr + a_shdr.sh_size;
for (j = i + 1; j < shnum; ++j) {
ML_(img_get)(&a_extra_shdr, dimg,
INDEX_BIS(shdr_dioff, j, shdr_dent_szB),
sizeof(a_shdr));
if (0 == ML_(img_strcmp_n)(dimg, shdr_strtab_dioff
+ a_extra_shdr.sh_name, ".rodata", 7)) {
if (a_extra_shdr.sh_addr ==
VG_ROUNDUP(next_addr, a_extra_shdr.sh_addralign)) {
sh_size = VG_ROUNDUP(sh_size, a_extra_shdr.sh_addralign) + a_extra_shdr.sh_size;
}
next_addr = a_extra_shdr.sh_addr + a_extra_shdr.sh_size;
} else {
break;
}
}
vg_assert(di->rodata_size == sh_size);
vg_assert(di->rodata_avma + a_shdr.sh_addr + rw_dbias);
di->rodata_debug_svma = a_shdr.sh_addr;
di->rodata_debug_bias = di->rodata_bias +
di->rodata_svma - di->rodata_debug_svma;
TRACE_SYMTAB("acquiring .rodata debug svma = %#lx .. %#lx\n",
di->rodata_debug_svma,
di->rodata_debug_svma + di->rodata_size - 1);
TRACE_SYMTAB("acquiring .rodata debug bias = %#lx\n", (UWord)di->rodata_debug_bias);
}
}
Bool ML_(read_elf_debug) ( struct _DebugInfo* di )
{
Word i, j;
Bool res = True;
Bool ok;
/* Image for the main ELF file we're working with. */
DiImage* mimg = NULL;
/* Ditto for any ELF debuginfo file that we might happen to load. */
DiImage* dimg = NULL;
/* Ditto for alternate ELF debuginfo file that we might happen to load. */
DiImage* aimg = NULL;
/* Section header image addr, # entries, entry size. Also the
associated string table. */
DiOffT shdr_mioff = 0;
UWord shdr_mnent = 0;
UWord shdr_ment_szB = 0;
DiOffT shdr_strtab_mioff = 0;
DiOffT ehdr_mioff = 0;
/* Connect to the primary object image, so that we can read symbols
and line number info out of it. It will be disconnected
immediately thereafter; it is only connected transiently. */
mimg = ML_(img_from_local_file)(di->fsm.filename);
if (mimg == NULL) {
VG_(message)(Vg_UserMsg, "warning: connection to image %s failed\n",
di->fsm.filename );
VG_(message)(Vg_UserMsg, " no debug info loaded\n" );
return False;
}
/* Ok, the object image is available. Now verify that it is a
valid ELF .so or executable image. */
ok = is_elf_object_file_by_DiImage(mimg, False);
if (!ok) {
ML_(symerr)(di, True, "Invalid ELF Header");
goto out;
}
/* Find where the program and section header tables are, and give
up if either is missing or outside the image (bogus). */
ElfXX_Ehdr ehdr_m;
vg_assert(ehdr_mioff == 0); // ensured by its initialisation
ok = ML_(img_valid)(mimg, ehdr_mioff, sizeof(ehdr_m));
vg_assert(ok); // ML_(is_elf_object_file) should ensure this
ML_(img_get)(&ehdr_m, mimg, ehdr_mioff, sizeof(ehdr_m));
shdr_mioff = ehdr_mioff + ehdr_m.e_shoff;
shdr_mnent = ehdr_m.e_shnum;
shdr_ment_szB = ehdr_m.e_shentsize;
if (shdr_mnent == 0
|| !ML_(img_valid)(mimg, shdr_mioff, shdr_mnent * shdr_ment_szB)) {
ML_(symerr)(di, True, "Missing or invalid ELF Section Header Table");
goto out;
}
/* Also find the section header's string table, and validate. */
/* checked previously by is_elf_object_file: */
vg_assert(ehdr_m.e_shstrndx != SHN_UNDEF);
// shdr_mioff is the offset of the section header table
// and we need the ehdr_m.e_shstrndx'th entry
{ ElfXX_Shdr a_shdr;
ML_(img_get)(&a_shdr, mimg,
INDEX_BIS(shdr_mioff, ehdr_m.e_shstrndx, shdr_ment_szB),
sizeof(a_shdr));
shdr_strtab_mioff
= ehdr_mioff /* isn't this always zero? */ + a_shdr.sh_offset;
if (!ML_(img_valid)(mimg, shdr_strtab_mioff,
1/*bogus, but we don't know the real size*/ )) {
ML_(symerr)(di, True, "Invalid ELF Section Header String Table");
goto out;
}
}
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ Finding image addresses "
"for debug-info sections ------\n");
/* TOPLEVEL */
/* Find interesting sections, read the symbol table(s), read any
debug information. Each section is located either in the main,
debug or alt-debug files, but only in one. For each section,
|section_escn| records which of |mimg|, |dimg| or |aimg| we
found it in, along with the section's image offset and its size.
The triples (section_img, section_ioff, section_szB) are
consistent, in that they are always either (NULL,
DiOffT_INVALID, 0), or refer to the same image, and are all
assigned together. */
{
/* TOPLEVEL */
DiSlice strtab_escn = DiSlice_INVALID; // .strtab
DiSlice symtab_escn = DiSlice_INVALID; // .symtab
DiSlice debuglink_escn = DiSlice_INVALID; // .gnu_debuglink
DiSlice debugaltlink_escn = DiSlice_INVALID; // .gnu_debugaltlink
DiSlice debug_line_escn = DiSlice_INVALID; // .debug_line (dwarf2)
DiSlice debug_info_escn = DiSlice_INVALID; // .debug_info (dwarf2)
DiSlice debug_types_escn = DiSlice_INVALID; // .debug_types (dwarf4)
DiSlice debug_abbv_escn = DiSlice_INVALID; // .debug_abbrev (dwarf2)
DiSlice debug_str_escn = DiSlice_INVALID; // .debug_str (dwarf2)
DiSlice debug_line_str_escn = DiSlice_INVALID; // .debug_line_str(dwarf5)
DiSlice debug_ranges_escn = DiSlice_INVALID; // .debug_ranges (dwarf2)
DiSlice debug_rnglists_escn = DiSlice_INVALID; // .debug_rnglists(dwarf5)
DiSlice debug_loclists_escn = DiSlice_INVALID; // .debug_loclists(dwarf5)
DiSlice debug_addr_escn = DiSlice_INVALID; // .debug_addr (dwarf5)
DiSlice debug_str_offsets_escn = DiSlice_INVALID; // .debug_str_offsets (dwarf5)
DiSlice debug_loc_escn = DiSlice_INVALID; // .debug_loc (dwarf2)
DiSlice debug_frame_escn = DiSlice_INVALID; // .debug_frame (dwarf2)
DiSlice debug_line_alt_escn = DiSlice_INVALID; // .debug_line (alt)
DiSlice debug_info_alt_escn = DiSlice_INVALID; // .debug_info (alt)
DiSlice debug_abbv_alt_escn = DiSlice_INVALID; // .debug_abbrev (alt)
DiSlice debug_str_alt_escn = DiSlice_INVALID; // .debug_str (alt)
DiSlice dwarf1d_escn = DiSlice_INVALID; // .debug (dwarf1)
DiSlice dwarf1l_escn = DiSlice_INVALID; // .line (dwarf1)
DiSlice opd_escn = DiSlice_INVALID; // .opd (dwarf2,
// ppc64be-linux)
/* TOPLEVEL */
/* Iterate over section headers (again) */
for (i = 0; i < ehdr_m.e_shnum; i++) {
/* NAME ElfSec */
FIND_MIMG( ".symtab", symtab_escn)
FIND_MIMG( ".strtab", strtab_escn)
FIND_MIMG( ".gnu_debuglink", debuglink_escn)
FIND_MIMG( ".gnu_debugaltlink", debugaltlink_escn)
FIND_MIMG( ".debug_line", debug_line_escn)
if (!ML_(sli_is_valid)(debug_line_escn))
FIND_MIMG(".zdebug_line", debug_line_escn)
FIND_MIMG( ".debug_info", debug_info_escn)
if (!ML_(sli_is_valid)(debug_info_escn))
FIND_MIMG(".zdebug_info", debug_info_escn)
FIND_MIMG( ".debug_types", debug_types_escn)
if (!ML_(sli_is_valid)(debug_types_escn))
FIND_MIMG(".zdebug_types", debug_types_escn)
FIND_MIMG( ".debug_abbrev", debug_abbv_escn)
if (!ML_(sli_is_valid)(debug_abbv_escn))
FIND_MIMG(".zdebug_abbrev", debug_abbv_escn)
FIND_MIMG( ".debug_str", debug_str_escn)
if (!ML_(sli_is_valid)(debug_str_escn))
FIND_MIMG(".zdebug_str", debug_str_escn)
FIND_MIMG( ".debug_line_str", debug_line_str_escn)
if (!ML_(sli_is_valid)(debug_line_str_escn))
FIND_MIMG(".zdebug_str", debug_line_str_escn)
FIND_MIMG( ".debug_ranges", debug_ranges_escn)
if (!ML_(sli_is_valid)(debug_ranges_escn))
FIND_MIMG(".zdebug_ranges", debug_ranges_escn)
FIND_MIMG( ".debug_rnglists", debug_rnglists_escn)
if (!ML_(sli_is_valid)(debug_rnglists_escn))
FIND_MIMG(".zdebug_rnglists", debug_rnglists_escn)
FIND_MIMG( ".debug_loclists", debug_loclists_escn)
if (!ML_(sli_is_valid)(debug_loclists_escn))
FIND_MIMG(".zdebug_loclists", debug_loclists_escn)
FIND_MIMG( ".debug_loc", debug_loc_escn)
if (!ML_(sli_is_valid)(debug_loc_escn))
FIND_MIMG(".zdebug_loc", debug_loc_escn)
FIND_MIMG( ".debug_frame", debug_frame_escn)
if (!ML_(sli_is_valid)(debug_frame_escn))
FIND_MIMG(".zdebug_frame", debug_frame_escn)
FIND_MIMG( ".debug_addr", debug_addr_escn)
if (!ML_(sli_is_valid)(debug_addr_escn))
FIND_MIMG(".zdebug_addr", debug_addr_escn)
FIND_MIMG( ".debug_str_offsets", debug_str_offsets_escn)
if (!ML_(sli_is_valid)(debug_str_offsets_escn))
FIND_MIMG(".zdebug_str_offsets", debug_str_offsets_escn)
FIND_MIMG( ".debug", dwarf1d_escn)
FIND_MIMG( ".line", dwarf1l_escn)
FIND_MIMG( ".opd", opd_escn)
/* Comment_on_EH_FRAME_MULTIPLE_INSTANCES: w.r.t. .eh_frame
multi-instance kludgery, how are we assured that the order
in which we fill in ehframe_escn[] is consistent with the
order in which we previously filled in di->ehframe_avma[]
and di->ehframe_size[] ? By the fact that in both cases,
these arrays were filled in by iterating over the section
headers top-to-bottom. So both loops (this one and the
previous one) encounter the .eh_frame entries in the same
order and so fill in these arrays in a consistent order.
*/
} /* Iterate over section headers (again) */
/* TOPLEVEL */
/* Now, see if we can find a debuginfo object, and if so connect
|dimg| to it. */
vg_assert(dimg == NULL && aimg == NULL);
#if defined(VGO_freebsd)
/* */
read_and_set_osrel(mimg);
#endif
/* Look for a build-id */
HChar* buildid = find_buildid(mimg, False, False);
/* If we don't have a .debug_info section in the main image then
look for a debug image that matches either the build-id or
the debuglink-CRC32 in the main image. If the main image
doesn't contain either of those then this won't even bother
to try looking. This looks in all known places, including
the --extra-debuginfo-path if specified and on the
--debuginfo-server if specified. */
if (debug_info_escn.img == NULL &&
(buildid != NULL || debuglink_escn.img != NULL)) {
/* Do have a debuglink section? */
if (debuglink_escn.img != NULL) {
UInt crc_offset
= VG_ROUNDUP(ML_(img_strlen)(debuglink_escn.img,
debuglink_escn.ioff)+1, 4);
vg_assert(crc_offset + sizeof(UInt) <= debuglink_escn.szB);
/* Extract the CRC from the debuglink section */
UInt crc = ML_(img_get_UInt)(debuglink_escn.img,
debuglink_escn.ioff + crc_offset);
/* See if we can find a matching debug file */
HChar* debuglink_str_m
= ML_(img_strdup)(debuglink_escn.img,
"di.redi_dlk.1", debuglink_escn.ioff);
dimg = find_debug_file( di, di->fsm.filename, buildid,
debuglink_str_m, crc, False );
if (debuglink_str_m)
ML_(dinfo_free)(debuglink_str_m);
} else {
/* See if we can find a matching debug file */
dimg = find_debug_file( di, di->fsm.filename, buildid,
NULL, 0, False );
}
}
if (buildid) {
ML_(dinfo_free)(buildid);
buildid = NULL; /* paranoia */
}
/* As a last-ditch measure, try looking for in the
--extra-debuginfo-path and/or on the --debuginfo-server, but
only in the case where --allow-mismatched-debuginfo=yes.
This is dangerous in that (1) it gives no assurance that the
debuginfo object matches the main one, and hence (2) we will
very likely get an assertion in the code below, if indeed
there is a mismatch. Hence it is disabled by default
(--allow-mismatched-debuginfo=no). Nevertheless it's
sometimes a useful way of getting out of a tight spot.
Note that we're ignoring the name in the .gnu_debuglink
section here, and just looking for a file of the same name
either the extra-path or on the server. */
if (dimg == NULL && VG_(clo_allow_mismatched_debuginfo)) {
dimg = find_debug_file_ad_hoc( di, di->fsm.filename );
}
/* TOPLEVEL */
/* If we were successful in finding a debug image, pull various
SVMA/bias/size and image addresses out of it. */
if (dimg != NULL && is_elf_object_file_by_DiImage(dimg, False)) {
/* Pull out and validate program header and section header info */
DiOffT ehdr_dioff = 0;
ElfXX_Ehdr ehdr_dimg;
ML_(img_get)(&ehdr_dimg, dimg, ehdr_dioff, sizeof(ehdr_dimg));
DiOffT phdr_dioff = ehdr_dimg.e_phoff;
UWord phdr_dnent = ehdr_dimg.e_phnum;
UWord phdr_dent_szB = ehdr_dimg.e_phentsize;
DiOffT shdr_dioff = ehdr_dimg.e_shoff;
UWord shdr_dnent = ehdr_dimg.e_shnum;
UWord shdr_dent_szB = ehdr_dimg.e_shentsize;
DiOffT shdr_strtab_dioff = DiOffT_INVALID;
/* SVMAs covered by rx and rw segments and corresponding bias. */
Addr rx_dsvma_limit = 0;
PtrdiffT rx_dbias = 0;
Addr rw_dsvma_limit = 0;
PtrdiffT rw_dbias = 0;
Bool need_symtab, need_dwarf2, need_dwarf1;
if (phdr_dnent == 0
|| !ML_(img_valid)(dimg, phdr_dioff,
phdr_dnent * phdr_dent_szB)) {
ML_(symerr)(di, True,
"Missing or invalid ELF Program Header Table"
" (debuginfo file)");
goto out;
}
if (shdr_dnent == 0
|| !ML_(img_valid)(dimg, shdr_dioff,
shdr_dnent * shdr_dent_szB)) {
ML_(symerr)(di, True,
"Missing or invalid ELF Section Header Table"
" (debuginfo file)");
goto out;
}
/* Also find the section header's string table, and validate. */
/* checked previously by is_elf_object_file: */
vg_assert(ehdr_dimg.e_shstrndx != SHN_UNDEF);
// shdr_dioff is the offset of the section header table
// and we need the ehdr_dimg.e_shstrndx'th entry
{ ElfXX_Shdr a_shdr;
ML_(img_get)(&a_shdr, dimg,
INDEX_BIS(shdr_dioff, ehdr_dimg.e_shstrndx,
shdr_dent_szB),
sizeof(a_shdr));
shdr_strtab_dioff = a_shdr.sh_offset;
if (!ML_(img_valid)(dimg, shdr_strtab_dioff,
1/*bogus, but we don't know the real size*/)) {
ML_(symerr)(di, True,
"Invalid ELF Section Header String Table"
" (debuginfo file)");
goto out;
}
}
for (i = 0; i < ehdr_dimg.e_phnum; i++) {
ElfXX_Phdr a_phdr;
ML_(img_get)(&a_phdr, dimg, INDEX_BIS(ehdr_dimg.e_phoff,
i, phdr_dent_szB),
sizeof(a_phdr));
if (a_phdr.p_type == PT_LOAD) {
for (j = 0; j < VG_(sizeXA)(di->fsm.maps); j++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, j);
if ( a_phdr.p_offset >= map->foff
&& a_phdr.p_offset < map->foff + map->size
&& a_phdr.p_offset + a_phdr.p_filesz
< map->foff + map->size) {
if (map->rx && rx_dsvma_limit == 0) {
rx_dsvma_limit = a_phdr.p_vaddr + a_phdr.p_memsz;
rx_dbias = map->avma - map->foff + a_phdr.p_offset
- a_phdr.p_vaddr;
}
if (map->rw && rw_dsvma_limit == 0) {
rw_dsvma_limit = a_phdr.p_vaddr + a_phdr.p_memsz;
rw_dbias = map->avma - map->foff + a_phdr.p_offset
- a_phdr.p_vaddr;
}
break;
}
}
}
}
need_symtab = (symtab_escn.img == NULL);
need_dwarf2 = (debug_info_escn.img == NULL);
need_dwarf1 = (dwarf1d_escn.img == NULL);
/* Find all interesting sections in the debug image */
for (i = 0; i < ehdr_dimg.e_shnum; i++) {
/* Find debug svma and bias information for sections
we found in the main file. */
# define FIND(_sec, _seg) \
do { \
ElfXX_Shdr a_shdr; \
ML_(img_get)(&a_shdr, dimg, \
INDEX_BIS(shdr_dioff, i, shdr_dent_szB), \
sizeof(a_shdr)); \
if (di->_sec##_present \
&& 0 == ML_(img_strcmp_c)(dimg, shdr_strtab_dioff \
+ a_shdr.sh_name, "." #_sec)) { \
vg_assert(di->_sec##_size == a_shdr.sh_size); \
/* JRS 2013-Jun-01: the following assert doesn't contain */ \
/* any ==s, which seems to me to be suspicious. */ \
vg_assert(di->_sec##_avma + a_shdr.sh_addr + _seg##_dbias); \
/* Assume we have a correct value for the main */ \
/* object's bias. Use that to derive the debuginfo */ \
/* object's bias, by adding the difference in SVMAs */ \
/* for the corresponding sections in the two files. */ \
/* That should take care of all prelinking effects. */ \
di->_sec##_debug_svma = a_shdr.sh_addr; \
di->_sec##_debug_bias \
= di->_sec##_bias + \
di->_sec##_svma - di->_sec##_debug_svma; \
TRACE_SYMTAB("acquiring ." #_sec \
" debug svma = %#lx .. %#lx\n", \
di->_sec##_debug_svma, \
di->_sec##_debug_svma + di->_sec##_size - 1); \
TRACE_SYMTAB("acquiring ." #_sec " debug bias = %#lx\n", \
(UWord)di->_sec##_debug_bias); \
} \
} while (0);
/* SECTION SEGMENT */
FIND(text, rx)
FIND(data, rw)
FIND(sdata, rw)
// https://bugs.kde.org/show_bug.cgi?id=476548
// special handling for rodata as adjacent
// rodata sections may have been merged in ML_(read_elf_object)
//FIND(rodata, rw)
find_rodata(i, ehdr_dimg.e_shnum, dimg, di, shdr_dioff, shdr_dent_szB, shdr_strtab_dioff, rw_dbias);
FIND(bss, rw)
FIND(sbss, rw)
# undef FIND
/* Same deal as previous FIND, except only do it for those
sections which we didn't find in the main file. */
# define FIND(_condition, _sec_name, _sec_escn) \
do { \
ElfXX_Shdr a_shdr; \
ML_(img_get)(&a_shdr, dimg, \
INDEX_BIS(shdr_dioff, i, shdr_dent_szB), \
sizeof(a_shdr)); \
if (_condition \
&& 0 == ML_(img_strcmp_c)(dimg, shdr_strtab_dioff \
+ a_shdr.sh_name, _sec_name)) { \
Bool nobits; \
if (_sec_escn.img != NULL) { \
ML_(symerr)(di, True, \
" debuginfo section duplicates a" \
" section in the main ELF file"); \
goto out; \
} \
_sec_escn.img = dimg; \
_sec_escn.ioff = (DiOffT)a_shdr.sh_offset; \
_sec_escn.szB = a_shdr.sh_size; \
if (!check_compression(&a_shdr, &_sec_escn)) { \
ML_(symerr)(di, True, " Compression type is unsupported"); \
goto out; \
} \
nobits = a_shdr.sh_type == SHT_NOBITS; \
vg_assert(_sec_escn.img != NULL); \
vg_assert(_sec_escn.ioff != DiOffT_INVALID); \
TRACE_SYMTAB( "%-18s: dioff %llu .. %llu\n", \
_sec_name, \
(ULong)a_shdr.sh_offset, \
((ULong)a_shdr.sh_offset) + a_shdr.sh_size - 1); \
/* SHT_NOBITS sections have zero size in the file. */ \
if (!nobits && a_shdr.sh_offset \
+ a_shdr.sh_size > ML_(img_real_size)(_sec_escn.img)) { \
ML_(symerr)(di, True, \
" section beyond image end?!"); \
goto out; \
} \
} \
} while (0);
/* NEEDED? NAME ElfSec */
FIND( need_symtab, ".symtab", symtab_escn)
FIND( need_symtab, ".strtab", strtab_escn)
FIND( need_dwarf2, ".debug_line", debug_line_escn)
if (!ML_(sli_is_valid)(debug_line_escn))
FIND(need_dwarf2, ".zdebug_line", debug_line_escn)
FIND( need_dwarf2, ".debug_info", debug_info_escn)
if (!ML_(sli_is_valid)(debug_info_escn))
FIND(need_dwarf2, ".zdebug_info", debug_info_escn)
FIND( need_dwarf2, ".debug_types", debug_types_escn)
if (!ML_(sli_is_valid)(debug_types_escn))
FIND(need_dwarf2, ".zdebug_types", debug_types_escn)
FIND( need_dwarf2, ".debug_abbrev", debug_abbv_escn)
if (!ML_(sli_is_valid)(debug_abbv_escn))
FIND(need_dwarf2, ".zdebug_abbrev", debug_abbv_escn)
FIND( need_dwarf2, ".debug_str", debug_str_escn)
if (!ML_(sli_is_valid)(debug_str_escn))
FIND(need_dwarf2, ".zdebug_str", debug_str_escn)
FIND( need_dwarf2, ".debug_line_str", debug_line_str_escn)
if (!ML_(sli_is_valid)(debug_line_str_escn))
FIND(need_dwarf2, ".zdebug_line_str", debug_line_str_escn)
FIND( need_dwarf2, ".debug_ranges", debug_ranges_escn)
if (!ML_(sli_is_valid)(debug_ranges_escn))
FIND(need_dwarf2, ".zdebug_ranges", debug_ranges_escn)
FIND( need_dwarf2, ".debug_rnglists", debug_rnglists_escn)
if (!ML_(sli_is_valid)(debug_rnglists_escn))
FIND(need_dwarf2, ".zdebug_rnglists", debug_rnglists_escn)
FIND( need_dwarf2, ".debug_loclists", debug_loclists_escn)
if (!ML_(sli_is_valid)(debug_loclists_escn))
FIND(need_dwarf2, ".zdebug_loclists", debug_loclists_escn)
FIND( need_dwarf2, ".debug_loc", debug_loc_escn)
if (!ML_(sli_is_valid)(debug_loc_escn))
FIND(need_dwarf2, ".zdebug_loc", debug_loc_escn)
FIND( need_dwarf2, ".debug_frame", debug_frame_escn)
if (!ML_(sli_is_valid)(debug_frame_escn))
FIND(need_dwarf2, ".zdebug_frame", debug_frame_escn)
FIND( need_dwarf2, ".debug_addr", debug_addr_escn)
if (!ML_(sli_is_valid)(debug_addr_escn))
FIND(need_dwarf2, ".zdebug_addr", debug_addr_escn)
FIND( need_dwarf2, ".debug_str_offsets", debug_str_offsets_escn)
if (!ML_(sli_is_valid)(debug_str_offsets_escn))
FIND(need_dwarf2, ".zdebug_str_offsets", debug_str_offsets_escn)
if (!ML_(sli_is_valid)(debugaltlink_escn))
FIND( need_dwarf2, ".gnu_debugaltlink", debugaltlink_escn)
FIND( need_dwarf1, ".debug", dwarf1d_escn)
FIND( need_dwarf1, ".line", dwarf1l_escn)
# undef FIND
} /* Find all interesting sections */
} /* do we have a debug image? */
/* TOPLEVEL */
/* Look for alternate debug image, and if found, connect |aimg|
to it. */
vg_assert(aimg == NULL);
if (debugaltlink_escn.img != NULL) {
HChar* altfile_str_m
= ML_(img_strdup)(debugaltlink_escn.img,
"di.fbi.3", debugaltlink_escn.ioff);
UInt buildid_offset = ML_(img_strlen)(debugaltlink_escn.img,
debugaltlink_escn.ioff)+1;
vg_assert(buildid_offset < debugaltlink_escn.szB);
HChar *altbuildid
= ML_(dinfo_zalloc)("di.fbi.4",
(debugaltlink_escn.szB - buildid_offset)
* 2 + 1);
/* The altfile might be relative to the debug file or main file.
Make sure that we got the real file, not a symlink. */
HChar *dbgname = di->fsm.dbgname ? di->fsm.dbgname : di->fsm.filename;
HChar* rdbgname = readlink_path (dbgname);
if (rdbgname == NULL)
rdbgname = ML_(dinfo_strdup)("rdbgname", dbgname);
for (j = 0; j < debugaltlink_escn.szB - buildid_offset; j++)
VG_(sprintf)(
altbuildid + 2 * j, "%02x",
(UInt)ML_(img_get_UChar)(debugaltlink_escn.img,
debugaltlink_escn.ioff
+ buildid_offset + j));
/* See if we can find a matching debug file */
aimg = find_debug_file( di, rdbgname, altbuildid,
altfile_str_m, 0, True );
ML_(dinfo_free)(rdbgname);
if (altfile_str_m)
ML_(dinfo_free)(altfile_str_m);
ML_(dinfo_free)(altbuildid);
}
/* TOPLEVEL */
/* If we were successful in finding alternate debug image, pull various
size and image addresses out of it. */
if (aimg != NULL && is_elf_object_file_by_DiImage(aimg, True)) {
/* Pull out and validate program header and section header info */
DiOffT ehdr_aioff = 0;
ElfXX_Ehdr ehdr_aimg;
ML_(img_get)(&ehdr_aimg, aimg, ehdr_aioff, sizeof(ehdr_aimg));
DiOffT shdr_aioff = ehdr_aimg.e_shoff;
UWord shdr_anent = ehdr_aimg.e_shnum;
UWord shdr_aent_szB = ehdr_aimg.e_shentsize;
DiOffT shdr_strtab_aioff = DiOffT_INVALID;
if (shdr_anent == 0
|| !ML_(img_valid)(aimg, shdr_aioff,
shdr_anent * shdr_aent_szB)) {
ML_(symerr)(di, True,
"Missing or invalid ELF Section Header Table"
" (alternate debuginfo file)");
goto out;
}
/* Also find the section header's string table, and validate. */
/* checked previously by is_elf_object_file: */
vg_assert(ehdr_aimg.e_shstrndx != SHN_UNDEF);
// shdr_aioff is the offset of the section header table
// and we need the ehdr_aimg.e_shstrndx'th entry
{ ElfXX_Shdr a_shdr;
ML_(img_get)(&a_shdr, aimg,
INDEX_BIS(shdr_aioff, ehdr_aimg.e_shstrndx,
shdr_aent_szB),
sizeof(a_shdr));
shdr_strtab_aioff = a_shdr.sh_offset;
if (!ML_(img_valid)(aimg, shdr_strtab_aioff,
1/*bogus, but we don't know the real size*/)) {
ML_(symerr)(di, True,
"Invalid ELF Section Header String Table"
" (alternate debuginfo file)");
goto out;
}
}
/* Find all interesting sections */
for (i = 0; i < ehdr_aimg.e_shnum; i++) {
# define FIND(_sec_name, _sec_escn) \
do { \
ElfXX_Shdr a_shdr; \
ML_(img_get)(&a_shdr, aimg, \
INDEX_BIS(shdr_aioff, i, shdr_aent_szB), \
sizeof(a_shdr)); \
if (0 == ML_(img_strcmp_c)(aimg, shdr_strtab_aioff \
+ a_shdr.sh_name, _sec_name)) { \
if (_sec_escn.img != NULL) { \
ML_(symerr)(di, True, \
" alternate debuginfo section duplicates a" \
" section in the main ELF file"); \
goto out; \
} \
_sec_escn.img = aimg; \
_sec_escn.ioff = (DiOffT)a_shdr.sh_offset; \
_sec_escn.szB = a_shdr.sh_size; \
if (!check_compression(&a_shdr, &_sec_escn)) { \
ML_(symerr)(di, True, " Compression type is " \
"unsupported"); \
goto out; \
} \
vg_assert(_sec_escn.img != NULL); \
vg_assert(_sec_escn.ioff != DiOffT_INVALID); \
TRACE_SYMTAB( "%-18s: aioff %llu .. %llu\n", \
_sec_name, \
(ULong)a_shdr.sh_offset, \
((ULong)a_shdr.sh_offset) + a_shdr.sh_size - 1); \
} \
} while (0);
/* NAME ElfSec */
FIND(".debug_line", debug_line_alt_escn)
if (!ML_(sli_is_valid)(debug_line_alt_escn))
FIND(".zdebug_line", debug_line_alt_escn)
FIND(".debug_info", debug_info_alt_escn)
if (!ML_(sli_is_valid)(debug_info_alt_escn))
FIND(".zdebug_info", debug_info_alt_escn)
FIND(".debug_abbrev", debug_abbv_alt_escn)
if (!ML_(sli_is_valid)(debug_abbv_alt_escn))
FIND(".zdebug_abbrev", debug_abbv_alt_escn)
FIND(".debug_str", debug_str_alt_escn)
if (!ML_(sli_is_valid)(debug_str_alt_escn))
FIND(".zdebug_str", debug_str_alt_escn)
# undef FIND
} /* Find all interesting sections */
} /* do we have a debug image? */
/* TOPLEVEL */
vg_assert((symtab_escn.szB % sizeof(ElfXX_Sym)) == 0);
/* TOPLEVEL */
/* Read symbols */
{
void (*read_elf_symtab)(struct _DebugInfo*, const HChar*,
DiSlice*, DiSlice*, DiSlice*, Bool);
# if defined(VGP_ppc64be_linux)
read_elf_symtab = read_elf_symtab__ppc64be_linux;
# else
read_elf_symtab = read_elf_symtab__normal;
# endif
if (symtab_escn.img != NULL)
read_elf_symtab(di, "symbol table",
&symtab_escn, &strtab_escn, &opd_escn,
True);
}
if (ML_(sli_is_valid)(debug_frame_escn)) {
ML_(read_callframe_info_dwarf3)( di,
debug_frame_escn,
0/*assume zero avma*/,
False/*!is_ehframe*/ );
}
/* TOPLEVEL */
/* jrs 2006-01-01: icc-8.1 has been observed to generate
binaries without debug_str sections. Don't preclude
debuginfo reading for that reason, but, in
read_unitinfo_dwarf2, do check that debugstr is non-NULL
before using it. */
if (ML_(sli_is_valid)(debug_info_escn)
&& ML_(sli_is_valid)(debug_abbv_escn)
&& ML_(sli_is_valid)(debug_line_escn)) {
/* The old reader: line numbers and unwind info only */
ML_(read_debuginfo_dwarf3) ( di,
debug_info_escn,
debug_types_escn,
debug_abbv_escn,
debug_line_escn,
debug_str_escn,
debug_str_alt_escn,
debug_line_str_escn);
/* The new reader: read the DIEs in .debug_info to acquire
information on variable types and locations or inline info.
But only if the tool asks for it, or the user requests it on
the command line. */
if (VG_(clo_read_var_info) /* the user or tool asked for it */
|| VG_(clo_read_inline_info)) {
ML_(new_dwarf3_reader)(
di, debug_info_escn, debug_types_escn,
debug_abbv_escn, debug_line_escn,
debug_str_escn, debug_ranges_escn,
debug_rnglists_escn, debug_loclists_escn,
debug_loc_escn, debug_info_alt_escn,
debug_abbv_alt_escn, debug_line_alt_escn,
debug_str_alt_escn, debug_line_str_escn,
debug_addr_escn, debug_str_offsets_escn
);
}
}
/* TOPLEVEL */
// JRS 31 July 2014: dwarf-1 reading is currently broken and
// therefore deactivated.
//if (dwarf1d_img && dwarf1l_img) {
// ML_(read_debuginfo_dwarf1) ( di, dwarf1d_img, dwarf1d_sz,
// dwarf1l_img, dwarf1l_sz );
//}
# if defined(VGA_arm)
/* TOPLEVEL */
/* ARM32 only: read .exidx/.extab if present. Note we are
reading these directly out of the mapped in (running) image.
Also, read these only if no CFI based unwind info was
acquired for this file.
An .exidx section is always required, but the .extab section
can be optionally omitted, provided that .exidx does not
refer to it. If the .exidx is erroneous and does refer to
.extab even though .extab is missing, the range checks done
by GET_EX_U32 in ExtabEntryExtract in readexidx.c should
prevent any invalid memory accesses, and cause the .extab to
be rejected as invalid.
FIXME:
* check with m_aspacemgr that the entire [exidx_avma, +exidx_size)
and [extab_avma, +extab_size) areas are readable, since we're
reading this stuff out of the running image (not from a file/socket)
and we don't want to segfault.
* DebugInfo::exidx_bias and use text_bias instead.
I think it's always the same.
* remove DebugInfo::{extab_bias, exidx_svma, extab_svma} since
they are never used.
*/
if (di->exidx_present
&& di->cfsi_used == 0
&& di->text_present && di->text_size > 0) {
Addr text_last_svma = di->text_svma + di->text_size - 1;
ML_(read_exidx)( di, (UChar*)di->exidx_avma, di->exidx_size,
(UChar*)di->extab_avma, di->extab_size,
text_last_svma,
di->exidx_bias );
}
# endif /* defined(VGA_arm) */
} /* "Find interesting sections, read the symbol table(s), read any debug
information" (a local scope) */
/* TOPLEVEL */
res = True;
/* If reading Dwarf3 variable type/location info, print a line
showing the number of variables read for each object.
(Currently disabled -- is a sanity-check mechanism for
exp-sgcheck.) */
if (0 && VG_(clo_read_var_info)) {
UWord nVars = 0;
if (di->varinfo) {
for (j = 0; j < VG_(sizeXA)(di->varinfo); j++) {
OSet* /* of DiAddrRange */ scope
= *(OSet**)VG_(indexXA)(di->varinfo, j);
vg_assert(scope);
VG_(OSetGen_ResetIter)( scope );
while (True) {
DiAddrRange* range = VG_(OSetGen_Next)( scope );
if (!range) break;
vg_assert(range->vars);
Word w = VG_(sizeXA)(range->vars);
vg_assert(w >= 0);
if (0) VG_(printf)("range %#lx %#lx %ld\n",
range->aMin, range->aMax, w);
nVars += (UWord)w;
}
}
}
VG_(umsg)("VARINFO: %7lu vars %7lu text_size %s\n",
nVars, di->text_size, di->fsm.filename);
}
/* TOPLEVEL */
out:
{
/* Last, but not least, detach from the image(s). */
if (mimg) ML_(img_done)(mimg);
if (dimg) ML_(img_done)(dimg);
if (aimg) ML_(img_done)(aimg);
return res;
} /* out: */
/* NOTREACHED */
}
Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename,
Int * rw_load_count, Bool from_nsegments )
{
Bool res, ok;
UWord i;
DiImage* mimg = NULL;
DiOffT ehdr_mioff = 0;
DiOffT phdr_mioff = 0;
UWord phdr_mnent = 0U;
UWord phdr_ment_szB = 0U;
ElfXX_Phdr previous_rw_a_phdr;
res = False;
mimg = ML_(img_from_fd)(fd, filename);
if (mimg == NULL) {
VG_(message)(Vg_UserMsg, "warning: connection to image %s failed\n",
filename );
VG_(message)(Vg_UserMsg, " cannot read program headers \n" );
return False;
}
ok = is_elf_object_file_by_DiImage(mimg, False);
if (!ok) {
goto out;
}
ElfXX_Ehdr ehdr_m;
Elf64_Word flag_x;
#if defined(VGA_amd64) || defined(VGA_ppc64be) || defined(VGA_ppc64le) || defined(VGA_arm) || defined(VGA_arm64)
flag_x = PF_X;
#else
flag_x = 0;
#endif
#if defined(VGO_solaris)
flag_x = 0;
#endif
vg_assert(ehdr_mioff == 0); // ensured by its initialisation
ok = ML_(img_valid)(mimg, ehdr_mioff, sizeof(ehdr_m));
vg_assert(ok); // ML_(is_elf_object_file) should ensure this
ML_(img_get)(&ehdr_m, mimg, ehdr_mioff, sizeof(ehdr_m));
phdr_mioff = ehdr_mioff + ehdr_m.e_phoff;
phdr_mnent = ehdr_m.e_phnum;
phdr_ment_szB = ehdr_m.e_phentsize;
/* Sets p_memsz to 0 to indicate we have not yet a previous a_phdr. */
previous_rw_a_phdr.p_memsz = 0;
/* and silence compiler warnings */
previous_rw_a_phdr.p_filesz = 0;
previous_rw_a_phdr.p_vaddr = 0;
for (i = 0U; i < phdr_mnent; i++) {
ElfXX_Phdr a_phdr;
ML_(img_get)(&a_phdr, mimg,
INDEX_BIS(phdr_mioff, i, phdr_ment_szB),
sizeof(a_phdr));
if (a_phdr.p_type == PT_LOAD) {
if (a_phdr.p_memsz > 0) {
if (((a_phdr.p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) &&
((a_phdr.p_flags & flag_x) == 0)) {
++*rw_load_count;
if (VG_(debugLog_getLevel)() > 1)
VG_(message)(Vg_DebugMsg, "check_elf_and_get_rw_loads: "
"++*rw_load_count to %d for %s "
"p_vaddr %#lx p_offset %lu, p_filesz %lu\n",
*rw_load_count, filename,
(UWord)a_phdr.p_vaddr, (UWord)a_phdr.p_offset,
(UWord)a_phdr.p_filesz);
/*
* Hold your horses
* Just because The ELF file contains 2 RW PT_LOAD segments
* doesn't mean that Valgrind will also make 2 calls to
* VG_(di_notify_mmap): in some cases, the 2 NSegments will
* have been merged and VG_(di_notify_mmap) only gets called
* once.
* How to detect that the segments were be merged ?
* Logically, they will be merged if the first segment ends
* at the beginning of the second segment:
* Seg1 virtual address + Seg1 segment_size
* == Seg2 virtual address.
* However, it is not very clear how the file section will be
* loaded: the PT_LOAD specifies a file size and a memory size.
* Logically, the memory size should be used in the above
* condition, but strangely enough, in some cases the file size
* can be smaller than the memory size. And that then result in
* an "anonymous" mapping done between the 2 segments that
* otherwise would be consecutive.
* This has been seen in an executable linked by the mold linker
* (see bug 473944). In this case, the file segments were loaded
* with a "page rounded up" file size (observed on RHEL 8.6,
* ld-2.28.so, mold 1.5.1).
* However, in FreeBSD with lld (see 452802 and 473944), rounding
* up p_filesz in the below condition makes at least one test
* fail.
* As on the mold case, the below condition correctly ensures
* the 2 different segments loaded separately are both counted
* here, we use the non rounded up p_filesz.
* This is all a nightmare/hack. Something cleaner should be
* done than other than reverse engineering whether this call
* results from merged nsegments or not. Particularly as
* the mmap'ing and nsegment merging is all under our control.
*/
if (previous_rw_a_phdr.p_memsz > 0 &&
from_nsegments &&
previous_rw_a_phdr.p_vaddr + previous_rw_a_phdr.p_filesz
== a_phdr.p_vaddr)
{
--*rw_load_count;
if (VG_(debugLog_getLevel)() > 1)
VG_(message)(Vg_DebugMsg, "check_elf_and_get_rw_loads: "
" --*rw_load_count to %d for %s\n",
*rw_load_count, filename);
}
previous_rw_a_phdr = a_phdr;
}
}
}
} /* for (i = 0; i < phdr_Mnent; i++) ... */
res = True;
out:
{
/* Last, but not least, detach from the image(s). */
if (mimg) ML_(img_free)(mimg);
return res;
} /* out: */
/* NOTREACHED */
}
#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
|