OLD | NEW |
(Empty) | |
| 1 #! /usr/bin/env python |
| 2 |
| 3 # Copyright (C) 2011-2012 Free Software Foundation, Inc. |
| 4 # |
| 5 # This file is part of GDB. |
| 6 # |
| 7 # This program is free software; you can redistribute it and/or modify |
| 8 # it under the terms of the GNU General Public License as published by |
| 9 # the Free Software Foundation; either version 3 of the License, or |
| 10 # (at your option) any later version. |
| 11 # |
| 12 # This program is distributed in the hope that it will be useful, |
| 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 # GNU General Public License for more details. |
| 16 # |
| 17 # You should have received a copy of the GNU General Public License |
| 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 |
| 20 # This program requires readelf, gdb and objcopy. The default values are gdb |
| 21 # from the build tree and objcopy and readelf from $PATH. They may be |
| 22 # overridden by setting environment variables GDB, READELF and OBJCOPY |
| 23 # respectively. We assume the current directory is either $obj/gdb or |
| 24 # $obj/gdb/testsuite. |
| 25 # |
| 26 # Example usage: |
| 27 # |
| 28 # bash$ cd $objdir/gdb/testsuite |
| 29 # bash$ python test_pubnames_and_indexes.py <binary_name> |
| 30 |
| 31 """test_pubnames_and_indexes.py |
| 32 |
| 33 Test that the gdb_index produced by gold is identical to the gdb_index |
| 34 produced by gdb itself. |
| 35 |
| 36 Further check that the pubnames and pubtypes produced by gcc are identical |
| 37 to those that gdb produces. |
| 38 |
| 39 Finally, check that all strings are canonicalized identically. |
| 40 """ |
| 41 |
| 42 __author__ = 'saugustine@google.com (Sterling Augustine)' |
| 43 |
| 44 import os |
| 45 import subprocess |
| 46 import sys |
| 47 |
| 48 OBJCOPY = None |
| 49 READELF = None |
| 50 GDB = None |
| 51 |
| 52 def get_pub_info(filename, readelf_option): |
| 53 """Parse and return all the pubnames or pubtypes produced by readelf with the |
| 54 given option. |
| 55 """ |
| 56 readelf = subprocess.Popen([READELF, '--debug-dump=' + readelf_option, |
| 57 filename], stdout=subprocess.PIPE) |
| 58 pubnames = [] |
| 59 |
| 60 in_list = False; |
| 61 for line in readelf.stdout: |
| 62 fields = line.split(None, 1) |
| 63 if (len(fields) == 2 and fields[0] == 'Offset' |
| 64 and fields[1].strip() == 'Name'): |
| 65 in_list = True |
| 66 # Either a blank-line or a new Length field terminates the current section. |
| 67 elif (len(fields) == 0 or fields[0] == 'Length:'): |
| 68 in_list = False; |
| 69 elif (in_list): |
| 70 pubnames.append(fields[1].strip()) |
| 71 |
| 72 readelf.wait() |
| 73 return pubnames |
| 74 |
| 75 |
| 76 def get_gdb_index(filename): |
| 77 """Use readelf to dump the gdb index and collect the types and names""" |
| 78 readelf = subprocess.Popen([READELF, '--debug-dump=gdb_index', |
| 79 filename], stdout=subprocess.PIPE) |
| 80 index_symbols = [] |
| 81 symbol_table_started = False |
| 82 for line in readelf.stdout: |
| 83 if (line == 'Symbol table:\n'): |
| 84 symbol_table_started = True; |
| 85 elif (symbol_table_started): |
| 86 # Readelf prints gdb-index lines formatted like so: |
| 87 # [ 4] two::c2<double>::c2: 0 |
| 88 # So take the string between the first close bracket and the last colon. |
| 89 index_symbols.append(line[line.find(']') + 2: line.rfind(':')]) |
| 90 |
| 91 readelf.wait() |
| 92 return index_symbols |
| 93 |
| 94 |
| 95 def CheckSets(list0, list1, name0, name1): |
| 96 """Report any setwise differences between the two lists""" |
| 97 |
| 98 if len(list0) == 0 or len(list1) == 0: |
| 99 return False |
| 100 |
| 101 difference0 = set(list0) - set(list1) |
| 102 if len(difference0) != 0: |
| 103 print "Elements in " + name0 + " but not " + name1 + ": (", |
| 104 print len(difference0), |
| 105 print ")" |
| 106 for element in difference0: |
| 107 print " " + element |
| 108 |
| 109 difference1 = set(list1) - set(list0) |
| 110 if len(difference1) != 0: |
| 111 print "Elements in " + name1 + " but not " + name0 + ": (", |
| 112 print len(difference1), |
| 113 print ")" |
| 114 for element in difference1: |
| 115 print " " + element |
| 116 |
| 117 if (len(difference0) != 0 or len(difference1) != 0): |
| 118 return True |
| 119 |
| 120 print name0 + " and " + name1 + " are identical." |
| 121 return False |
| 122 |
| 123 |
| 124 def find_executables(): |
| 125 """Find the copies of readelf, objcopy and gdb to use.""" |
| 126 # Executable finding logic follows cc-with-index.sh |
| 127 global READELF |
| 128 READELF = os.getenv('READELF') |
| 129 if READELF is None: |
| 130 READELF = 'readelf' |
| 131 global OBJCOPY |
| 132 OBJCOPY = os.getenv('OBJCOPY') |
| 133 if OBJCOPY is None: |
| 134 OBJCOPY = 'objcopy' |
| 135 |
| 136 global GDB |
| 137 GDB = os.getenv('GDB') |
| 138 if (GDB is None): |
| 139 if os.path.isfile('./gdb') and os.access('./gdb', os.X_OK): |
| 140 GDB = './gdb' |
| 141 elif os.path.isfile('../gdb') and os.access('../gdb', os.X_OK): |
| 142 GDB = '../gdb' |
| 143 elif os.path.isfile('../../gdb') and os.access('../../gdb', os.X_OK): |
| 144 GDB = '../../gdb' |
| 145 else: |
| 146 # Punt and use the gdb in the path. |
| 147 GDB = 'gdb' |
| 148 |
| 149 |
| 150 def main(argv): |
| 151 """The main subprogram.""" |
| 152 if len(argv) != 2: |
| 153 print "Usage: test_pubnames_and_indexes.py <filename>" |
| 154 sys.exit(2) |
| 155 |
| 156 find_executables(); |
| 157 |
| 158 # Get the index produced by Gold--It should have been built into the binary. |
| 159 gold_index = get_gdb_index(argv[1]) |
| 160 |
| 161 # Collect the pubnames and types list |
| 162 pubs_list = get_pub_info(argv[1], "pubnames") |
| 163 pubs_list = pubs_list + get_pub_info(argv[1], "pubtypes") |
| 164 |
| 165 # Generate a .gdb_index with gdb |
| 166 gdb_index_file = argv[1] + '.gdb-generated-index' |
| 167 subprocess.check_call([OBJCOPY, '--remove-section', '.gdb_index', |
| 168 argv[1], gdb_index_file]) |
| 169 subprocess.check_call([GDB, '-batch', '-nx', gdb_index_file, |
| 170 '-ex', 'save gdb-index ' + os.path.dirname(argv[1]), |
| 171 '-ex', 'quit']) |
| 172 subprocess.check_call([OBJCOPY, '--add-section', |
| 173 '.gdb_index=' + gdb_index_file + '.gdb-index', |
| 174 gdb_index_file]) |
| 175 gdb_index = get_gdb_index(gdb_index_file) |
| 176 os.remove(gdb_index_file) |
| 177 os.remove(gdb_index_file + '.gdb-index') |
| 178 |
| 179 failed = False |
| 180 gdb_index.sort() |
| 181 gold_index.sort() |
| 182 pubs_list.sort() |
| 183 |
| 184 # Find the differences between the various indices. |
| 185 if len(gold_index) == 0: |
| 186 print "Gold index is empty" |
| 187 failed |= True |
| 188 |
| 189 if len(gdb_index) == 0: |
| 190 print "Gdb index is empty" |
| 191 failed |= True |
| 192 |
| 193 if len(pubs_list) == 0: |
| 194 print "Pubs list is empty" |
| 195 failed |= True |
| 196 |
| 197 failed |= CheckSets(gdb_index, gold_index, "gdb index", "gold index") |
| 198 failed |= CheckSets(pubs_list, gold_index, "pubs list", "gold index") |
| 199 failed |= CheckSets(pubs_list, gdb_index, "pubs list", "gdb index") |
| 200 |
| 201 if failed: |
| 202 print "Test failed" |
| 203 sys.exit(1) |
| 204 |
| 205 |
| 206 if __name__ == '__main__': |
| 207 main(sys.argv) |
OLD | NEW |