You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.7 KiB
138 lines
4.7 KiB
#!/usr/bin/env python
|
|
# Copyright (c) Sasha Goldshtein
|
|
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
|
|
import os
|
|
import subprocess
|
|
from bcc import SymbolCache, BPF
|
|
from unittest import main, TestCase
|
|
|
|
class TestKSyms(TestCase):
|
|
def grab_sym(self):
|
|
address = ""
|
|
aliases = []
|
|
|
|
# Grab the first symbol in kallsyms that has type 't' or 'T'.
|
|
# Also, find all aliases of this symbol which are identifiable
|
|
# by the same address.
|
|
with open("/proc/kallsyms", "rb") as f:
|
|
for line in f:
|
|
|
|
# Extract the first 3 columns only. The 4th column
|
|
# containing the module name may not exist for all
|
|
# symbols.
|
|
(addr, t, name) = line.strip().split()[:3]
|
|
if t == b"t" or t == b"T":
|
|
if not address:
|
|
address = addr
|
|
if addr == address:
|
|
aliases.append(name)
|
|
|
|
# Return all aliases of the first symbol.
|
|
return (address, aliases)
|
|
|
|
def test_ksymname(self):
|
|
sym = BPF.ksymname(b"__kmalloc")
|
|
self.assertIsNotNone(sym)
|
|
self.assertNotEqual(sym, 0)
|
|
|
|
def test_ksym(self):
|
|
(addr, aliases) = self.grab_sym()
|
|
sym = BPF.ksym(int(addr, 16))
|
|
found = sym in aliases
|
|
self.assertTrue(found)
|
|
|
|
class Harness(TestCase):
|
|
def setUp(self):
|
|
self.build_command()
|
|
subprocess.check_output('objcopy --only-keep-debug dummy dummy.debug'
|
|
.split())
|
|
self.debug_command()
|
|
subprocess.check_output('strip dummy'.split())
|
|
self.process = subprocess.Popen('./dummy', stdout=subprocess.PIPE)
|
|
# The process prints out the address of some symbol, which we then
|
|
# try to resolve in the test.
|
|
self.addr = int(self.process.stdout.readline().strip(), 16)
|
|
self.syms = SymbolCache(self.process.pid)
|
|
|
|
def tearDown(self):
|
|
self.process.kill()
|
|
self.process.wait()
|
|
self.process.stdout.close()
|
|
self.process = None
|
|
|
|
def resolve_addr(self):
|
|
sym, offset, module = self.syms.resolve(self.addr, False)
|
|
self.assertEqual(sym, self.mangled_name)
|
|
self.assertEqual(offset, 0)
|
|
self.assertTrue(module[-5:] == b'dummy')
|
|
sym, offset, module = self.syms.resolve(self.addr, True)
|
|
self.assertEqual(sym, b'some_namespace::some_function(int, int)')
|
|
self.assertEqual(offset, 0)
|
|
self.assertTrue(module[-5:] == b'dummy')
|
|
|
|
|
|
def resolve_name(self):
|
|
script_dir = os.path.dirname(os.path.realpath(__file__).encode("utf8"))
|
|
addr = self.syms.resolve_name(os.path.join(script_dir, b'dummy'),
|
|
self.mangled_name)
|
|
self.assertEqual(addr, self.addr)
|
|
pass
|
|
|
|
class TestDebuglink(Harness):
|
|
def build_command(self):
|
|
subprocess.check_output('g++ -o dummy dummy.cc'.split())
|
|
lines = subprocess.check_output('nm dummy'.split()).splitlines()
|
|
for line in lines:
|
|
if b"some_function" in line:
|
|
self.mangled_name = line.split(b' ')[2]
|
|
break
|
|
self.assertTrue(self.mangled_name)
|
|
|
|
def debug_command(self):
|
|
subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy'
|
|
.split())
|
|
|
|
def tearDown(self):
|
|
super(TestDebuglink, self).tearDown()
|
|
subprocess.check_output('rm dummy dummy.debug'.split())
|
|
|
|
def test_resolve_addr(self):
|
|
self.resolve_addr()
|
|
|
|
def test_resolve_name(self):
|
|
self.resolve_name()
|
|
|
|
class TestBuildid(Harness):
|
|
def build_command(self):
|
|
subprocess.check_output(('g++ -o dummy -Xlinker ' + \
|
|
'--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.cc')
|
|
.split())
|
|
lines = subprocess.check_output('nm dummy'.split()).splitlines()
|
|
for line in lines:
|
|
if b"some_function" in line:
|
|
self.mangled_name = line.split(b' ')[2]
|
|
break
|
|
self.assertTrue(self.mangled_name)
|
|
|
|
|
|
def debug_command(self):
|
|
subprocess.check_output('mkdir -p /usr/lib/debug/.build-id/12'.split())
|
|
subprocess.check_output(('mv dummy.debug /usr/lib/debug/.build-id' + \
|
|
'/12/3456789abcdef0123456789abcdef012345678.debug').split())
|
|
|
|
def tearDown(self):
|
|
super(TestBuildid, self).tearDown()
|
|
subprocess.check_output('rm dummy'.split())
|
|
subprocess.check_output(('rm /usr/lib/debug/.build-id/12' +
|
|
'/3456789abcdef0123456789abcdef012345678.debug').split())
|
|
|
|
def test_resolve_name(self):
|
|
self.resolve_addr()
|
|
|
|
def test_resolve_addr(self):
|
|
self.resolve_name()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|