xref: /minix3/external/bsd/bind/dist/lib/isc/backtrace.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: backtrace.c,v 1.7 2014/12/10 04:37:59 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id: backtrace.c,v 1.3 2009/09/02 23:48:02 tbox Exp  */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek /*! \file */
22*00b67f09SDavid van Moolenbroek 
23*00b67f09SDavid van Moolenbroek #include "config.h"
24*00b67f09SDavid van Moolenbroek 
25*00b67f09SDavid van Moolenbroek #include <string.h>
26*00b67f09SDavid van Moolenbroek #include <stdlib.h>
27*00b67f09SDavid van Moolenbroek #ifdef HAVE_LIBCTRACE
28*00b67f09SDavid van Moolenbroek #include <execinfo.h>
29*00b67f09SDavid van Moolenbroek #endif
30*00b67f09SDavid van Moolenbroek 
31*00b67f09SDavid van Moolenbroek #include <isc/backtrace.h>
32*00b67f09SDavid van Moolenbroek #include <isc/result.h>
33*00b67f09SDavid van Moolenbroek #include <isc/util.h>
34*00b67f09SDavid van Moolenbroek 
35*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_USEBACKTRACE
36*00b67f09SDavid van Moolenbroek /*
37*00b67f09SDavid van Moolenbroek  * Getting a back trace of a running process is tricky and highly platform
38*00b67f09SDavid van Moolenbroek  * dependent.  Our current approach is as follows:
39*00b67f09SDavid van Moolenbroek  * 1. If the system library supports the "backtrace()" function, use it.
40*00b67f09SDavid van Moolenbroek  * 2. Otherwise, if the compiler is gcc and the architecture is x86_64 or IA64,
41*00b67f09SDavid van Moolenbroek  *    then use gcc's (hidden) Unwind_Backtrace() function.  Note that this
42*00b67f09SDavid van Moolenbroek  *    function doesn't work for C programs on many other architectures.
43*00b67f09SDavid van Moolenbroek  * 3. Otherwise, if the architecture x86 or x86_64, try to unwind the stack
44*00b67f09SDavid van Moolenbroek  *    frame following frame pointers.  This assumes the executable binary
45*00b67f09SDavid van Moolenbroek  *    compiled with frame pointers; this is not always true for x86_64 (rather,
46*00b67f09SDavid van Moolenbroek  *    compiler optimizations often disable frame pointers).  The validation
47*00b67f09SDavid van Moolenbroek  *    checks in getnextframeptr() hopefully rejects bogus values stored in
48*00b67f09SDavid van Moolenbroek  *    the RBP register in such a case.  If the backtrace function itself crashes
49*00b67f09SDavid van Moolenbroek  *    due to this problem, the whole package should be rebuilt with
50*00b67f09SDavid van Moolenbroek  *    --disable-backtrace.
51*00b67f09SDavid van Moolenbroek  */
52*00b67f09SDavid van Moolenbroek #ifdef HAVE_LIBCTRACE
53*00b67f09SDavid van Moolenbroek #define BACKTRACE_LIBC
54*00b67f09SDavid van Moolenbroek #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__))
55*00b67f09SDavid van Moolenbroek #define BACKTRACE_GCC
56*00b67f09SDavid van Moolenbroek #elif defined(WIN32)
57*00b67f09SDavid van Moolenbroek #define BACKTRACE_WIN32
58*00b67f09SDavid van Moolenbroek #elif defined(__x86_64__) || defined(__i386__)
59*00b67f09SDavid van Moolenbroek #define BACKTRACE_X86STACK
60*00b67f09SDavid van Moolenbroek #else
61*00b67f09SDavid van Moolenbroek #define BACKTRACE_DISABLED
62*00b67f09SDavid van Moolenbroek #endif  /* HAVE_LIBCTRACE */
63*00b67f09SDavid van Moolenbroek #else	/* !ISC_PLATFORM_USEBACKTRACE */
64*00b67f09SDavid van Moolenbroek #define BACKTRACE_DISABLED
65*00b67f09SDavid van Moolenbroek #endif	/* ISC_PLATFORM_USEBACKTRACE */
66*00b67f09SDavid van Moolenbroek 
67*00b67f09SDavid van Moolenbroek #ifdef BACKTRACE_LIBC
68*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_gettrace(void ** addrs,int maxaddrs,int * nframes)69*00b67f09SDavid van Moolenbroek isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
70*00b67f09SDavid van Moolenbroek 	int n;
71*00b67f09SDavid van Moolenbroek 
72*00b67f09SDavid van Moolenbroek 	/*
73*00b67f09SDavid van Moolenbroek 	 * Validate the arguments: intentionally avoid using REQUIRE().
74*00b67f09SDavid van Moolenbroek 	 * See notes in backtrace.h.
75*00b67f09SDavid van Moolenbroek 	 */
76*00b67f09SDavid van Moolenbroek 	if (addrs == NULL || nframes == NULL)
77*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek 	/*
80*00b67f09SDavid van Moolenbroek 	 * backtrace(3) includes this function itself in the address array,
81*00b67f09SDavid van Moolenbroek 	 * which should be eliminated from the returned sequence.
82*00b67f09SDavid van Moolenbroek 	 */
83*00b67f09SDavid van Moolenbroek 	n = backtrace(addrs, maxaddrs);
84*00b67f09SDavid van Moolenbroek 	if (n < 2)
85*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTFOUND);
86*00b67f09SDavid van Moolenbroek 	n--;
87*00b67f09SDavid van Moolenbroek 	memmove(addrs, &addrs[1], sizeof(void *) * n);
88*00b67f09SDavid van Moolenbroek 	*nframes = n;
89*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
90*00b67f09SDavid van Moolenbroek }
91*00b67f09SDavid van Moolenbroek #elif defined(BACKTRACE_GCC)
92*00b67f09SDavid van Moolenbroek extern int _Unwind_Backtrace(void* fn, void* a);
93*00b67f09SDavid van Moolenbroek extern void* _Unwind_GetIP(void* ctx);
94*00b67f09SDavid van Moolenbroek 
95*00b67f09SDavid van Moolenbroek typedef struct {
96*00b67f09SDavid van Moolenbroek 	void **result;
97*00b67f09SDavid van Moolenbroek 	int max_depth;
98*00b67f09SDavid van Moolenbroek 	int skip_count;
99*00b67f09SDavid van Moolenbroek 	int count;
100*00b67f09SDavid van Moolenbroek } trace_arg_t;
101*00b67f09SDavid van Moolenbroek 
102*00b67f09SDavid van Moolenbroek static int
btcallback(void * uc,void * opq)103*00b67f09SDavid van Moolenbroek btcallback(void *uc, void *opq) {
104*00b67f09SDavid van Moolenbroek 	trace_arg_t *arg = (trace_arg_t *)opq;
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek 	if (arg->skip_count > 0)
107*00b67f09SDavid van Moolenbroek 		arg->skip_count--;
108*00b67f09SDavid van Moolenbroek 	else
109*00b67f09SDavid van Moolenbroek 		arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
110*00b67f09SDavid van Moolenbroek 	if (arg->count == arg->max_depth)
111*00b67f09SDavid van Moolenbroek 		return (5); /* _URC_END_OF_STACK */
112*00b67f09SDavid van Moolenbroek 
113*00b67f09SDavid van Moolenbroek 	return (0); /* _URC_NO_REASON */
114*00b67f09SDavid van Moolenbroek }
115*00b67f09SDavid van Moolenbroek 
116*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_gettrace(void ** addrs,int maxaddrs,int * nframes)117*00b67f09SDavid van Moolenbroek isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
118*00b67f09SDavid van Moolenbroek 	trace_arg_t arg;
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek 	/* Argument validation: see above. */
121*00b67f09SDavid van Moolenbroek 	if (addrs == NULL || nframes == NULL)
122*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
123*00b67f09SDavid van Moolenbroek 
124*00b67f09SDavid van Moolenbroek 	arg.skip_count = 1;
125*00b67f09SDavid van Moolenbroek 	arg.result = addrs;
126*00b67f09SDavid van Moolenbroek 	arg.max_depth = maxaddrs;
127*00b67f09SDavid van Moolenbroek 	arg.count = 0;
128*00b67f09SDavid van Moolenbroek 	_Unwind_Backtrace(btcallback, &arg);
129*00b67f09SDavid van Moolenbroek 
130*00b67f09SDavid van Moolenbroek 	*nframes = arg.count;
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
133*00b67f09SDavid van Moolenbroek }
134*00b67f09SDavid van Moolenbroek #elif defined(BACKTRACE_WIN32)
135*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_gettrace(void ** addrs,int maxaddrs,int * nframes)136*00b67f09SDavid van Moolenbroek isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
137*00b67f09SDavid van Moolenbroek 	unsigned long ftc = (unsigned long)maxaddrs;
138*00b67f09SDavid van Moolenbroek 
139*00b67f09SDavid van Moolenbroek 	*nframes = (int)CaptureStackBackTrace(1, ftc, addrs, NULL);
140*00b67f09SDavid van Moolenbroek 	return ISC_R_SUCCESS;
141*00b67f09SDavid van Moolenbroek }
142*00b67f09SDavid van Moolenbroek #elif defined(BACKTRACE_X86STACK)
143*00b67f09SDavid van Moolenbroek #ifdef __x86_64__
144*00b67f09SDavid van Moolenbroek static unsigned long
getrbp(void)145*00b67f09SDavid van Moolenbroek getrbp(void) {
146*00b67f09SDavid van Moolenbroek 	__asm("movq %rbp, %rax\n");
147*00b67f09SDavid van Moolenbroek }
148*00b67f09SDavid van Moolenbroek #endif
149*00b67f09SDavid van Moolenbroek 
150*00b67f09SDavid van Moolenbroek static void **
getnextframeptr(void ** sp)151*00b67f09SDavid van Moolenbroek getnextframeptr(void **sp) {
152*00b67f09SDavid van Moolenbroek 	void **newsp = (void **)*sp;
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek 	/*
155*00b67f09SDavid van Moolenbroek 	 * Perform sanity check for the new frame pointer, derived from
156*00b67f09SDavid van Moolenbroek 	 * google glog.  This can actually be bogus depending on compiler.
157*00b67f09SDavid van Moolenbroek 	 */
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek 	/* prohibit the stack frames from growing downwards */
160*00b67f09SDavid van Moolenbroek 	if (newsp <= sp)
161*00b67f09SDavid van Moolenbroek 		return (NULL);
162*00b67f09SDavid van Moolenbroek 
163*00b67f09SDavid van Moolenbroek 	/* A heuristics to reject "too large" frame: this actually happened. */
164*00b67f09SDavid van Moolenbroek 	if ((char *)newsp - (char *)sp > 100000)
165*00b67f09SDavid van Moolenbroek 		return (NULL);
166*00b67f09SDavid van Moolenbroek 
167*00b67f09SDavid van Moolenbroek 	/*
168*00b67f09SDavid van Moolenbroek 	 * Not sure if other checks used in glog are needed at this moment.
169*00b67f09SDavid van Moolenbroek 	 * For our purposes we don't have to consider non-contiguous frames,
170*00b67f09SDavid van Moolenbroek 	 * for example.
171*00b67f09SDavid van Moolenbroek 	 */
172*00b67f09SDavid van Moolenbroek 
173*00b67f09SDavid van Moolenbroek 	return (newsp);
174*00b67f09SDavid van Moolenbroek }
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_gettrace(void ** addrs,int maxaddrs,int * nframes)177*00b67f09SDavid van Moolenbroek isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
178*00b67f09SDavid van Moolenbroek 	int i = 0;
179*00b67f09SDavid van Moolenbroek 	void **sp;
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek 	/* Argument validation: see above. */
182*00b67f09SDavid van Moolenbroek 	if (addrs == NULL || nframes == NULL)
183*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek #ifdef __x86_64__
186*00b67f09SDavid van Moolenbroek 	sp = (void **)getrbp();
187*00b67f09SDavid van Moolenbroek 	if (sp == NULL)
188*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTFOUND);
189*00b67f09SDavid van Moolenbroek 	/*
190*00b67f09SDavid van Moolenbroek 	 * sp is the frame ptr of this function itself due to the call to
191*00b67f09SDavid van Moolenbroek 	 * getrbp(), so need to unwind one frame for consistency.
192*00b67f09SDavid van Moolenbroek 	 */
193*00b67f09SDavid van Moolenbroek 	sp = getnextframeptr(sp);
194*00b67f09SDavid van Moolenbroek #else
195*00b67f09SDavid van Moolenbroek 	/*
196*00b67f09SDavid van Moolenbroek 	 * i386: the frame pointer is stored 2 words below the address for the
197*00b67f09SDavid van Moolenbroek 	 * first argument.  Note that the body of this function cannot be
198*00b67f09SDavid van Moolenbroek 	 * inlined since it depends on the address of the function argument.
199*00b67f09SDavid van Moolenbroek 	 */
200*00b67f09SDavid van Moolenbroek 	sp = (void **)(void *)&addrs - 2;
201*00b67f09SDavid van Moolenbroek #endif
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek 	while (sp != NULL && i < maxaddrs) {
204*00b67f09SDavid van Moolenbroek 		addrs[i++] = *(sp + 1);
205*00b67f09SDavid van Moolenbroek 		sp = getnextframeptr(sp);
206*00b67f09SDavid van Moolenbroek 	}
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek 	*nframes = i;
209*00b67f09SDavid van Moolenbroek 
210*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
211*00b67f09SDavid van Moolenbroek }
212*00b67f09SDavid van Moolenbroek #elif defined(BACKTRACE_DISABLED)
213*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_gettrace(void ** addrs,int maxaddrs,int * nframes)214*00b67f09SDavid van Moolenbroek isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) {
215*00b67f09SDavid van Moolenbroek 	/* Argument validation: see above. */
216*00b67f09SDavid van Moolenbroek 	if (addrs == NULL || nframes == NULL)
217*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek 	UNUSED(maxaddrs);
220*00b67f09SDavid van Moolenbroek 
221*00b67f09SDavid van Moolenbroek 	return (ISC_R_NOTIMPLEMENTED);
222*00b67f09SDavid van Moolenbroek }
223*00b67f09SDavid van Moolenbroek #endif
224*00b67f09SDavid van Moolenbroek 
225*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_getsymbolfromindex(int index,const void ** addrp,const char ** symbolp)226*00b67f09SDavid van Moolenbroek isc_backtrace_getsymbolfromindex(int index, const void **addrp,
227*00b67f09SDavid van Moolenbroek 				 const char **symbolp)
228*00b67f09SDavid van Moolenbroek {
229*00b67f09SDavid van Moolenbroek 	REQUIRE(addrp != NULL && *addrp == NULL);
230*00b67f09SDavid van Moolenbroek 	REQUIRE(symbolp != NULL && *symbolp == NULL);
231*00b67f09SDavid van Moolenbroek 
232*00b67f09SDavid van Moolenbroek 	if (index < 0 || index >= isc__backtrace_nsymbols)
233*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
234*00b67f09SDavid van Moolenbroek 
235*00b67f09SDavid van Moolenbroek 	*addrp = isc__backtrace_symtable[index].addr;
236*00b67f09SDavid van Moolenbroek 	*symbolp = isc__backtrace_symtable[index].symbol;
237*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
238*00b67f09SDavid van Moolenbroek }
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek static int
symtbl_compare(const void * addr,const void * entryarg)241*00b67f09SDavid van Moolenbroek symtbl_compare(const void *addr, const void *entryarg) {
242*00b67f09SDavid van Moolenbroek 	const isc_backtrace_symmap_t *entry = entryarg;
243*00b67f09SDavid van Moolenbroek 	const isc_backtrace_symmap_t *end =
244*00b67f09SDavid van Moolenbroek 		&isc__backtrace_symtable[isc__backtrace_nsymbols - 1];
245*00b67f09SDavid van Moolenbroek 
246*00b67f09SDavid van Moolenbroek 	if (isc__backtrace_nsymbols == 1 || entry == end) {
247*00b67f09SDavid van Moolenbroek 		if (addr >= entry->addr) {
248*00b67f09SDavid van Moolenbroek 			/*
249*00b67f09SDavid van Moolenbroek 			 * If addr is equal to or larger than that of the last
250*00b67f09SDavid van Moolenbroek 			 * entry of the table, we cannot be sure if this is
251*00b67f09SDavid van Moolenbroek 			 * within a valid range so we consider it valid.
252*00b67f09SDavid van Moolenbroek 			 */
253*00b67f09SDavid van Moolenbroek 			return (0);
254*00b67f09SDavid van Moolenbroek 		}
255*00b67f09SDavid van Moolenbroek 		return (-1);
256*00b67f09SDavid van Moolenbroek 	}
257*00b67f09SDavid van Moolenbroek 
258*00b67f09SDavid van Moolenbroek 	/* entry + 1 is a valid entry from now on. */
259*00b67f09SDavid van Moolenbroek 	if (addr < entry->addr)
260*00b67f09SDavid van Moolenbroek 		return (-1);
261*00b67f09SDavid van Moolenbroek 	else if (addr >= (entry + 1)->addr)
262*00b67f09SDavid van Moolenbroek 		return (1);
263*00b67f09SDavid van Moolenbroek 	return (0);
264*00b67f09SDavid van Moolenbroek }
265*00b67f09SDavid van Moolenbroek 
266*00b67f09SDavid van Moolenbroek isc_result_t
isc_backtrace_getsymbol(const void * addr,const char ** symbolp,unsigned long * offsetp)267*00b67f09SDavid van Moolenbroek isc_backtrace_getsymbol(const void *addr, const char **symbolp,
268*00b67f09SDavid van Moolenbroek 			unsigned long *offsetp)
269*00b67f09SDavid van Moolenbroek {
270*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
271*00b67f09SDavid van Moolenbroek 	isc_backtrace_symmap_t *found;
272*00b67f09SDavid van Moolenbroek 
273*00b67f09SDavid van Moolenbroek 	/*
274*00b67f09SDavid van Moolenbroek 	 * Validate the arguments: intentionally avoid using REQUIRE().
275*00b67f09SDavid van Moolenbroek 	 * See notes in backtrace.h.
276*00b67f09SDavid van Moolenbroek 	 */
277*00b67f09SDavid van Moolenbroek 	if (symbolp == NULL || *symbolp != NULL || offsetp == NULL)
278*00b67f09SDavid van Moolenbroek 		return (ISC_R_FAILURE);
279*00b67f09SDavid van Moolenbroek 
280*00b67f09SDavid van Moolenbroek 	if (isc__backtrace_nsymbols < 1)
281*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTFOUND);
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	/*
284*00b67f09SDavid van Moolenbroek 	 * Search the table for the entry that meets:
285*00b67f09SDavid van Moolenbroek 	 * entry.addr <= addr < next_entry.addr.
286*00b67f09SDavid van Moolenbroek 	 */
287*00b67f09SDavid van Moolenbroek 	found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols,
288*00b67f09SDavid van Moolenbroek 			sizeof(isc__backtrace_symtable[0]), symtbl_compare);
289*00b67f09SDavid van Moolenbroek 	if (found == NULL)
290*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTFOUND;
291*00b67f09SDavid van Moolenbroek 	else {
292*00b67f09SDavid van Moolenbroek 		*symbolp = found->symbol;
293*00b67f09SDavid van Moolenbroek 		*offsetp = (unsigned long) ((const char *)addr -
294*00b67f09SDavid van Moolenbroek 					    (char *)found->addr);
295*00b67f09SDavid van Moolenbroek 	}
296*00b67f09SDavid van Moolenbroek 
297*00b67f09SDavid van Moolenbroek 	return (result);
298*00b67f09SDavid van Moolenbroek }
299