Project

General

Profile

Bug #2074

dtrace error: translator has already been declared

Added by David Pacheco over 7 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
DTrace
Start date:
2012-02-03
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage

Description

Save the following as /var/tmp/tmp/foo.d:

typedef struct {
        int foo;
} native_type1;

typedef struct {
        int bar;
} native_type2;

typedef struct {
        int number;
} translated_type;

translator translated_type <native_type1 *n> {
        number = n->foo;
};

translator translated_type <native_type2 *n> {
        number = n->bar;
};

Now run:

# dtrace -L/var/tmp/tmp -n BEGIN
dtrace: invalid probe specifier BEGIN: "/var/tmp/tmp/foo.d", line 19: translator from native_type2 * to translated_type has already been declared

dtrace claims we have redeclared the translator, but we obviously haven't. The two translators have different source types. I'd expect this to be legal, and DTrace would just pick the one that matches whatever it has.

The error comes from dt_node_xlator:

   2411     if (dt_xlator_lookup(dtp, &sn, &dn, DT_XLATE_EXACT) != NULL) {
   2412         xyerror(D_XLATE_REDECL,
   2413             "translator from %s to %s has already been declared\n",
   2414             dt_node_type_name(&sn, n1, sizeof (n1)),
   2415             dt_node_type_name(&dn, n2, sizeof (n2)));
   2416     }

dt_xlator_lookup is matching based on this:

    298     for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
    299         dxp = dt_list_next(dxp)) {
    300         if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
    301             src_ctfp, src_type) &&
    302             ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
    303             dst_ctfp, dst_base))
    304             goto out;
    305     }

That is, a previous translator matches an existing one if the two source and the two dest types are both compatible according to ctf_type_compat(), which does this:

    611     case CTF_K_STRUCT:
    612     case CTF_K_UNION:
    613         return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype));

So they're matching because the source structs happen to have the same size. Indeed, if you change native_type1 to have an extra int field, the above dtrace invocation works fine.

I also observed surprising behavior that may be related: while modifying the Node provider, I inadvertently renamed the probe argument type in the provider definition, but didn't define the new type in the library file. That is, the provider thought the probe took argument new_t, but new_t didn't exist in /usr/lib/dtrace/node.d. When you went to instrument a new Node binary, DTrace barfed on this, claiming it couldn't resolve the native type new_t. Fine. But if you instrumented all Node processes with "node*:::", this would work as long as you had old Node binaries whose provider definition referenced old_t (which was defined in /usr/lib/dtrace/node.d). Also fine. The surprising bit is that this enabling also instrumented the new binaries and successfully use the translators in the library file even though the source type didn't match. This may be a separate bug, but it may be related to this one if DTrace selects the translator to use based on the argument size.

This is only likely to be seen by people developing USDT providers, and even then probably only when modifying existing providers.

Also available in: Atom PDF