xref: /illumos-gate/usr/src/lib/libtnfctl/comb.c (revision fba8753d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright (c) 1994, by Sun Microsytems, Inc.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Functions that know how to create and decode combinations that are
287c478bd9Sstevel@tonic-gate  * used for connecting probe functions.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #ifndef DEBUG
327c478bd9Sstevel@tonic-gate #define	NDEBUG	1
337c478bd9Sstevel@tonic-gate #endif
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <search.h>
397c478bd9Sstevel@tonic-gate #include <assert.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
437c478bd9Sstevel@tonic-gate #include "dbg.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Typedefs
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate typedef struct comb_callinfo {
517c478bd9Sstevel@tonic-gate 	unsigned	offset;
527c478bd9Sstevel@tonic-gate 	unsigned	shift;	/* shift right <n> bits */
537c478bd9Sstevel@tonic-gate 	unsigned	mask;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate } comb_callinfo_t;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate typedef struct comb_calltmpl {
587c478bd9Sstevel@tonic-gate 	uintptr_t	entry;
597c478bd9Sstevel@tonic-gate 	uintptr_t	down;
607c478bd9Sstevel@tonic-gate 	uintptr_t	next;
617c478bd9Sstevel@tonic-gate 	uintptr_t	end;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate } comb_calltmpl_t;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate typedef struct comb_key {
667c478bd9Sstevel@tonic-gate 	comb_op_t	op;
677c478bd9Sstevel@tonic-gate 	uintptr_t	down;
687c478bd9Sstevel@tonic-gate 	uintptr_t	next;
697c478bd9Sstevel@tonic-gate 	uintptr_t	comb;
707c478bd9Sstevel@tonic-gate } comb_key_t;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate typedef struct decode_key {
737c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
747c478bd9Sstevel@tonic-gate 	char		**name_ptrs;
757c478bd9Sstevel@tonic-gate 	uintptr_t	*func_addrs;
767c478bd9Sstevel@tonic-gate } decode_key_t;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * Global - defined in assembler file
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate extern comb_callinfo_t prb_callinfo;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate extern void	 prb_chain_entry(void);
857c478bd9Sstevel@tonic-gate extern void	 prb_chain_down(void);
867c478bd9Sstevel@tonic-gate extern void	 prb_chain_next(void);
877c478bd9Sstevel@tonic-gate extern void	 prb_chain_end(void);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static comb_calltmpl_t calltmpl[PRB_COMB_COUNT] = {
907c478bd9Sstevel@tonic-gate {
9138fc59d1SToomas Soome 		(uintptr_t)prb_chain_entry,
9238fc59d1SToomas Soome 		(uintptr_t)prb_chain_down,
9338fc59d1SToomas Soome 		(uintptr_t)prb_chain_next,
9438fc59d1SToomas Soome 		(uintptr_t)prb_chain_end}
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Declarations
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static tnfctl_errcode_t decode(tnfctl_handle_t *hndl, uintptr_t addr,
1027c478bd9Sstevel@tonic-gate 	char ***func_names, uintptr_t **func_addrs);
1037c478bd9Sstevel@tonic-gate static boolean_t find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down,
10438fc59d1SToomas Soome 	uintptr_t next, uintptr_t *comb_p);
1057c478bd9Sstevel@tonic-gate static tnfctl_errcode_t build(tnfctl_handle_t *hndl, comb_op_t op,
10638fc59d1SToomas Soome 	uintptr_t down, uintptr_t next, uintptr_t *comb_p);
1077c478bd9Sstevel@tonic-gate static tnfctl_errcode_t add(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down,
1087c478bd9Sstevel@tonic-gate 	uintptr_t next, uintptr_t comb);
1097c478bd9Sstevel@tonic-gate static int comb_compare(const void *a, const void *b);
1107c478bd9Sstevel@tonic-gate static int decode_compare(const void *v0p, const void *v1p);
1117c478bd9Sstevel@tonic-gate static tnfctl_errcode_t iscomb(tnfctl_handle_t *hndl, uintptr_t addr,
1127c478bd9Sstevel@tonic-gate 	uintptr_t *down_p, uintptr_t *next_p, boolean_t *ret_val);
1137c478bd9Sstevel@tonic-gate static tnfctl_errcode_t findname(tnfctl_handle_t *hndl, uintptr_t addr,
1147c478bd9Sstevel@tonic-gate 	char **ret_name);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
1187c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */
1197c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * _tnfctl_comb_build() - finds (or builds) a combination satisfing the op,
1237c478bd9Sstevel@tonic-gate  * down and next constraints of the caller.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate tnfctl_errcode_t
_tnfctl_comb_build(tnfctl_handle_t * hndl,comb_op_t op,uintptr_t down,uintptr_t next,uintptr_t * comb_p)1267c478bd9Sstevel@tonic-gate _tnfctl_comb_build(tnfctl_handle_t *hndl, comb_op_t op,
12738fc59d1SToomas Soome     uintptr_t down, uintptr_t next, uintptr_t *comb_p)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
1307c478bd9Sstevel@tonic-gate 
131*fba8753dSToomas Soome 	*comb_p = 0;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_build_start, "libtnfctl",
13438fc59d1SToomas Soome 	    "start _tnfctl_comb_build; sunw%verbosity 1");
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (find(hndl, op, down, next, comb_p)) {
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_1(_tnfctl_comb_build_end, "libtnfctl",
13938fc59d1SToomas Soome 		    "end _tnfctl_comb_build; sunw%verbosity 1",
14038fc59d1SToomas Soome 		    tnf_opaque, found_comb_at, *comb_p);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 	prexstat = build(hndl, op, down, next, comb_p);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_1(_tnfctl_comb_build_end, "libtnfctl",
14738fc59d1SToomas Soome 	    "end _tnfctl_comb_build; sunw%verbosity 1",
14838fc59d1SToomas Soome 	    tnf_opaque, built_comb_at, *comb_p);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	return (prexstat);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * _tnfctl_comb_decode() - returns a string describing the probe functions
1567c478bd9Sstevel@tonic-gate  * NOTE - the string is for reference purposes ONLY, it should not be freed
1577c478bd9Sstevel@tonic-gate  * by the client.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate tnfctl_errcode_t
_tnfctl_comb_decode(tnfctl_handle_t * hndl,uintptr_t addr,char *** func_names,uintptr_t ** func_addrs)1607c478bd9Sstevel@tonic-gate _tnfctl_comb_decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names,
16138fc59d1SToomas Soome     uintptr_t **func_addrs)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_decode_start, "libtnfctl",
16638fc59d1SToomas Soome 	    "start _tnfctl_comb_decode; sunw%verbosity 2");
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	prexstat = decode(hndl, addr, func_names, func_addrs);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(_tnfctl_comb_decode_end, "libtnfctl",
17138fc59d1SToomas Soome 	    "end _tnfctl_comb_decode; sunw%verbosity 2");
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	return (prexstat);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
1787c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */
1797c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * if combination has been decoded, return decoded info., else
1837c478bd9Sstevel@tonic-gate  * decode combination and cache information
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
decode(tnfctl_handle_t * hndl,uintptr_t addr,char *** func_names,uintptr_t ** func_addrs)1867c478bd9Sstevel@tonic-gate decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names,
18738fc59d1SToomas Soome     uintptr_t **func_addrs)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat = TNFCTL_ERR_NONE;
1907c478bd9Sstevel@tonic-gate 	decode_key_t	key;
1917c478bd9Sstevel@tonic-gate 	decode_key_t	*new_p = NULL;
1927c478bd9Sstevel@tonic-gate 	decode_key_t	**find_pp;
1937c478bd9Sstevel@tonic-gate 	uintptr_t	down;
1947c478bd9Sstevel@tonic-gate 	uintptr_t	next;
1957c478bd9Sstevel@tonic-gate 	char 		*thisname = NULL;
1967c478bd9Sstevel@tonic-gate 	boolean_t	is_combination;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	/* see if we can find the previously decoded answer */
1997c478bd9Sstevel@tonic-gate 	key.addr = addr;
20038fc59d1SToomas Soome 	find_pp = (decode_key_t **)tfind(&key, &hndl->decoderoot,
20138fc59d1SToomas Soome 	    decode_compare);
2027c478bd9Sstevel@tonic-gate 	if (find_pp) {
2037c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_0(decode_1, "libtnfctl",
20438fc59d1SToomas Soome 		    "sunw%verbosity 2; sunw%debug 'found existing'");
2057c478bd9Sstevel@tonic-gate 		*func_names = (*find_pp)->name_ptrs;
2067c478bd9Sstevel@tonic-gate 		*func_addrs = (*find_pp)->func_addrs;
2077c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
21038fc59d1SToomas Soome 	new_p = calloc(1, sizeof (decode_key_t));
2117c478bd9Sstevel@tonic-gate 	if (!new_p)
2127c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
2137c478bd9Sstevel@tonic-gate 	new_p->addr = addr;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	prexstat = iscomb(hndl, addr, &down, &next, &is_combination);
2167c478bd9Sstevel@tonic-gate 	if (prexstat)
2177c478bd9Sstevel@tonic-gate 		goto Error;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (is_combination) {
2207c478bd9Sstevel@tonic-gate 		char **nextnames;
2217c478bd9Sstevel@tonic-gate 		uintptr_t *nextaddrs;
2227c478bd9Sstevel@tonic-gate 		char **name_pp;
2237c478bd9Sstevel@tonic-gate 		uintptr_t *addr_p;
2247c478bd9Sstevel@tonic-gate 		int count, j;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_2(decode_2, "libtnfctl", "sunw%verbosity 2;",
22738fc59d1SToomas Soome 		    tnf_opaque, down, down, tnf_opaque, next, next);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		prexstat = findname(hndl, down, &thisname);
2307c478bd9Sstevel@tonic-gate 		if (prexstat == TNFCTL_ERR_USR1) {
2317c478bd9Sstevel@tonic-gate 			/*
2327c478bd9Sstevel@tonic-gate 			 * should never happen - combination should not
2337c478bd9Sstevel@tonic-gate 			 * point at the end function
2347c478bd9Sstevel@tonic-gate 			 */
2357c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_INTERNAL;
2367c478bd9Sstevel@tonic-gate 			goto Error;
2377c478bd9Sstevel@tonic-gate 		} else if (prexstat)
2387c478bd9Sstevel@tonic-gate 			goto Error;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		prexstat = decode(hndl, next, &nextnames, &nextaddrs);
2417c478bd9Sstevel@tonic-gate 		if (prexstat)
2427c478bd9Sstevel@tonic-gate 			goto Error;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 		/* count number of elements - caution: empty 'for' loop */
24538fc59d1SToomas Soome 		for (count = 0; nextnames[count]; count++)
24638fc59d1SToomas Soome 			;
2477c478bd9Sstevel@tonic-gate 		count++;	/* since it was 0 based */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/* allocate one more for new function name */
2507c478bd9Sstevel@tonic-gate 		new_p->name_ptrs = malloc((count + 1) *
25138fc59d1SToomas Soome 		    sizeof (new_p->name_ptrs[0]));
2527c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs == NULL) {
2537c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
2547c478bd9Sstevel@tonic-gate 			goto Error;
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 		new_p->func_addrs = malloc((count + 1) *
25738fc59d1SToomas Soome 		    sizeof (new_p->func_addrs[0]));
2587c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs == NULL) {
2597c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
2607c478bd9Sstevel@tonic-gate 			goto Error;
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 		name_pp = new_p->name_ptrs;
2637c478bd9Sstevel@tonic-gate 		addr_p = new_p->func_addrs;
2647c478bd9Sstevel@tonic-gate 		addr_p[0] = down;
2657c478bd9Sstevel@tonic-gate 		name_pp[0] = thisname;
2667c478bd9Sstevel@tonic-gate 		for (j = 0; j < count; j++) {
2677c478bd9Sstevel@tonic-gate 			name_pp[j + 1] = nextnames[j];
2687c478bd9Sstevel@tonic-gate 			addr_p[j + 1] = nextaddrs[j];
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 	} else {
2717c478bd9Sstevel@tonic-gate 		prexstat = findname(hndl, addr, &thisname);
2727c478bd9Sstevel@tonic-gate 		if (prexstat != TNFCTL_ERR_USR1) {
2737c478bd9Sstevel@tonic-gate 			/*
2747c478bd9Sstevel@tonic-gate 			 * base case - end function is the only function
2757c478bd9Sstevel@tonic-gate 			 * that can be pointed at directly
2767c478bd9Sstevel@tonic-gate 			 */
2777c478bd9Sstevel@tonic-gate 			if (prexstat == TNFCTL_ERR_NONE)
2787c478bd9Sstevel@tonic-gate 				prexstat = TNFCTL_ERR_NONE;
2797c478bd9Sstevel@tonic-gate 			goto Error;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 		new_p->name_ptrs = malloc(sizeof (new_p->name_ptrs[0]));
2827c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs == NULL) {
2837c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
2847c478bd9Sstevel@tonic-gate 			goto Error;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		new_p->func_addrs = malloc(sizeof (new_p->func_addrs[0]));
2877c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs == NULL) {
2887c478bd9Sstevel@tonic-gate 			prexstat = TNFCTL_ERR_ALLOCFAIL;
2897c478bd9Sstevel@tonic-gate 			goto Error;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		new_p->name_ptrs[0] = NULL;
292*fba8753dSToomas Soome 		new_p->func_addrs[0] = 0;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_1(decode_3, "libtnfctl",
29638fc59d1SToomas Soome 	    "sunw%verbosity 2; sunw%debug 'decode built'",
29738fc59d1SToomas Soome 	    tnf_string, func_name, (thisname) ? (thisname) : "end_func");
2987c478bd9Sstevel@tonic-gate 
29938fc59d1SToomas Soome 	find_pp = (decode_key_t **)tsearch(new_p, &hndl->decoderoot,
30038fc59d1SToomas Soome 	    decode_compare);
3017c478bd9Sstevel@tonic-gate 	assert(*find_pp == new_p);
3027c478bd9Sstevel@tonic-gate 	*func_names = new_p->name_ptrs;
3037c478bd9Sstevel@tonic-gate 	*func_addrs = new_p->func_addrs;
3047c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate Error:
3077c478bd9Sstevel@tonic-gate 	if (new_p) {
3087c478bd9Sstevel@tonic-gate 		if (new_p->name_ptrs)
3097c478bd9Sstevel@tonic-gate 			free(new_p->name_ptrs);
3107c478bd9Sstevel@tonic-gate 		if (new_p->func_addrs)
3117c478bd9Sstevel@tonic-gate 			free(new_p->func_addrs);
3127c478bd9Sstevel@tonic-gate 		free(new_p);
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 	return (prexstat);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate  * iscomb() - determine whether the pointed to function is a combination.  If
3207c478bd9Sstevel@tonic-gate  * it is, return the down and next pointers
3217c478bd9Sstevel@tonic-gate  */
3227c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
iscomb(tnfctl_handle_t * hndl,uintptr_t addr,uintptr_t * down_p,uintptr_t * next_p,boolean_t * ret_val)32338fc59d1SToomas Soome iscomb(tnfctl_handle_t *hndl, uintptr_t addr, uintptr_t *down_p,
32438fc59d1SToomas Soome     uintptr_t *next_p, boolean_t *ret_val)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	int		type;
3277c478bd9Sstevel@tonic-gate 	boolean_t	matched = B_FALSE;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	for (type = 0; type < PRB_COMB_COUNT; type++) {
3307c478bd9Sstevel@tonic-gate 		size_t		size;
3317c478bd9Sstevel@tonic-gate 		int		miscstat;
3327c478bd9Sstevel@tonic-gate 		char		*targ_p;
3337c478bd9Sstevel@tonic-gate 		char		*ptr;
3347c478bd9Sstevel@tonic-gate 		char		*tptr;
3357c478bd9Sstevel@tonic-gate 		uintptr_t	downaddr;
3367c478bd9Sstevel@tonic-gate 		uintptr_t	nextaddr;
3377c478bd9Sstevel@tonic-gate 		int		num_bits = 0;
3387c478bd9Sstevel@tonic-gate 		int		tmp_bits = prb_callinfo.mask;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		/* allocate room to copy the target code */
34138fc59d1SToomas Soome 		size = (size_t)(calltmpl[type].end - calltmpl[type].entry);
34238fc59d1SToomas Soome 		targ_p = malloc(size);
3437c478bd9Sstevel@tonic-gate 		if (!targ_p)
3447c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_ALLOCFAIL);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		/* copy code from target */
3477c478bd9Sstevel@tonic-gate 		miscstat = hndl->p_read(hndl->proc_p, addr, targ_p, size);
3487c478bd9Sstevel@tonic-gate 		if (miscstat) {
3497c478bd9Sstevel@tonic-gate 			free(targ_p);
3507c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		/* find the number of bits before the highest bit in mask */
3547c478bd9Sstevel@tonic-gate 		while (tmp_bits > 0) {
3557c478bd9Sstevel@tonic-gate 			num_bits++;
3567c478bd9Sstevel@tonic-gate 			tmp_bits <<= 1;
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		/* loop over all the words */
36038fc59d1SToomas Soome 		tptr = (char *)calltmpl[type].entry;
3617c478bd9Sstevel@tonic-gate 		for (ptr = targ_p; ptr < (targ_p + size); ptr++, tptr++) {
3627c478bd9Sstevel@tonic-gate 			int			 downbits;
3637c478bd9Sstevel@tonic-gate 			int			 nextbits;
3647c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
36538fc59d1SToomas Soome 			int			*uptr = (int *)ptr;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 			/*
3687c478bd9Sstevel@tonic-gate 			 * If we are pointing at one of the words that we
3697c478bd9Sstevel@tonic-gate 			 * patch, * (down or next displ) then read that value
3707c478bd9Sstevel@tonic-gate 			 * in. * Otherwise make sure the words match.
3717c478bd9Sstevel@tonic-gate 			 */
37238fc59d1SToomas Soome 			if ((uintptr_t)tptr == calltmpl[type].down +
37338fc59d1SToomas Soome 			    prb_callinfo.offset) {
3747c478bd9Sstevel@tonic-gate 				downbits = *uptr;
3757c478bd9Sstevel@tonic-gate 				downbits &= prb_callinfo.mask;
3767c478bd9Sstevel@tonic-gate 				/* sign extend */
3777c478bd9Sstevel@tonic-gate 				downbits  = (downbits << num_bits) >> num_bits;
3787c478bd9Sstevel@tonic-gate 				downbits <<= prb_callinfo.shift;
3797c478bd9Sstevel@tonic-gate 				downaddr = addr + (ptr - targ_p) + downbits;
3807c478bd9Sstevel@tonic-gate #if defined(i386)
3817c478bd9Sstevel@tonic-gate 				downaddr += 4;
3827c478bd9Sstevel@tonic-gate 				/* intel is relative to *next* instruction */
3837c478bd9Sstevel@tonic-gate #endif
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 				ptr += 3;
3867c478bd9Sstevel@tonic-gate 				tptr += 3;
38738fc59d1SToomas Soome 			} else if ((uintptr_t)tptr == calltmpl[type].next +
38838fc59d1SToomas Soome 			    prb_callinfo.offset) {
3897c478bd9Sstevel@tonic-gate 				nextbits = *uptr;
3907c478bd9Sstevel@tonic-gate 				nextbits &= prb_callinfo.mask;
3917c478bd9Sstevel@tonic-gate 				/* sign extend */
3927c478bd9Sstevel@tonic-gate 				nextbits  = (nextbits << num_bits) >> num_bits;
3937c478bd9Sstevel@tonic-gate 				nextbits <<= prb_callinfo.shift;
3947c478bd9Sstevel@tonic-gate 				nextaddr = addr + (ptr - targ_p) + nextbits;
3957c478bd9Sstevel@tonic-gate #if defined(i386)
3967c478bd9Sstevel@tonic-gate 				nextaddr += 4;
3977c478bd9Sstevel@tonic-gate 				/* intel is relative to *next* instruction */
3987c478bd9Sstevel@tonic-gate #endif
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 				ptr += 3;
4017c478bd9Sstevel@tonic-gate 				tptr += 3;
4027c478bd9Sstevel@tonic-gate 			} else {
4037c478bd9Sstevel@tonic-gate 				/* the byte better match or we bail */
4047c478bd9Sstevel@tonic-gate 				if (*ptr != *tptr)
4057c478bd9Sstevel@tonic-gate 					goto NextComb;
4067c478bd9Sstevel@tonic-gate 			}
4077c478bd9Sstevel@tonic-gate 		}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		/* YOWSA! - its a match */
4107c478bd9Sstevel@tonic-gate 		matched = B_TRUE;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate NextComb:
4137c478bd9Sstevel@tonic-gate 		/* free allocated memory */
4147c478bd9Sstevel@tonic-gate 		if (targ_p)
4157c478bd9Sstevel@tonic-gate 			free(targ_p);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 		if (matched) {
4187c478bd9Sstevel@tonic-gate 			*down_p = downaddr;
4197c478bd9Sstevel@tonic-gate 			*next_p = nextaddr;
4207c478bd9Sstevel@tonic-gate 			*ret_val = B_TRUE;
4217c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	*ret_val = B_FALSE;
4267c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate #define	FUNC_BUF_SIZE	32
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate  * findname() - find a name for a function given its address.
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
findname(tnfctl_handle_t * hndl,uintptr_t addr,char ** ret_name)4357c478bd9Sstevel@tonic-gate findname(tnfctl_handle_t *hndl, uintptr_t addr, char **ret_name)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	char		*symname;
4387c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	symname = NULL;
4417c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_findname(hndl, addr, &symname);
4427c478bd9Sstevel@tonic-gate 	if ((prexstat == TNFCTL_ERR_NONE) && (symname != NULL)) {
4437c478bd9Sstevel@tonic-gate 		/* found a name */
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		/*
4467c478bd9Sstevel@tonic-gate 		 * SPECIAL CASE
4477c478bd9Sstevel@tonic-gate 		 * If we find "tnf_trace_end" then we should not report it
4487c478bd9Sstevel@tonic-gate 		 * as this is the "end-cap" function and should be hidden
4497c478bd9Sstevel@tonic-gate 		 * from the user.  Return a null string instead ...
4507c478bd9Sstevel@tonic-gate 		 */
4517c478bd9Sstevel@tonic-gate 		if (strcmp(symname, TRACE_END_FUNC) == 0) {
4527c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_USR1);
4537c478bd9Sstevel@tonic-gate 		} else {
4547c478bd9Sstevel@tonic-gate 			*ret_name = symname;
4557c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 	} else {
4587c478bd9Sstevel@tonic-gate 		char *buffer;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		buffer = malloc(FUNC_BUF_SIZE);
4617c478bd9Sstevel@tonic-gate 		if (buffer == NULL)
4627c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_ALLOCFAIL);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		/* no name found, use the address */
4657c478bd9Sstevel@tonic-gate 		(void) sprintf(buffer, "func@0x%p", addr);
4667c478bd9Sstevel@tonic-gate 		*ret_name = buffer;
4677c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate  * find() - try to find an existing combination that satisfies ...
4747c478bd9Sstevel@tonic-gate  */
4757c478bd9Sstevel@tonic-gate static boolean_t
find(tnfctl_handle_t * hndl,comb_op_t op,uintptr_t down,uintptr_t next,uintptr_t * comb_p)4767c478bd9Sstevel@tonic-gate find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
47738fc59d1SToomas Soome     uintptr_t *comb_p)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	comb_key_t	key;
4807c478bd9Sstevel@tonic-gate 	comb_key_t	**find_pp;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	key.op = op;
4837c478bd9Sstevel@tonic-gate 	key.down = down;
4847c478bd9Sstevel@tonic-gate 	key.next = next;
485*fba8753dSToomas Soome 	key.comb = 0;
4867c478bd9Sstevel@tonic-gate 
48738fc59d1SToomas Soome 	find_pp = (comb_key_t **)tfind(&key, &hndl->buildroot, comb_compare);
4887c478bd9Sstevel@tonic-gate 	if (find_pp) {
4897c478bd9Sstevel@tonic-gate 		*comb_p = (*find_pp)->comb;
4907c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4917c478bd9Sstevel@tonic-gate 	} else
4927c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * add() - adds a combination to combination cache
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
add(tnfctl_handle_t * hndl,comb_op_t op,uintptr_t down,uintptr_t next,uintptr_t comb)5007c478bd9Sstevel@tonic-gate add(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
50138fc59d1SToomas Soome     uintptr_t comb)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	comb_key_t	 *new_p;
5047c478bd9Sstevel@tonic-gate 	/* LINTED set but not used in function */
50538fc59d1SToomas Soome 	comb_key_t	**ret_pp __unused;
5067c478bd9Sstevel@tonic-gate 
50738fc59d1SToomas Soome 	new_p = malloc(sizeof (comb_key_t));
5087c478bd9Sstevel@tonic-gate 	if (!new_p)
5097c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	new_p->op = op;
5127c478bd9Sstevel@tonic-gate 	new_p->down = down;
5137c478bd9Sstevel@tonic-gate 	new_p->next = next;
5147c478bd9Sstevel@tonic-gate 	new_p->comb = comb;
5157c478bd9Sstevel@tonic-gate 
51638fc59d1SToomas Soome 	ret_pp = (comb_key_t **)tsearch(new_p, &hndl->buildroot,
51738fc59d1SToomas Soome 	    comb_compare);
5187c478bd9Sstevel@tonic-gate 	assert(*ret_pp == new_p);
5197c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate  * decode_compare() - comparison function used for tree search for
5257c478bd9Sstevel@tonic-gate  * combinations
5267c478bd9Sstevel@tonic-gate  */
5277c478bd9Sstevel@tonic-gate static int
decode_compare(const void * v0p,const void * v1p)5287c478bd9Sstevel@tonic-gate decode_compare(const void *v0p, const void *v1p)
5297c478bd9Sstevel@tonic-gate {
53038fc59d1SToomas Soome 	const decode_key_t   *k0p = v0p;
53138fc59d1SToomas Soome 	const decode_key_t   *k1p = v1p;
5327c478bd9Sstevel@tonic-gate 
53338fc59d1SToomas Soome 	return (int)((uintptr_t)k1p->addr - (uintptr_t)k0p->addr);
5347c478bd9Sstevel@tonic-gate }				/* end decode_compare */
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate  * comb_compare() - comparison function used for tree search for combinations
5397c478bd9Sstevel@tonic-gate  */
5407c478bd9Sstevel@tonic-gate static int
comb_compare(const void * v0p,const void * v1p)5417c478bd9Sstevel@tonic-gate comb_compare(const void *v0p, const void *v1p)
5427c478bd9Sstevel@tonic-gate {
54338fc59d1SToomas Soome 	const comb_key_t *k0p = v0p;
54438fc59d1SToomas Soome 	const comb_key_t *k1p = v1p;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (k0p->op != k1p->op)
5477c478bd9Sstevel@tonic-gate 		return ((k0p->op < k1p->op) ? -1 : 1);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (k0p->down != k1p->down)
5507c478bd9Sstevel@tonic-gate 		return ((k0p->down < k1p->down) ? -1 : 1);
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if (k0p->next != k1p->next)
5537c478bd9Sstevel@tonic-gate 		return ((k0p->next < k1p->next) ? -1 : 1);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	return (0);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate }				/* end comb_compare */
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * build() - build a composition
5617c478bd9Sstevel@tonic-gate  */
5627c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
build(tnfctl_handle_t * hndl,comb_op_t op,uintptr_t down,uintptr_t next,uintptr_t * comb_p)5637c478bd9Sstevel@tonic-gate build(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
56438fc59d1SToomas Soome     uintptr_t *comb_p)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate 	size_t		size;
5677c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
5687c478bd9Sstevel@tonic-gate 	char		*buffer_p = NULL;
5697c478bd9Sstevel@tonic-gate 	uintptr_t	offset;
5707c478bd9Sstevel@tonic-gate 	uintptr_t	contents;
5717c478bd9Sstevel@tonic-gate 	unsigned	*word_p;
5727c478bd9Sstevel@tonic-gate 	int		miscstat;
5737c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
5747c478bd9Sstevel@tonic-gate 
575*fba8753dSToomas Soome 	*comb_p = 0;
5767c478bd9Sstevel@tonic-gate 	size = calltmpl[op].end - calltmpl[op].entry;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/* allocate memory in the target process */
5797c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_targmem_alloc(hndl, size, &addr);
5807c478bd9Sstevel@tonic-gate 	if (prexstat) {
5817c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
58238fc59d1SToomas Soome 		    "build: trouble allocating target memory:\n"));
5837c478bd9Sstevel@tonic-gate 		goto Error;
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/* allocate a scratch buffer, copy the template into it */
5877c478bd9Sstevel@tonic-gate 	buffer_p = malloc(size);
5887c478bd9Sstevel@tonic-gate 	if (!buffer_p) {
5897c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr, "build: alloc failed\n"));
5907c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_ALLOCFAIL;
5917c478bd9Sstevel@tonic-gate 		goto Error;
5927c478bd9Sstevel@tonic-gate 	}
5937c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer_p, (void *) calltmpl[op].entry, size);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/* poke the down address */
5967c478bd9Sstevel@tonic-gate 	offset = calltmpl[op].down - calltmpl[op].entry;
5977c478bd9Sstevel@tonic-gate 	/*LINTED pointer cast may result in improper alignment*/
59838fc59d1SToomas Soome 	word_p = (unsigned *)(buffer_p + offset + prb_callinfo.offset);
5997c478bd9Sstevel@tonic-gate 	contents = down - (addr + offset);
6007c478bd9Sstevel@tonic-gate #if defined(i386)
6017c478bd9Sstevel@tonic-gate 	contents -= 5;		/* intel offset is relative to *next* instr */
6027c478bd9Sstevel@tonic-gate #endif
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_4(build_1, "libtnfctl", "sunw%verbosity 3",
60538fc59d1SToomas Soome 	    tnf_opaque, down, down, tnf_opaque, contents, contents,
60638fc59d1SToomas Soome 	    tnf_opaque, word_p, word_p, tnf_long, offset, offset);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	*word_p &= ~prb_callinfo.mask;	/* clear the relevant field */
6097c478bd9Sstevel@tonic-gate 	*word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* poke the next address */
6127c478bd9Sstevel@tonic-gate 	offset = calltmpl[op].next - calltmpl[op].entry;
6137c478bd9Sstevel@tonic-gate 	/*LINTED pointer cast may result in improper alignment*/
61438fc59d1SToomas Soome 	word_p = (unsigned *)(buffer_p + offset + prb_callinfo.offset);
6157c478bd9Sstevel@tonic-gate 	contents = next - (addr + offset);
6167c478bd9Sstevel@tonic-gate #if defined(i386)
6177c478bd9Sstevel@tonic-gate 	contents -= 5;		/* intel offset is relative to *next* instr */
6187c478bd9Sstevel@tonic-gate #endif
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_4(build_2, "libtnfctl", "sunw%verbosity 3",
62138fc59d1SToomas Soome 	    tnf_opaque, next, next, tnf_opaque, contents, contents,
62238fc59d1SToomas Soome 	    tnf_opaque, word_p, word_p, tnf_long, offset, offset);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	*word_p &= ~prb_callinfo.mask;	/* clear the relevant field */
6257c478bd9Sstevel@tonic-gate 	*word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	/* copy the combination template into target memory */
6287c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_write(hndl->proc_p, addr, buffer_p, size);
6297c478bd9Sstevel@tonic-gate 	if (miscstat) {
6307c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
63138fc59d1SToomas Soome 		    "build: trouble writing combination: \n"));
6327c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_INTERNAL;
6337c478bd9Sstevel@tonic-gate 		goto Error;
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 	*comb_p = addr;
6367c478bd9Sstevel@tonic-gate 	prexstat = add(hndl, op, down, next, addr);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate Error:
6397c478bd9Sstevel@tonic-gate 	if (buffer_p)
6407c478bd9Sstevel@tonic-gate 		free(buffer_p);
6417c478bd9Sstevel@tonic-gate 	return (prexstat);
6427c478bd9Sstevel@tonic-gate }
643