xref: /titanic_51/usr/src/lib/libtnfctl/comb.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994, by Sun Microsytems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Functions that know how to create and decode combinations that are
30*7c478bd9Sstevel@tonic-gate  * used for connecting probe functions.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
34*7c478bd9Sstevel@tonic-gate #define	NDEBUG	1
35*7c478bd9Sstevel@tonic-gate #endif
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <stdio.h>
38*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate #include <search.h>
41*7c478bd9Sstevel@tonic-gate #include <assert.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
45*7c478bd9Sstevel@tonic-gate #include "dbg.h"
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Typedefs
50*7c478bd9Sstevel@tonic-gate  */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate typedef struct comb_callinfo {
53*7c478bd9Sstevel@tonic-gate 	unsigned	offset;
54*7c478bd9Sstevel@tonic-gate 	unsigned	shift;	/* shift right <n> bits */
55*7c478bd9Sstevel@tonic-gate 	unsigned	mask;
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate } comb_callinfo_t;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate typedef struct comb_calltmpl {
60*7c478bd9Sstevel@tonic-gate 	uintptr_t	entry;
61*7c478bd9Sstevel@tonic-gate 	uintptr_t	down;
62*7c478bd9Sstevel@tonic-gate 	uintptr_t	next;
63*7c478bd9Sstevel@tonic-gate 	uintptr_t	end;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate } comb_calltmpl_t;
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate typedef struct comb_key {
68*7c478bd9Sstevel@tonic-gate 	comb_op_t	op;
69*7c478bd9Sstevel@tonic-gate 	uintptr_t	down;
70*7c478bd9Sstevel@tonic-gate 	uintptr_t	next;
71*7c478bd9Sstevel@tonic-gate 	uintptr_t	comb;
72*7c478bd9Sstevel@tonic-gate } comb_key_t;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate typedef struct decode_key {
75*7c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
76*7c478bd9Sstevel@tonic-gate 	char		**name_ptrs;
77*7c478bd9Sstevel@tonic-gate 	uintptr_t	*func_addrs;
78*7c478bd9Sstevel@tonic-gate } decode_key_t;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * Global - defined in assembler file
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate extern comb_callinfo_t prb_callinfo;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate extern void	 prb_chain_entry(void);
87*7c478bd9Sstevel@tonic-gate extern void	 prb_chain_down(void);
88*7c478bd9Sstevel@tonic-gate extern void	 prb_chain_next(void);
89*7c478bd9Sstevel@tonic-gate extern void	 prb_chain_end(void);
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static comb_calltmpl_t calltmpl[PRB_COMB_COUNT] = {
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 		(uintptr_t) prb_chain_entry,
94*7c478bd9Sstevel@tonic-gate 		(uintptr_t) prb_chain_down,
95*7c478bd9Sstevel@tonic-gate 		(uintptr_t) prb_chain_next,
96*7c478bd9Sstevel@tonic-gate 		(uintptr_t) prb_chain_end}
97*7c478bd9Sstevel@tonic-gate };
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * Declarations
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t decode(tnfctl_handle_t *hndl, uintptr_t addr,
104*7c478bd9Sstevel@tonic-gate 	char ***func_names, uintptr_t **func_addrs);
105*7c478bd9Sstevel@tonic-gate static boolean_t find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down,
106*7c478bd9Sstevel@tonic-gate 	uintptr_t next, uintptr_t * comb_p);
107*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t build(tnfctl_handle_t *hndl, comb_op_t op,
108*7c478bd9Sstevel@tonic-gate 	uintptr_t down, uintptr_t next, uintptr_t * comb_p);
109*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t add(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down,
110*7c478bd9Sstevel@tonic-gate 	uintptr_t next, uintptr_t comb);
111*7c478bd9Sstevel@tonic-gate static int comb_compare(const void *a, const void *b);
112*7c478bd9Sstevel@tonic-gate static int decode_compare(const void *v0p, const void *v1p);
113*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t iscomb(tnfctl_handle_t *hndl, uintptr_t addr,
114*7c478bd9Sstevel@tonic-gate 	uintptr_t *down_p, uintptr_t *next_p, boolean_t *ret_val);
115*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t findname(tnfctl_handle_t *hndl, uintptr_t addr,
116*7c478bd9Sstevel@tonic-gate 	char **ret_name);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
120*7c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */
121*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /*
124*7c478bd9Sstevel@tonic-gate  * _tnfctl_comb_build() - finds (or builds) a combination satisfing the op,
125*7c478bd9Sstevel@tonic-gate  * down and next constraints of the caller.
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
128*7c478bd9Sstevel@tonic-gate _tnfctl_comb_build(tnfctl_handle_t *hndl, comb_op_t op,
129*7c478bd9Sstevel@tonic-gate 	uintptr_t down, uintptr_t next, uintptr_t *comb_p)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	*comb_p = NULL;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_build_start, "libtnfctl",
136*7c478bd9Sstevel@tonic-gate 			"start _tnfctl_comb_build; sunw%verbosity 1");
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (find(hndl, op, down, next, comb_p)) {
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_1(_tnfctl_comb_build_end, "libtnfctl",
141*7c478bd9Sstevel@tonic-gate 			"end _tnfctl_comb_build; sunw%verbosity 1",
142*7c478bd9Sstevel@tonic-gate 			tnf_opaque, found_comb_at, *comb_p);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 	prexstat = build(hndl, op, down, next, comb_p);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_1(_tnfctl_comb_build_end, "libtnfctl",
149*7c478bd9Sstevel@tonic-gate 			"end _tnfctl_comb_build; sunw%verbosity 1",
150*7c478bd9Sstevel@tonic-gate 			tnf_opaque, built_comb_at, *comb_p);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	return (prexstat);
153*7c478bd9Sstevel@tonic-gate }
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate /*
157*7c478bd9Sstevel@tonic-gate  * _tnfctl_comb_decode() - returns a string describing the probe functions
158*7c478bd9Sstevel@tonic-gate  * NOTE - the string is for reference purposes ONLY, it should not be freed
159*7c478bd9Sstevel@tonic-gate  * by the client.
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
162*7c478bd9Sstevel@tonic-gate _tnfctl_comb_decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names,
163*7c478bd9Sstevel@tonic-gate 	uintptr_t **func_addrs)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_decode_start, "libtnfctl",
168*7c478bd9Sstevel@tonic-gate 			"start _tnfctl_comb_decode; sunw%verbosity 2");
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	prexstat = decode(hndl, addr, func_names, func_addrs);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_decode_end, "libtnfctl",
173*7c478bd9Sstevel@tonic-gate 			"end _tnfctl_comb_decode; sunw%verbosity 2");
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	return (prexstat);
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
180*7c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */
181*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate /*
184*7c478bd9Sstevel@tonic-gate  * if combination has been decoded, return decoded info., else
185*7c478bd9Sstevel@tonic-gate  * decode combination and cache information
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
188*7c478bd9Sstevel@tonic-gate decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names,
189*7c478bd9Sstevel@tonic-gate 	uintptr_t **func_addrs)
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat = TNFCTL_ERR_NONE;
192*7c478bd9Sstevel@tonic-gate 	decode_key_t	key;
193*7c478bd9Sstevel@tonic-gate 	decode_key_t	*new_p = NULL;
194*7c478bd9Sstevel@tonic-gate 	decode_key_t	**find_pp;
195*7c478bd9Sstevel@tonic-gate 	uintptr_t	down;
196*7c478bd9Sstevel@tonic-gate 	uintptr_t	next;
197*7c478bd9Sstevel@tonic-gate 	char 		*thisname = NULL;
198*7c478bd9Sstevel@tonic-gate 	boolean_t	is_combination;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/* see if we can find the previously decoded answer */
201*7c478bd9Sstevel@tonic-gate 	key.addr = addr;
202*7c478bd9Sstevel@tonic-gate 	find_pp = (decode_key_t **) tfind(&key, &hndl->decoderoot,
203*7c478bd9Sstevel@tonic-gate 			decode_compare);
204*7c478bd9Sstevel@tonic-gate 	if (find_pp) {
205*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_0(decode_1, "libtnfctl",
206*7c478bd9Sstevel@tonic-gate 			"sunw%verbosity 2; sunw%debug 'found existing'");
207*7c478bd9Sstevel@tonic-gate 		*func_names = (*find_pp)->name_ptrs;
208*7c478bd9Sstevel@tonic-gate 		*func_addrs = (*find_pp)->func_addrs;
209*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	new_p = (decode_key_t *) calloc(1, sizeof (decode_key_t));
213*7c478bd9Sstevel@tonic-gate 	if (!new_p)
214*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
215*7c478bd9Sstevel@tonic-gate 	new_p->addr = addr;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	prexstat = iscomb(hndl, addr, &down, &next, &is_combination);
218*7c478bd9Sstevel@tonic-gate 	if (prexstat)
219*7c478bd9Sstevel@tonic-gate 		goto Error;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	if (is_combination) {
222*7c478bd9Sstevel@tonic-gate 		char **nextnames;
223*7c478bd9Sstevel@tonic-gate 		uintptr_t *nextaddrs;
224*7c478bd9Sstevel@tonic-gate 		char **name_pp;
225*7c478bd9Sstevel@tonic-gate 		uintptr_t *addr_p;
226*7c478bd9Sstevel@tonic-gate 		int count, j;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_2(decode_2, "libtnfctl", "sunw%verbosity 2;",
229*7c478bd9Sstevel@tonic-gate 			tnf_opaque, down, down,
230*7c478bd9Sstevel@tonic-gate 			tnf_opaque, next, next);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 		prexstat = findname(hndl, down, &thisname);
233*7c478bd9Sstevel@tonic-gate 		if (prexstat == TNFCTL_ERR_USR1) {
234*7c478bd9Sstevel@tonic-gate 			/*
235*7c478bd9Sstevel@tonic-gate 			 * should never happen - combination should not
236*7c478bd9Sstevel@tonic-gate 			 * point at the end function
237*7c478bd9Sstevel@tonic-gate 			 */
238*7c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_INTERNAL;
239*7c478bd9Sstevel@tonic-gate 			goto Error;
240*7c478bd9Sstevel@tonic-gate 		} else if (prexstat)
241*7c478bd9Sstevel@tonic-gate 			goto Error;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 		prexstat = decode(hndl, next, &nextnames, &nextaddrs);
244*7c478bd9Sstevel@tonic-gate 		if (prexstat)
245*7c478bd9Sstevel@tonic-gate 			goto Error;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 		/* count number of elements - caution: empty 'for' loop */
248*7c478bd9Sstevel@tonic-gate 		for (count = 0; nextnames[count]; count++);
249*7c478bd9Sstevel@tonic-gate 		count++;	/* since it was 0 based */
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 		/* allocate one more for new function name */
252*7c478bd9Sstevel@tonic-gate 		new_p->name_ptrs = malloc((count + 1) *
253*7c478bd9Sstevel@tonic-gate 					sizeof (new_p->name_ptrs[0]));
254*7c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs == NULL) {
255*7c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
256*7c478bd9Sstevel@tonic-gate 			goto Error;
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 		new_p->func_addrs = malloc((count + 1) *
259*7c478bd9Sstevel@tonic-gate 					sizeof (new_p->func_addrs[0]));
260*7c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs == NULL) {
261*7c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
262*7c478bd9Sstevel@tonic-gate 			goto Error;
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 		name_pp = new_p->name_ptrs;
265*7c478bd9Sstevel@tonic-gate 		addr_p = new_p->func_addrs;
266*7c478bd9Sstevel@tonic-gate 		addr_p[0] = down;
267*7c478bd9Sstevel@tonic-gate 		name_pp[0] = thisname;
268*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < count; j++) {
269*7c478bd9Sstevel@tonic-gate 			name_pp[j + 1] = nextnames[j];
270*7c478bd9Sstevel@tonic-gate 			addr_p[j + 1] = nextaddrs[j];
271*7c478bd9Sstevel@tonic-gate 		}
272*7c478bd9Sstevel@tonic-gate 	} else {
273*7c478bd9Sstevel@tonic-gate 		prexstat = findname(hndl, addr, &thisname);
274*7c478bd9Sstevel@tonic-gate 		if (prexstat != TNFCTL_ERR_USR1) {
275*7c478bd9Sstevel@tonic-gate 			/*
276*7c478bd9Sstevel@tonic-gate 			 * base case - end function is the only function
277*7c478bd9Sstevel@tonic-gate 			 * that can be pointed at directly
278*7c478bd9Sstevel@tonic-gate 			 */
279*7c478bd9Sstevel@tonic-gate 			if (prexstat == TNFCTL_ERR_NONE)
280*7c478bd9Sstevel@tonic-gate 				prexstat = TNFCTL_ERR_NONE;
281*7c478bd9Sstevel@tonic-gate 			goto Error;
282*7c478bd9Sstevel@tonic-gate 		}
283*7c478bd9Sstevel@tonic-gate 		new_p->name_ptrs = malloc(sizeof (new_p->name_ptrs[0]));
284*7c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs == NULL) {
285*7c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
286*7c478bd9Sstevel@tonic-gate 			goto Error;
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 		new_p->func_addrs = malloc(sizeof (new_p->func_addrs[0]));
289*7c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs == NULL) {
290*7c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
291*7c478bd9Sstevel@tonic-gate 			goto Error;
292*7c478bd9Sstevel@tonic-gate 		}
293*7c478bd9Sstevel@tonic-gate 		new_p->name_ptrs[0] = NULL;
294*7c478bd9Sstevel@tonic-gate 		new_p->func_addrs[0] = NULL;
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_1(decode_3, "libtnfctl",
298*7c478bd9Sstevel@tonic-gate 			"sunw%verbosity 2; sunw%debug 'decode built'",
299*7c478bd9Sstevel@tonic-gate 			tnf_string, func_name,
300*7c478bd9Sstevel@tonic-gate 				(thisname) ? (thisname) : "end_func");
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	find_pp = (decode_key_t **) tsearch(new_p,
303*7c478bd9Sstevel@tonic-gate 		&hndl->decoderoot, decode_compare);
304*7c478bd9Sstevel@tonic-gate 	assert(*find_pp == new_p);
305*7c478bd9Sstevel@tonic-gate 	*func_names = new_p->name_ptrs;
306*7c478bd9Sstevel@tonic-gate 	*func_addrs = new_p->func_addrs;
307*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate Error:
310*7c478bd9Sstevel@tonic-gate 	if (new_p) {
311*7c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs)
312*7c478bd9Sstevel@tonic-gate 			free(new_p->name_ptrs);
313*7c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs)
314*7c478bd9Sstevel@tonic-gate 			free(new_p->func_addrs);
315*7c478bd9Sstevel@tonic-gate 		free(new_p);
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 	return (prexstat);
318*7c478bd9Sstevel@tonic-gate }
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate /*
322*7c478bd9Sstevel@tonic-gate  * iscomb() - determine whether the pointed to function is a combination.  If
323*7c478bd9Sstevel@tonic-gate  * it is, return the down and next pointers
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
326*7c478bd9Sstevel@tonic-gate iscomb(tnfctl_handle_t *hndl,
327*7c478bd9Sstevel@tonic-gate 	uintptr_t addr, uintptr_t *down_p, uintptr_t *next_p,
328*7c478bd9Sstevel@tonic-gate 	boolean_t *ret_val)
329*7c478bd9Sstevel@tonic-gate {
330*7c478bd9Sstevel@tonic-gate 	int		type;
331*7c478bd9Sstevel@tonic-gate 	boolean_t	matched = B_FALSE;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	for (type = 0; type < PRB_COMB_COUNT; type++) {
334*7c478bd9Sstevel@tonic-gate 		size_t		size;
335*7c478bd9Sstevel@tonic-gate 		int		miscstat;
336*7c478bd9Sstevel@tonic-gate 		char		*targ_p;
337*7c478bd9Sstevel@tonic-gate 		char		*ptr;
338*7c478bd9Sstevel@tonic-gate 		char		*tptr;
339*7c478bd9Sstevel@tonic-gate 		uintptr_t	downaddr;
340*7c478bd9Sstevel@tonic-gate 		uintptr_t	nextaddr;
341*7c478bd9Sstevel@tonic-gate 		int		num_bits = 0;
342*7c478bd9Sstevel@tonic-gate 		int		tmp_bits = prb_callinfo.mask;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 		/* allocate room to copy the target code */
345*7c478bd9Sstevel@tonic-gate 		size = (size_t) (calltmpl[type].end - calltmpl[type].entry);
346*7c478bd9Sstevel@tonic-gate 		targ_p = (char *) malloc(size);
347*7c478bd9Sstevel@tonic-gate 		if (!targ_p)
348*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_ALLOCFAIL);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		/* copy code from target */
351*7c478bd9Sstevel@tonic-gate 		miscstat = hndl->p_read(hndl->proc_p, addr, targ_p, size);
352*7c478bd9Sstevel@tonic-gate 		if (miscstat) {
353*7c478bd9Sstevel@tonic-gate 			free(targ_p);
354*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		/* find the number of bits before the highest bit in mask */
358*7c478bd9Sstevel@tonic-gate 		while (tmp_bits > 0) {
359*7c478bd9Sstevel@tonic-gate 			num_bits++;
360*7c478bd9Sstevel@tonic-gate 			tmp_bits <<= 1;
361*7c478bd9Sstevel@tonic-gate 		}
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 		/* loop over all the words */
364*7c478bd9Sstevel@tonic-gate 		tptr = (char *) calltmpl[type].entry;
365*7c478bd9Sstevel@tonic-gate 		for (ptr = targ_p; ptr < (targ_p + size); ptr++, tptr++) {
366*7c478bd9Sstevel@tonic-gate 			int			 downbits;
367*7c478bd9Sstevel@tonic-gate 			int			 nextbits;
368*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
369*7c478bd9Sstevel@tonic-gate 			int			*uptr = (int *) ptr;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 			/*
372*7c478bd9Sstevel@tonic-gate 			 * If we are pointing at one of the words that we
373*7c478bd9Sstevel@tonic-gate 			 * patch, * (down or next displ) then read that value
374*7c478bd9Sstevel@tonic-gate 			 * in. * Otherwise make sure the words match.
375*7c478bd9Sstevel@tonic-gate 			 */
376*7c478bd9Sstevel@tonic-gate 			if ((uintptr_t) tptr == calltmpl[type].down +
377*7c478bd9Sstevel@tonic-gate 				prb_callinfo.offset) {
378*7c478bd9Sstevel@tonic-gate 				downbits = *uptr;
379*7c478bd9Sstevel@tonic-gate 				downbits &= prb_callinfo.mask;
380*7c478bd9Sstevel@tonic-gate 				/* sign extend */
381*7c478bd9Sstevel@tonic-gate 				downbits  = (downbits << num_bits) >> num_bits;
382*7c478bd9Sstevel@tonic-gate 				downbits <<= prb_callinfo.shift;
383*7c478bd9Sstevel@tonic-gate 				downaddr = addr + (ptr - targ_p) + downbits;
384*7c478bd9Sstevel@tonic-gate #if defined(i386)
385*7c478bd9Sstevel@tonic-gate 				downaddr += 4;
386*7c478bd9Sstevel@tonic-gate 				/* intel is relative to *next* instruction */
387*7c478bd9Sstevel@tonic-gate #endif
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 				ptr += 3;
390*7c478bd9Sstevel@tonic-gate 				tptr += 3;
391*7c478bd9Sstevel@tonic-gate 			} else if ((uintptr_t) tptr == calltmpl[type].next +
392*7c478bd9Sstevel@tonic-gate 				prb_callinfo.offset) {
393*7c478bd9Sstevel@tonic-gate 				nextbits = *uptr;
394*7c478bd9Sstevel@tonic-gate 				nextbits &= prb_callinfo.mask;
395*7c478bd9Sstevel@tonic-gate 				/* sign extend */
396*7c478bd9Sstevel@tonic-gate 				nextbits  = (nextbits << num_bits) >> num_bits;
397*7c478bd9Sstevel@tonic-gate 				nextbits <<= prb_callinfo.shift;
398*7c478bd9Sstevel@tonic-gate 				nextaddr = addr + (ptr - targ_p) + nextbits;
399*7c478bd9Sstevel@tonic-gate #if defined(i386)
400*7c478bd9Sstevel@tonic-gate 				nextaddr += 4;
401*7c478bd9Sstevel@tonic-gate 				/* intel is relative to *next* instruction */
402*7c478bd9Sstevel@tonic-gate #endif
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 				ptr += 3;
405*7c478bd9Sstevel@tonic-gate 				tptr += 3;
406*7c478bd9Sstevel@tonic-gate 			} else {
407*7c478bd9Sstevel@tonic-gate 				/* the byte better match or we bail */
408*7c478bd9Sstevel@tonic-gate 				if (*ptr != *tptr)
409*7c478bd9Sstevel@tonic-gate 					goto NextComb;
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 		}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 		/* YOWSA! - its a match */
414*7c478bd9Sstevel@tonic-gate 		matched = B_TRUE;
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate NextComb:
417*7c478bd9Sstevel@tonic-gate 		/* free allocated memory */
418*7c478bd9Sstevel@tonic-gate 		if (targ_p)
419*7c478bd9Sstevel@tonic-gate 			free(targ_p);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		if (matched) {
422*7c478bd9Sstevel@tonic-gate 			*down_p = downaddr;
423*7c478bd9Sstevel@tonic-gate 			*next_p = nextaddr;
424*7c478bd9Sstevel@tonic-gate 			*ret_val = B_TRUE;
425*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	*ret_val = B_FALSE;
430*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate #define	FUNC_BUF_SIZE	32
435*7c478bd9Sstevel@tonic-gate /*
436*7c478bd9Sstevel@tonic-gate  * findname() - find a name for a function given its address.
437*7c478bd9Sstevel@tonic-gate  */
438*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
439*7c478bd9Sstevel@tonic-gate findname(tnfctl_handle_t *hndl, uintptr_t addr, char **ret_name)
440*7c478bd9Sstevel@tonic-gate {
441*7c478bd9Sstevel@tonic-gate 	char		*symname;
442*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	symname = NULL;
445*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_findname(hndl, addr, &symname);
446*7c478bd9Sstevel@tonic-gate 	if ((prexstat == TNFCTL_ERR_NONE) && (symname != NULL)) {
447*7c478bd9Sstevel@tonic-gate 		/* found a name */
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		/*
450*7c478bd9Sstevel@tonic-gate 		 * SPECIAL CASE
451*7c478bd9Sstevel@tonic-gate 		 * If we find "tnf_trace_end" then we should not report it
452*7c478bd9Sstevel@tonic-gate 		 * as this is the "end-cap" function and should be hidden
453*7c478bd9Sstevel@tonic-gate 		 * from the user.  Return a null string instead ...
454*7c478bd9Sstevel@tonic-gate 		 */
455*7c478bd9Sstevel@tonic-gate 		if (strcmp(symname, TRACE_END_FUNC) == 0) {
456*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_USR1);
457*7c478bd9Sstevel@tonic-gate 		} else {
458*7c478bd9Sstevel@tonic-gate 			*ret_name = symname;
459*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
460*7c478bd9Sstevel@tonic-gate 		}
461*7c478bd9Sstevel@tonic-gate 	} else {
462*7c478bd9Sstevel@tonic-gate 		char *buffer;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 		buffer = malloc(FUNC_BUF_SIZE);
465*7c478bd9Sstevel@tonic-gate 		if (buffer == NULL)
466*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_ALLOCFAIL);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 		/* no name found, use the address */
469*7c478bd9Sstevel@tonic-gate 		(void) sprintf(buffer, "func@0x%p", addr);
470*7c478bd9Sstevel@tonic-gate 		*ret_name = buffer;
471*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate }
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate /*
477*7c478bd9Sstevel@tonic-gate  * find() - try to find an existing combination that satisfies ...
478*7c478bd9Sstevel@tonic-gate  */
479*7c478bd9Sstevel@tonic-gate static boolean_t
480*7c478bd9Sstevel@tonic-gate find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
481*7c478bd9Sstevel@tonic-gate 	uintptr_t * comb_p)
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	comb_key_t	key;
484*7c478bd9Sstevel@tonic-gate 	comb_key_t	**find_pp;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	key.op = op;
487*7c478bd9Sstevel@tonic-gate 	key.down = down;
488*7c478bd9Sstevel@tonic-gate 	key.next = next;
489*7c478bd9Sstevel@tonic-gate 	key.comb = NULL;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	find_pp = (comb_key_t **) tfind(&key, &hndl->buildroot, comb_compare);
492*7c478bd9Sstevel@tonic-gate 	if (find_pp) {
493*7c478bd9Sstevel@tonic-gate 		*comb_p = (*find_pp)->comb;
494*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
495*7c478bd9Sstevel@tonic-gate 	} else
496*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
497*7c478bd9Sstevel@tonic-gate }
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate /*
501*7c478bd9Sstevel@tonic-gate  * add() - adds a combination to combination cache
502*7c478bd9Sstevel@tonic-gate  */
503*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
504*7c478bd9Sstevel@tonic-gate add(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
505*7c478bd9Sstevel@tonic-gate 	uintptr_t comb)
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	comb_key_t	 *new_p;
508*7c478bd9Sstevel@tonic-gate 	/* LINTED set but not used in function */
509*7c478bd9Sstevel@tonic-gate 	comb_key_t	**ret_pp;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	new_p = (comb_key_t *) malloc(sizeof (comb_key_t));
512*7c478bd9Sstevel@tonic-gate 	if (!new_p)
513*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	new_p->op = op;
516*7c478bd9Sstevel@tonic-gate 	new_p->down = down;
517*7c478bd9Sstevel@tonic-gate 	new_p->next = next;
518*7c478bd9Sstevel@tonic-gate 	new_p->comb = comb;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	ret_pp = (comb_key_t **) tsearch(new_p, &hndl->buildroot,
521*7c478bd9Sstevel@tonic-gate 			comb_compare);
522*7c478bd9Sstevel@tonic-gate 	assert(*ret_pp == new_p);
523*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
524*7c478bd9Sstevel@tonic-gate }
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate /*
528*7c478bd9Sstevel@tonic-gate  * decode_compare() - comparison function used for tree search for
529*7c478bd9Sstevel@tonic-gate  * combinations
530*7c478bd9Sstevel@tonic-gate  */
531*7c478bd9Sstevel@tonic-gate static int
532*7c478bd9Sstevel@tonic-gate decode_compare(const void *v0p, const void *v1p)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	decode_key_t   *k0p = (decode_key_t *) v0p;
535*7c478bd9Sstevel@tonic-gate 	decode_key_t   *k1p = (decode_key_t *) v1p;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	return (int) ((uintptr_t) k1p->addr - (uintptr_t) k0p->addr);
538*7c478bd9Sstevel@tonic-gate }				/* end decode_compare */
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate /*
542*7c478bd9Sstevel@tonic-gate  * comb_compare() - comparison function used for tree search for combinations
543*7c478bd9Sstevel@tonic-gate  */
544*7c478bd9Sstevel@tonic-gate static int
545*7c478bd9Sstevel@tonic-gate comb_compare(const void *v0p, const void *v1p)
546*7c478bd9Sstevel@tonic-gate {
547*7c478bd9Sstevel@tonic-gate 	comb_key_t	 *k0p = (comb_key_t *) v0p;
548*7c478bd9Sstevel@tonic-gate 	comb_key_t	 *k1p = (comb_key_t *) v1p;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (k0p->op != k1p->op)
551*7c478bd9Sstevel@tonic-gate 		return ((k0p->op < k1p->op) ? -1 : 1);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	if (k0p->down != k1p->down)
554*7c478bd9Sstevel@tonic-gate 		return ((k0p->down < k1p->down) ? -1 : 1);
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	if (k0p->next != k1p->next)
557*7c478bd9Sstevel@tonic-gate 		return ((k0p->next < k1p->next) ? -1 : 1);
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	return (0);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate }				/* end comb_compare */
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate /*
564*7c478bd9Sstevel@tonic-gate  * build() - build a composition
565*7c478bd9Sstevel@tonic-gate  */
566*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
567*7c478bd9Sstevel@tonic-gate build(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
568*7c478bd9Sstevel@tonic-gate 	uintptr_t *comb_p)
569*7c478bd9Sstevel@tonic-gate {
570*7c478bd9Sstevel@tonic-gate 	size_t		size;
571*7c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
572*7c478bd9Sstevel@tonic-gate 	char		*buffer_p = NULL;
573*7c478bd9Sstevel@tonic-gate 	uintptr_t	offset;
574*7c478bd9Sstevel@tonic-gate 	uintptr_t	contents;
575*7c478bd9Sstevel@tonic-gate 	unsigned	*word_p;
576*7c478bd9Sstevel@tonic-gate 	int		miscstat;
577*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate #if 0
580*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "off=0x%x shift=0x%x mask=0x%x size=%d\n",
581*7c478bd9Sstevel@tonic-gate 		prb_callinfo.offset,
582*7c478bd9Sstevel@tonic-gate 		prb_callinfo.shift,
583*7c478bd9Sstevel@tonic-gate 		prb_callinfo.mask,
584*7c478bd9Sstevel@tonic-gate 		calltmpl[op].end - calltmpl[op].entry);
585*7c478bd9Sstevel@tonic-gate #endif
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	*comb_p = NULL;
588*7c478bd9Sstevel@tonic-gate 	size = calltmpl[op].end - calltmpl[op].entry;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/* allocate memory in the target process */
591*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_targmem_alloc(hndl, size, &addr);
592*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
593*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
594*7c478bd9Sstevel@tonic-gate 			"build: trouble allocating target memory:\n"));
595*7c478bd9Sstevel@tonic-gate 		goto Error;
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/* allocate a scratch buffer, copy the template into it */
599*7c478bd9Sstevel@tonic-gate 	buffer_p = malloc(size);
600*7c478bd9Sstevel@tonic-gate 	if (!buffer_p) {
601*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr, "build: alloc failed\n"));
602*7c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_ALLOCFAIL;
603*7c478bd9Sstevel@tonic-gate 		goto Error;
604*7c478bd9Sstevel@tonic-gate 	}
605*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer_p, (void *) calltmpl[op].entry, size);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/* poke the down address */
608*7c478bd9Sstevel@tonic-gate 	offset = calltmpl[op].down - calltmpl[op].entry;
609*7c478bd9Sstevel@tonic-gate 	/*LINTED pointer cast may result in improper alignment*/
610*7c478bd9Sstevel@tonic-gate 	word_p = (unsigned *) (buffer_p + offset + prb_callinfo.offset);
611*7c478bd9Sstevel@tonic-gate 	contents = down - (addr + offset);
612*7c478bd9Sstevel@tonic-gate #if defined(i386)
613*7c478bd9Sstevel@tonic-gate 	contents -= 5;		/* intel offset is relative to *next* instr */
614*7c478bd9Sstevel@tonic-gate #endif
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_4(build_1, "libtnfctl", "sunw%verbosity 3",
617*7c478bd9Sstevel@tonic-gate 			tnf_opaque, down, down,
618*7c478bd9Sstevel@tonic-gate 			tnf_opaque, contents, contents,
619*7c478bd9Sstevel@tonic-gate 			tnf_opaque, word_p, word_p,
620*7c478bd9Sstevel@tonic-gate 			tnf_long, offset, offset);
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	*word_p &= ~prb_callinfo.mask;	/* clear the relevant field */
623*7c478bd9Sstevel@tonic-gate 	*word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask);
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	/* poke the next address */
626*7c478bd9Sstevel@tonic-gate 	offset = calltmpl[op].next - calltmpl[op].entry;
627*7c478bd9Sstevel@tonic-gate 	/*LINTED pointer cast may result in improper alignment*/
628*7c478bd9Sstevel@tonic-gate 	word_p = (unsigned *) (buffer_p + offset + prb_callinfo.offset);
629*7c478bd9Sstevel@tonic-gate 	contents = next - (addr + offset);
630*7c478bd9Sstevel@tonic-gate #if defined(i386)
631*7c478bd9Sstevel@tonic-gate 	contents -= 5;		/* intel offset is relative to *next* instr */
632*7c478bd9Sstevel@tonic-gate #endif
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_4(build_2, "libtnfctl", "sunw%verbosity 3",
635*7c478bd9Sstevel@tonic-gate 			tnf_opaque, next, next,
636*7c478bd9Sstevel@tonic-gate 			tnf_opaque, contents, contents,
637*7c478bd9Sstevel@tonic-gate 			tnf_opaque, word_p, word_p,
638*7c478bd9Sstevel@tonic-gate 			tnf_long, offset, offset);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	*word_p &= ~prb_callinfo.mask;	/* clear the relevant field */
641*7c478bd9Sstevel@tonic-gate 	*word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask);
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	/* copy the combination template into target memory */
644*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_write(hndl->proc_p, addr, buffer_p, size);
645*7c478bd9Sstevel@tonic-gate 	if (miscstat) {
646*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
647*7c478bd9Sstevel@tonic-gate 			"build: trouble writing combination: \n"));
648*7c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_INTERNAL;
649*7c478bd9Sstevel@tonic-gate 		goto Error;
650*7c478bd9Sstevel@tonic-gate 	}
651*7c478bd9Sstevel@tonic-gate 	*comb_p = addr;
652*7c478bd9Sstevel@tonic-gate 	prexstat = add(hndl, op, down, next, addr);
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate Error:
655*7c478bd9Sstevel@tonic-gate 	if (buffer_p)
656*7c478bd9Sstevel@tonic-gate 		free(buffer_p);
657*7c478bd9Sstevel@tonic-gate 	return (prexstat);
658*7c478bd9Sstevel@tonic-gate }
659