This file is indexed.

/usr/include/libelfin/dwarf/dwarf++.hh is in libelfin-dev 0.3-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

#ifndef _DWARFPP_HH_
#define _DWARFPP_HH_

#ifndef DWARFPP_BEGIN_NAMESPACE
#define DWARFPP_BEGIN_NAMESPACE namespace dwarf {
#define DWARFPP_END_NAMESPACE   }
#endif

#include "data.hh"
#include "small_vector.hh"

#include <initializer_list>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

DWARFPP_BEGIN_NAMESPACE

// Forward declarations
class dwarf;
class loader;
class compilation_unit;
class type_unit;
class die;
class value;
class expr;
class expr_context;
class expr_result;
class rangelist;
class line_table;

// Internal type forward-declarations
struct section;
struct abbrev_entry;
struct cursor;

// XXX Audit for binary-compatibility

// XXX Might be able to reduce private coupling by making class
// section public (and clean it up and maybe rename it slice) and
// provide methods to get the backing data of things.
//
// XXX Make slice generic, without formatting information?  Still want
// lightweight cursors, so maybe the cursor methods that need the
// format should take a const reference to a format stored in the
// compilation unit?

// XXX operator==/!= and hash functions

// XXX Indicate DWARF4 in all spec references

// XXX Big missing support: .debug_aranges, .debug_frame, loclists,
// macros

//////////////////////////////////////////////////////////////////
// DWARF files
//

/**
 * An exception indicating malformed DWARF data.
 */
class format_error : public std::runtime_error
{
public:
        explicit format_error(const std::string &what_arg)
                : std::runtime_error(what_arg) { }
        explicit format_error(const char *what_arg)
                : std::runtime_error(what_arg) { }
};

/**
 * DWARF section types.  These correspond to the names of ELF
 * sections, though DWARF can be embedded in other formats.
 */
enum class section_type
{
        abbrev,
        aranges,
        frame,
        info,
        line,
        loc,
        macinfo,
        pubnames,
        pubtypes,
        ranges,
        str,
        types,
};

std::string
to_string(section_type v);

/**
 * A DWARF file.  This class is internally reference counted and can
 * be efficiently copied.
 *
 * Objects retrieved from this object may depend on it; the caller is
 * responsible for keeping this object live as long as any retrieved
 * object may be in use.
 */
class dwarf
{
public:
        /**
         * Construct a DWARF file that is backed by sections read from
         * the given loader.
         */
        explicit dwarf(const std::shared_ptr<loader> &l);

        /**
         * Construct a DWARF file that is initially not valid.
         */
        dwarf() = default;
        dwarf(const dwarf&) = default;
        dwarf(dwarf&&) = default;
        ~dwarf();

        dwarf& operator=(const dwarf &o) = default;
        dwarf& operator=(dwarf &&o) = default;

        bool operator==(const dwarf &o) const
        {
                return m == o.m;
        }

        bool operator!=(const dwarf &o) const
        {
                return m != o.m;
        }

        /**
         * Return true if this object represents a DWARF file.
         * Default constructed dwarf objects are not valid.
         */
        bool valid() const
        {
                return !!m;
        }

        // XXX This allows the compilation units to be modified and
        // ties us to a vector.  Probably should return an opaque
        // iterable collection over const references.
        /**
         * Return the list of compilation units in this DWARF file.
         */
        const std::vector<compilation_unit> &compilation_units() const;

        /**
         * Return the type unit with the given signature.  If the
         * signature does not correspond to a type unit, throws
         * out_of_range.
         */
        const type_unit &get_type_unit(uint64_t type_signature) const;

        /**
         * \internal Retrieve the specified section from this file.
         * If the section does not exist, throws format_error.
         */
        std::shared_ptr<section> get_section(section_type type) const;

private:
        struct impl;
        std::shared_ptr<impl> m;
};

/**
 * An interface for lazily loading DWARF sections.
 */
class loader
{
public:
        virtual ~loader() { }

        /**
         * Load the requested DWARF section into memory and return a
         * pointer to the beginning of it.  This memory must remain
         * valid and unchanged until the loader is destroyed.  If the
         * requested section does not exist, this should return
         * nullptr.  If the section exists but cannot be loaded for
         * any reason, this should throw an exception.
         */
        virtual const void *load(section_type section, size_t *size_out) = 0;
};

/**
 * The base class for a compilation unit or type unit within a DWARF
 * file.  A unit consists of a rooted tree of DIEs, plus additional
 * metadata that depends on the type of unit.
 */
class unit
{
public:
        virtual ~unit() = 0;

        bool operator==(const unit &o) const
        {
                return m == o.m;
        }

        bool operator!=(const unit &o) const
        {
                return m != o.m;
        }

        /**
         * Return true if this object is valid.  Default constructed
         * unit objects are not valid.
         */
        bool valid() const
        {
                return !!m;
        }

        /**
         * Return the dwarf file this unit is in.
         */
        const dwarf &get_dwarf() const;

        /**
         * Return the byte offset of this unit's header in its
         * section (.debug_info or .debug_types).
         */
        section_offset get_section_offset() const;

        /**
         * Return the root DIE of this unit.  For a compilation unit,
         * this should be a DW_TAG::compilation_unit or
         * DW_TAG::partial_unit.
         */
        const die &root() const;

        /**
         * \internal Return the data for this unit.
         */
        const std::shared_ptr<section> &data() const;

        /**
         * \internal Return the abbrev for the specified abbrev
         * code.
         */
        const abbrev_entry &get_abbrev(std::uint64_t acode) const;

protected:
        friend struct ::std::hash<unit>;
        struct impl;
        std::shared_ptr<impl> m;
};

/**
 * A compilation unit within a DWARF file.  Most of the information
 * in a DWARF file is divided up by compilation unit.  This class is
 * internally reference counted and can be efficiently copied.
 */
class compilation_unit : public unit
{
public:
        compilation_unit() = default;
        compilation_unit(const compilation_unit &o) = default;
        compilation_unit(compilation_unit &&o) = default;

        compilation_unit& operator=(const compilation_unit &o) = default;
        compilation_unit& operator=(compilation_unit &&o) = default;

        /**
         * \internal Construct a compilation unit whose header begins
         * offset bytes into the .debug_info section of file.
         */
        compilation_unit(const dwarf &file, section_offset offset);

        /**
         * Return the line number table of this compilation unit.
         * Returns an invalid line table if this unit has no line
         * table.
         */
        const line_table &get_line_table() const;
};

/**
 * A type unit.  Type units allow complex type information to be
 * shared between compilation units.
 */
class type_unit : public unit
{
public:
        type_unit() = default;
        type_unit(const type_unit &o) = default;
        type_unit(type_unit &&o) = default;

        type_unit &operator=(const type_unit &o) = default;
        type_unit &operator=(type_unit &&o) = default;

        /**
         * \internal Construct a type unit whose header begins offset
         * bytes into the .debug_types section of file.
         */
        type_unit(const dwarf &file, section_offset offset);

        /**
         * Return the 64-bit unique signature that identifies this
         * type unit.  This is how DIEs from other units refer to type
         * described by this unit.
         */
        uint64_t get_type_signature() const;

        // XXX Can a type unit contain more than one top-level DIE?
        // The description of type_offset makes it sound like it
        // might.

        /**
         * Return the DIE of the type described by this type unit.
         * This may not be the root DIE of this unit if the type is
         * nested in namespaces or other structures.
         */
        const die &type() const;
};

//////////////////////////////////////////////////////////////////
// Debugging information entries (DIEs)
//

/**
 * A Debugging Information Entry, or DIE.  The basic unit of
 * information in a DWARF file.
 */
class die
{
        // XXX Make this class better for use in maps.  Currently dies
        // are fairly big and expensive to copy, but most of that
        // information can be constructed lazily.  This is also bad
        // for use in caches since it will keep the DWARF file alive.
        // OTOH, maybe caches need eviction anyway.
public:
        DW_TAG tag;

        die() : cu(nullptr), abbrev(nullptr) { }
        die(const die &o) = default;
        die(die &&o) = default;

        die& operator=(const die &o) = default;
        die& operator=(die &&o) = default;

        /**
         * Return true if this object represents a DIE in a DWARF
         * file.  Default constructed objects are not valid and some
         * methods return invalid DIEs to indicate failures.
         */
        bool valid() const
        {
                return abbrev != nullptr;
        }

        /**
         * Return the unit containing this DIE.
         */
        const unit &get_unit() const;

        /**
         * Return this DIE's byte offset within its compilation unit.
         */
        section_offset get_unit_offset() const
        {
                return offset;
        }

        /**
         * Return this DIE's byte offset within its section.
         */
        section_offset get_section_offset() const;

        /**
         * Return true if this DIE has the requested attribute.
         */
        bool has(DW_AT attr) const;

        /**
         * Return the value of attr.  Throws out_of_range if this DIE
         * does not have the specified attribute.  It is generally
         * better to use the type-safe attribute getters (the global
         * functions beginning with at_*) when possible.
         */
        value operator[](DW_AT attr) const;

        /**
         * Return the value of attr after resolving specification and
         * abstract origin references.  If the attribute cannot be
         * resolved, returns an invalid value.  Declaration DIEs can
         * "complete" a previous non-defining declaration DIE and
         * similarly inherit the non-defining declaration's attributes
         * (DWARF4 section 2.13) Likewise, any DIE that is a child of
         * a concrete inlined instance can specify another DIE as its
         * "abstract origin" and the original DIE will inherit the
         * attributes of its abstract origin (DWARF4 section 3.3.8.2).
         */
        value resolve(DW_AT attr) const;

        class iterator;

        /**
         * Return an iterator over the children of this DIE.  Note
         * that the DIEs returned by this iterator are temporary, so
         * if you need to store a DIE for more than one loop
         * iteration, you must copy it.
         */
        iterator begin() const;
        iterator end() const;

        /**
         * Return a vector of the attributes of this DIE.
         */
        const std::vector<std::pair<DW_AT, value> > attributes() const;

        bool operator==(const die &o) const;
        bool operator!=(const die &o) const;

private:
        friend class unit;
        friend class type_unit;
        friend class value;
        // XXX If we can get the CU, we don't need this
        friend struct ::std::hash<die>;

        const unit *cu;
        // The abbrev of this DIE.  By convention, if this DIE
        // represents a sibling list terminator, this is null.  This
        // object is kept live by the CU.
        const abbrev_entry *abbrev;
        // The beginning of this DIE, relative to the CU.
        section_offset offset;
        // Offsets of attributes, relative to cu's subsection.  The
        // vast majority of DIEs tend to have six or fewer attributes,
        // so we reserve space in the DIE itself for six attributes.
        small_vector<section_offset, 6> attrs;
        // The offset of the next DIE, relative to cu'd subsection.
        // This is set even for sibling list terminators.
        section_offset next;

        die(const unit *cu);

        /**
         * Read this DIE from the given offset in cu.
         */
        void read(section_offset off);
};

/**
 * An iterator over a sequence of sibling DIEs.
 */
class die::iterator
{
public:
        iterator() = default;
        iterator(const iterator &o) = default;
        iterator(iterator &&o) = default;

        iterator& operator=(const iterator &o) = default;
        iterator& operator=(iterator &&o) = default;

        const die &operator*() const
        {
                return d;
        }

        const die *operator->() const
        {
                return &d;
        }

        // XXX Make this less confusing by implementing operator== instead
        bool operator!=(const iterator &o) const
        {
                // Quick test of abbrevs.  In particular, this weeds
                // out non-end against end, which is a common
                // comparison while iterating, though it also weeds
                // out many other things.
                if (d.abbrev != o.d.abbrev)
                        return true;

                // Same, possibly NULL abbrev.  If abbrev is NULL,
                // then next's are uncomparable, so we need to stop
                // now.  We consider all ends to be the same, without
                // comparing cu's.
                if (d.abbrev == nullptr)
                        return false;

                // Comparing two non-end abbrevs.
                return d.next != o.d.next || d.cu != o.d.cu;
        }

        iterator &operator++();

private:
        friend class die;

        iterator(const unit *cu, section_offset off);

        die d;
};

inline die::iterator
die::end() const
{
        return iterator();
}

/**
 * An exception indicating that a value is not of the requested type.
 */
class value_type_mismatch : public std::logic_error
{
public:
        explicit value_type_mismatch(const std::string &what_arg)
                : std::logic_error(what_arg) { }
        explicit value_type_mismatch(const char *what_arg)
                : std::logic_error(what_arg) { }
};

/**
 * The value of a DIE attribute.
 *
 * This is logically a union of many different types.  Each type has a
 * corresponding as_* methods that will return the value as that type
 * or throw value_type_mismatch if the attribute is not of the
 * requested type.
 *
 * Values of "constant" type are somewhat ambiguous and
 * context-dependent.  Constant forms with specified signed-ness have
 * type "uconstant" or "sconstant", while other constant forms have
 * type "constant".  If the value's type is "constant", it can be
 * retrieved using either as_uconstant or as_sconstant.
 *
 * Some other types can also be coerced.  These are documented on the
 * individual as_* methods.
 *
 * There is no as_line; while there is an attribute for line tables,
 * line tables are really associated with compilation units (and
 * require additional context from the compilation unit).  Use
 * compilation_unit::get_line_table instead.
 */
class value
{
public:
        enum class type
        {
                invalid,
                address,
                block,
                constant,
                uconstant,
                sconstant,
                exprloc,
                flag,
                line,
                loclist,
                mac,
                rangelist,
                reference,
                string
        };

        /**
         * Construct a value with type `type::invalid`.
         */
        value() : cu(nullptr), typ(type::invalid) { }

        value(const value &o) = default;
        value(value &&o) = default;

        value& operator=(const value &o) = default;
        value& operator=(value &&o) = default;

        /**
         * Return true if this object represents a valid value.
         * Default constructed line tables are not valid.
         */
        bool valid() const
        {
                return typ != type::invalid;
        }

        /**
         * Return this value's byte offset within its compilation
         * unit.
         */
        section_offset get_unit_offset() const
        {
                return offset;
        }

        /**
         * Return this value's byte offset within its section.
         */
        section_offset get_section_offset() const;

        type get_type() const
        {
                return typ;
        }

        /**
         * Return this value's attribute encoding.  This automatically
         * resolves indirect encodings, so this will never return
         * DW_FORM::indirect.  Note that the mapping from forms to
         * types is non-trivial and often depends on the attribute
         * (especially prior to DWARF 4).
         */
        DW_FORM get_form() const
        {
                return form;
        }

        /**
         * Return this value as a target machine address.
         */
        taddr as_address() const;

        /**
         * Return this value as a block.  The returned pointer points
         * directly into the section data, so the caller must ensure
         * that remains valid as long as the data is in use.
         * *size_out is set to the length of the returned block, in
         * bytes.
         *
         * This automatically coerces "exprloc" type values by
         * returning the raw bytes of the encoded expression.
         */
        const void *as_block(size_t *size_out) const;

        /**
         * Return this value as an unsigned constant.  This
         * automatically coerces "constant" type values by
         * interpreting their bytes as unsigned.
         */
        uint64_t as_uconstant() const;

        /**
         * Return this value as a signed constant.  This automatically
         * coerces "constant" type values by interpreting their bytes
         * as twos-complement signed values.
         */
        int64_t as_sconstant() const;

        /**
         * Return this value as an expression.  This automatically
         * coerces "block" type values by interpreting the bytes in
         * the block as an expression (prior to DWARF 4, exprlocs were
         * always encoded as blocks, though the library automatically
         * distinguishes these types based on context).
         */
        expr as_exprloc() const;

        /**
         * Return this value as a boolean flag.
         */
        bool as_flag() const;

        // XXX loclistptr, macptr

        /**
         * Return this value as a rangelist.
         */
        rangelist as_rangelist() const;

        /**
         * For a reference type value, return the referenced DIE.
         * This DIE may be in a different compilation unit or could
         * be a DIE in a type unit.
         */
        die as_reference() const;

        /**
         * Return this value as a string.
         */
        std::string as_string() const;

        /**
         * Fill the given string buffer with the string value of this
         * value.  This is useful to minimize allocation when reading
         * several string-type values.
         */
        void as_string(std::string &buf) const;

        /**
         * Return this value as a NUL-terminated character string.
         * The returned pointer points directly into the section data,
         * so the caller must ensure that remains valid as long as the
         * data is in use.  *size_out, if not NULL, is set to the
         * length of the returned string without the NUL-terminator.
         */
        const char *as_cstr(size_t *size_out = nullptr) const;

        /**
         * Return this value as a section offset.  This is applicable
         * to lineptr, loclistptr, macptr, and rangelistptr.
         */
        section_offset as_sec_offset() const;

private:
        friend class die;

        value(const unit *cu,
              DW_AT name, DW_FORM form, type typ, section_offset offset);

        void resolve_indirect(DW_AT name);

        const unit *cu;
        DW_FORM form;
        type typ;
        section_offset offset;
};

std::string
to_string(value::type v);

std::string
to_string(const value &v);

//////////////////////////////////////////////////////////////////
// Expressions and location descriptions
//

/**
 * An exception during expression evaluation.
 */
class expr_error : public std::runtime_error
{
public:
        explicit expr_error(const std::string &what_arg)
                : std::runtime_error(what_arg) { }
        explicit expr_error(const char *what_arg)
                : std::runtime_error(what_arg) { }
};

/**
 * A DWARF expression or location description.
 */
class expr
{
public:
        /**
         * Short-hand for evaluate(ctx, {}).
         */
        expr_result evaluate(expr_context *ctx) const;

        /**
         * Short-hand for evaluate(ctx, {argument}).
         */
        expr_result evaluate(expr_context *ctx, taddr argument) const;

        /**
         * Return the result of evaluating this expression using the
         * specified expression context.  The expression stack will be
         * initialized with the given arguments such that the first
         * arguments is at the top of the stack and the last argument
         * at the bottom of the stack.
         *
         * Throws expr_error if there is an error evaluating the
         * expression (such as an unknown operation, stack underflow,
         * bounds error, etc.)
         */
        expr_result evaluate(expr_context *ctx, const std::initializer_list<taddr> &arguments) const;

private:
        // XXX This will need more information for some operations
        expr(const unit *cu,
             section_offset offset, section_length len);

        friend class value;

        const unit *cu;
        section_offset offset;
        section_length len;
};

/**
 * An interface that provides contextual information for expression
 * evaluation.  Callers of expr::evaluate are expected to subclass
 * this in order to provide this information to the expression
 * evaluation engine.  The default implementation throws expr_error
 * for all methods.
 */
class expr_context
{
public:
        virtual ~expr_context() { }

        /**
         * Return the value stored in register regnum.  This is used
         * to implement DW_OP_breg* operations.
         */
        virtual taddr reg(unsigned regnum)
        {
                throw expr_error("DW_OP_breg* operations not supported");
        }

        /**
         * Implement DW_OP_deref_size.
         */
        virtual taddr deref_size(taddr address, unsigned size)
        {
                throw expr_error("DW_OP_deref_size operations not supported");
        }

        /**
         * Implement DW_OP_xderef_size.
         */
        virtual taddr xderef_size(taddr address, taddr asid, unsigned size)
        {
                throw expr_error("DW_OP_xderef_size operations not supported");
        }

        /**
         * Implement DW_OP_form_tls_address.
         */
        virtual taddr form_tls_address(taddr address)
        {
                throw expr_error("DW_OP_form_tls_address operations not supported");
        }
};

/**
 * An instance of expr_context that throws expr_error for all methods.
 * This is equivalent to the default construction of expr_context, but
 * often more convenient to use.
 */
extern expr_context no_expr_context;

// XXX Provide methods to check type and fetch value?
/**
 * The result of evaluating a DWARF expression or location
 * description.
 */
class expr_result
{
public:
        enum class type {
                /**
                 * value specifies the address in memory of an object.
                 * This is also the result type used for general
                 * expressions that do not refer to object locations.
                 */
                address,
                /**
                 * value specifies a register storing an object.
                 */
                reg,
                /**
                 * The object does not have a location.  value is the
                 * value of the object.
                 */
                literal,
                /**
                 * The object does not have a location.  Its value is
                 * pointed to by the 'implicit' field.
                 */
                implicit,
                /**
                 * The object is present in the source, but not in the
                 * object code, and hence does not have a location or
                 * a value.
                 */
                empty,
        };

        /**
         * For location descriptions, the type of location this result
         * describes.
         */
        type location_type;

        /**
         * For general-purpose expressions, the result of expression.
         * For address location descriptions, the address in memory of
         * the object.  For register location descriptions, the
         * register storing the object.  For literal location
         * descriptions, the value of the object.
         */
        taddr value;

        /**
         * For implicit location descriptions, a pointer to a block
         * representing the value in the memory representation of the
         * target machine.
         */
        const char *implicit;
        size_t implicit_len;

        // XXX Composite locations
};

std::string
to_string(expr_result::type v);

//////////////////////////////////////////////////////////////////
// Range lists
//

/**
 * A DWARF range list describing a set of possibly non-contiguous
 * addresses.
 */
class rangelist
{
public:
        /**
         * \internal Construct a range list whose data begins at the
         * given offset in sec.  cu_addr_size is the address size of
         * the associated compilation unit.  cu_low_pc is the
         * DW_AT::low_pc attribute of the compilation unit containing
         * the referring DIE or 0 (this is used as the base address of
         * the range list).
         */
        rangelist(const std::shared_ptr<section> &sec, section_offset off,
                  unsigned cu_addr_size, taddr cu_low_pc);

        /**
         * Construct a range list from a sequence of {low, high}
         * pairs.
         */
        rangelist(const std::initializer_list<std::pair<taddr, taddr> > &ranges);

        /**
         * Construct an empty range list.
         */
        rangelist() = default;

        /** Copy constructor */
        rangelist(const rangelist &o) = default;
        /** Move constructor */
        rangelist(rangelist &&o) = default;

        rangelist& operator=(const rangelist &o) = default;
        rangelist& operator=(rangelist &&o) = default;

        class entry;
        typedef entry value_type;

        class iterator;

        /**
         * Return an iterator over the entries in this range list.
         * The ranges returned by this iterator are temporary, so if
         * you need to store a range for more than one loop iteration,
         * you must copy it.
         */
        iterator begin() const;

        /**
         * Return an iterator to one past the last entry in this range
         * list.
         */
        iterator end() const;

        /**
         * Return true if this range list contains the given address.
         */
        bool contains(taddr addr) const;

private:
        std::vector<taddr> synthetic;
        std::shared_ptr<section> sec;
        taddr base_addr;
};

/**
 * An entry in a range list.  The range spans addresses [low, high).
 */
class rangelist::entry
{
public:
        taddr low, high;

        /**
         * Return true if addr is within this entry's bounds.
         */
        bool contains(taddr addr) const
        {
                return low <= addr && addr < high;
        }
};

/**
 * An iterator over a sequence of ranges in a range list.
 */
class rangelist::iterator
{
public:
        /**
         * \internal Construct an end iterator.
         */
        iterator() : sec(nullptr), base_addr(0), pos(0) { }

        /**
         * \internal Construct an iterator that reads rangelist data
         * from the beginning of the given section and starts with the
         * given base address.
         */
        iterator(const std::shared_ptr<section> &sec, taddr base_addr);

        /** Copy constructor */
        iterator(const iterator &o) = default;
        /** Move constructor */
        iterator(iterator &&o) = default;

        iterator& operator=(const iterator &o) = default;
        iterator& operator=(iterator &&o) = default;

        /**
         * Return the current range list entry.  This entry is reused
         * internally, so the caller should copy it if it needs to
         * persist past the next increment.
         */
        const rangelist::entry &operator*() const
        {
                return entry;
        }

        /** Dereference operator */
        const rangelist::entry *operator->() const
        {
                return &entry;
        }

        /** Equality operator */
        bool operator==(const iterator &o) const
        {
                return sec == o.sec && pos == o.pos;
        }

        /** Inequality operator */
        bool operator!=(const iterator &o) const
        {
                return !(*this == o);
        }

        /**
         * Increment this iterator to point to the next range list
         * entry.
         */
        iterator &operator++();

private:
        std::shared_ptr<section> sec;
        taddr base_addr;
        section_offset pos;
        rangelist::entry entry;
};

//////////////////////////////////////////////////////////////////
// Line number tables
//

/**
 * A DWARF line number table.  A line number table is a list of line
 * table entries, broken up into "sequences".  Within a sequence,
 * entries are in order of increasing program counter ("address") and
 * an entry provides information for all program counters between the
 * entry's address and the address of the next entry.  Each sequence
 * is terminated by a special entry with its
 * line_table::entry::end_sequence flag set.  The line number table
 * also records the set of source files for a given compilation unit,
 * which can be referred to from other DIE attributes.
 */
class line_table
{
public:
        /**
         * \internal Construct a line number table whose header begins
         * at the given offset in sec.  cu_addr_size is the address
         * size of the associated compilation unit.  cu_comp_dir and
         * cu_name give the DW_AT::comp_dir and DW_AT::name attributes
         * of the associated compilation unit.
         */
        line_table(const std::shared_ptr<section> &sec, section_offset offset,
                   unsigned cu_addr_size, const std::string &cu_comp_dir,
                   const std::string &cu_name);

        /**
         * Construct an invalid, empty line table.
         */
        line_table() = default;

        /** Copy constructor */
        line_table(const line_table &o) = default;
        /** Move constructor */
        line_table(line_table &&o) = default;

        line_table &operator=(const line_table &o) = default;
        line_table &operator=(line_table &&o) = default;

        /**
         * Return true if this object represents an initialized line
         * table.  Default constructed line tables are not valid.
         */
        bool valid() const
        {
                return !!m;
        }

        class file;
        class entry;
        typedef entry value_type;

        class iterator;

        /**
         * Return an iterator to the beginning of this line number
         * table.  If called on an invalid line table, this will
         * return an iterator equal to end().
         */
        iterator begin() const;

        /**
         * Return an iterator to one past the last entry in this line
         * number table.
         */
        iterator end() const;

        /**
         * Return an iterator to the line table entry containing addr
         * (roughly, the entry with the highest address less than or
         * equal to addr, but accounting for end_sequence entries).
         * Returns end() if there is no such entry.
         */
        iterator find_address(taddr addr) const;

        /**
         * Return the index'th file in the line table.  These indexes
         * are typically used by declaration and call coordinates.  If
         * index is out of range, throws out_of_range.
         */
        const file *get_file(unsigned index) const;

private:
        friend class iterator;

        struct impl;
        std::shared_ptr<impl> m;
};

/**
 * A source file in a line table.
 */
class line_table::file
{
public:
        /**
         * The absolute path of this source file.
         */
        std::string path;

        /**
         * The last modification time of this source file in an
         * implementation-defined encoding or 0 if unknown.
         */
        uint64_t mtime;

        /**
         * The size in bytes of this source file or 0 if unknown.
         */
        uint64_t length;

        /**
         * Construct a source file object.
         */
        file(std::string path = "", uint64_t mtime = 0, uint64_t length = 0);
};

/**
 * An entry in the line table.
 */
class line_table::entry
{
public:
        /**
         * The program counter value corresponding to a machine
         * instruction generated by the compiler.
         */
        taddr address;

        /**
         * The index of an operation within a VLIW instruction. The
         * index of the first operation is 0. For non-VLIW
         * architectures, this will always be 0.
         */
        unsigned op_index;

        /**
         * The source file containing this instruction.
         */
        const line_table::file *file;

        /**
         * The index of the source file containing this instruction.
         */
        unsigned file_index;

        /**
         * The source line number of this instruction, starting at 1.
         * This may be 0 if this instruction cannot be attributed to
         * any source line.
         */
        unsigned line;

        /**
         * The column number within this source line, starting at 1.
         * The value 0 indicates that a statement begins at the "left
         * edge" of the line, whatever that means.
         */
        unsigned column;

        /**
         * True if this instruction is a recommended breakpoint
         * location.  Typically this is the beginning of a statement.
         */
        bool is_stmt;

        /**
         * True if this instruction is the beginning of a basic block.
         */
        bool basic_block;

        /**
         * True if this address is the first byte after the end of a
         * sequence of target machine instructions.  In this case, all
         * other fields besides address are not meaningful.
         */
        bool end_sequence;

        /**
         * True if this address is one where execution should be
         * suspended for an entry breakpoint of a function.
         */
        bool prologue_end;

        /**
         * True if this address is one where execution should be
         * suspended for an exit breakpoint of a function.
         */
        bool epilogue_begin;

        /**
         * The instruction set architecture of this instruction.  The
         * meaning of this field is generally defined by an
         * architecture's ABI.
         */
        unsigned isa;

        /**
         * A number that identifies the block containing the current
         * instruction if multiple blocks are associated with the same
         * source file, line, and column.
         */
        unsigned discriminator;

        /**
         * Reset this line info object to the default initial values
         * for all fields.  is_stmt has no default value, so the
         * caller must provide it.
         */
        void reset(bool is_stmt);

        /**
         * Return a descriptive string of the form
         * "filename[:line[:column]]".
         */
        std::string get_description() const;
};

/**
 * An iterator over the entries in a line table.
 */
class line_table::iterator
{
public:
        /**
         * \internal Construct an iterator for the given line table
         * starting pos bytes into the table's section.
         */
        iterator(const line_table *table, section_offset pos);

        /** Copy constructor */
        iterator(const iterator &o) = default;
        /** Move constructor */
        iterator(iterator &&o) = default;

        iterator &operator=(const iterator &o) = default;
        iterator &operator=(iterator &&o) = default;

        /**
         * Return the current line table entry.  This entry is reused
         * internally, so the caller should copy it if it needs to
         * persist past the next increment.
         */
        const line_table::entry &operator*() const
        {
                return entry;
        }

        /** Dereference operator */
        const line_table::entry *operator->() const
        {
                return &entry;
        }

        /** Equality operator */
        bool operator==(const iterator &o) const
        {
                return o.pos == pos && o.table == table;
        }

        /** Inequality operator */
        bool operator!=(const iterator &o) const
        {
                return !(*this == o);
        }

        /**
         * Increment this iterator to point to the next line table
         * entry.
         */
        iterator &operator++();

        /** Post-increment operator */
        iterator operator++(int)
        {
                iterator tmp(*this);
                ++(*this);
                return tmp;
        }

private:
        const line_table *table;
        line_table::entry entry, regs;
        section_offset pos;

        /**
         * Process the next opcode.  If the opcode "adds a row to the
         * table", update entry to reflect the row and return true.
         */
        bool step(cursor *cur);
};

//////////////////////////////////////////////////////////////////
// Type-safe attribute getters
//

// XXX More

die at_abstract_origin(const die &d);
DW_ACCESS at_accessibility(const die &d);
uint64_t at_allocated(const die &d, expr_context *ctx);
bool at_artificial(const die &d);
uint64_t at_associated(const die &d, expr_context *ctx);
uint64_t at_bit_offset(const die &d, expr_context *ctx);
uint64_t at_bit_size(const die &d, expr_context *ctx);
uint64_t at_bit_stride(const die &d, expr_context *ctx);
uint64_t at_byte_size(const die &d, expr_context *ctx);
uint64_t at_byte_stride(const die &d, expr_context *ctx);
DW_CC at_calling_convention(const die &d);
die at_common_reference(const die &d);
std::string at_comp_dir(const die &d);
value at_const_value(const die &d);
bool at_const_expr(const die &d);
die at_containing_type(const die &d);
uint64_t at_count(const die &d, expr_context *ctx);
expr_result at_data_member_location(const die &d, expr_context *ctx, taddr base, taddr pc);
bool at_declaration(const die &d);
std::string at_description(const die &d);
die at_discr(const die &d);
value at_discr_value(const die &d);
bool at_elemental(const die &d);
DW_ATE at_encoding(const die &d);
DW_END at_endianity(const die &d);
taddr at_entry_pc(const die &d);
bool at_enum_class(const die &d);
bool at_explicit(const die &d);
die at_extension(const die &d);
bool at_external(const die &d);
die at_friend(const die &d);
taddr at_high_pc(const die &d);
DW_ID at_identifier_case(const die &d);
die at_import(const die &d);
DW_INL at_inline(const die &d);
bool at_is_optional(const die &d);
DW_LANG at_language(const die &d);
std::string at_linkage_name(const die &d);
taddr at_low_pc(const die &d);
uint64_t at_lower_bound(const die &d, expr_context *ctx);
bool at_main_subprogram(const die &d);
bool at_mutable(const die &d);
std::string at_name(const die &d);
die at_namelist_item(const die &d);
die at_object_pointer(const die &d);
DW_ORD at_ordering(const die &d);
std::string at_picture_string(const die &d);
die at_priority(const die &d);
std::string at_producer(const die &d);
bool at_prototyped(const die &d);
bool at_pure(const die &d);
rangelist at_ranges(const die &d);
bool at_recursive(const die &d);
die at_sibling(const die &d);
die at_signature(const die &d);
die at_small(const die &d);
die at_specification(const die &d);
bool at_threads_scaled(const die &d);
die at_type(const die &d);
uint64_t at_upper_bound(const die &d, expr_context *ctx);
bool at_use_UTF8(const die &d);
bool at_variable_parameter(const die &d);
DW_VIRTUALITY at_virtuality(const die &d);
DW_VIS at_visibility(const die &d);

/**
 * Return the PC range spanned by the code of a DIE.  The DIE must
 * either have DW_AT::ranges or DW_AT::low_pc.  It may optionally have
 * DW_AT::high_pc.
 */
rangelist die_pc_range(const die &d);

//////////////////////////////////////////////////////////////////
// Utilities
//

/**
 * An index of sibling DIEs by some string attribute.  This index is
 * lazily constructed and space-efficient.
 */
class die_str_map
{
public:
        /**
         * Construct the index of the attr attribute of all immediate
         * children of parent whose tags are in accept.
         */
        die_str_map(const die &parent, DW_AT attr,
                    const std::initializer_list<DW_TAG> &accept);

        die_str_map() = default;
        die_str_map(const die_str_map &o) = default;
        die_str_map(die_str_map &&o) = default;

        die_str_map& operator=(const die_str_map &o) = default;
        die_str_map& operator=(die_str_map &&o) = default;

        /**
         * Construct a string map for the type names of parent's
         * immediate children.
         *
         * XXX This should use .debug_pubtypes if parent is a compile
         * unit's root DIE, but it currently does not.
         */
        static die_str_map from_type_names(const die &parent);

        /**
         * Return the DIE whose attribute matches val.  If no such DIE
         * exists, return an invalid die object.
         */
        const die &operator[](const char *val) const;

        /**
         * Short-hand for [value.c_str()].
         */
        const die &operator[](const std::string &val) const
        {
                return (*this)[val.c_str()];
        }

private:
        struct impl;
        std::shared_ptr<impl> m;
};

//////////////////////////////////////////////////////////////////
// ELF support
//

namespace elf
{
        /**
         * Translate an ELF section name info a DWARF section type.
         * If the section is a valid DWARF section name, sets *out to
         * the type and returns true.  If not, returns false.
         */
        bool section_name_to_type(const char *name, section_type *out);

        /**
         * Translate a DWARF section type into an ELF section name.
         */
        const char *section_type_to_name(section_type type);

        template<typename Elf>
        class elf_loader : public loader
        {
                Elf f;

        public:
                elf_loader(const Elf &file) : f(file) { }

                const void *load(section_type section, size_t *size_out)
                {
                        auto sec = f.get_section(section_type_to_name(section));
                        if (!sec.valid())
                                return nullptr;
                        *size_out = sec.size();
                        return sec.data();
                }
        };

        /**
         * Create a DWARF section loader backed by the given ELF
         * file.  This is templatized to eliminate a static dependency
         * between the libelf++ and libdwarf++, though it can only
         * reasonably be used with elf::elf from libelf++.
         */
        template<typename Elf>
        std::shared_ptr<elf_loader<Elf> > create_loader(const Elf &f)
        {
                return std::make_shared<elf_loader<Elf> >(f);
        }
};

DWARFPP_END_NAMESPACE

//////////////////////////////////////////////////////////////////
// Hash specializations
//

namespace std
{
        template<>
        struct hash<dwarf::unit>
        {
                typedef size_t result_type;
                typedef const dwarf::unit &argument_type;
                result_type operator()(argument_type a) const
                {
                        return hash<decltype(a.m)>()(a.m);
                }
        };

        template<>
        struct hash<dwarf::die>
        {
                typedef size_t result_type;
                typedef const dwarf::die &argument_type;
                result_type operator()(argument_type a) const;
        };
}

#endif