};
 
 static void check_property_phandle_args(struct check *c,
-                                         struct dt_info *dti,
-                                         struct node *node,
-                                         struct property *prop,
-                                         const struct provider *provider)
+                                       struct dt_info *dti,
+                                       struct node *node,
+                                       struct property *prop,
+                                       const struct provider *provider)
 {
        struct node *root = dti->dt;
        unsigned int cell, cellsize = 0;
                struct node *provider_node;
                struct property *cellprop;
                cell_t phandle;
+               unsigned int expected;
 
                phandle = propval_cell_n(prop, cell);
                /*
                        break;
                }
 
-               if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
+               expected = (cell + cellsize + 1) * sizeof(cell_t);
+               if ((expected <= cell) || prop->val.len < expected) {
                        FAIL_PROP(c, dti, node, prop,
-                                 "property size (%d) too small for cell size %d",
+                                 "property size (%d) too small for cell size %u",
                                  prop->val.len, cellsize);
+                       break;
                }
        }
 }
 
                        return DT_LABEL_REF;
                }
 
-<*>"&{/"{PATHCHAR}*\}  {       /* new-style path reference */
+<*>"&{"{PATHCHAR}*\}   {       /* new-style path reference */
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
                        yylval.labelref = xstrdup(yytext+2);
 
 
 extern struct dt_info *parser_output;
 extern bool treesource_error;
+
+static bool is_ref_relative(const char *ref)
+{
+       return ref[0] != '/' && strchr(&ref[1], '/');
+}
+
 %}
 
 %union {
                         */
                        if (!($<flags>-1 & DTSF_PLUGIN))
                                ERROR(&@2, "Label or path %s not found", $1);
+                       else if (is_ref_relative($1))
+                               ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
                        $$ = add_orphan_node(
                                        name_node(build_node(NULL, NULL, NULL),
                                                  ""),
                {
                        struct node *target = get_node_by_ref($1, $3);
 
+                       if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
+                               ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
+
                        if (target) {
                                add_label(&target->labels, $2);
                                merge_nodes(target, $4);
                         * so $-1 is what we want (plugindecl)
                         */
                        if ($<flags>-1 & DTSF_PLUGIN) {
+                               if (is_ref_relative($2))
+                                       ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
                                add_orphan_node($1, $3, $2);
                        } else {
                                struct node *target = get_node_by_ref($1, $2);
 
        }
        hdrsize = fdt_header_size(fdt);
        if (!can_assume(VALID_DTB)) {
-
                if ((fdt_totalsize(fdt) < hdrsize)
                    || (fdt_totalsize(fdt) > INT_MAX))
                        return -FDT_ERR_TRUNCATED;
                if (!check_off_(hdrsize, fdt_totalsize(fdt),
                                fdt_off_mem_rsvmap(fdt)))
                        return -FDT_ERR_TRUNCATED;
-       }
 
-       if (!can_assume(VALID_DTB)) {
                /* Bounds check structure block */
                if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
                        if (!check_off_(hdrsize, fdt_totalsize(fdt),
 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 {
        const fdt32_t *tagp, *lenp;
-       uint32_t tag;
+       uint32_t tag, len, sum;
        int offset = startoffset;
        const char *p;
 
                lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
                if (!can_assume(VALID_DTB) && !lenp)
                        return FDT_END; /* premature end */
+
+               len = fdt32_to_cpu(*lenp);
+               sum = len + offset;
+               if (!can_assume(VALID_DTB) &&
+                   (INT_MAX <= sum || sum < (uint32_t) offset))
+                       return FDT_END; /* premature end */
+
                /* skip-name offset, length and value */
-               offset += sizeof(struct fdt_property) - FDT_TAGSIZE
-                       + fdt32_to_cpu(*lenp);
+               offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;
+
                if (!can_assume(LATEST) &&
-                   fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
-                   ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+                   fdt_version(fdt) < 0x10 && len >= 8 &&
+                   ((offset - len) % 8) != 0)
                        offset += 4;
                break;
 
 
 
 struct fdt_node_header {
        fdt32_t tag;
-       char name[];
+       char name[0];
 };
 
 struct fdt_property {
        fdt32_t tag;
        fdt32_t len;
        fdt32_t nameoff;
-       char data[];
+       char data[0];
 };
 
 #endif /* !__ASSEMBLY */
 
        /* check validity of address */
        prop = data;
        if (addr_cells == 1) {
-               if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+               if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
                        return -FDT_ERR_BADVALUE;
 
                fdt32_st(prop, (uint32_t)addr);
 
        return fdt32_to_cpu(*val);
 }
 
-/**
- * overlay_get_target - retrieves the offset of a fragment's target
- * @fdt: Base device tree blob
- * @fdto: Device tree overlay blob
- * @fragment: node offset of the fragment in the overlay
- * @pathp: pointer which receives the path of the target (or NULL)
- *
- * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targeting is
- * done (through a phandle or a path)
- *
- * returns:
- *      the targeted node offset in the base device tree
- *      Negative error code on error
- */
-static int overlay_get_target(const void *fdt, const void *fdto,
-                             int fragment, char const **pathp)
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+                             int fragment_offset, char const **pathp)
 {
        uint32_t phandle;
        const char *path = NULL;
        int path_len = 0, ret;
 
        /* Try first to do a phandle based lookup */
-       phandle = overlay_get_target_phandle(fdto, fragment);
+       phandle = overlay_get_target_phandle(fdto, fragment_offset);
        if (phandle == (uint32_t)-1)
                return -FDT_ERR_BADPHANDLE;
 
        /* no phandle, try path */
        if (!phandle) {
                /* And then a path based lookup */
-               path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+               path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
                if (path)
                        ret = fdt_path_offset(fdt, path);
                else
                if (overlay < 0)
                        return overlay;
 
-               target = overlay_get_target(fdt, fdto, fragment, NULL);
+               target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
                if (target < 0)
                        return target;
 
                        return -FDT_ERR_BADOVERLAY;
 
                /* get the target of the fragment */
-               ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+               ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
                if (ret < 0)
                        return ret;
                target = ret;
 
                if (!target_path) {
                        /* again in case setprop_placeholder changed it */
-                       ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+                       ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
                        if (ret < 0)
                                return ret;
                        target = ret;
 
                if (!can_assume(VALID_INPUT)) {
                        name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
                                              &namelen);
+                       *namep = name;
                        if (!name) {
                                if (lenp)
                                        *lenp = namelen;
                                return NULL;
                        }
-                       *namep = name;
                } else {
                        *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
                }
 
 const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
                                                      int offset,
                                                      int *lenp);
+static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt,
+                                                               int offset,
+                                                               int *lenp)
+{
+       return (struct fdt_property *)(uintptr_t)
+               fdt_get_property_by_offset(fdt, offset, lenp);
+}
 
 /**
  * fdt_get_property_namelen - find a property based on substring
  */
 int fdt_overlay_apply(void *fdt, void *fdto);
 
+/**
+ * fdt_overlay_target_offset - retrieves the offset of a fragment's target
+ * @fdt: Base device tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment_offset: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
+ *
+ * fdt_overlay_target_offset() retrieves the target offset in the base
+ * device tree of a fragment, no matter how the actual targeting is
+ * done (through a phandle or a path)
+ *
+ * returns:
+ *      the targeted node offset in the base device tree
+ *      Negative error code on error
+ */
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+                             int fragment_offset, char const **pathp);
+
 /**********************************************************************/
 /* Debugging / informational functions                                */
 /**********************************************************************/
 
 
 struct node *get_node_by_ref(struct node *tree, const char *ref)
 {
+       struct node *target = tree;
+       const char *label = NULL, *path = NULL;
+
        if (streq(ref, "/"))
                return tree;
-       else if (ref[0] == '/')
-               return get_node_by_path(tree, ref);
+
+       if (ref[0] == '/')
+               path = ref;
        else
-               return get_node_by_label(tree, ref);
+               label = ref;
+
+       if (label) {
+               const char *slash = strchr(label, '/');
+               char *buf = NULL;
+
+               if (slash) {
+                       buf = xstrndup(label, slash - label);
+                       label = buf;
+                       path = slash + 1;
+               }
+
+               target = get_node_by_label(tree, label);
+
+               free(buf);
+
+               if (!target)
+                       return NULL;
+       }
+
+       if (path)
+               target = get_node_by_path(target, path);
+
+       return target;
 }
 
 cell_t get_node_phandle(struct node *root, struct node *node)
        /* m->ref can only be a REF_PHANDLE, but check anyway */
        assert(m->type == REF_PHANDLE);
 
+       /* The format only permits fixups for references to label, not
+        * references to path */
+       if (strchr(m->ref, '/'))
+               die("Can't generate fixup for reference to path &{%s}\n",
+                   m->ref);
+
        /* there shouldn't be any ':' in the arguments */
        if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
                die("arguments should not contain ':'\n");
 
        return d;
 }
 
+char *xstrndup(const char *s, size_t n)
+{
+       size_t len = strnlen(s, n) + 1;
+       char *d = xmalloc(len);
+
+       memcpy(d, s, len - 1);
+       d[len - 1] = '\0';
+
+       return d;
+}
+
 int xavsprintf_append(char **strp, const char *fmt, va_list ap)
 {
        int n, size = 0;        /* start with 128 bytes */
        }
 
        /* we should now have a type */
-       if ((*fmt == '\0') || !strchr("iuxs", *fmt))
+       if ((*fmt == '\0') || !strchr("iuxsr", *fmt))
                return -1;
 
        /* convert qualifier (bhL) to byte size */
-       if (*fmt != 's')
+       if (*fmt != 's' && *fmt != 'r')
                *size = qualifier == 'b' ? 1 :
                                qualifier == 'h' ? 2 :
                                qualifier == 'l' ? 4 : -1;
 
 }
 
 extern char *xstrdup(const char *s);
+extern char *xstrndup(const char *s, size_t len);
 
 extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
 extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
  *             i       signed integer
  *             u       unsigned integer
  *             x       hex
+ *             r       raw
  *
  * TODO: Implement ll modifier (8 bytes)
  * TODO: Implement o type (octal)
  */
 
 #define USAGE_TYPE_MSG \
-       "<type>\ts=string, i=int, u=unsigned, x=hex\n" \
+       "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \
        "\tOptional modifier prefix:\n" \
        "\t\thh or b=byte, h=2 byte, l=4 byte (default)";
 
 
-#define DTC_VERSION "DTC 1.6.1-g0a3a9d34"
+#define DTC_VERSION "DTC 1.6.1-g55778a03"