1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
/*
* Oracle Linux DTrace.
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
/*
* DTrace Parsing Control Block
*
* A DTrace Parsing Control Block (PCB) contains all of the state that is used
* by a single pass of the D compiler, other than the global variables used by
* lex and yacc. The routines in this file are used to set up and tear down
* PCBs, which are kept on a stack pointed to by the libdtrace global 'yypcb'.
* The main engine of the compiler, dt_compile(), is located in dt_cc.c and is
* responsible for calling these routines to begin and end a compilation pass.
*
* Sun's lex/yacc are not MT-safe or re-entrant, but we permit limited nested
* use of dt_compile() once the entire parse tree has been constructed but has
* not yet executed the "cooking" pass (see dt_cc.c for more information). The
* PCB design also makes it easier to debug (since all global state is kept in
* one place) and could permit us to make the D compiler MT-safe or re-entrant
* in the future by adding locks to libdtrace or switching to Flex and Bison.
*/
#include <stdlib.h>
#include <assert.h>
#include <dt_impl.h>
#include <dt_program.h>
#include <dt_provider.h>
#include <dt_probe.h>
#include <dt_pcb.h>
/*
* Initialize the specified PCB by zeroing it and filling in a few default
* members, and then pushing it on to the top of the PCB stack and setting
* yypcb to point to it. Increment the current handle's generation count.
*/
void
dt_pcb_push(dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
/*
* Since lex/yacc are not re-entrant and we don't implement state save,
* assert that if another PCB is active, it is from the same handle and
* has completed execution of yyparse(). If the first assertion fires,
* the caller is calling libdtrace without proper MT locking. If the
* second assertion fires, dt_compile() is being called recursively
* from an illegal location in libdtrace, or a dt_pcb_pop() is missing.
*/
if (yypcb != NULL) {
assert(yypcb->pcb_hdl == dtp);
assert(yypcb->pcb_yystate == YYS_DONE);
}
memset(pcb, 0, sizeof(dt_pcb_t));
dt_scope_create(&pcb->pcb_dstack);
dt_idstack_push(&pcb->pcb_globals, dtp->dt_globals);
dt_irlist_create(&pcb->pcb_ir);
pcb->pcb_exitlbl = dt_irlist_label(&pcb->pcb_ir);
pcb->pcb_hdl = dtp;
pcb->pcb_prev = dtp->dt_pcb;
dtp->dt_pcb = pcb;
dtp->dt_gen++;
yyinit(pcb);
}
static int
dt_pcb_pop_ident(dt_idhash_t *dhp, dt_ident_t *idp, void *arg)
{
dtrace_hdl_t *dtp = arg;
if (idp->di_gen == dtp->dt_gen)
dt_idhash_delete(dhp, idp);
return 0;
}
static int
dt_pcb_destroy_probe(dtrace_hdl_t *dtp, dt_probe_t *prp, void *dummy)
{
dt_probe_destroy(prp);
return 0;
}
/*
* Pop the topmost PCB from the PCB stack and destroy any data structures that
* are associated with it. If 'err' is non-zero, destroy any intermediate
* state that is left behind as part of a compilation that has failed.
*/
void
dt_pcb_pop(dtrace_hdl_t *dtp, int err)
{
dt_pcb_t *pcb = yypcb;
uint_t i;
assert(pcb != NULL);
assert(pcb == dtp->dt_pcb);
while (pcb->pcb_dstack.ds_next != NULL)
dt_scope_pop();
dt_scope_destroy(&pcb->pcb_dstack);
dt_irlist_destroy(&pcb->pcb_ir);
dt_node_link_free(&pcb->pcb_list);
dt_node_link_free(&pcb->pcb_hold);
if (err != 0) {
dt_xlator_t *dxp, *nxp;
dt_provider_t *pvp;
dt_htab_next_t *it = NULL;
if (pcb->pcb_prog != NULL)
dt_program_destroy(dtp, pcb->pcb_prog);
if (pcb->pcb_stmt != NULL)
dtrace_stmt_destroy(dtp, pcb->pcb_stmt);
if (pcb->pcb_ecbdesc != NULL)
dt_ecbdesc_release(dtp, pcb->pcb_ecbdesc);
for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) {
nxp = dt_list_next(dxp);
if (dxp->dx_gen == dtp->dt_gen)
dt_xlator_destroy(dtp, dxp);
}
while ((pvp = dt_htab_next(dtp->dt_provs, &it)) != NULL) {
if (pvp->pv_gen == dtp->dt_gen) {
dtrace_probedesc_t pdp;
/* Destroy all probes for this provider. */
pdp.id = DTRACE_IDNONE;
pdp.prv = pvp->desc.dtvd_name;
pdp.mod = "";
pdp.fun = "";
pdp.prb = "";
dt_probe_iter(dtp, &pdp, dt_pcb_destroy_probe,
NULL, NULL);
dt_htab_delete(dtp->dt_provs, pvp);
}
}
dt_idhash_iter(dtp->dt_aggs, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_aggs);
dt_idhash_iter(dtp->dt_globals, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_globals);
dt_idhash_iter(dtp->dt_tls, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_tls);
ctf_discard(dtp->dt_cdefs->dm_ctfp);
ctf_discard(dtp->dt_ddefs->dm_ctfp);
}
if (dtp->dt_maxlvaralloc < pcb->pcb_locals->dh_nextoff)
dtp->dt_maxlvaralloc = pcb->pcb_locals->dh_nextoff;
if (pcb->pcb_pragmas != NULL)
dt_idhash_destroy(pcb->pcb_pragmas);
if (pcb->pcb_locals != NULL)
dt_idhash_destroy(pcb->pcb_locals);
if (pcb->pcb_idents != NULL)
dt_idhash_destroy(pcb->pcb_idents);
if (pcb->pcb_regs != NULL)
dt_regset_destroy(pcb->pcb_regs);
for (i = 0; i < pcb->pcb_asxreflen; i++)
dt_free(dtp, pcb->pcb_asxrefs[i]);
dt_free(dtp, pcb->pcb_asxrefs);
dt_difo_free(dtp, pcb->pcb_difo);
free(pcb->pcb_filetag);
free(pcb->pcb_sflagv);
dtp->dt_pcb = pcb->pcb_prev;
memset(pcb, 0, sizeof(dt_pcb_t));
yyinit(dtp->dt_pcb);
}
|