4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright (c) 2013 by Delphix. All rights reserved.
28 * Copyright (c) 2013 Joyent, Inc. All rights reserved.
31 #include <sys/types.h>
37 #include <dt_parser.h>
41 dt_irlist_create(dt_irlist_t
*dlp
)
43 bzero(dlp
, sizeof (dt_irlist_t
));
48 dt_irlist_destroy(dt_irlist_t
*dlp
)
50 dt_irnode_t
*dip
, *nip
;
52 for (dip
= dlp
->dl_list
; dip
!= NULL
; dip
= nip
) {
59 dt_irlist_append(dt_irlist_t
*dlp
, dt_irnode_t
*dip
)
61 if (dlp
->dl_last
!= NULL
)
62 dlp
->dl_last
->di_next
= dip
;
68 if (dip
->di_label
== DT_LBL_NONE
|| dip
->di_instr
!= DIF_INSTR_NOP
)
69 dlp
->dl_len
++; /* don't count forward refs in instr count */
73 dt_irlist_label(dt_irlist_t
*dlp
)
75 return (dlp
->dl_label
++);
80 dt_countvar(dt_idhash_t
*dhp
, dt_ident_t
*idp
, void *data
)
84 if (idp
->di_flags
& (DT_IDFLG_DIFR
| DT_IDFLG_DIFW
))
85 (*np
)++; /* include variable in vartab */
92 dt_copyvar(dt_idhash_t
*dhp
, dt_ident_t
*idp
, void *data
)
99 if (!(idp
->di_flags
& (DT_IDFLG_DIFR
| DT_IDFLG_DIFW
)))
100 return (0); /* omit variable from vartab */
102 dvp
= &pcb
->pcb_difo
->dtdo_vartab
[pcb
->pcb_asvidx
++];
103 stroff
= dt_strtab_insert(pcb
->pcb_strtab
, idp
->di_name
);
106 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
107 if (stroff
> DIF_STROFF_MAX
)
108 longjmp(pcb
->pcb_jmpbuf
, EDT_STR2BIG
);
110 dvp
->dtdv_name
= (uint_t
)stroff
;
111 dvp
->dtdv_id
= idp
->di_id
;
114 dvp
->dtdv_kind
= (idp
->di_kind
== DT_IDENT_ARRAY
) ?
115 DIFV_KIND_ARRAY
: DIFV_KIND_SCALAR
;
117 if (idp
->di_flags
& DT_IDFLG_LOCAL
)
118 dvp
->dtdv_scope
= DIFV_SCOPE_LOCAL
;
119 else if (idp
->di_flags
& DT_IDFLG_TLS
)
120 dvp
->dtdv_scope
= DIFV_SCOPE_THREAD
;
122 dvp
->dtdv_scope
= DIFV_SCOPE_GLOBAL
;
124 if (idp
->di_flags
& DT_IDFLG_DIFR
)
125 dvp
->dtdv_flags
|= DIFV_F_REF
;
126 if (idp
->di_flags
& DT_IDFLG_DIFW
)
127 dvp
->dtdv_flags
|= DIFV_F_MOD
;
129 bzero(&dn
, sizeof (dn
));
130 dt_node_type_assign(&dn
, idp
->di_ctfp
, idp
->di_type
, B_FALSE
);
131 dt_node_diftype(pcb
->pcb_hdl
, &dn
, &dvp
->dtdv_type
);
133 idp
->di_flags
&= ~(DT_IDFLG_DIFR
| DT_IDFLG_DIFW
);
138 dt_copystr(const char *s
, size_t n
, size_t off
, dt_pcb_t
*pcb
)
140 bcopy(s
, pcb
->pcb_difo
->dtdo_strtab
+ off
, n
);
145 * Rewrite the xlate/xlarg instruction at dtdo_buf[i] so that the instruction's
146 * xltab index reflects the offset 'xi' of the assigned dtdo_xlmtab[] location.
147 * We track the cumulative references to translators and members in the pcb's
148 * pcb_asxrefs[] array, a two-dimensional array of bitmaps indexed by the
149 * global translator id and then by the corresponding translator member id.
152 dt_as_xlate(dt_pcb_t
*pcb
, dtrace_difo_t
*dp
,
153 uint_t i
, uint_t xi
, dt_node_t
*dnp
)
155 dtrace_hdl_t
*dtp
= pcb
->pcb_hdl
;
156 dt_xlator_t
*dxp
= dnp
->dn_membexpr
->dn_xlator
;
158 assert(i
< dp
->dtdo_len
);
159 assert(xi
< dp
->dtdo_xlmlen
);
161 assert(dnp
->dn_kind
== DT_NODE_MEMBER
);
162 assert(dnp
->dn_membexpr
->dn_kind
== DT_NODE_XLATOR
);
164 assert(dxp
->dx_id
< dtp
->dt_xlatorid
);
165 assert(dnp
->dn_membid
< dxp
->dx_nmembers
);
167 if (pcb
->pcb_asxrefs
== NULL
) {
168 pcb
->pcb_asxreflen
= dtp
->dt_xlatorid
;
170 dt_zalloc(dtp
, sizeof (ulong_t
*) * pcb
->pcb_asxreflen
);
171 if (pcb
->pcb_asxrefs
== NULL
)
172 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
175 if (pcb
->pcb_asxrefs
[dxp
->dx_id
] == NULL
) {
176 pcb
->pcb_asxrefs
[dxp
->dx_id
] =
177 dt_zalloc(dtp
, BT_SIZEOFMAP(dxp
->dx_nmembers
));
178 if (pcb
->pcb_asxrefs
[dxp
->dx_id
] == NULL
)
179 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
182 dp
->dtdo_buf
[i
] = DIF_INSTR_XLATE(
183 DIF_INSTR_OP(dp
->dtdo_buf
[i
]), xi
, DIF_INSTR_RD(dp
->dtdo_buf
[i
]));
185 BT_SET(pcb
->pcb_asxrefs
[dxp
->dx_id
], dnp
->dn_membid
);
186 dp
->dtdo_xlmtab
[xi
] = dnp
;
190 dt_as_undef(const dt_ident_t
*idp
, uint_t offset
)
192 const char *kind
, *mark
= (idp
->di_flags
& DT_IDFLG_USER
) ? "``" : "`";
193 const dtrace_syminfo_t
*dts
= idp
->di_data
;
195 if (idp
->di_flags
& DT_IDFLG_USER
)
197 else if (idp
->di_flags
& DT_IDFLG_PRIM
)
198 kind
= "primary kernel";
200 kind
= "loadable kernel";
202 yylineno
= idp
->di_lineno
;
204 xyerror(D_ASRELO
, "relocation remains against %s symbol %s%s%s (offset "
205 "0x%x)\n", kind
, dts
->dts_object
, mark
, dts
->dts_name
, offset
);
211 dtrace_hdl_t
*dtp
= pcb
->pcb_hdl
;
212 dt_irlist_t
*dlp
= &pcb
->pcb_ir
;
213 uint_t
*labels
= NULL
;
221 uint_t kmask
, kbits
, umask
, ubits
;
222 uint_t krel
= 0, urel
= 0, xlrefs
= 0;
225 * Select bitmasks based upon the desired symbol linking policy. We
226 * test (di_extern->di_flags & xmask) == xbits to determine if the
227 * symbol should have a relocation entry generated in the loop below.
229 * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic
230 * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic
231 * DT_LINK_DYNAMIC = all symbols dynamic
232 * DT_LINK_STATIC = all symbols static
234 * By 'static' we mean that we use the symbol's value at compile-time
235 * in the final DIF. By 'dynamic' we mean that we create a relocation
236 * table entry for the symbol's value so it can be relocated later.
238 switch (dtp
->dt_linkmode
) {
242 umask
= DT_IDFLG_USER
;
243 ubits
= DT_IDFLG_USER
;
245 case DT_LINK_PRIMARY
:
246 kmask
= DT_IDFLG_USER
| DT_IDFLG_PRIM
;
248 umask
= DT_IDFLG_USER
;
249 ubits
= DT_IDFLG_USER
;
251 case DT_LINK_DYNAMIC
:
252 kmask
= DT_IDFLG_USER
;
254 umask
= DT_IDFLG_USER
;
255 ubits
= DT_IDFLG_USER
;
262 xyerror(D_UNKNOWN
, "internal error -- invalid link mode %u\n",
266 assert(pcb
->pcb_difo
== NULL
);
267 pcb
->pcb_difo
= dt_zalloc(dtp
, sizeof (dtrace_difo_t
));
269 if ((dp
= pcb
->pcb_difo
) == NULL
)
270 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
272 dp
->dtdo_buf
= dt_alloc(dtp
, sizeof (dif_instr_t
) * dlp
->dl_len
);
274 if (dp
->dtdo_buf
== NULL
)
275 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
277 if ((labels
= dt_alloc(dtp
, sizeof (uint_t
) * dlp
->dl_label
)) == NULL
)
278 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
281 * Make an initial pass through the instruction list, filling in the
282 * instruction buffer with valid instructions and skipping labeled nops.
283 * While doing this, we also fill in our labels[] translation table
284 * and we count up the number of relocation table entries we will need.
286 for (i
= 0, dip
= dlp
->dl_list
; dip
!= NULL
; dip
= dip
->di_next
) {
287 if (dip
->di_label
!= DT_LBL_NONE
)
288 labels
[dip
->di_label
] = i
;
290 if (dip
->di_label
== DT_LBL_NONE
||
291 dip
->di_instr
!= DIF_INSTR_NOP
)
292 dp
->dtdo_buf
[i
++] = dip
->di_instr
;
294 if (dip
->di_extern
== NULL
)
295 continue; /* no external references needed */
297 switch (DIF_INSTR_OP(dip
->di_instr
)) {
299 idp
= dip
->di_extern
;
300 if ((idp
->di_flags
& kmask
) == kbits
)
302 else if ((idp
->di_flags
& umask
) == ubits
)
310 xyerror(D_UNKNOWN
, "unexpected assembler relocation "
311 "for opcode 0x%x\n", DIF_INSTR_OP(dip
->di_instr
));
315 assert(i
== dlp
->dl_len
);
316 dp
->dtdo_len
= dlp
->dl_len
;
319 * Make a second pass through the instructions, relocating each branch
320 * label to the index of the final instruction in the buffer and noting
321 * any other instruction-specific DIFO flags such as dtdo_destructive.
323 for (i
= 0; i
< dp
->dtdo_len
; i
++) {
324 dif_instr_t instr
= dp
->dtdo_buf
[i
];
325 uint_t op
= DIF_INSTR_OP(instr
);
327 if (op
== DIF_OP_CALL
) {
328 if (DIF_INSTR_SUBR(instr
) == DIF_SUBR_COPYOUT
||
329 DIF_INSTR_SUBR(instr
) == DIF_SUBR_COPYOUTSTR
)
330 dp
->dtdo_destructive
= 1;
334 if (op
>= DIF_OP_BA
&& op
<= DIF_OP_BLEU
) {
335 assert(DIF_INSTR_LABEL(instr
) < dlp
->dl_label
);
336 dp
->dtdo_buf
[i
] = DIF_INSTR_BRANCH(op
,
337 labels
[DIF_INSTR_LABEL(instr
)]);
341 dt_free(dtp
, labels
);
345 * Allocate memory for the appropriate number of variable records and
346 * then fill in each variable record. As we populate the variable
347 * table we insert the corresponding variable names into the strtab.
349 (void) dt_idhash_iter(dtp
->dt_tls
, dt_countvar
, &n
);
350 (void) dt_idhash_iter(dtp
->dt_globals
, dt_countvar
, &n
);
351 (void) dt_idhash_iter(pcb
->pcb_locals
, dt_countvar
, &n
);
354 dp
->dtdo_vartab
= dt_alloc(dtp
, n
* sizeof (dtrace_difv_t
));
355 dp
->dtdo_varlen
= (uint32_t)n
;
357 if (dp
->dtdo_vartab
== NULL
)
358 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
360 (void) dt_idhash_iter(dtp
->dt_tls
, dt_copyvar
, pcb
);
361 (void) dt_idhash_iter(dtp
->dt_globals
, dt_copyvar
, pcb
);
362 (void) dt_idhash_iter(pcb
->pcb_locals
, dt_copyvar
, pcb
);
366 * Allocate memory for the appropriate number of relocation table
367 * entries based upon our kernel and user counts from the first pass.
370 dp
->dtdo_kreltab
= dt_alloc(dtp
,
371 krel
* sizeof (dof_relodesc_t
));
372 dp
->dtdo_krelen
= krel
;
374 if (dp
->dtdo_kreltab
== NULL
)
375 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
379 dp
->dtdo_ureltab
= dt_alloc(dtp
,
380 urel
* sizeof (dof_relodesc_t
));
381 dp
->dtdo_urelen
= urel
;
383 if (dp
->dtdo_ureltab
== NULL
)
384 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
388 dp
->dtdo_xlmtab
= dt_zalloc(dtp
, sizeof (dt_node_t
*) * xlrefs
);
389 dp
->dtdo_xlmlen
= xlrefs
;
391 if (dp
->dtdo_xlmtab
== NULL
)
392 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
396 * If any relocations are needed, make another pass through the
397 * instruction list and fill in the relocation table entries.
399 if (krel
+ urel
+ xlrefs
!= 0) {
400 uint_t knodef
= pcb
->pcb_cflags
& DTRACE_C_KNODEF
;
401 uint_t unodef
= pcb
->pcb_cflags
& DTRACE_C_UNODEF
;
403 dof_relodesc_t
*krp
= dp
->dtdo_kreltab
;
404 dof_relodesc_t
*urp
= dp
->dtdo_ureltab
;
405 dt_node_t
**xlp
= dp
->dtdo_xlmtab
;
407 i
= 0; /* dtdo_buf[] index */
409 for (dip
= dlp
->dl_list
; dip
!= NULL
; dip
= dip
->di_next
) {
414 if (dip
->di_label
!= DT_LBL_NONE
&&
415 dip
->di_instr
== DIF_INSTR_NOP
)
416 continue; /* skip label declarations */
418 i
++; /* advance dtdo_buf[] index */
420 if (DIF_INSTR_OP(dip
->di_instr
) == DIF_OP_XLATE
||
421 DIF_INSTR_OP(dip
->di_instr
) == DIF_OP_XLARG
) {
422 assert(dp
->dtdo_buf
[i
- 1] == dip
->di_instr
);
423 dt_as_xlate(pcb
, dp
, i
- 1, (uint_t
)
424 (xlp
++ - dp
->dtdo_xlmtab
), dip
->di_extern
);
428 if ((idp
= dip
->di_extern
) == NULL
)
429 continue; /* no relocation entry needed */
431 if ((idp
->di_flags
& kmask
) == kbits
) {
434 } else if ((idp
->di_flags
& umask
) == ubits
) {
443 assert(DIF_INSTR_OP(dip
->di_instr
) == DIF_OP_SETX
);
444 soff
= dt_strtab_insert(pcb
->pcb_strtab
, idp
->di_name
);
447 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
448 if (soff
> DIF_STROFF_MAX
)
449 longjmp(pcb
->pcb_jmpbuf
, EDT_STR2BIG
);
451 rp
->dofr_name
= (dof_stridx_t
)soff
;
452 rp
->dofr_type
= DOF_RELO_SETX
;
453 rp
->dofr_offset
= DIF_INSTR_INTEGER(dip
->di_instr
) *
458 assert(krp
== dp
->dtdo_kreltab
+ dp
->dtdo_krelen
);
459 assert(urp
== dp
->dtdo_ureltab
+ dp
->dtdo_urelen
);
460 assert(xlp
== dp
->dtdo_xlmtab
+ dp
->dtdo_xlmlen
);
461 assert(i
== dp
->dtdo_len
);
465 * Allocate memory for the compiled string table and then copy the
466 * chunks from the string table into the final string buffer.
468 if ((n
= dt_strtab_size(pcb
->pcb_strtab
)) != 0) {
469 if ((dp
->dtdo_strtab
= dt_alloc(dtp
, n
)) == NULL
)
470 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
472 (void) dt_strtab_write(pcb
->pcb_strtab
,
473 (dt_strtab_write_f
*)dt_copystr
, pcb
);
474 dp
->dtdo_strlen
= (uint32_t)n
;
478 * Allocate memory for the compiled integer table and then copy the
479 * integer constants from the table into the final integer buffer.
481 if ((n
= dt_inttab_size(pcb
->pcb_inttab
)) != 0) {
482 if ((dp
->dtdo_inttab
= dt_alloc(dtp
,
483 n
* sizeof (uint64_t))) == NULL
)
484 longjmp(pcb
->pcb_jmpbuf
, EDT_NOMEM
);
486 dt_inttab_write(pcb
->pcb_inttab
, dp
->dtdo_inttab
);
487 dp
->dtdo_intlen
= (uint32_t)n
;
491 * Fill in the DIFO return type from the type associated with the
492 * node saved in pcb_dret, and then clear pcb_difo and pcb_dret
493 * now that the assembler has completed successfully.
495 dt_node_diftype(dtp
, pcb
->pcb_dret
, &dp
->dtdo_rtype
);
496 pcb
->pcb_difo
= NULL
;
497 pcb
->pcb_dret
= NULL
;
499 if (pcb
->pcb_cflags
& DTRACE_C_DIFV
)