1#!/usr/local/bin/python 2# 3# Copyright 2004 John-Mark Gurney 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# $FreeBSD$ 28 29import sys 30import os 31import popen2 32import re 33 34gdb_cmd = 'kgdb %(p)s/kernel.debug %(core)s | tee /tmp/gdb.log' 35#GDB regex 36filenamere = re.compile(r'filename\s+=\s+0x[0-9a-f]+\s("(?P<fn>[^"]+)"|(?P<error><[^>]*>))', re.M) 37addressre = re.compile(r'address\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) 38nextre = re.compile(r'tqe_next\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) 39printre = re.compile(r'\$\d+\s+=\s+') 40 41#Paths to search for ko's/debugs 42kld_debug_paths = [] 43 44if len(sys.argv[1:]) < 2: 45 print 'Usage: prog <kerncomp> <core> [<paths>]' 46 sys.exit(1) 47 48#Get the base modules path 49pfs = sys.argv[1].split('/') 50try: 51 i = 0 52 while 1: 53 i = i + pfs[i:].index('sys') + 1 54except: 55 pass 56 57if i == -1: 58 sys.stderr.write("No sys dir in kernel source path: %s\n" % sys.argv[1]) 59 sys.exit(0) 60 61kld_debug_paths.append('/'.join(pfs[:i] + ['modules'])) 62kld_debug_paths.append(sys.argv[1]) 63#kld_debug_paths.append(sys.argv[3:]) 64gdb_cmd = gdb_cmd % {'p': sys.argv[1], 'core': sys.argv[2] } 65 66#Start gdb 67gdb = popen2.popen4(gdb_cmd) 68 69def searchfor(inp, re, j = 0, l = None): 70 """searchfor(inp, re, j, l): Searches for regex re in inp. It will 71automatically add more lines. If j is set, the lines will be joined together. 72l can provide a starting line to help search against. Return value is a 73tuple of the last line, and the match if any.""" 74 ret = None 75 if not l: 76 l = inp.readline() 77 ret = re.search(l) 78 while l and not ret: 79 if j: 80 l += inp.readline() 81 else: 82 l = inp.readline() 83 ret = re.search(l) 84 85 return (l, ret) 86 87def get_addresses(inp, out): 88 """get_addresses(inp, out): It will search for addresses from gdb. 89inp and out, are the gdb input and output respectively. Return value is 90a list of tuples. The tuples contain the filename and the address the 91filename was loaded.""" 92 addr = [] 93 nxad = 1 94 while nxad: 95 if nxad == 1: 96 out.write("print linker_files.tqh_first[0]\n") 97 else: 98 out.write("print *(struct linker_file *)%d\n" % nxad) 99 out.flush() 100 l = searchfor(inp, printre)[0] 101 l, fn = searchfor(inp, filenamere, 1, l) 102 if not fn.group('fn'): 103 sys.stderr.write("got error: %s\n" % fn.group('error')) 104 nxad = 0 105 else: 106 l, ad = searchfor(inp, addressre, 1, l) 107 l, nx = searchfor(inp, nextre, 1, l) 108 addr.append((fn.group('fn'), long(ad.group('ad'), 16))) 109 nxad = long(nx.group('ad'), 16) 110 111 return addr 112 113#Get the addresses 114addr = get_addresses(gdb[0], gdb[1]) 115 116#Pass through the resulting addresses, skipping the kernel. 117for i in addr[1:]: 118 for j in kld_debug_paths: 119 #Try .debug first. 120 p = popen2.popen4('find %s -type f -name "%s.debug"' % (j, i[0]))[0].read().strip() 121 if p: 122 break 123 #Try just .ko if .debug wasn't found. 124 p = popen2.popen4('find %s -type f -name "%s"' % (j, i[0]))[0].read().strip() 125 if p: 126 break 127 128 if not p: 129 #Tell our user that we couldn't find it. 130 a = i[1] 131 sys.stderr.write("Can't find module: %s (addr: %d + header)\n" % (i[0], a)) 132 print '#add-symbol-file <file>', a, '#add header' 133 continue 134 135 #j = popen2.popen4('objdump --section-headers /boot/kernel/%s | grep "\.text"' % i[0])[0].read().strip().split() 136 #Output the necessary information 137 j = popen2.popen4('objdump --section-headers "%s" | grep "\.text"' % p)[0].read().strip().split() 138 try: 139 a = int(j[5], 16) 140 print 'add-symbol-file', p, i[1] + a 141 except IndexError: 142 sys.stderr.write('Bad file: %s, address: %d\n' % (i[0], i[1])) 143