1133123Sjmg#!/usr/local/bin/python
2133123Sjmg#
3133123Sjmg# Copyright 2004 John-Mark Gurney
4133123Sjmg# All rights reserved.
5133123Sjmg#
6133123Sjmg# Redistribution and use in source and binary forms, with or without
7133123Sjmg# modification, are permitted provided that the following conditions
8133123Sjmg# are met:
9133123Sjmg# 1. Redistributions of source code must retain the above copyright
10133123Sjmg#    notice, this list of conditions and the following disclaimer.
11133123Sjmg# 2. Redistributions in binary form must reproduce the above copyright
12133123Sjmg#    notice, this list of conditions and the following disclaimer in the
13133123Sjmg#    documentation and/or other materials provided with the distribution.
14133123Sjmg#
15133123Sjmg# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16133123Sjmg# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17133123Sjmg# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18133123Sjmg# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19133123Sjmg# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20133123Sjmg# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21133123Sjmg# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22133123Sjmg# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23133123Sjmg# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24133123Sjmg# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25133123Sjmg# SUCH DAMAGE.
26133123Sjmg#
27133123Sjmg# $FreeBSD$
28133123Sjmg
29133123Sjmgimport sys
30133123Sjmgimport os
31133123Sjmgimport popen2
32133123Sjmgimport re
33133123Sjmg
34143864Sjmggdb_cmd = 'kgdb %(p)s/kernel.debug %(core)s | tee /tmp/gdb.log'
35133123Sjmg#GDB regex
36133123Sjmgfilenamere = re.compile(r'filename\s+=\s+0x[0-9a-f]+\s("(?P<fn>[^"]+)"|(?P<error><[^>]*>))', re.M)
37133123Sjmgaddressre = re.compile(r'address\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M)
38133123Sjmgnextre = re.compile(r'tqe_next\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M)
39133123Sjmgprintre = re.compile(r'\$\d+\s+=\s+')
40133123Sjmg
41133123Sjmg#Paths to search for ko's/debugs
42133123Sjmgkld_debug_paths = []
43133123Sjmg
44133123Sjmgif len(sys.argv[1:]) < 2:
45133123Sjmg	print 'Usage: prog <kerncomp> <core> [<paths>]'
46133123Sjmg	sys.exit(1)
47133123Sjmg
48133123Sjmg#Get the base modules path
49133123Sjmgpfs = sys.argv[1].split('/')
50133123Sjmgtry:
51133123Sjmg	i = 0
52133123Sjmg	while 1:
53133123Sjmg		i = i + pfs[i:].index('sys') + 1
54133123Sjmgexcept:
55133123Sjmg	pass
56133123Sjmg
57133123Sjmgif i == -1:
58133123Sjmg	sys.stderr.write("No sys dir in kernel source path: %s\n" % sys.argv[1])
59133123Sjmg	sys.exit(0)
60133123Sjmg
61133123Sjmgkld_debug_paths.append('/'.join(pfs[:i] + ['modules']))
62133123Sjmgkld_debug_paths.append(sys.argv[1])
63133123Sjmg#kld_debug_paths.append(sys.argv[3:])
64143864Sjmggdb_cmd = gdb_cmd % {'p': sys.argv[1], 'core': sys.argv[2] }
65133123Sjmg
66133123Sjmg#Start gdb
67133123Sjmggdb = popen2.popen4(gdb_cmd)
68133123Sjmg
69133123Sjmgdef searchfor(inp, re, j = 0, l = None):
70133123Sjmg	"""searchfor(inp, re, j, l):  Searches for regex re in inp.  It will
71228975Suqsautomatically add more lines.  If j is set, the lines will be joined together.
72133123Sjmgl can provide a starting line to help search against.  Return value is a
73228975Suqstuple of the last line, and the match if any."""
74133123Sjmg	ret = None
75133123Sjmg	if not l:
76133123Sjmg		l = inp.readline()
77133123Sjmg	ret = re.search(l)
78133123Sjmg	while l and not ret:
79133123Sjmg		if j:
80133123Sjmg			l += inp.readline()
81133123Sjmg		else:
82133123Sjmg			l = inp.readline()
83133123Sjmg		ret = re.search(l)
84133123Sjmg
85133123Sjmg	return (l, ret)
86133123Sjmg
87133123Sjmgdef get_addresses(inp, out):
88133123Sjmg	"""get_addresses(inp, out):  It will search for addresses from gdb.
89133123Sjmginp and out, are the gdb input and output respectively.  Return value is
90228975Suqsa list of tuples.  The tuples contain the filename and the address the
91133123Sjmgfilename was loaded."""
92133123Sjmg	addr = []
93133123Sjmg	nxad = 1
94133123Sjmg	while nxad:
95133123Sjmg		if nxad == 1:
96133123Sjmg			out.write("print linker_files.tqh_first[0]\n")
97133123Sjmg		else:
98133123Sjmg			out.write("print *(struct linker_file *)%d\n" % nxad)
99133123Sjmg		out.flush()
100133123Sjmg		l = searchfor(inp, printre)[0]
101133123Sjmg		l, fn = searchfor(inp, filenamere, 1, l)
102133123Sjmg		if not fn.group('fn'):
103133123Sjmg			sys.stderr.write("got error: %s\n" % fn.group('error'))
104133123Sjmg			nxad = 0
105133123Sjmg		else:
106133123Sjmg			l, ad = searchfor(inp, addressre, 1, l)
107133123Sjmg			l, nx = searchfor(inp, nextre, 1, l)
108133123Sjmg			addr.append((fn.group('fn'), long(ad.group('ad'), 16)))
109133123Sjmg			nxad = long(nx.group('ad'), 16)
110133123Sjmg
111133123Sjmg	return addr
112133123Sjmg
113133123Sjmg#Get the addresses
114133123Sjmgaddr = get_addresses(gdb[0], gdb[1])
115133123Sjmg
116133123Sjmg#Pass through the resulting addresses, skipping the kernel.
117133123Sjmgfor i in addr[1:]:
118133123Sjmg	for j in kld_debug_paths:
119133123Sjmg		#Try .debug first.
120133123Sjmg		p = popen2.popen4('find %s -type f -name "%s.debug"' % (j, i[0]))[0].read().strip()
121133123Sjmg		if p:
122133123Sjmg			break
123133123Sjmg		#Try just .ko if .debug wasn't found.
124133123Sjmg		p = popen2.popen4('find %s -type f -name "%s"' % (j, i[0]))[0].read().strip()
125133123Sjmg		if p:
126133123Sjmg			break
127133123Sjmg
128133123Sjmg	if not p:
129133123Sjmg		#Tell our user that we couldn't find it.
130133123Sjmg		a = i[1]
131133123Sjmg		sys.stderr.write("Can't find module: %s (addr: %d + header)\n" % (i[0], a))
132133123Sjmg		print '#add-symbol-file <file>', a, '#add header'
133133123Sjmg		continue
134133123Sjmg
135133123Sjmg	#j = popen2.popen4('objdump --section-headers /boot/kernel/%s | grep "\.text"' % i[0])[0].read().strip().split()
136133123Sjmg	#Output the necessary information
137133123Sjmg	j = popen2.popen4('objdump --section-headers "%s" | grep "\.text"' % p)[0].read().strip().split()
138133123Sjmg	try:
139133123Sjmg		a = int(j[5], 16)
140133123Sjmg		print 'add-symbol-file', p, i[1] + a
141133123Sjmg	except IndexError:
142133123Sjmg		sys.stderr.write('Bad file: %s, address: %d\n' % (i[0], i[1]))
143