| #! /usr/bin/env python |
| |
| # Copyright (C) 2011-2021 Free Software Foundation, Inc. |
| # |
| # This file is part of GDB. |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
| # This program requires readelf, gdb and objcopy. The default values are gdb |
| # from the build tree and objcopy and readelf from $PATH. They may be |
| # overridden by setting environment variables GDB, READELF and OBJCOPY |
| # respectively. We assume the current directory is either $obj/gdb or |
| # $obj/gdb/testsuite. |
| # |
| # Example usage: |
| # |
| # bash$ cd $objdir/gdb/testsuite |
| # bash$ python test_pubnames_and_indexes.py <binary_name> |
| |
| """test_pubnames_and_indexes.py |
| |
| Test that the gdb_index produced by gold is identical to the gdb_index |
| produced by gdb itself. |
| |
| Further check that the pubnames and pubtypes produced by gcc are identical |
| to those that gdb produces. |
| |
| Finally, check that all strings are canonicalized identically. |
| """ |
| |
| __author__ = "saugustine@google.com (Sterling Augustine)" |
| |
| import os |
| import subprocess |
| import sys |
| |
| OBJCOPY = None |
| READELF = None |
| GDB = None |
| |
| |
| def get_pub_info(filename, readelf_option): |
| """Parse and return all the pubnames or pubtypes produced by readelf with the |
| given option. |
| """ |
| readelf = subprocess.Popen( |
| [READELF, "--debug-dump=" + readelf_option, filename], stdout=subprocess.PIPE |
| ) |
| pubnames = [] |
| |
| in_list = False |
| for line in readelf.stdout: |
| fields = line.split(None, 1) |
| if len(fields) == 2 and fields[0] == "Offset" and fields[1].strip() == "Name": |
| in_list = True |
| # Either a blank-line or a new Length field terminates the current section. |
| elif len(fields) == 0 or fields[0] == "Length:": |
| in_list = False |
| elif in_list: |
| pubnames.append(fields[1].strip()) |
| |
| readelf.wait() |
| return pubnames |
| |
| |
| def get_gdb_index(filename): |
| """Use readelf to dump the gdb index and collect the types and names""" |
| readelf = subprocess.Popen( |
| [READELF, "--debug-dump=gdb_index", filename], stdout=subprocess.PIPE |
| ) |
| index_symbols = [] |
| symbol_table_started = False |
| for line in readelf.stdout: |
| if line == "Symbol table:\n": |
| symbol_table_started = True |
| elif symbol_table_started: |
| # Readelf prints gdb-index lines formatted like so: |
| # [ 4] two::c2<double>::c2: 0 |
| # So take the string between the first close bracket and the last colon. |
| index_symbols.append(line[line.find("]") + 2 : line.rfind(":")]) |
| |
| readelf.wait() |
| return index_symbols |
| |
| |
| def CheckSets(list0, list1, name0, name1): |
| """Report any setwise differences between the two lists""" |
| |
| if len(list0) == 0 or len(list1) == 0: |
| return False |
| |
| difference0 = set(list0) - set(list1) |
| if len(difference0) != 0: |
| print "Elements in " + name0 + " but not " + name1 + ": (", |
| print len(difference0), |
| print ")" |
| for element in difference0: |
| print " " + element |
| |
| difference1 = set(list1) - set(list0) |
| if len(difference1) != 0: |
| print "Elements in " + name1 + " but not " + name0 + ": (", |
| print len(difference1), |
| print ")" |
| for element in difference1: |
| print " " + element |
| |
| if len(difference0) != 0 or len(difference1) != 0: |
| return True |
| |
| print name0 + " and " + name1 + " are identical." |
| return False |
| |
| |
| def find_executables(): |
| """Find the copies of readelf, objcopy and gdb to use.""" |
| # Executable finding logic follows cc-with-index.sh |
| global READELF |
| READELF = os.getenv("READELF") |
| if READELF is None: |
| READELF = "readelf" |
| global OBJCOPY |
| OBJCOPY = os.getenv("OBJCOPY") |
| if OBJCOPY is None: |
| OBJCOPY = "objcopy" |
| |
| global GDB |
| GDB = os.getenv("GDB") |
| if GDB is None: |
| if os.path.isfile("./gdb") and os.access("./gdb", os.X_OK): |
| GDB = "./gdb" |
| elif os.path.isfile("../gdb") and os.access("../gdb", os.X_OK): |
| GDB = "../gdb" |
| elif os.path.isfile("../../gdb") and os.access("../../gdb", os.X_OK): |
| GDB = "../../gdb" |
| else: |
| # Punt and use the gdb in the path. |
| GDB = "gdb" |
| |
| |
| def main(argv): |
| """The main subprogram.""" |
| if len(argv) != 2: |
| print "Usage: test_pubnames_and_indexes.py <filename>" |
| sys.exit(2) |
| |
| find_executables() |
| |
| # Get the index produced by Gold--It should have been built into the binary. |
| gold_index = get_gdb_index(argv[1]) |
| |
| # Collect the pubnames and types list |
| pubs_list = get_pub_info(argv[1], "pubnames") |
| pubs_list = pubs_list + get_pub_info(argv[1], "pubtypes") |
| |
| # Generate a .gdb_index with gdb |
| gdb_index_file = argv[1] + ".gdb-generated-index" |
| subprocess.check_call( |
| [OBJCOPY, "--remove-section", ".gdb_index", argv[1], gdb_index_file] |
| ) |
| subprocess.check_call( |
| [ |
| GDB, |
| "-batch", |
| "-nx", |
| gdb_index_file, |
| "-ex", |
| "save gdb-index " + os.path.dirname(argv[1]), |
| "-ex", |
| "quit", |
| ] |
| ) |
| subprocess.check_call( |
| [ |
| OBJCOPY, |
| "--add-section", |
| ".gdb_index=" + gdb_index_file + ".gdb-index", |
| gdb_index_file, |
| ] |
| ) |
| gdb_index = get_gdb_index(gdb_index_file) |
| os.remove(gdb_index_file) |
| os.remove(gdb_index_file + ".gdb-index") |
| |
| failed = False |
| gdb_index.sort() |
| gold_index.sort() |
| pubs_list.sort() |
| |
| # Find the differences between the various indices. |
| if len(gold_index) == 0: |
| print "Gold index is empty" |
| failed |= True |
| |
| if len(gdb_index) == 0: |
| print "Gdb index is empty" |
| failed |= True |
| |
| if len(pubs_list) == 0: |
| print "Pubs list is empty" |
| failed |= True |
| |
| failed |= CheckSets(gdb_index, gold_index, "gdb index", "gold index") |
| failed |= CheckSets(pubs_list, gold_index, "pubs list", "gold index") |
| failed |= CheckSets(pubs_list, gdb_index, "pubs list", "gdb index") |
| |
| if failed: |
| print "Test failed" |
| sys.exit(1) |
| |
| |
| if __name__ == "__main__": |
| main(sys.argv) |