From 3abf7f5fc5b397f8c69a1f943c1892c5546641e7 Mon Sep 17 00:00:00 2001 From: Sasha Goldshtein Date: Thu, 9 Feb 2017 15:59:47 -0500 Subject: [PATCH] tests: Test debuginfo through debuglink and build-id sections This commit introduces support for tests of the new debuglink and build-id debuginfo resolution functionality. The tests build a dummy.c file with a debuglink section, and again with a build-id section, and make sure that the symbol resolution code can locate the debug information correctly (in the binary's directory for debuglink, and in /usr/lib/debug/.build-id for the build-id). --- tests/python/CMakeLists.txt | 3 +- tests/python/dummy.c | 15 ++++++++ tests/python/test_debuginfo.py | 79 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/python/dummy.c create mode 100755 tests/python/test_debuginfo.py diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index afdf92b..75f4ab2 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -36,6 +36,8 @@ add_test(NAME py_test_trace4 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_trace4 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace4.py) add_test(NAME py_test_probe_count WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_probe_count sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_probe_count.py) +add_test(NAME py_test_debuginfo WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${TEST_WRAPPER} py_test_debuginfo sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_debuginfo.py) add_test(NAME py_test_brb WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_brb_c sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_brb.py test_brb.c) add_test(NAME py_test_brb2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -60,6 +62,5 @@ add_test(NAME py_test_utils WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_test_utils sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_utils.py) add_test(NAME py_test_percpu WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_test_percpu sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_percpu.py) - add_test(NAME py_test_dump_func WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_dump_func simple ${CMAKE_CURRENT_SOURCE_DIR}/test_dump_func.py) diff --git a/tests/python/dummy.c b/tests/python/dummy.c new file mode 100644 index 0000000..8a3ced2 --- /dev/null +++ b/tests/python/dummy.c @@ -0,0 +1,15 @@ +#include +#include + +static __attribute__((noinline)) int some_function(int x, int y) { + volatile int z = x + y; + return z; +} + +int main() { + printf("%p\n", &some_function); + fflush(stdout); + printf("result = %d\n", some_function(42, 11)); + sleep(1000); + return 0; +} diff --git a/tests/python/test_debuginfo.py b/tests/python/test_debuginfo.py new file mode 100755 index 0000000..744e4cc --- /dev/null +++ b/tests/python/test_debuginfo.py @@ -0,0 +1,79 @@ +#!/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 +from unittest import main, TestCase + +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() + + def resolve_addr(self): + sym, offset, module = self.syms.resolve(self.addr) + self.assertEqual(sym, 'some_function') + self.assertEqual(offset, 0) + self.assertTrue(module[-5:] == 'dummy') + + def resolve_name(self): + script_dir = os.path.dirname(os.path.realpath(__file__)) + addr = self.syms.resolve_name(os.path.join(script_dir, 'dummy'), + 'some_function') + self.assertEqual(addr, self.addr) + pass + +class TestDebuglink(Harness): + def build_command(self): + subprocess.check_output('gcc -o dummy dummy.c'.split()) + + def debug_command(self): + subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy' + .split()) + + def tearDown(self): + 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(('gcc -o dummy -Xlinker ' + \ + '--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.c') + .split()) + + 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): + 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() -- 2.7.4