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 29from __future__ import print_function 30import sys 31import os 32import popen2 33import re 34 35gdb_cmd = 'kgdb %(p)s/kernel.debug %(core)s | tee /tmp/gdb.log' 36#GDB regex 37filenamere = re.compile(r'filename\s+=\s+0x[0-9a-f]+\s("(?P<fn>[^"]+)"|(?P<error><[^>]*>))', re.M) 38addressre = re.compile(r'address\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) 39nextre = re.compile(r'tqe_next\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) 40printre = re.compile(r'\$\d+\s+=\s+') 41 42#Paths to search for ko's/debugs 43kld_debug_paths = [] 44 45if len(sys.argv[1:]) < 2: 46 print('Usage: prog <kerncomp> <core> [<paths>]') 47 sys.exit(1) 48 49#Get the base modules path 50pfs = sys.argv[1].split('/') 51try: 52 i = 0 53 while 1: 54 i = i + pfs[i:].index('sys') + 1 55except: 56 pass 57 58if i == -1: 59 sys.stderr.write("No sys dir in kernel source path: %s\n" % sys.argv[1]) 60 sys.exit(0) 61 62kld_debug_paths.append('/'.join(pfs[:i] + ['modules'])) 63kld_debug_paths.append(sys.argv[1]) 64#kld_debug_paths.append(sys.argv[3:]) 65gdb_cmd = gdb_cmd % {'p': sys.argv[1], 'core': sys.argv[2] } 66 67#Start gdb 68gdb = popen2.popen4(gdb_cmd) 69 70def searchfor(inp, re, j = 0, l = None): 71 """searchfor(inp, re, j, l): Searches for regex re in inp. It will 72automatically add more lines. If j is set, the lines will be joined together. 73l can provide a starting line to help search against. Return value is a 74tuple of the last line, and the match if any.""" 75 ret = None 76 if not l: 77 l = inp.readline() 78 ret = re.search(l) 79 while l and not ret: 80 if j: 81 l += inp.readline() 82 else: 83 l = inp.readline() 84 ret = re.search(l) 85 86 return (l, ret) 87 88def get_addresses(inp, out): 89 """get_addresses(inp, out): It will search for addresses from gdb. 90inp and out, are the gdb input and output respectively. Return value is 91a list of tuples. The tuples contain the filename and the address the 92filename was loaded.""" 93 addr = [] 94 nxad = 1 95 while nxad: 96 if nxad == 1: 97 out.write("print linker_files.tqh_first[0]\n") 98 else: 99 out.write("print *(struct linker_file *)%d\n" % nxad) 100 out.flush() 101 l = searchfor(inp, printre)[0] 102 l, fn = searchfor(inp, filenamere, 1, l) 103 if not fn.group('fn'): 104 sys.stderr.write("got error: %s\n" % fn.group('error')) 105 nxad = 0 106 else: 107 l, ad = searchfor(inp, addressre, 1, l) 108 l, nx = searchfor(inp, nextre, 1, l) 109 addr.append((fn.group('fn'), long(ad.group('ad'), 16))) 110 nxad = long(nx.group('ad'), 16) 111 112 return addr 113 114#Get the addresses 115addr = get_addresses(gdb[0], gdb[1]) 116 117#Pass through the resulting addresses, skipping the kernel. 118for i in addr[1:]: 119 for j in kld_debug_paths: 120 #Try .debug first. 121 p = popen2.popen4('find %s -type f -name "%s.debug"' % (j, i[0]))[0].read().strip() 122 if p: 123 break 124 #Try just .ko if .debug wasn't found. 125 p = popen2.popen4('find %s -type f -name "%s"' % (j, i[0]))[0].read().strip() 126 if p: 127 break 128 129 if not p: 130 #Tell our user that we couldn't find it. 131 a = i[1] 132 sys.stderr.write("Can't find module: %s (addr: %d + header)\n" % (i[0], a)) 133 print('#add-symbol-file <file>', a, '#add header') 134 continue 135 136 #j = popen2.popen4('objdump --section-headers /boot/kernel/%s | grep "\.text"' % i[0])[0].read().strip().split() 137 #Output the necessary information 138 j = popen2.popen4('objdump --section-headers "%s" | grep "\.text"' % p)[0].read().strip().split() 139 try: 140 a = int(j[5], 16) 141 print('add-symbol-file', p, i[1] + a) 142 except IndexError: 143 sys.stderr.write('Bad file: %s, address: %d\n' % (i[0], i[1])) 144