1 /* 2 * CDDL HEADER START 3 * 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 7 * with the License. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <assert.h> 33 34 #include <dt_impl.h> 35 #include <dt_parser.h> 36 #include <dt_as.h> 37 38 void 39 dt_irlist_create(dt_irlist_t *dlp) 40 { 41 bzero(dlp, sizeof (dt_irlist_t)); 42 dlp->dl_label = 1; 43 } 44 45 void 46 dt_irlist_destroy(dt_irlist_t *dlp) 47 { 48 dt_irnode_t *dip, *nip; 49 50 for (dip = dlp->dl_list; dip != NULL; dip = nip) { 51 nip = dip->di_next; 52 free(dip); 53 } 54 } 55 56 void 57 dt_irlist_append(dt_irlist_t *dlp, dt_irnode_t *dip) 58 { 59 if (dlp->dl_last != NULL) 60 dlp->dl_last->di_next = dip; 61 else 62 dlp->dl_list = dip; 63 64 dlp->dl_last = dip; 65 66 if (dip->di_label == DT_LBL_NONE || dip->di_instr != DIF_INSTR_NOP) 67 dlp->dl_len++; /* don't count forward refs in instr count */ 68 } 69 70 uint_t 71 dt_irlist_label(dt_irlist_t *dlp) 72 { 73 return (dlp->dl_label++); 74 } 75 76 /*ARGSUSED*/ 77 static int 78 dt_countvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 79 { 80 size_t *np = data; 81 82 if (idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)) 83 (*np)++; /* include variable in vartab */ 84 85 return (0); 86 } 87 88 /*ARGSUSED*/ 89 static int 90 dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 91 { 92 dt_pcb_t *pcb = data; 93 dtrace_difv_t *dvp; 94 ssize_t stroff; 95 dt_node_t dn; 96 97 if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW))) 98 return (0); /* omit variable from vartab */ 99 100 dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++]; 101 stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name); 102 103 if (stroff == -1L) 104 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 105 if (stroff > DIF_STROFF_MAX) 106 longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG); 107 108 dvp->dtdv_name = (uint_t)stroff; 109 dvp->dtdv_id = idp->di_id; 110 dvp->dtdv_flags = 0; 111 112 dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ? 113 DIFV_KIND_ARRAY : DIFV_KIND_SCALAR; 114 115 if (idp->di_flags & DT_IDFLG_LOCAL) 116 dvp->dtdv_scope = DIFV_SCOPE_LOCAL; 117 else if (idp->di_flags & DT_IDFLG_TLS) 118 dvp->dtdv_scope = DIFV_SCOPE_THREAD; 119 else 120 dvp->dtdv_scope = DIFV_SCOPE_GLOBAL; 121 122 if (idp->di_flags & DT_IDFLG_DIFR) 123 dvp->dtdv_flags |= DIFV_F_REF; 124 if (idp->di_flags & DT_IDFLG_DIFW) 125 dvp->dtdv_flags |= DIFV_F_MOD; 126 127 bzero(&dn, sizeof (dn)); 128 dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type); 129 dt_node_diftype(&dn, &dvp->dtdv_type); 130 131 idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW); 132 return (0); 133 } 134 135 static ssize_t 136 dt_copystr(const char *s, size_t n, size_t off, dt_pcb_t *pcb) 137 { 138 bcopy(s, pcb->pcb_difo->dtdo_strtab + off, n); 139 return (n); 140 } 141 142 static void 143 dt_as_undef(const dt_ident_t *idp, uint_t offset) 144 { 145 const char *kind, *mark = (idp->di_flags & DT_IDFLG_USER) ? "``" : "`"; 146 const dtrace_syminfo_t *dts = idp->di_data; 147 148 if (idp->di_flags & DT_IDFLG_USER) 149 kind = "user"; 150 else if (idp->di_flags & DT_IDFLG_PRIM) 151 kind = "primary kernel"; 152 else 153 kind = "loadable kernel"; 154 155 yylineno = idp->di_lineno; 156 157 xyerror(D_ASRELO, "relocation remains against %s symbol %s%s%s (offset " 158 "0x%x)\n", kind, dts->dts_object, mark, dts->dts_name, offset); 159 } 160 161 dtrace_difo_t * 162 dt_as(dt_pcb_t *pcb) 163 { 164 dtrace_hdl_t *dtp = pcb->pcb_hdl; 165 dt_irlist_t *dlp = &pcb->pcb_ir; 166 uint_t *labels = NULL; 167 dt_irnode_t *dip; 168 dtrace_difo_t *dp; 169 dt_ident_t *idp; 170 171 size_t n = 0; 172 uint_t i; 173 174 uint_t kmask, kbits, umask, ubits; 175 uint_t krel = 0, urel = 0; 176 177 /* 178 * Select bitmasks based upon the desired symbol linking policy. We 179 * test (di_ident->di_flags & xmask) == xbits to determine if the 180 * symbol should have a relocation entry generated in the loop below. 181 * 182 * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic 183 * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic 184 * DT_LINK_DYNAMIC = all symbols dynamic 185 * DT_LINK_STATIC = all symbols static 186 * 187 * By 'static' we mean that we use the symbol's value at compile-time 188 * in the final DIF. By 'dynamic' we mean that we create a relocation 189 * table entry for the symbol's value so it can be relocated later. 190 */ 191 switch (dtp->dt_linkmode) { 192 case DT_LINK_KERNEL: 193 kmask = 0; 194 kbits = -1u; 195 umask = DT_IDFLG_USER; 196 ubits = DT_IDFLG_USER; 197 break; 198 case DT_LINK_PRIMARY: 199 kmask = DT_IDFLG_USER | DT_IDFLG_PRIM; 200 kbits = 0; 201 umask = DT_IDFLG_USER; 202 ubits = DT_IDFLG_USER; 203 break; 204 case DT_LINK_DYNAMIC: 205 kmask = DT_IDFLG_USER; 206 kbits = 0; 207 umask = DT_IDFLG_USER; 208 ubits = DT_IDFLG_USER; 209 break; 210 case DT_LINK_STATIC: 211 kmask = umask = 0; 212 kbits = ubits = -1u; 213 break; 214 default: 215 xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n", 216 dtp->dt_linkmode); 217 } 218 219 if ((dp = malloc(sizeof (dtrace_difo_t))) == NULL) 220 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 221 222 assert(yypcb->pcb_difo == NULL); 223 yypcb->pcb_difo = dp; 224 225 bzero(dp, sizeof (dtrace_difo_t)); 226 dp->dtdo_refcnt = 1; 227 dp->dtdo_buf = malloc(sizeof (dif_instr_t) * dlp->dl_len); 228 229 if (dp->dtdo_buf == NULL) 230 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 231 232 if ((labels = malloc(sizeof (uint_t) * dlp->dl_label)) == NULL) 233 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 234 235 /* 236 * Make an initial pass through the instruction list, filling in the 237 * instruction buffer with valid instructions and skipping labeled nops. 238 * While doing this, we also fill in our labels[] translation table 239 * and we count up the number of relocation table entries we will need. 240 */ 241 for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) { 242 if (dip->di_label != DT_LBL_NONE) 243 labels[dip->di_label] = i; 244 245 if (dip->di_label == DT_LBL_NONE || 246 dip->di_instr != DIF_INSTR_NOP) 247 dp->dtdo_buf[i++] = dip->di_instr; 248 249 if ((idp = dip->di_ident) == NULL) 250 continue; /* no relocation entry needed */ 251 252 if ((idp->di_flags & kmask) == kbits) 253 krel++; 254 else if ((idp->di_flags & umask) == ubits) 255 urel++; 256 } 257 258 assert(i == dlp->dl_len); 259 dp->dtdo_len = dlp->dl_len; 260 261 /* 262 * Make a second pass through the instructions, relocating each branch 263 * label to the index of the final instruction in the buffer and noting 264 * any other instruction-specific DIFO flags such as dtdo_destructive. 265 */ 266 for (i = 0; i < dp->dtdo_len; i++) { 267 dif_instr_t instr = dp->dtdo_buf[i]; 268 uint_t op = DIF_INSTR_OP(instr); 269 270 if (op == DIF_OP_CALL) { 271 if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT || 272 DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR) 273 dp->dtdo_destructive = 1; 274 continue; 275 } 276 277 if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) { 278 assert(DIF_INSTR_LABEL(instr) < dlp->dl_label); 279 dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op, 280 labels[DIF_INSTR_LABEL(instr)]); 281 } 282 } 283 284 free(labels); 285 yypcb->pcb_asvidx = 0; 286 287 /* 288 * Allocate memory for the appropriate number of variable records and 289 * then fill in each variable record. As we populate the variable 290 * table we insert the corresponding variable names into the strtab. 291 */ 292 (void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n); 293 (void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n); 294 (void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n); 295 296 if (n != 0) { 297 dp->dtdo_vartab = malloc(n * sizeof (dtrace_difv_t)); 298 dp->dtdo_varlen = (uint32_t)n; 299 300 if (dp->dtdo_vartab == NULL) 301 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 302 303 (void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb); 304 (void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb); 305 (void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb); 306 } 307 308 /* 309 * Allocate memory for the appropriate number of relocation table 310 * entries based upon our kernel and user counts from the first pass. 311 */ 312 if (krel != 0) { 313 dp->dtdo_kreltab = malloc(krel * sizeof (dof_relodesc_t)); 314 dp->dtdo_krelen = krel; 315 316 if (dp->dtdo_kreltab == NULL) 317 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 318 } 319 320 if (urel != 0) { 321 dp->dtdo_ureltab = malloc(urel * sizeof (dof_relodesc_t)); 322 dp->dtdo_urelen = urel; 323 324 if (dp->dtdo_ureltab == NULL) 325 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 326 } 327 328 /* 329 * If any relocations are needed, make another pass through the 330 * instruction list and fill in the relocation table entries. 331 */ 332 if (krel + urel != 0) { 333 uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF; 334 uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF; 335 336 dof_relodesc_t *krp = dp->dtdo_kreltab; 337 dof_relodesc_t *urp = dp->dtdo_ureltab; 338 339 i = 0; /* dtdo_buf[] index */ 340 341 for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) { 342 dof_relodesc_t *rp; 343 ssize_t soff; 344 uint_t nodef; 345 346 if (dip->di_label != DT_LBL_NONE && 347 dip->di_instr == DIF_INSTR_NOP) 348 continue; /* skip label declarations */ 349 350 i++; /* advance dtdo_buf[] index */ 351 352 if ((idp = dip->di_ident) == NULL) 353 continue; /* no relocation entry needed */ 354 355 if ((idp->di_flags & kmask) == kbits) { 356 nodef = knodef; 357 rp = krp++; 358 } else if ((idp->di_flags & umask) == ubits) { 359 nodef = unodef; 360 rp = urp++; 361 } else 362 continue; 363 364 if (!nodef) 365 dt_as_undef(idp, i); 366 367 assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX); 368 soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name); 369 370 if (soff == -1L) 371 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 372 if (soff > DIF_STROFF_MAX) 373 longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG); 374 375 rp->dofr_name = (dof_stridx_t)soff; 376 rp->dofr_type = DOF_RELO_SETX; 377 rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) * 378 sizeof (uint64_t); 379 rp->dofr_data = 0; 380 } 381 382 assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen); 383 assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen); 384 assert(i == dp->dtdo_len); 385 } 386 387 /* 388 * Allocate memory for the compiled string table and then copy the 389 * chunks from the string table into the final string buffer. 390 */ 391 if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) { 392 if ((dp->dtdo_strtab = malloc(n)) == NULL) 393 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 394 395 (void) dt_strtab_write(pcb->pcb_strtab, 396 (dt_strtab_write_f *)dt_copystr, pcb); 397 dp->dtdo_strlen = (uint32_t)n; 398 } 399 400 /* 401 * Allocate memory for the compiled integer table and then copy the 402 * integer constants from the table into the final integer buffer. 403 */ 404 if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) { 405 if ((dp->dtdo_inttab = malloc(n * sizeof (uint64_t))) == NULL) 406 longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); 407 408 dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab); 409 dp->dtdo_intlen = (uint32_t)n; 410 } 411 412 /* 413 * Fill in the DIFO return type from the type associated with the 414 * node saved in pcb_dret, and then clear pcb_difo and pcb_dret 415 * now that the assembler has completed successfully. 416 */ 417 dt_node_diftype(pcb->pcb_dret, &dp->dtdo_rtype); 418 pcb->pcb_difo = NULL; 419 pcb->pcb_dret = NULL; 420 421 if (pcb->pcb_cflags & DTRACE_C_DIFV) 422 dtrace_difo_print(dp, stderr); 423 424 return (dp); 425 } 426