GDB (API)
|
00001 #! /usr/bin/env python 00002 00003 # Copyright (C) 2011-2013 Free Software Foundation, Inc. 00004 # 00005 # This file is part of GDB. 00006 # 00007 # This program is free software; you can redistribute it and/or modify 00008 # it under the terms of the GNU General Public License as published by 00009 # the Free Software Foundation; either version 3 of the License, or 00010 # (at your option) any later version. 00011 # 00012 # This program is distributed in the hope that it will be useful, 00013 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 # GNU General Public License for more details. 00016 # 00017 # You should have received a copy of the GNU General Public License 00018 # along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 00020 # This program requires readelf, gdb and objcopy. The default values are gdb 00021 # from the build tree and objcopy and readelf from $PATH. They may be 00022 # overridden by setting environment variables GDB, READELF and OBJCOPY 00023 # respectively. We assume the current directory is either $obj/gdb or 00024 # $obj/gdb/testsuite. 00025 # 00026 # Example usage: 00027 # 00028 # bash$ cd $objdir/gdb/testsuite 00029 # bash$ python test_pubnames_and_indexes.py <binary_name> 00030 00031 """test_pubnames_and_indexes.py 00032 00033 Test that the gdb_index produced by gold is identical to the gdb_index 00034 produced by gdb itself. 00035 00036 Further check that the pubnames and pubtypes produced by gcc are identical 00037 to those that gdb produces. 00038 00039 Finally, check that all strings are canonicalized identically. 00040 """ 00041 00042 __author__ = 'saugustine@google.com (Sterling Augustine)' 00043 00044 import os 00045 import subprocess 00046 import sys 00047 00048 OBJCOPY = None 00049 READELF = None 00050 GDB = None 00051 00052 def get_pub_info(filename, readelf_option): 00053 """Parse and return all the pubnames or pubtypes produced by readelf with the 00054 given option. 00055 """ 00056 readelf = subprocess.Popen([READELF, '--debug-dump=' + readelf_option, 00057 filename], stdout=subprocess.PIPE) 00058 pubnames = [] 00059 00060 in_list = False; 00061 for line in readelf.stdout: 00062 fields = line.split(None, 1) 00063 if (len(fields) == 2 and fields[0] == 'Offset' 00064 and fields[1].strip() == 'Name'): 00065 in_list = True 00066 # Either a blank-line or a new Length field terminates the current section. 00067 elif (len(fields) == 0 or fields[0] == 'Length:'): 00068 in_list = False; 00069 elif (in_list): 00070 pubnames.append(fields[1].strip()) 00071 00072 readelf.wait() 00073 return pubnames 00074 00075 00076 def get_gdb_index(filename): 00077 """Use readelf to dump the gdb index and collect the types and names""" 00078 readelf = subprocess.Popen([READELF, '--debug-dump=gdb_index', 00079 filename], stdout=subprocess.PIPE) 00080 index_symbols = [] 00081 symbol_table_started = False 00082 for line in readelf.stdout: 00083 if (line == 'Symbol table:\n'): 00084 symbol_table_started = True; 00085 elif (symbol_table_started): 00086 # Readelf prints gdb-index lines formatted like so: 00087 # [ 4] two::c2<double>::c2: 0 00088 # So take the string between the first close bracket and the last colon. 00089 index_symbols.append(line[line.find(']') + 2: line.rfind(':')]) 00090 00091 readelf.wait() 00092 return index_symbols 00093 00094 00095 def CheckSets(list0, list1, name0, name1): 00096 """Report any setwise differences between the two lists""" 00097 00098 if len(list0) == 0 or len(list1) == 0: 00099 return False 00100 00101 difference0 = set(list0) - set(list1) 00102 if len(difference0) != 0: 00103 print "Elements in " + name0 + " but not " + name1 + ": (", 00104 print len(difference0), 00105 print ")" 00106 for element in difference0: 00107 print " " + element 00108 00109 difference1 = set(list1) - set(list0) 00110 if len(difference1) != 0: 00111 print "Elements in " + name1 + " but not " + name0 + ": (", 00112 print len(difference1), 00113 print ")" 00114 for element in difference1: 00115 print " " + element 00116 00117 if (len(difference0) != 0 or len(difference1) != 0): 00118 return True 00119 00120 print name0 + " and " + name1 + " are identical." 00121 return False 00122 00123 00124 def find_executables(): 00125 """Find the copies of readelf, objcopy and gdb to use.""" 00126 # Executable finding logic follows cc-with-index.sh 00127 global READELF 00128 READELF = os.getenv('READELF') 00129 if READELF is None: 00130 READELF = 'readelf' 00131 global OBJCOPY 00132 OBJCOPY = os.getenv('OBJCOPY') 00133 if OBJCOPY is None: 00134 OBJCOPY = 'objcopy' 00135 00136 global GDB 00137 GDB = os.getenv('GDB') 00138 if (GDB is None): 00139 if os.path.isfile('./gdb') and os.access('./gdb', os.X_OK): 00140 GDB = './gdb' 00141 elif os.path.isfile('../gdb') and os.access('../gdb', os.X_OK): 00142 GDB = '../gdb' 00143 elif os.path.isfile('../../gdb') and os.access('../../gdb', os.X_OK): 00144 GDB = '../../gdb' 00145 else: 00146 # Punt and use the gdb in the path. 00147 GDB = 'gdb' 00148 00149 00150 def main(argv): 00151 """The main subprogram.""" 00152 if len(argv) != 2: 00153 print "Usage: test_pubnames_and_indexes.py <filename>" 00154 sys.exit(2) 00155 00156 find_executables(); 00157 00158 # Get the index produced by Gold--It should have been built into the binary. 00159 gold_index = get_gdb_index(argv[1]) 00160 00161 # Collect the pubnames and types list 00162 pubs_list = get_pub_info(argv[1], "pubnames") 00163 pubs_list = pubs_list + get_pub_info(argv[1], "pubtypes") 00164 00165 # Generate a .gdb_index with gdb 00166 gdb_index_file = argv[1] + '.gdb-generated-index' 00167 subprocess.check_call([OBJCOPY, '--remove-section', '.gdb_index', 00168 argv[1], gdb_index_file]) 00169 subprocess.check_call([GDB, '-batch', '-nx', gdb_index_file, 00170 '-ex', 'save gdb-index ' + os.path.dirname(argv[1]), 00171 '-ex', 'quit']) 00172 subprocess.check_call([OBJCOPY, '--add-section', 00173 '.gdb_index=' + gdb_index_file + '.gdb-index', 00174 gdb_index_file]) 00175 gdb_index = get_gdb_index(gdb_index_file) 00176 os.remove(gdb_index_file) 00177 os.remove(gdb_index_file + '.gdb-index') 00178 00179 failed = False 00180 gdb_index.sort() 00181 gold_index.sort() 00182 pubs_list.sort() 00183 00184 # Find the differences between the various indices. 00185 if len(gold_index) == 0: 00186 print "Gold index is empty" 00187 failed |= True 00188 00189 if len(gdb_index) == 0: 00190 print "Gdb index is empty" 00191 failed |= True 00192 00193 if len(pubs_list) == 0: 00194 print "Pubs list is empty" 00195 failed |= True 00196 00197 failed |= CheckSets(gdb_index, gold_index, "gdb index", "gold index") 00198 failed |= CheckSets(pubs_list, gold_index, "pubs list", "gold index") 00199 failed |= CheckSets(pubs_list, gdb_index, "pubs list", "gdb index") 00200 00201 if failed: 00202 print "Test failed" 00203 sys.exit(1) 00204 00205 00206 if __name__ == '__main__': 00207 main(sys.argv)