File: find-pc.cc

package info (click to toggle)
libelfin 0.3-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 668 kB
  • sloc: cpp: 4,883; makefile: 189; python: 139; sh: 129; ansic: 10
file content (113 lines) | stat: -rw-r--r-- 3,428 bytes parent folder | download | duplicates (3)
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
#include "elf++.hh"
#include "dwarf++.hh"

#include <fcntl.h>
#include <string>
#include <inttypes.h>

using namespace std;

void
usage(const char *cmd) 
{
        fprintf(stderr, "usage: %s elf-file pc\n", cmd);
        exit(2);
}

bool
find_pc(const dwarf::die &d, dwarf::taddr pc, vector<dwarf::die> *stack)
{
        using namespace dwarf;

        // Scan children first to find most specific DIE
        bool found = false;
        for (auto &child : d) {
                if ((found = find_pc(child, pc, stack)))
                        break;
        }
        switch (d.tag) {
        case DW_TAG::subprogram:
        case DW_TAG::inlined_subroutine:
                try {
                        if (found || die_pc_range(d).contains(pc)) {
                                found = true;
                                stack->push_back(d);
                        }
                } catch (out_of_range &e) {
                } catch (value_type_mismatch &e) {
                }
                break;
        default:
                break;
        }
        return found;
}

void
dump_die(const dwarf::die &node)
{
        printf("<%" PRIx64 "> %s\n",
               node.get_section_offset(),
               to_string(node.tag).c_str());
        for (auto &attr : node.attributes())
                printf("      %s %s\n",
                       to_string(attr.first).c_str(),
                       to_string(attr.second).c_str());
}

int
main(int argc, char **argv)
{
        if (argc != 3)
                usage(argv[0]);

        dwarf::taddr pc;
        try {
                pc = stoll(argv[2], nullptr, 0);
        } catch (invalid_argument &e) {
                usage(argv[0]);
        } catch (out_of_range &e) {
                usage(argv[0]);
        }

        int fd = open(argv[1], O_RDONLY);
        if (fd < 0) {
                fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
                return 1;
        }

        elf::elf ef(elf::create_mmap_loader(fd));
        dwarf::dwarf dw(dwarf::elf::create_loader(ef));

        // Find the CU containing pc
        // XXX Use .debug_aranges
        for (auto &cu : dw.compilation_units()) {
                if (die_pc_range(cu.root()).contains(pc)) {
                        // Map PC to a line
                        auto &lt = cu.get_line_table();
                        auto it = lt.find_address(pc);
                        if (it == lt.end())
                                printf("UNKNOWN\n");
                        else
                                printf("%s\n",
                                       it->get_description().c_str());

                        // Map PC to an object
                        // XXX Index/helper/something for looking up PCs
                        // XXX DW_AT_specification and DW_AT_abstract_origin
                        vector<dwarf::die> stack;
                        if (find_pc(cu.root(), pc, &stack)) {
                                bool first = true;
                                for (auto &d : stack) {
                                        if (!first)
                                                printf("\nInlined in:\n");
                                        first = false;
                                        dump_die(d);
                                }
                        }
                        break;
                }
        }

        return 0;
}