Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c
39562 views
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
* Copyright (c) 2013 by Delphix. All rights reserved.
28
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
29
*/
30
31
#include <sys/types.h>
32
#include <strings.h>
33
#include <stdlib.h>
34
#include <assert.h>
35
36
#include <dt_impl.h>
37
#include <dt_parser.h>
38
#include <dt_as.h>
39
40
void
41
dt_irlist_create(dt_irlist_t *dlp)
42
{
43
bzero(dlp, sizeof (dt_irlist_t));
44
dlp->dl_label = 1;
45
}
46
47
void
48
dt_irlist_destroy(dt_irlist_t *dlp)
49
{
50
dt_irnode_t *dip, *nip;
51
52
for (dip = dlp->dl_list; dip != NULL; dip = nip) {
53
nip = dip->di_next;
54
free(dip);
55
}
56
}
57
58
void
59
dt_irlist_append(dt_irlist_t *dlp, dt_irnode_t *dip)
60
{
61
if (dlp->dl_last != NULL)
62
dlp->dl_last->di_next = dip;
63
else
64
dlp->dl_list = dip;
65
66
dlp->dl_last = dip;
67
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 */
70
}
71
72
uint_t
73
dt_irlist_label(dt_irlist_t *dlp)
74
{
75
return (dlp->dl_label++);
76
}
77
78
/*ARGSUSED*/
79
static int
80
dt_countvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
81
{
82
size_t *np = data;
83
84
if (idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW))
85
(*np)++; /* include variable in vartab */
86
87
return (0);
88
}
89
90
/*ARGSUSED*/
91
static int
92
dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
93
{
94
dt_pcb_t *pcb = data;
95
dtrace_difv_t *dvp;
96
ssize_t stroff;
97
dt_node_t dn;
98
99
if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)))
100
return (0); /* omit variable from vartab */
101
102
dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++];
103
stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
104
105
if (stroff == -1L)
106
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
107
if (stroff > DIF_STROFF_MAX)
108
longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
109
110
dvp->dtdv_name = (uint_t)stroff;
111
dvp->dtdv_id = idp->di_id;
112
dvp->dtdv_flags = 0;
113
114
dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ?
115
DIFV_KIND_ARRAY : DIFV_KIND_SCALAR;
116
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;
121
else
122
dvp->dtdv_scope = DIFV_SCOPE_GLOBAL;
123
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;
128
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);
132
133
idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
134
return (0);
135
}
136
137
static ssize_t
138
dt_copystr(const char *s, size_t n, size_t off, dt_pcb_t *pcb)
139
{
140
bcopy(s, pcb->pcb_difo->dtdo_strtab + off, n);
141
return (n);
142
}
143
144
/*
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.
150
*/
151
static void
152
dt_as_xlate(dt_pcb_t *pcb, dtrace_difo_t *dp,
153
uint_t i, uint_t xi, dt_node_t *dnp)
154
{
155
dtrace_hdl_t *dtp = pcb->pcb_hdl;
156
dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
157
158
assert(i < dp->dtdo_len);
159
assert(xi < dp->dtdo_xlmlen);
160
161
assert(dnp->dn_kind == DT_NODE_MEMBER);
162
assert(dnp->dn_membexpr->dn_kind == DT_NODE_XLATOR);
163
164
assert(dxp->dx_id < dtp->dt_xlatorid);
165
assert(dnp->dn_membid < dxp->dx_nmembers);
166
167
if (pcb->pcb_asxrefs == NULL) {
168
pcb->pcb_asxreflen = dtp->dt_xlatorid;
169
pcb->pcb_asxrefs =
170
dt_zalloc(dtp, sizeof (ulong_t *) * pcb->pcb_asxreflen);
171
if (pcb->pcb_asxrefs == NULL)
172
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
173
}
174
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);
180
}
181
182
dp->dtdo_buf[i] = DIF_INSTR_XLATE(
183
DIF_INSTR_OP(dp->dtdo_buf[i]), xi, DIF_INSTR_RD(dp->dtdo_buf[i]));
184
185
BT_SET(pcb->pcb_asxrefs[dxp->dx_id], dnp->dn_membid);
186
dp->dtdo_xlmtab[xi] = dnp;
187
}
188
189
static void
190
dt_as_undef(const dt_ident_t *idp, uint_t offset)
191
{
192
const char *kind, *mark = (idp->di_flags & DT_IDFLG_USER) ? "``" : "`";
193
const dtrace_syminfo_t *dts = idp->di_data;
194
195
if (idp->di_flags & DT_IDFLG_USER)
196
kind = "user";
197
else if (idp->di_flags & DT_IDFLG_PRIM)
198
kind = "primary kernel";
199
else
200
kind = "loadable kernel";
201
202
yylineno = idp->di_lineno;
203
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);
206
}
207
208
dtrace_difo_t *
209
dt_as(dt_pcb_t *pcb)
210
{
211
dtrace_hdl_t *dtp = pcb->pcb_hdl;
212
dt_irlist_t *dlp = &pcb->pcb_ir;
213
uint_t *labels = NULL;
214
dt_irnode_t *dip;
215
dtrace_difo_t *dp;
216
dt_ident_t *idp;
217
218
size_t n = 0;
219
uint_t i;
220
221
uint_t kmask, kbits, umask, ubits;
222
uint_t krel = 0, urel = 0, xlrefs = 0;
223
224
/*
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.
228
*
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
233
*
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.
237
*/
238
switch (dtp->dt_linkmode) {
239
case DT_LINK_KERNEL:
240
kmask = 0;
241
kbits = -1u;
242
umask = DT_IDFLG_USER;
243
ubits = DT_IDFLG_USER;
244
break;
245
case DT_LINK_PRIMARY:
246
kmask = DT_IDFLG_USER | DT_IDFLG_PRIM;
247
kbits = 0;
248
umask = DT_IDFLG_USER;
249
ubits = DT_IDFLG_USER;
250
break;
251
case DT_LINK_DYNAMIC:
252
kmask = DT_IDFLG_USER;
253
kbits = 0;
254
umask = DT_IDFLG_USER;
255
ubits = DT_IDFLG_USER;
256
break;
257
case DT_LINK_STATIC:
258
kmask = umask = 0;
259
kbits = ubits = -1u;
260
break;
261
default:
262
xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
263
dtp->dt_linkmode);
264
}
265
266
assert(pcb->pcb_difo == NULL);
267
pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t));
268
269
if ((dp = pcb->pcb_difo) == NULL)
270
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
271
272
dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len);
273
274
if (dp->dtdo_buf == NULL)
275
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
276
277
if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL)
278
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
279
280
/*
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.
285
*/
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;
289
290
if (dip->di_label == DT_LBL_NONE ||
291
dip->di_instr != DIF_INSTR_NOP)
292
dp->dtdo_buf[i++] = dip->di_instr;
293
294
if (dip->di_extern == NULL)
295
continue; /* no external references needed */
296
297
switch (DIF_INSTR_OP(dip->di_instr)) {
298
case DIF_OP_SETX:
299
idp = dip->di_extern;
300
if ((idp->di_flags & kmask) == kbits)
301
krel++;
302
else if ((idp->di_flags & umask) == ubits)
303
urel++;
304
break;
305
case DIF_OP_XLATE:
306
case DIF_OP_XLARG:
307
xlrefs++;
308
break;
309
default:
310
xyerror(D_UNKNOWN, "unexpected assembler relocation "
311
"for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr));
312
}
313
}
314
315
assert(i == dlp->dl_len);
316
dp->dtdo_len = dlp->dl_len;
317
318
/*
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.
322
*/
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);
326
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;
331
continue;
332
}
333
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)]);
338
}
339
}
340
341
dt_free(dtp, labels);
342
pcb->pcb_asvidx = 0;
343
344
/*
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.
348
*/
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);
352
353
if (n != 0) {
354
dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t));
355
dp->dtdo_varlen = (uint32_t)n;
356
357
if (dp->dtdo_vartab == NULL)
358
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
359
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);
363
}
364
365
/*
366
* Allocate memory for the appropriate number of relocation table
367
* entries based upon our kernel and user counts from the first pass.
368
*/
369
if (krel != 0) {
370
dp->dtdo_kreltab = dt_alloc(dtp,
371
krel * sizeof (dof_relodesc_t));
372
dp->dtdo_krelen = krel;
373
374
if (dp->dtdo_kreltab == NULL)
375
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
376
}
377
378
if (urel != 0) {
379
dp->dtdo_ureltab = dt_alloc(dtp,
380
urel * sizeof (dof_relodesc_t));
381
dp->dtdo_urelen = urel;
382
383
if (dp->dtdo_ureltab == NULL)
384
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
385
}
386
387
if (xlrefs != 0) {
388
dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs);
389
dp->dtdo_xlmlen = xlrefs;
390
391
if (dp->dtdo_xlmtab == NULL)
392
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
393
}
394
395
/*
396
* If any relocations are needed, make another pass through the
397
* instruction list and fill in the relocation table entries.
398
*/
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;
402
403
dof_relodesc_t *krp = dp->dtdo_kreltab;
404
dof_relodesc_t *urp = dp->dtdo_ureltab;
405
dt_node_t **xlp = dp->dtdo_xlmtab;
406
407
i = 0; /* dtdo_buf[] index */
408
409
for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
410
dof_relodesc_t *rp;
411
ssize_t soff;
412
uint_t nodef;
413
414
if (dip->di_label != DT_LBL_NONE &&
415
dip->di_instr == DIF_INSTR_NOP)
416
continue; /* skip label declarations */
417
418
i++; /* advance dtdo_buf[] index */
419
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);
425
continue;
426
}
427
428
if ((idp = dip->di_extern) == NULL)
429
continue; /* no relocation entry needed */
430
431
if ((idp->di_flags & kmask) == kbits) {
432
nodef = knodef;
433
rp = krp++;
434
} else if ((idp->di_flags & umask) == ubits) {
435
nodef = unodef;
436
rp = urp++;
437
} else
438
continue;
439
440
if (!nodef)
441
dt_as_undef(idp, i);
442
443
assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX);
444
soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
445
446
if (soff == -1L)
447
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
448
if (soff > DIF_STROFF_MAX)
449
longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
450
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) *
454
sizeof (uint64_t);
455
rp->dofr_data = 0;
456
}
457
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);
462
}
463
464
/*
465
* Allocate memory for the compiled string table and then copy the
466
* chunks from the string table into the final string buffer.
467
*/
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);
471
472
(void) dt_strtab_write(pcb->pcb_strtab,
473
(dt_strtab_write_f *)dt_copystr, pcb);
474
dp->dtdo_strlen = (uint32_t)n;
475
}
476
477
/*
478
* Allocate memory for the compiled integer table and then copy the
479
* integer constants from the table into the final integer buffer.
480
*/
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);
485
486
dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab);
487
dp->dtdo_intlen = (uint32_t)n;
488
}
489
490
/*
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.
494
*/
495
dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype);
496
pcb->pcb_difo = NULL;
497
pcb->pcb_dret = NULL;
498
499
if (pcb->pcb_cflags & DTRACE_C_DIFV)
500
dt_dis(dp, stderr);
501
502
return (dp);
503
}
504
505