GDB (API)
/home/stan/gdb/src/gdb/contrib/test_pubnames_and_indexes.py
Go to the documentation of this file.
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)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines