Example #1
0
static void
dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type)
{
	dtrace_hdl_t *dtp = ddo->ddo_hdl;
	dof_xlmember_t dofxm;
	dof_xlator_t dofxl;
	dof_secidx_t *xst;

	char buf[DT_TYPE_NAMELEN];
	dt_node_t *dnp;
	uint_t i = 0;

	assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT);
	xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport;

	if (xst[dxp->dx_id] != DOF_SECIDX_NONE)
		return; /* translator has already been emitted */

	dt_buf_reset(dtp, &ddo->ddo_xlms);

	/*
	 * Generate an array of dof_xlmember_t's into ddo_xlms.  If we are
	 * importing the translator, add only those members referenced by the
	 * program and set the dofxm_difo reference of each member to NONE.  If
	 * we're exporting the translator, add all members and a DIFO for each.
	 */
	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) {
		if (type == DOF_SECT_XLIMPORT) {
			if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i))
				continue; /* member is not referenced */
			dofxm.dofxm_difo = DOF_SECIDX_NONE;
		} else {
			dofxm.dofxm_difo = dof_add_difo(ddo,
			    dxp->dx_membdif[dnp->dn_membid]);
		}

		dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname);
		dt_node_diftype(dtp, dnp, &dofxm.dofxm_type);

		dt_buf_write(dtp, &ddo->ddo_xlms,
		    &dofxm, sizeof (dofxm), sizeof (uint32_t));
	}

	dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS,
	    sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms));

	dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t));

	dofxl.dofxl_strtab = ddo->ddo_strsec;
	dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name(
	    dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf)));
	dofxl.dofxl_argc = 1;
	dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name(
	    dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf)));
	dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr);

	xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type,
	    sizeof (uint32_t), 0, 0, sizeof (dofxl));
}
/*ARGSUSED*/
static int
dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
	dt_pcb_t *pcb = data;
	dtrace_difv_t *dvp;
	ssize_t stroff;
	dt_node_t dn;
	RT_NOREF1(dhp);

	if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)))
		return (0); /* omit variable from vartab */

	dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++];
	stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);

	if (stroff == -1L)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	if (stroff > DIF_STROFF_MAX)
		longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);

	dvp->dtdv_name = (uint_t)stroff;
	dvp->dtdv_id = idp->di_id;
	dvp->dtdv_flags = 0;

	dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ?
	    DIFV_KIND_ARRAY : DIFV_KIND_SCALAR;

	if (idp->di_flags & DT_IDFLG_LOCAL)
		dvp->dtdv_scope = DIFV_SCOPE_LOCAL;
	else if (idp->di_flags & DT_IDFLG_TLS)
		dvp->dtdv_scope = DIFV_SCOPE_THREAD;
	else
		dvp->dtdv_scope = DIFV_SCOPE_GLOBAL;

	if (idp->di_flags & DT_IDFLG_DIFR)
		dvp->dtdv_flags |= DIFV_F_REF;
	if (idp->di_flags & DT_IDFLG_DIFW)
		dvp->dtdv_flags |= DIFV_F_MOD;

	bzero(&dn, sizeof (dn));
	dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type);
	dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);

	idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
	return (0);
}
Example #3
0
dtrace_difo_t *
dt_as(dt_pcb_t *pcb)
{
	dtrace_hdl_t *dtp = pcb->pcb_hdl;
	dt_irlist_t *dlp = &pcb->pcb_ir;
	uint_t *labels = NULL;
	dt_irnode_t *dip;
	dtrace_difo_t *dp;
	dt_ident_t *idp;

	size_t n = 0;
	uint_t i;

	uint_t kmask, kbits, umask, ubits;
	uint_t krel = 0, urel = 0, xlrefs = 0;

	/*
	 * Select bitmasks based upon the desired symbol linking policy.  We
	 * test (di_extern->di_flags & xmask) == xbits to determine if the
	 * symbol should have a relocation entry generated in the loop below.
	 *
	 * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic
	 * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic
	 * DT_LINK_DYNAMIC = all symbols dynamic
	 * DT_LINK_STATIC = all symbols static
	 *
	 * By 'static' we mean that we use the symbol's value at compile-time
	 * in the final DIF.  By 'dynamic' we mean that we create a relocation
	 * table entry for the symbol's value so it can be relocated later.
	 */
	switch (dtp->dt_linkmode) {
	case DT_LINK_KERNEL:
		kmask = 0;
		kbits = -1u;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_PRIMARY:
		kmask = DT_IDFLG_USER | DT_IDFLG_PRIM;
		kbits = 0;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_DYNAMIC:
		kmask = DT_IDFLG_USER;
		kbits = 0;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_STATIC:
		kmask = umask = 0;
		kbits = ubits = -1u;
		break;
	default:
		xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
		    dtp->dt_linkmode);
	}

	assert(pcb->pcb_difo == NULL);
	pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t));

	if ((dp = pcb->pcb_difo) == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len);

	if (dp->dtdo_buf == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	/*
	 * Make an initial pass through the instruction list, filling in the
	 * instruction buffer with valid instructions and skipping labeled nops.
	 * While doing this, we also fill in our labels[] translation table
	 * and we count up the number of relocation table entries we will need.
	 */
	for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
		if (dip->di_label != DT_LBL_NONE)
			labels[dip->di_label] = i;

		if (dip->di_label == DT_LBL_NONE ||
		    dip->di_instr != DIF_INSTR_NOP)
			dp->dtdo_buf[i++] = dip->di_instr;

		if (dip->di_extern == NULL)
			continue; /* no external references needed */

		switch (DIF_INSTR_OP(dip->di_instr)) {
		case DIF_OP_SETX:
			idp = dip->di_extern;
			if ((idp->di_flags & kmask) == kbits)
				krel++;
			else if ((idp->di_flags & umask) == ubits)
				urel++;
			break;
		case DIF_OP_XLATE:
		case DIF_OP_XLARG:
			xlrefs++;
			break;
		default:
			xyerror(D_UNKNOWN, "unexpected assembler relocation "
			    "for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr));
		}
	}

	assert(i == dlp->dl_len);
	dp->dtdo_len = dlp->dl_len;

	/*
	 * Make a second pass through the instructions, relocating each branch
	 * label to the index of the final instruction in the buffer and noting
	 * any other instruction-specific DIFO flags such as dtdo_destructive.
	 */
	for (i = 0; i < dp->dtdo_len; i++) {
		dif_instr_t instr = dp->dtdo_buf[i];
		uint_t op = DIF_INSTR_OP(instr);

		if (op == DIF_OP_CALL) {
			if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT ||
			    DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR)
				dp->dtdo_destructive = 1;
			continue;
		}

		if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) {
			assert(DIF_INSTR_LABEL(instr) < dlp->dl_label);
			dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op,
			    labels[DIF_INSTR_LABEL(instr)]);
		}
	}

	dt_free(dtp, labels);
	pcb->pcb_asvidx = 0;

	/*
	 * Allocate memory for the appropriate number of variable records and
	 * then fill in each variable record.  As we populate the variable
	 * table we insert the corresponding variable names into the strtab.
	 */
	(void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n);
	(void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n);
	(void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n);

	if (n != 0) {
		dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t));
		dp->dtdo_varlen = (uint32_t)n;

		if (dp->dtdo_vartab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		(void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb);
		(void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb);
		(void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb);
	}

	/*
	 * Allocate memory for the appropriate number of relocation table
	 * entries based upon our kernel and user counts from the first pass.
	 */
	if (krel != 0) {
		dp->dtdo_kreltab = dt_alloc(dtp,
		    krel * sizeof (dof_relodesc_t));
		dp->dtdo_krelen = krel;

		if (dp->dtdo_kreltab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	if (urel != 0) {
		dp->dtdo_ureltab = dt_alloc(dtp,
		    urel * sizeof (dof_relodesc_t));
		dp->dtdo_urelen = urel;

		if (dp->dtdo_ureltab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	if (xlrefs != 0) {
		dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs);
		dp->dtdo_xlmlen = xlrefs;

		if (dp->dtdo_xlmtab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	/*
	 * If any relocations are needed, make another pass through the
	 * instruction list and fill in the relocation table entries.
	 */
	if (krel + urel + xlrefs != 0) {
		uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF;
		uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF;

		dof_relodesc_t *krp = dp->dtdo_kreltab;
		dof_relodesc_t *urp = dp->dtdo_ureltab;
		dt_node_t **xlp = dp->dtdo_xlmtab;

		i = 0; /* dtdo_buf[] index */

		for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
			dof_relodesc_t *rp;
			ssize_t soff;
			uint_t nodef;

			if (dip->di_label != DT_LBL_NONE &&
			    dip->di_instr == DIF_INSTR_NOP)
				continue; /* skip label declarations */

			i++; /* advance dtdo_buf[] index */

			if (DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLATE ||
			    DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLARG) {
				assert(dp->dtdo_buf[i - 1] == dip->di_instr);
				dt_as_xlate(pcb, dp, i - 1, (uint_t)
				    (xlp++ - dp->dtdo_xlmtab), dip->di_extern);
				continue;
			}

			if ((idp = dip->di_extern) == NULL)
				continue; /* no relocation entry needed */

			if ((idp->di_flags & kmask) == kbits) {
				nodef = knodef;
				rp = krp++;
			} else if ((idp->di_flags & umask) == ubits) {
				nodef = unodef;
				rp = urp++;
			} else
				continue;

			if (!nodef)
				dt_as_undef(idp, i);

			assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX);
			soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);

			if (soff == -1L)
				longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
			if (soff > DIF_STROFF_MAX)
				longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);

			rp->dofr_name = (dof_stridx_t)soff;
			rp->dofr_type = DOF_RELO_SETX;
			rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) *
			    sizeof (uint64_t);
			rp->dofr_data = 0;
		}

		assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen);
		assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen);
		assert(xlp == dp->dtdo_xlmtab + dp->dtdo_xlmlen);
		assert(i == dp->dtdo_len);
	}

	/*
	 * Allocate memory for the compiled string table and then copy the
	 * chunks from the string table into the final string buffer.
	 */
	if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) {
		if ((dp->dtdo_strtab = dt_alloc(dtp, n)) == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		(void) dt_strtab_write(pcb->pcb_strtab,
		    (dt_strtab_write_f *)dt_copystr, pcb);
		dp->dtdo_strlen = (uint32_t)n;
	}

	/*
	 * Allocate memory for the compiled integer table and then copy the
	 * integer constants from the table into the final integer buffer.
	 */
	if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) {
		if ((dp->dtdo_inttab = dt_alloc(dtp,
		    n * sizeof (uint64_t))) == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab);
		dp->dtdo_intlen = (uint32_t)n;
	}

	/*
	 * Fill in the DIFO return type from the type associated with the
	 * node saved in pcb_dret, and then clear pcb_difo and pcb_dret
	 * now that the assembler has completed successfully.
	 */
	dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype);
	pcb->pcb_difo = NULL;
	pcb->pcb_dret = NULL;

	if (pcb->pcb_cflags & DTRACE_C_DIFV)
		dt_dis(dp, stderr);

	return (dp);
}