xref: /aosp_15_r20/external/bcc/tests/python/test_debuginfo.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) Sasha Goldshtein
3*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
4*387f9dfdSAndroid Build Coastguard Worker
5*387f9dfdSAndroid Build Coastguard Workerimport os
6*387f9dfdSAndroid Build Coastguard Workerimport subprocess
7*387f9dfdSAndroid Build Coastguard Workerfrom bcc import SymbolCache, BPF
8*387f9dfdSAndroid Build Coastguard Workerfrom unittest import main, TestCase
9*387f9dfdSAndroid Build Coastguard Workerfrom utils import mayFail
10*387f9dfdSAndroid Build Coastguard Worker
11*387f9dfdSAndroid Build Coastguard Workerclass TestKSyms(TestCase):
12*387f9dfdSAndroid Build Coastguard Worker    def grab_sym(self):
13*387f9dfdSAndroid Build Coastguard Worker        address = ""
14*387f9dfdSAndroid Build Coastguard Worker        aliases = []
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker        # Grab the first symbol in kallsyms that has type 't' or 'T'.
17*387f9dfdSAndroid Build Coastguard Worker        # Also, find all aliases of this symbol which are identifiable
18*387f9dfdSAndroid Build Coastguard Worker        # by the same address.
19*387f9dfdSAndroid Build Coastguard Worker        with open("/proc/kallsyms", "rb") as f:
20*387f9dfdSAndroid Build Coastguard Worker            for line in f:
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker                # Extract the first 3 columns only. The 4th column
23*387f9dfdSAndroid Build Coastguard Worker                # containing the module name may not exist for all
24*387f9dfdSAndroid Build Coastguard Worker                # symbols.
25*387f9dfdSAndroid Build Coastguard Worker                (addr, t, name) = line.strip().split()[:3]
26*387f9dfdSAndroid Build Coastguard Worker                if t == b"t" or t == b"T":
27*387f9dfdSAndroid Build Coastguard Worker                    if not address:
28*387f9dfdSAndroid Build Coastguard Worker                        address = addr
29*387f9dfdSAndroid Build Coastguard Worker                    if addr == address:
30*387f9dfdSAndroid Build Coastguard Worker                        aliases.append(name)
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard Worker        # Return all aliases of the first symbol.
33*387f9dfdSAndroid Build Coastguard Worker        return (address, aliases)
34*387f9dfdSAndroid Build Coastguard Worker
35*387f9dfdSAndroid Build Coastguard Worker    def test_ksymname(self):
36*387f9dfdSAndroid Build Coastguard Worker        sym = BPF.ksymname(b"__kmalloc")
37*387f9dfdSAndroid Build Coastguard Worker        self.assertIsNotNone(sym)
38*387f9dfdSAndroid Build Coastguard Worker        self.assertNotEqual(sym, 0)
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker    def test_ksym(self):
41*387f9dfdSAndroid Build Coastguard Worker        (addr, aliases) = self.grab_sym()
42*387f9dfdSAndroid Build Coastguard Worker        sym = BPF.ksym(int(addr, 16))
43*387f9dfdSAndroid Build Coastguard Worker        found = sym in aliases
44*387f9dfdSAndroid Build Coastguard Worker        self.assertTrue(found)
45*387f9dfdSAndroid Build Coastguard Worker
46*387f9dfdSAndroid Build Coastguard Workerclass Harness(TestCase):
47*387f9dfdSAndroid Build Coastguard Worker    def setUp(self):
48*387f9dfdSAndroid Build Coastguard Worker        self.build_command()
49*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('objcopy --only-keep-debug dummy dummy.debug'
50*387f9dfdSAndroid Build Coastguard Worker                                .split())
51*387f9dfdSAndroid Build Coastguard Worker        self.debug_command()
52*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('strip dummy'.split())
53*387f9dfdSAndroid Build Coastguard Worker        self.process = subprocess.Popen('./dummy', stdout=subprocess.PIPE)
54*387f9dfdSAndroid Build Coastguard Worker        # The process prints out the address of some symbol, which we then
55*387f9dfdSAndroid Build Coastguard Worker        # try to resolve in the test.
56*387f9dfdSAndroid Build Coastguard Worker        self.addr = int(self.process.stdout.readline().strip(), 16)
57*387f9dfdSAndroid Build Coastguard Worker        self.syms = SymbolCache(self.process.pid)
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker    def tearDown(self):
60*387f9dfdSAndroid Build Coastguard Worker        self.process.kill()
61*387f9dfdSAndroid Build Coastguard Worker        self.process.wait()
62*387f9dfdSAndroid Build Coastguard Worker        self.process.stdout.close()
63*387f9dfdSAndroid Build Coastguard Worker        self.process = None
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker    def resolve_addr(self):
66*387f9dfdSAndroid Build Coastguard Worker        sym, offset, module = self.syms.resolve(self.addr, False)
67*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(sym, self.mangled_name)
68*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(offset, 0)
69*387f9dfdSAndroid Build Coastguard Worker        self.assertTrue(module[-5:] == b'dummy')
70*387f9dfdSAndroid Build Coastguard Worker        sym, offset, module = self.syms.resolve(self.addr, True)
71*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(sym, b'some_namespace::some_function(int, int)')
72*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(offset, 0)
73*387f9dfdSAndroid Build Coastguard Worker        self.assertTrue(module[-5:] == b'dummy')
74*387f9dfdSAndroid Build Coastguard Worker
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker    def resolve_name(self):
77*387f9dfdSAndroid Build Coastguard Worker        script_dir = os.path.dirname(os.path.realpath(__file__).encode("utf8"))
78*387f9dfdSAndroid Build Coastguard Worker        addr = self.syms.resolve_name(os.path.join(script_dir, b'dummy'),
79*387f9dfdSAndroid Build Coastguard Worker                                      self.mangled_name)
80*387f9dfdSAndroid Build Coastguard Worker        self.assertEqual(addr, self.addr)
81*387f9dfdSAndroid Build Coastguard Worker        pass
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Workerclass TestDebuglink(Harness):
84*387f9dfdSAndroid Build Coastguard Worker    def build_command(self):
85*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('g++ -o dummy dummy.cc'.split())
86*387f9dfdSAndroid Build Coastguard Worker        lines = subprocess.check_output('nm dummy'.split()).splitlines()
87*387f9dfdSAndroid Build Coastguard Worker        for line in lines:
88*387f9dfdSAndroid Build Coastguard Worker            if b"some_function" in line:
89*387f9dfdSAndroid Build Coastguard Worker                self.mangled_name = line.split(b' ')[2]
90*387f9dfdSAndroid Build Coastguard Worker                break
91*387f9dfdSAndroid Build Coastguard Worker        self.assertTrue(self.mangled_name)
92*387f9dfdSAndroid Build Coastguard Worker
93*387f9dfdSAndroid Build Coastguard Worker    def debug_command(self):
94*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy'
95*387f9dfdSAndroid Build Coastguard Worker                                .split())
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Worker    def tearDown(self):
98*387f9dfdSAndroid Build Coastguard Worker        super(TestDebuglink, self).tearDown()
99*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('rm dummy dummy.debug'.split())
100*387f9dfdSAndroid Build Coastguard Worker
101*387f9dfdSAndroid Build Coastguard Worker    def test_resolve_addr(self):
102*387f9dfdSAndroid Build Coastguard Worker        self.resolve_addr()
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Worker    @mayFail("This fails on github actions environment, and needs to be fixed")
105*387f9dfdSAndroid Build Coastguard Worker    def test_resolve_name(self):
106*387f9dfdSAndroid Build Coastguard Worker        self.resolve_name()
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Workerclass TestBuildid(Harness):
109*387f9dfdSAndroid Build Coastguard Worker    def build_command(self):
110*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output(('g++ -o dummy -Xlinker ' + \
111*387f9dfdSAndroid Build Coastguard Worker               '--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.cc')
112*387f9dfdSAndroid Build Coastguard Worker               .split())
113*387f9dfdSAndroid Build Coastguard Worker        lines = subprocess.check_output('nm dummy'.split()).splitlines()
114*387f9dfdSAndroid Build Coastguard Worker        for line in lines:
115*387f9dfdSAndroid Build Coastguard Worker            if b"some_function" in line:
116*387f9dfdSAndroid Build Coastguard Worker                self.mangled_name = line.split(b' ')[2]
117*387f9dfdSAndroid Build Coastguard Worker                break
118*387f9dfdSAndroid Build Coastguard Worker        self.assertTrue(self.mangled_name)
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker    def debug_command(self):
122*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('mkdir -p /usr/lib/debug/.build-id/12'.split())
123*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output(('mv dummy.debug /usr/lib/debug/.build-id' + \
124*387f9dfdSAndroid Build Coastguard Worker            '/12/3456789abcdef0123456789abcdef012345678.debug').split())
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Worker    def tearDown(self):
127*387f9dfdSAndroid Build Coastguard Worker        super(TestBuildid, self).tearDown()
128*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output('rm dummy'.split())
129*387f9dfdSAndroid Build Coastguard Worker        subprocess.check_output(('rm /usr/lib/debug/.build-id/12' +
130*387f9dfdSAndroid Build Coastguard Worker            '/3456789abcdef0123456789abcdef012345678.debug').split())
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker    def test_resolve_name(self):
133*387f9dfdSAndroid Build Coastguard Worker        self.resolve_addr()
134*387f9dfdSAndroid Build Coastguard Worker
135*387f9dfdSAndroid Build Coastguard Worker    @mayFail("This fails on github actions environment, and needs to be fixed")
136*387f9dfdSAndroid Build Coastguard Worker    def test_resolve_addr(self):
137*387f9dfdSAndroid Build Coastguard Worker        self.resolve_name()
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__":
140*387f9dfdSAndroid Build Coastguard Worker    main()
141