Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 Mar 2013 12:29:41 +0200
From:      Andriy Gapon <avg@FreeBSD.org>
To:        freebsd-hackers <freebsd-hackers@FreeBSD.org>
Subject:   Re: dtrace: operands have incompatible types: "dmu_buf_t **" = "dmu_buf_t **"
Message-ID:  <5141A695.8060905@FreeBSD.org>
In-Reply-To: <513F385B.9010106@FreeBSD.org>
References:  <513F385B.9010106@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help

First, this link
http://docs.oracle.com/cd/E37670_01/E38608/html/dt_typcondef_dlang.html has a
rather good description in section 2.13.4 of how types are managed in DTrace and
of the special "C" and "D" namespaces/modules.

on 12/03/2013 16:14 Andriy Gapon said the following:
> 
> For your amusement:
> 
> ============= testcase.d =============
> dmu_buf_t **buf;

CTF data in my kernel contains these types:
<1964> STRUCT dmu_buf (32 bytes)
<1965> TYPEDEF dmu_buf_t refers to 1964
<1966> POINTER __anon__ refers to 1965
[2501] POINTER __anon__ refers to 1966

Type 2501 is "dmu_buf_t **" and DTrace uses this type for 'buf'.

> /* Remove the following line to defuse. */
> bpobj_t *bpobj;

Now, there are the following types related to bpobj_t [*footnote]:
<8775> STRUCT bpobj (80 bytes)
<8776> TYPEDEF bpobj_t refers to 8775
but there is no type for POINTER that refers to 8776.

So, as described in the referenced document, dtrace creates bpobj_t* type in the
D module.  For that it also has to copy bpobj_t and struct bpobj types and also
types for each member in struct bpobj and so on.
As a result, copies of struct dmu_buf and typedef dmu_buf_t are also created in
D namespace.

These copied types have different type IDs, but all other of their properties
are supposed to be such that the CTF handling code should be able to determine
that the copies and the originals are equivalent types.

> fbt::dmu_bonus_hold:entry
> {
> 	buf = args[3]; /* the error is about this line */
> }

When DTrace resolves types for arguments of 'dmu_bonus_hold' it first looks in C
and D namespaces and only then it looks in the kernel CTF data.
So, now "dmu_buf_t **" is resolved to a copy of the original type.

Unfortunately, there is a quirk that may lead to an error like incompatible
types "dmu_buf_t **" and "dmu_buf_t **".
The CTF code assumes that the types like a pointer to another type or a
qualifier plus another type are always anonymous.  And in fact they are in C
language (note that I am talking about "raw" things like char* or const int, and
not about typedefs).  Also, the DWARF specification mandates that anonymous
types either should not have a name attribute at all or its value should be an
empty string (a single zero byte).
For the above reasons, when the CTF code creates a copy of a type such as a
pointer to another type, it simply sets a name of the copy to an empty string.
And here is the quirk: in a violation of the DWARF specification our libdwarf
sets names of all anonymous types to "__anon__".  This name surely looks special
to a human, but unfortunately there is nothing special about it to the code.
In the end, the original type with "__anon__" name and the copied type with
empty name are no longer considered to be equivalent.


The following patch seems to resolve the problem:
--- a/lib/libdwarf/dwarf_die.c
+++ b/lib/libdwarf/dwarf_die.c
@@ -29,8 +29,6 @@
 #include <stdlib.h>
 #include "_libdwarf.h"

-static const char *anon_name = "__anon__";
-
 int
 dwarf_die_add(Dwarf_CU cu, int level, uint64_t offset, uint64_t abnum,
Dwarf_Abbrev a, Dwarf_Die *diep, Dwarf_Error *err)
 {
@@ -57,7 +55,7 @@ dwarf_die_add(Dwarf_CU cu, int level, uint64_t offset,
uint64_t abnum, Dwarf_Abb
 	die->die_abnum	= abnum;
 	die->die_a	= a;
 	die->die_cu	= cu;
-	die->die_name	= anon_name;
+	die->die_name	= "";

 	/* Initialise the list of attribute values. */
 	STAILQ_INIT(&die->die_attrval);


[*footnote] In fact I see that for some, unknown to me, reason there are more
than one entries for struct bpobj and typedef bpobj_t in the ctf data.  For one
of those entries there is a related bpobj_t pointer entry.  But as far as I can
tell from the code, it's always the last entry with a given name that is
actually used as a type definition for that name.
-- 
Andriy Gapon



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5141A695.8060905>