Update DTC to git d75b33af676d0beac8398651a7f09037555a550b.

Obtained from:	git://git.jdl.com/software/dtc.git
This commit is contained in:
Rafal Jaworowski 2010-02-27 20:38:41 +00:00
parent cb591ed209
commit b7b62f4139
76 changed files with 1628 additions and 610 deletions

View File

@ -19,6 +19,10 @@ II - The DT block format
III - libfdt
IV - Utility Tools
1) convert-dtsv0 -- Conversion to Version 1
1) ftdump
I - "dtc", the device tree compiler
===================================
@ -28,7 +32,7 @@ I - "dtc", the device tree compiler
Source code for the Device Tree Compiler can be found at jdl.com.
The gitweb interface is:
http://www.jdl.com/git_repos/
http://git.jdl.com/gitweb/
The repository is here:
@ -37,7 +41,7 @@ The repository is here:
Tarballs of the 1.0.0 and latest releases are here:
http://www.jdl.com/software/dtc-1.0.0.tgz
http://www.jdl.com/software/dtc-v1.2.0.tgz
http://www.jdl.com/software/dtc-latest.tgz
@ -613,6 +617,36 @@ strings block.
III - libfdt
============
This library should be merged into dtc proper.
This library should likely be worked into U-Boot and the kernel.
IV - Utility Tools
==================
1) convert-dtsv0 -- Conversion to Version 1
convert-dtsv0 is a small utility program which converts (DTS)
Device Tree Source from the obsolete version 0 to version 1.
Version 1 DTS files are marked by line "/dts-v1/;" at the top of the file.
The syntax of the convert-dtsv0 command line is:
convert-dtsv0 [<input_filename ... >]
Each file passed will be converted to the new /dts-v1/ version by creating
a new file with a "v1" appended the filename.
Comments, empty lines, etc. are preserved.
2) ftdump -- Flat Tree dumping utility
The ftdump program prints a readable version of a flat device tree file.
The syntax of the ftdump command line is:
ftdump <DTB-file-name>

View File

@ -16,7 +16,7 @@ LOCAL_VERSION =
CONFIG_LOCALVERSION =
CPPFLAGS = -I libfdt
CFLAGS = -Wall -g -Os -Wpointer-arith -Wcast-qual
CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
BISON = bison
LEX = flex
@ -28,6 +28,17 @@ BINDIR = $(PREFIX)/bin
LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
ifeq ($(HOSTOS),darwin)
SHAREDLIB_EXT=dylib
SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
else
SHAREDLIB_EXT=so
SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
endif
#
# Overall rules
#
@ -46,17 +57,6 @@ else
DEPTARGETS = $(filter-out $(NODEPTARGETS),$(MAKECMDGOALS))
endif
all: dtc ftdump convert-dtsv0 libfdt
install: all
@$(VECHO) INSTALL
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -m 755 dtc $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
$(INSTALL) -m 644 $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
#
# Rules for versioning
#
@ -100,63 +100,82 @@ define filechk
fi;
endef
$(VERSION_FILE): Makefile FORCE
$(call filechk,version)
#
# Rules for dtc proper
#
include Makefile.convert-dtsv0
include Makefile.dtc
include Makefile.ftdump
BIN += convert-dtsv0
BIN += dtc
BIN += ftdump
# This stops make from generating the lex and bison output during
# auto-dependency computation, but throwing them away as an
# intermediate target and building them again "for real"
.SECONDARY: $(DTC_GEN_SRCS)
dtc: $(DTC_OBJS)
all: $(BIN) libfdt
ifneq ($(DEPTARGETS),)
-include $(DTC_OBJS:%.o=%.d)
-include $(CONVERT_OBJS:%.o=%.d)
-include $(FTDUMP_OBJS:%.o=%.d)
endif
#
# Rules for ftdump & convert-dtsv0
#
BIN += ftdump convert-dtsv0
ftdump: ftdump.o
convert-dtsv0: convert-dtsv0-lexer.lex.o srcpos.o
@$(VECHO) LD $@
$(LINK.c) -o $@ $^
ifneq ($(DEPTARGETS),)
-include ftdump.d
endif
#
# Rules for libfdt
#
LIBFDT_objdir = libfdt
LIBFDT_srcdir = libfdt
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.a
LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
LIBFDT_lib = $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
include $(LIBFDT_srcdir)/Makefile.libfdt
.PHONY: libfdt
libfdt: $(LIBFDT_lib)
libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
libfdt_clean:
@$(VECHO) CLEAN "(libfdt)"
rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
rm -f $(LIBFDT_objdir)/*.so
ifneq ($(DEPTARGETS),)
-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
endif
# This stops make from generating the lex and bison output during
# auto-dependency computation, but throwing them away as an
# intermediate target and building them again "for real"
.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
install: all
@$(VECHO) INSTALL
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) $(BIN) $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
$(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
$(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
$(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
$(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
$(VERSION_FILE): Makefile FORCE
$(call filechk,version)
dtc: $(DTC_OBJS)
convert-dtsv0: $(CONVERT_OBJS)
@$(VECHO) LD $@
$(LINK.c) -o $@ $^
ftdump: $(FTDUMP_OBJS)
#
# Testsuite rules
#
@ -166,7 +185,7 @@ include tests/Makefile.tests
#
# Clean rules
#
STD_CLEANFILES = *~ *.o *.d *.a *.i *.s core a.out vgcore.* \
STD_CLEANFILES = *~ *.o *.so *.d *.a *.i *.s core a.out vgcore.* \
*.tab.[ch] *.lex.c *.output
clean: libfdt_clean tests_clean
@ -210,6 +229,11 @@ clean: libfdt_clean tests_clean
@$(VECHO) AR $@
$(AR) $(ARFLAGS) $@ $^
$(LIBFDT_lib):
@$(VECHO) LD $@
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(notdir $@) -o $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $^
ln -sf libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
%.lex.c: %.l
@$(VECHO) LEX $@
$(LEX) -o$@ $<

13
Makefile.convert-dtsv0 Normal file
View File

@ -0,0 +1,13 @@
#
# This is not a complete Makefile of itself.
# Instead, it is designed to be easily embeddable
# into other systems of Makefiles.
#
CONVERT_SRCS = \
srcpos.c \
util.c
CONVERT_GEN_SRCS = convert-dtsv0-lexer.lex.c
CONVERT_OBJS = $(CONVERT_SRCS:%.c=%.o) $(CONVERT_GEN_SRCS:%.c=%.o)

View File

@ -3,7 +3,16 @@
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
checks.c
DTC_SRCS = \
checks.c \
data.c \
dtc.c \
flattree.c \
fstree.c \
livetree.c \
srcpos.c \
treesource.c \
util.c
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)

12
Makefile.ftdump Normal file
View File

@ -0,0 +1,12 @@
#
# This is not a complete Makefile of itself.
# Instead, it is designed to be easily embeddable
# into other systems of Makefiles.
#
FTDUMP_SRCS = \
ftdump.c
FTDUMP_GEN_SRCS =
FTDUMP_OBJS = $(FTDUMP_SRCS:%.c=%.o) $(FTDUMP_GEN_SRCS:%.c=%.o)

View File

@ -279,31 +279,55 @@ static void check_property_name_chars(struct check *c, struct node *dt,
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node)
struct node *node, struct property *prop)
{
struct property *prop;
struct marker *m;
struct node *other;
cell_t phandle;
prop = get_property(node, "linux,phandle");
if (! prop)
return; /* No phandle, that's fine */
if (!streq(prop->name, "phandle")
&& !streq(prop->name, "linux,phandle"))
return;
if (prop->val.len != sizeof(cell_t)) {
FAIL(c, "%s has bad length (%d) linux,phandle property",
node->fullpath, prop->val.len);
FAIL(c, "%s has bad length (%d) %s property",
node->fullpath, prop->val.len, prop->name);
return;
}
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset == 0);
if (node != get_node_by_ref(root, m->ref))
/* "Set this node's phandle equal to some
* other node's phandle". That's nonsensical
* by construction. */ {
FAIL(c, "%s in %s is a reference to another node",
prop->name, node->fullpath);
return;
}
/* But setting this node's phandle equal to its own
* phandle is allowed - that means allocate a unique
* phandle for this node, even if it's not otherwise
* referenced. The value will be filled in later, so
* no further checking for now. */
return;
}
phandle = propval_cell(prop);
if ((phandle == 0) || (phandle == -1)) {
FAIL(c, "%s has invalid linux,phandle value 0x%x",
node->fullpath, phandle);
FAIL(c, "%s has bad value (0x%x) in %s property",
node->fullpath, phandle, prop->name);
return;
}
if (node->phandle && (node->phandle != phandle))
FAIL(c, "%s has %s property which replaces existing phandle information",
node->fullpath, prop->name);
other = get_node_by_phandle(root, phandle);
if (other) {
if (other && (other != node)) {
FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
node->fullpath, phandle, other->fullpath);
return;
@ -311,7 +335,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
node->phandle = phandle;
}
NODE_CHECK(explicit_phandles, NULL, ERROR);
PROP_CHECK(explicit_phandles, NULL, ERROR);
static void check_name_properties(struct check *c, struct node *root,
struct node *node)

View File

@ -17,7 +17,7 @@
* USA
*/
%option noyywrap nounput
%option noyywrap nounput noinput
%x INCLUDE
%x BYTESTRING
@ -42,6 +42,7 @@ GAP ({WS}|{COMMENT}|{LINECOMMENT})*
#include <fnmatch.h>
#include "srcpos.h"
#include "util.h"
static int v1_tagged; /* = 0 */
static int cbase = 16;
@ -51,26 +52,6 @@ static char *last_name; /* = NULL */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static inline void __attribute__((noreturn)) die(char * str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (! new)
die("malloc() failed\n");
return new;
}
const struct {
const char *pattern;
int obase, width;
@ -185,7 +166,7 @@ const struct {
<PROPNODENAME>{PROPNODECHAR}+ {
ECHO;
last_name = strdup(yytext);
last_name = xstrdup(yytext);
BEGIN(INITIAL);
}

2
data.c
View File

@ -217,7 +217,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
return d;
}
struct data data_append_markers(struct data d, struct marker *m)
static struct data data_append_markers(struct data d, struct marker *m)
{
struct marker **mp = &d.markers;

View File

@ -18,7 +18,7 @@
* USA
*/
%option noyywrap nounput yylineno
%option noyywrap nounput noinput yylineno
%x INCLUDE
%x BYTESTRING
@ -38,6 +38,11 @@ LINECOMMENT "//".*\n
#include "srcpos.h"
#include "dtc-parser.tab.h"
#define YY_USER_ACTION \
{ \
yylloc.file = srcpos_file; \
yylloc.first_line = yylineno; \
}
/*#define LEXDEBUG 1*/
@ -47,15 +52,10 @@ LINECOMMENT "//".*\n
#define DPRINT(fmt, ...) do { } while (0)
#endif
static int dts_version; /* = 0 */
static int dts_version = 1;
#define BEGIN_DEFAULT() if (dts_version == 0) { \
DPRINT("<INITIAL>\n"); \
BEGIN(INITIAL); \
} else { \
DPRINT("<V1>\n"); \
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
BEGIN(V1); \
}
static void push_input_file(const char *filename);
static int pop_input_file(void);
@ -75,18 +75,13 @@ static int pop_input_file(void);
}
<*>{STRING} {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
yylloc.first_line = yylineno;
return DT_STRING;
}
<*>"/dts-v1/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /dts-v1/\n");
dts_version = 1;
BEGIN_DEFAULT();
@ -94,106 +89,57 @@ static int pop_input_file(void);
}
<*>"/memreserve/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
return DT_MEMRESERVE;
}
<*>{LABEL}: {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext);
yylval.labelref = strdup(yytext);
yylval.labelref = xstrdup(yytext);
yylval.labelref[yyleng-1] = '\0';
return DT_LABEL;
}
<INITIAL>[bodh]# {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
if (*yytext == 'b')
yylval.cbase = 2;
else if (*yytext == 'o')
yylval.cbase = 8;
else if (*yytext == 'd')
yylval.cbase = 10;
else
yylval.cbase = 16;
DPRINT("Base: %d\n", yylval.cbase);
return DT_BASE;
}
<INITIAL>[0-9a-fA-F]+ {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LEGACYLITERAL;
}
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
yylval.literal = xstrdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL;
}
\&{LABEL} { /* label reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
}
"&{/"{PATHCHAR}+\} { /* new-style path reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = strdup(yytext+2);
return DT_REF;
}
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
yylval.labelref = xstrdup(yytext+2);
return DT_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
<BYTESTRING>"]" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
return ']';
}
<PROPNODENAME>{PROPNODECHAR}+ {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = strdup(yytext);
yylval.propnodename = xstrdup(yytext);
BEGIN_DEFAULT();
return DT_PROPNODENAME;
}
"/incbin/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Binary Include\n");
return DT_INCBIN;
}
@ -203,8 +149,6 @@ static int pop_input_file(void);
<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>. {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
if (yytext[0] == '[') {

View File

@ -27,6 +27,7 @@
#include "srcpos.h"
extern int yylex(void);
extern void yyerror(char const *s);
extern struct boot_info *the_boot_info;
extern int treesource_error;
@ -55,7 +56,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%token DT_MEMRESERVE
%token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL
%token <literal> DT_LEGACYLITERAL
%token <cbase> DT_BASE
%token <byte> DT_BYTE
%token <data> DT_STRING
@ -67,11 +67,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
%type <re> v0_memreserve
%type <re> v0_memreserves
%type <addr> addr
%type <data> celllist
%type <cbase> cellbase
%type <cell> cellval
%type <data> bytestring
%type <prop> propdef
@ -90,10 +87,6 @@ sourcefile:
{
the_boot_info = build_boot_info($3, $4, 0);
}
| v0_memreserves devicetree
{
the_boot_info = build_boot_info($1, $2, 0);
}
;
memreserves:
@ -114,37 +107,11 @@ memreserve:
}
;
v0_memreserves:
/* empty */
{
$$ = NULL;
}
| v0_memreserve v0_memreserves
{
$$ = chain_reserve_entry($1, $2);
};
;
v0_memreserve:
memreserve
{
$$ = $1;
}
| label DT_MEMRESERVE addr '-' addr ';'
{
$$ = build_reserve_entry($3, $5 - $3 + 1, $1);
}
;
addr:
DT_LITERAL
{
$$ = eval_literal($1, 0, 64);
}
| DT_LEGACYLITERAL
{
$$ = eval_literal($1, 16, 64);
}
;
devicetree:
@ -208,9 +175,11 @@ propdata:
if ($6 != 0)
if (fseek(file->file, $6, SEEK_SET) != 0)
yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6,
$4.val, strerror(errno));
srcpos_error(&yylloc,
"Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6,
$4.val,
strerror(errno));
d = data_copy_file(file->file, $8);
@ -269,23 +238,11 @@ celllist:
}
;
cellbase:
/* empty */
{
$$ = 16;
}
| DT_BASE
;
cellval:
DT_LITERAL
{
$$ = eval_literal($1, 0, 32);
}
| cellbase DT_LEGACYLITERAL
{
$$ = eval_literal($2, $1, 32);
}
;
bytestring:
@ -339,26 +296,10 @@ label:
%%
void yyerrorf(char const *s, ...)
void yyerror(char const *s)
{
const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
va_list va;
va_start(va, s);
if (strcmp(fname, "-") == 0)
fname = "stdin";
fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
vfprintf(stderr, s, va);
fprintf(stderr, "\n");
srcpos_error(&yylloc, "%s", s);
treesource_error = 1;
va_end(va);
}
void yyerror (char const *s)
{
yyerrorf("%s", s);
}
static unsigned long long eval_literal(const char *s, int base, int bits)

23
dtc.c
View File

@ -30,6 +30,7 @@ int quiet; /* Level of quietness */
int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
char *join_path(const char *path, const char *name)
{
@ -106,6 +107,11 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
fprintf(stderr, "\t-v\n");
fprintf(stderr, "\t\tPrint DTC version and exit\n");
fprintf(stderr, "\t-H <phandle format>\n");
fprintf(stderr, "\t\tphandle formats are:\n");
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
exit(3);
}
@ -127,7 +133,7 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) {
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:")) != EOF) {
switch (opt) {
case 'I':
inform = optarg;
@ -165,6 +171,18 @@ int main(int argc, char *argv[])
case 'v':
printf("Version: %s\n", DTC_VERSION);
exit(0);
case 'H':
if (streq(optarg, "legacy"))
phandle_format = PHANDLE_LEGACY;
else if (streq(optarg, "epapr"))
phandle_format = PHANDLE_EPAPR;
else if (streq(optarg, "both"))
phandle_format = PHANDLE_BOTH;
else
die("Invalid argument \"%s\" to -H option\n",
optarg);
break;
case 'h':
default:
usage();
@ -182,6 +200,9 @@ int main(int argc, char *argv[])
if (minsize && padsize)
die("Can't set both -p and -S\n");
if (minsize)
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);

43
dtc.h
View File

@ -34,7 +34,17 @@
#include <libfdt_env.h>
#include <fdt.h>
#include "util.h"
#ifdef DEBUG
#define debug(fmt,args...) printf(fmt, ##args)
#else
#define debug(fmt,args...)
#endif
#define DEFAULT_FDT_VERSION 17
/*
* Command line options
*/
@ -42,36 +52,11 @@ extern int quiet; /* Level of quietness */
extern int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int phandle_format; /* Use linux,phandle or phandle properties */
static inline void __attribute__((noreturn)) die(char * str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (! new)
die("malloc() failed\n");
return new;
}
static inline void *xrealloc(void *p, size_t len)
{
void *new = realloc(p, len);
if (! new)
die("realloc() failed (len=%d)\n", len);
return new;
}
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
#define PHANDLE_BOTH 0x3
typedef uint32_t cell_t;

View File

@ -127,11 +127,21 @@ static void emit_offset_label(FILE *f, const char *label, int offset)
fprintf(f, "%s\t= . + %d\n", label, offset);
}
#define ASM_EMIT_BELONG(f, fmt, ...) \
{ \
fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
}
static void asm_emit_cell(void *e, cell_t val)
{
FILE *f = e;
fprintf(f, "\t.long\t0x%x\n", val);
fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
(val >> 24) & 0xff, (val >> 16) & 0xff,
(val >> 8) & 0xff, val & 0xff);
}
static void asm_emit_string(void *e, char *str, int len)
@ -156,7 +166,7 @@ static void asm_emit_align(void *e, int a)
{
FILE *f = e;
fprintf(f, "\t.balign\t%d\n", a);
fprintf(f, "\t.balign\t%d, 0\n", a);
}
static void asm_emit_data(void *e, struct data d)
@ -169,8 +179,7 @@ static void asm_emit_data(void *e, struct data d)
emit_offset_label(f, m->ref, m->offset);
while ((d.len - off) >= sizeof(uint32_t)) {
fprintf(f, "\t.long\t0x%x\n",
fdt32_to_cpu(*((uint32_t *)(d.val+off))));
asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
off += sizeof(uint32_t);
}
@ -190,14 +199,16 @@ static void asm_emit_beginnode(void *e, const char *label)
fprintf(f, "\t.globl\t%s\n", label);
fprintf(f, "%s:\n", label);
}
fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
asm_emit_cell(e, FDT_BEGIN_NODE);
}
static void asm_emit_endnode(void *e, const char *label)
{
FILE *f = e;
fprintf(f, "\t.long\tFDT_END_NODE\n");
fprintf(f, "\t/* FDT_END_NODE */\n");
asm_emit_cell(e, FDT_END_NODE);
if (label) {
fprintf(f, "\t.globl\t%s_end\n", label);
fprintf(f, "%s_end:\n", label);
@ -212,7 +223,8 @@ static void asm_emit_property(void *e, const char *label)
fprintf(f, "\t.globl\t%s\n", label);
fprintf(f, "%s:\n", label);
}
fprintf(f, "\t.long\tFDT_PROP\n");
fprintf(f, "\t/* FDT_PROP */\n");
asm_emit_cell(e, FDT_PROP);
}
static struct emitter asm_emitter = {
@ -413,10 +425,13 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
if (padlen > 0)
blob = data_append_zeroes(blob, padlen);
fwrite(blob.val, blob.len, 1, f);
if (ferror(f))
die("Error writing device tree blob: %s\n", strerror(errno));
if (fwrite(blob.val, blob.len, 1, f) != 1) {
if (ferror(f))
die("Error writing device tree blob: %s\n",
strerror(errno));
else
die("Short write on device tree blob\n");
}
/*
* data_merge() frees the right-hand element so only the blob
@ -455,39 +470,44 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
die("Unknown device tree blob version %d\n", version);
fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
fprintf(f, "\n");
emit_label(f, symprefix, "blob_start");
emit_label(f, symprefix, "header");
fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
symprefix, symprefix);
fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
symprefix, symprefix);
fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
symprefix, symprefix);
fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
symprefix, symprefix);
fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
vi->last_comp_version);
if (vi->flags & FTF_BOOTCPUID)
fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
bi->boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE)
fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
fprintf(f, "\t/* magic */\n");
asm_emit_cell(f, FDT_MAGIC);
fprintf(f, "\t/* totalsize */\n");
ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_dt_struct */\n");
ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_dt_strings */\n");
ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_mem_rsvmap */\n");
ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* version */\n");
asm_emit_cell(f, vi->version);
fprintf(f, "\t/* last_comp_version */\n");
asm_emit_cell(f, vi->last_comp_version);
if (vi->flags & FTF_STRUCTSIZE)
fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
if (vi->flags & FTF_BOOTCPUID) {
fprintf(f, "\t/* boot_cpuid_phys */\n");
asm_emit_cell(f, bi->boot_cpuid_phys);
}
if (vi->flags & FTF_STRTABSIZE) {
fprintf(f, "\t/* size_dt_strings */\n");
ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
symprefix, symprefix);
}
if (vi->flags & FTF_STRUCTSIZE) {
fprintf(f, "\t/* size_dt_struct */\n");
ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
symprefix, symprefix);
}
/*
* Reserve map entries.
@ -509,12 +529,11 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
fprintf(f, "\t.globl\t%s\n", re->label);
fprintf(f, "%s:\n", re->label);
}
fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
(unsigned int)(re->re.address >> 32),
(unsigned int)(re->re.address & 0xffffffff));
fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
(unsigned int)(re->re.size >> 32),
(unsigned int)(re->re.size & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
ASM_EMIT_BELONG(f, "0x%08x",
(unsigned int)(re->re.address & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
}
for (i = 0; i < reservenum; i++) {
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
@ -524,7 +543,9 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
emit_label(f, symprefix, "struct_start");
flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
fprintf(f, "\t.long\tFDT_END\n");
fprintf(f, "\t/* FDT_END */\n");
asm_emit_cell(f, FDT_END);
emit_label(f, symprefix, "struct_end");
emit_label(f, symprefix, "strings_start");
@ -601,7 +622,7 @@ static char *flat_read_string(struct inbuf *inb)
len++;
} while ((*p++) != '\0');
str = strdup(inb->ptr);
str = xstrdup(inb->ptr);
inb->ptr += len;
@ -643,7 +664,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
p++;
}
return strdup(inb->base + offset);
return xstrdup(inb->base + offset);
}
static struct property *flat_read_property(struct inbuf *dtbuf,
@ -710,7 +731,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath)
if (!streq(ppath, "/"))
plen++;
return strdup(cpath + plen);
return xstrdup(cpath + plen);
}
static struct node *unflatten_tree(struct inbuf *dtbuf,

View File

@ -58,7 +58,7 @@ static struct node *read_fstree(const char *dirname)
"WARNING: Cannot open %s: %s\n",
tmpnam, strerror(errno));
} else {
prop = build_property(strdup(de->d_name),
prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile,
st.st_size),
NULL);
@ -69,7 +69,7 @@ static struct node *read_fstree(const char *dirname)
struct node *newchild;
newchild = read_fstree(tmpnam);
newchild = name_node(newchild, strdup(de->d_name),
newchild = name_node(newchild, xstrdup(de->d_name),
NULL);
add_child(tree, newchild);
}

View File

@ -4,15 +4,18 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fdt.h>
#include <libfdt_env.h>
#define FTDUMP_BUF_SIZE 65536
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4)))
#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
static int is_printable_string(const void *data, int len)
{
@ -38,10 +41,10 @@ static int is_printable_string(const void *data, int len)
return 1;
}
static void print_data(const void *data, int len)
static void print_data(const char *data, int len)
{
int i;
const uint8_t *s;
const char *p = data;
/* no data, don't print */
if (len == 0)
@ -52,13 +55,13 @@ static void print_data(const void *data, int len)
} else if ((len % 4) == 0) {
printf(" = <");
for (i = 0; i < len; i += 4)
printf("%08x%s", *((const uint32_t *)data + i),
printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
i < (len - 4) ? " " : "");
printf(">");
} else {
printf(" = [");
for (i = 0, s = data; i < len; i++)
printf("%02x%s", s[i], i < len - 1 ? " " : "");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
@ -71,13 +74,12 @@ static void dump_blob(void *blob)
uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
struct fdt_reserve_entry *p_rsvmap =
(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
char *p_struct = (char *)blob + off_dt;
char *p_strings = (char *)blob + off_str;
const char *p_struct = (const char *)blob + off_dt;
const char *p_strings = (const char *)blob + off_str;
uint32_t version = fdt32_to_cpu(bph->version);
uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
uint32_t tag;
char *p;
char *s, *t;
const char *p, *s, *t;
int depth, sz, shift;
int i;
uint64_t addr, size;
@ -85,6 +87,7 @@ static void dump_blob(void *blob)
depth = 0;
shift = 4;
printf("/dts-v1/;\n");
printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
printf("// off_dt_struct:\t0x%x\n", off_dt);
@ -167,7 +170,7 @@ static void dump_blob(void *blob)
int main(int argc, char *argv[])
{
FILE *fp;
char buf[16384]; /* 16k max */
char *buf;
int size;
if (argc < 2) {
@ -175,15 +178,25 @@ int main(int argc, char *argv[])
return 5;
}
fp = fopen(argv[1], "rb");
if (fp == NULL) {
fprintf(stderr, "unable to open %s\n", argv[1]);
if (strcmp(argv[1], "-") == 0) {
fp = stdin;
} else {
fp = fopen(argv[1], "rb");
if (fp == NULL) {
fprintf(stderr, "unable to open %s\n", argv[1]);
return 10;
}
}
buf = malloc(FTDUMP_BUF_SIZE);
if (!buf) {
fprintf(stderr, "Couldn't allocate %d byte buffer\n", FTDUMP_BUF_SIZE);
return 10;
}
size = fread(buf, 1, sizeof(buf), fp);
if (size == sizeof(buf)) { /* too large */
fprintf(stderr, "file too large\n");
size = fread(buf, 1, FTDUMP_BUF_SIZE, fp);
if (size == FTDUMP_BUF_SIZE) {
fprintf(stderr, "file too large (maximum is %d bytes)\n", FTDUMP_BUF_SIZE);
return 10;
}

View File

@ -4,5 +4,6 @@
# be easily embeddable into other systems of Makefiles.
#
LIBFDT_INCLUDES = fdt.h libfdt.h
LIBFDT_VERSION = version.lds
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)

View File

@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt)
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, int len)
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
const char *p;
@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len)
return p;
}
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
int offset = startoffset;
const char *p;
if (offset % FDT_TAGSIZE)
return -1;
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
if (!tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
*nextoffset = -FDT_ERR_BADSTRUCTURE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
if (!p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp)
return FDT_END;
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
if (!lenp)
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
break;
case FDT_END:
case FDT_END_NODE:
case FDT_NOP:
break;
default:
return FDT_END;
}
if (nextoffset)
*nextoffset = FDT_TAGALIGN(offset);
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
return tag;
}
@ -162,15 +173,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
break;
case FDT_END_NODE:
if (depth)
(*depth)--;
if (depth && ((--(*depth)) < 0))
return nextoffset;
break;
case FDT_END:
return -FDT_ERR_NOTFOUND;
default:
return -FDT_ERR_BADSTRUCTURE;
if ((nextoffset >= 0)
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
return -FDT_ERR_NOTFOUND;
else
return nextoffset;
}
} while (tag != FDT_BEGIN_NODE);

View File

@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset)
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
static int _fdt_string_eq(const void *fdt, int stroffset,
const char *s, int len)
{
const char *p = fdt_string(fdt, stroffset);
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
@ -105,15 +113,14 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
FDT_CHECK_HEADER(fdt);
for (depth = 0;
offset >= 0;
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth < 0)
return -FDT_ERR_NOTFOUND;
else if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen))
(offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen))
return offset;
}
if (depth < 0)
return -FDT_ERR_NOTFOUND;
return offset; /* error */
}
@ -131,8 +138,20 @@ int fdt_path_offset(const void *fdt, const char *path)
FDT_CHECK_HEADER(fdt);
if (*path != '/')
return -FDT_ERR_BADPATH;
/* see if we have an alias */
if (*path != '/') {
const char *q = strchr(path, '/');
if (!q)
q = end;
p = fdt_get_alias_namelen(fdt, p, q - p);
if (!p)
return -FDT_ERR_BADPATH;
offset = fdt_path_offset(fdt, p);
p = q;
}
while (*p) {
const char *q;
@ -175,13 +194,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
return NULL;
}
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset,
const char *name,
int namelen, int *lenp)
{
uint32_t tag;
const struct fdt_property *prop;
int namestroff;
int offset, nextoffset;
int err;
@ -196,38 +215,24 @@ const struct fdt_property *fdt_get_property(const void *fdt,
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
err = -FDT_ERR_TRUNCATED;
if (nextoffset < 0)
err = nextoffset;
else
/* FDT_END tag with unclosed nodes */
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
case FDT_BEGIN_NODE:
case FDT_END_NODE:
case FDT_NOP:
break;
case FDT_PROP:
err = -FDT_ERR_BADSTRUCTURE;
prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
if (! prop)
goto fail;
namestroff = fdt32_to_cpu(prop->nameoff);
if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
prop = _fdt_offset_ptr(fdt, offset);
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen)) {
/* Found it! */
int len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, offset,
sizeof(*prop)+len);
if (! prop)
goto fail;
if (lenp)
*lenp = len;
*lenp = fdt32_to_cpu(prop->len);
return prop;
}
break;
default:
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
@ -238,30 +243,66 @@ const struct fdt_property *fdt_get_property(const void *fdt,
return NULL;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
{
return fdt_get_property_namelen(fdt, nodeoffset, name,
strlen(name), lenp);
}
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property(fdt, nodeoffset, name, lenp);
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop)
return NULL;
return prop->data;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const uint32_t *php;
int len;
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice. */
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
if (!php || (len != sizeof(*php))) {
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
}
return fdt32_to_cpu(*php);
}
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
int aliasoffset;
aliasoffset = fdt_path_offset(fdt, "/aliases");
if (aliasoffset < 0)
return NULL;
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
}
const char *fdt_get_alias(const void *fdt, const char *name)
{
return fdt_get_alias_namelen(fdt, name, strlen(name));
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
@ -276,9 +317,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (pdepth < depth)
continue; /* overflowed buffer */
while (pdepth > depth) {
do {
p--;
@ -286,14 +324,16 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
pdepth--;
}
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
if (pdepth >= depth) {
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
}
}
if (offset == nodeoffset) {
@ -303,7 +343,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
if (p > 1) /* special case so that root path is "/", not "" */
p--;
buf[p] = '\0';
return p;
return 0;
}
}
@ -401,14 +441,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
phandle = cpu_to_fdt32(phandle);
return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
&phandle, sizeof(phandle));
FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle(), then if that didn't find what
* we want, we scan over them again making our way to the next
* node. Still it's the easiest to implement approach;
* performance can come later. */
for (offset = fdt_next_node(fdt, -1, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
if (fdt_get_phandle(fdt, offset) == phandle)
return offset;
}
return offset; /* error from fdt_next_node() */
}
int _stringlist_contains(const char *strlist, int listlen, const char *str)
static int _fdt_stringlist_contains(const char *strlist, int listlen,
const char *str)
{
int len = strlen(str);
const char *p;
@ -434,7 +491,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
if (_stringlist_contains(prop, len, compatible))
if (_fdt_stringlist_contains(prop, len, compatible))
return 0;
else
return 1;

View File

@ -406,6 +406,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
if (struct_size < 0)
return struct_size;
}
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {

View File

@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt)
return err; \
}
static void *_fdt_grab_space(void *fdt, int len)
static void *_fdt_grab_space(void *fdt, size_t len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, int len)
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w(fdt, offset, len);
return _fdt_offset_ptr_w(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
@ -237,18 +237,17 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
_fdt_offset_ptr_w(fdt, offset);
int nameoff;
if (! prop)
return -FDT_ERR_BADSTRUCTURE;
nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff);
}
offset = nextoffset;
}
if (nextoffset < 0)
return nextoffset;
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));

View File

@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
return 0;
}
int _fdt_node_end_offset(void *fdt, int nodeoffset)
int _fdt_node_end_offset(void *fdt, int offset)
{
int level = 0;
uint32_t tag;
int offset, nextoffset;
int depth = 0;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
while ((offset >= 0) && (depth >= 0))
offset = fdt_next_node(fdt, offset, &depth);
switch (tag) {
case FDT_END:
return offset;
case FDT_BEGIN_NODE:
level++;
break;
case FDT_END_NODE:
level--;
break;
case FDT_PROP:
case FDT_NOP:
break;
default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (level >= 0);
return nextoffset;
return offset;
}
int fdt_nop_node(void *fdt, int nodeoffset)

View File

@ -122,7 +122,7 @@
/* Low-level functions (you probably don't need these) */
/**********************************************************************/
const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
{
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
@ -156,7 +156,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth);
#define __fdt_set_hdr(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \
struct fdt_header *fdth = fdt; \
struct fdt_header *fdth = (struct fdt_header*)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
__fdt_set_hdr(magic);
@ -342,6 +342,22 @@ int fdt_path_offset(const void *fdt, const char *path);
*/
const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
/**
* fdt_get_property_namelen - find a property based on substring
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @namelen: number of characters of name to consider
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* Identical to fdt_get_property_namelen(), but only examine the first
* namelen characters of name for matching the property name.
*/
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset,
const char *name,
int namelen, int *lenp);
/**
* fdt_get_property - find a given property in a given node
* @fdt: pointer to the device tree blob
@ -379,6 +395,20 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
fdt_get_property(fdt, nodeoffset, name, lenp);
}
/**
* fdt_getprop_namelen - get property value based on substring
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @namelen: number of characters of name to consider
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* Identical to fdt_getprop(), but only examine the first namelen
* characters of name for matching the property name.
*/
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp);
/**
* fdt_getprop - retrieve the value of a given property
* @fdt: pointer to the device tree blob
@ -428,6 +458,32 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
*/
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
/**
* fdt_get_alias_namelen - get alias based on substring
* @fdt: pointer to the device tree blob
* @name: name of the alias th look up
* @namelen: number of characters of name to consider
*
* Identical to fdt_get_alias(), but only examine the first namelen
* characters of name for matching the alias name.
*/
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen);
/**
* fdt_get_alias - retreive the path referenced by a given alias
* @fdt: pointer to the device tree blob
* @name: name of the alias th look up
*
* fdt_get_alias() retrieves the value of a given alias. That is, the
* value of the property named 'name' in the node /aliases.
*
* returns:
* a pointer to the expansion of the alias named 'name', of it exists
* NULL, if the given alias or the /aliases node does not exist
*/
const char *fdt_get_alias(const void *fdt, const char *name);
/**
* fdt_get_path - determine the full path of a node
* @fdt: pointer to the device tree blob

View File

@ -62,7 +62,6 @@
return err; \
}
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
int _fdt_check_node_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);

54
libfdt/version.lds Normal file
View File

@ -0,0 +1,54 @@
LIBFDT_1.2 {
global:
fdt_next_node;
fdt_check_header;
fdt_move;
fdt_string;
fdt_num_mem_rsv;
fdt_get_mem_rsv;
fdt_subnode_offset_namelen;
fdt_subnode_offset;
fdt_path_offset;
fdt_get_name;
fdt_get_property_namelen;
fdt_get_property;
fdt_getprop_namelen;
fdt_getprop;
fdt_get_phandle;
fdt_get_alias_namelen;
fdt_get_alias;
fdt_get_path;
fdt_supernode_atdepth_offset;
fdt_node_depth;
fdt_parent_offset;
fdt_node_offset_by_prop_value;
fdt_node_offset_by_phandle;
fdt_node_check_compatible;
fdt_node_offset_by_compatible;
fdt_setprop_inplace;
fdt_nop_property;
fdt_nop_node;
fdt_create;
fdt_add_reservemap_entry;
fdt_finish_reservemap;
fdt_begin_node;
fdt_property;
fdt_end_node;
fdt_finish;
fdt_open_into;
fdt_pack;
fdt_add_mem_rsv;
fdt_del_mem_rsv;
fdt_set_name;
fdt_setprop;
fdt_delprop;
fdt_add_subnode_namelen;
fdt_add_subnode;
fdt_del_node;
fdt_strerror;
fdt_offset_ptr;
fdt_next_tag;
local:
*;
};

View File

@ -293,16 +293,28 @@ cell_t get_node_phandle(struct node *root, struct node *node)
if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle;
assert(! get_property(node, "linux,phandle"));
while (get_node_by_phandle(root, phandle))
phandle++;
node->phandle = phandle;
add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle),
NULL));
if (!get_property(node, "linux,phandle")
&& (phandle_format & PHANDLE_LEGACY))
add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle),
NULL));
if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR))
add_property(node,
build_property("phandle",
data_append_cell(empty_data, phandle),
NULL));
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
* fixed up momentarily in the caller */
return node->phandle;
}

148
srcpos.c
View File

@ -17,18 +17,40 @@
* USA
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "dtc.h"
#include "srcpos.h"
/*
* Like yylineno, this is the current open file pos.
*/
struct dtc_file *srcpos_file;
static int dtc_open_one(struct dtc_file *file,
const char *search,
const char *fname)
/*
* The empty source position.
*/
struct dtc_file dtc_empty_file = {
.dir = NULL,
.name = "<no file>",
.file = NULL
};
srcpos srcpos_empty = {
.first_line = 0,
.first_column = 0,
.last_line = 0,
.last_column = 0,
.file = &dtc_empty_file
};
static int
dtc_open_one(struct dtc_file *file, const char *search, const char *fname)
{
char *fullname;
@ -39,7 +61,7 @@ static int dtc_open_one(struct dtc_file *file,
strcat(fullname, "/");
strcat(fullname, fname);
} else {
fullname = strdup(fname);
fullname = xstrdup(fname);
}
file->file = fopen(fullname, "r");
@ -53,8 +75,8 @@ static int dtc_open_one(struct dtc_file *file,
}
struct dtc_file *dtc_open_file(const char *fname,
const struct search_path *search)
struct dtc_file *
dtc_open_file(const char *fname, const struct search_path *search)
{
static const struct search_path default_search = { NULL, NULL, NULL };
@ -85,7 +107,7 @@ struct dtc_file *dtc_open_file(const char *fname,
if (!file->file)
goto fail;
file->name = strdup(fname);
file->name = xstrdup(fname);
return file;
}
@ -106,11 +128,113 @@ struct dtc_file *dtc_open_file(const char *fname,
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
}
void dtc_close_file(struct dtc_file *file)
void
dtc_close_file(struct dtc_file *file)
{
if (fclose(file->file))
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
free(file->dir);
free(file);
}
srcpos *
srcpos_copy(srcpos *pos)
{
srcpos *pos_new;
pos_new = xmalloc(sizeof(srcpos));
memcpy(pos_new, pos, sizeof(srcpos));
return pos_new;
}
void
srcpos_dump(srcpos *pos)
{
printf("file : \"%s\"\n",
pos->file ? (char *) pos->file : "<no file>");
printf("first_line : %d\n", pos->first_line);
printf("first_column: %d\n", pos->first_column);
printf("last_line : %d\n", pos->last_line);
printf("last_column : %d\n", pos->last_column);
printf("file : %s\n", pos->file->name);
}
char *
srcpos_string(srcpos *pos)
{
const char *fname;
char col_buf[100];
char *pos_str;
if (!pos) {
fname = "<no-file>";
} else if (pos->file->name) {
fname = pos->file->name;
if (strcmp(fname, "-") == 0)
fname = "stdin";
} else {
fname = "<no-file>";
}
if (pos->first_line == pos->last_line) {
if (pos->first_column == pos->last_column) {
snprintf(col_buf, sizeof(col_buf),
"%d:%d",
pos->first_line, pos->first_column);
} else {
snprintf(col_buf, sizeof(col_buf),
"%d:%d-%d",
pos->first_line,
pos->first_column, pos->last_column);
}
} else {
snprintf(col_buf, sizeof(col_buf),
"%d:%d - %d:%d",
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
}
if (asprintf(&pos_str, "%s %s", fname, col_buf) == -1)
return "<unknown source position?";
return pos_str;
}
void
srcpos_error(srcpos *pos, char const *fmt, ...)
{
const char *srcstr;
va_list va;
va_start(va, fmt);
srcstr = srcpos_string(pos);
fprintf(stderr, "Error: %s ", srcstr);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
}
void
srcpos_warn(srcpos *pos, char const *fmt, ...)
{
const char *srcstr;
va_list va;
va_start(va, fmt);
srcstr = srcpos_string(pos);
fprintf(stderr, "Warning: %s ", srcstr);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
}

View File

@ -17,6 +17,9 @@
* USA
*/
#ifndef _SRCPOS_H_
#define _SRCPOS_H_
/*
* Augment the standard YYLTYPE with a filenum index into an
* array of all opened filenames.
@ -69,9 +72,14 @@ typedef struct YYLTYPE {
while (YYID (0))
typedef YYLTYPE srcpos;
extern void yyerror(char const *);
extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
/*
* Fictional source position used for IR nodes that are
* created without otherwise knowing a true source position.
* For example,constant definitions from the command line.
*/
extern srcpos srcpos_empty;
extern struct dtc_file *srcpos_file;
@ -83,3 +91,14 @@ struct search_path {
extern struct dtc_file *dtc_open_file(const char *fname,
const struct search_path *search);
extern void dtc_close_file(struct dtc_file *file);
extern srcpos *srcpos_copy(srcpos *pos);
extern char *srcpos_string(srcpos *pos);
extern void srcpos_dump(srcpos *pos);
extern void srcpos_error(srcpos *pos, char const *, ...)
__attribute__((format(printf, 2, 3)));
extern void srcpos_warn(srcpos *pos, char const *, ...)
__attribute__((format(printf, 2, 3)));
#endif /* _SRCPOS_H_ */

View File

@ -4,20 +4,26 @@ LIB_TESTS_L = get_mem_rsv \
get_path supernode_atdepth_offset parent_offset \
node_offset_by_prop_value node_offset_by_phandle \
node_check_compatible node_offset_by_compatible \
get_alias \
notfound \
setprop_inplace nop_property nop_node \
sw_tree1 \
move_and_save mangle-layout nopulate \
open_pack rw_tree1 set_name setprop del_property del_node \
string_escapes references path-references boot-cpuid incbin \
string_escapes references path-references phandle_format \
boot-cpuid incbin \
extra-terminating-null \
dtbs_equal_ordered \
add_subnode_with_nops
add_subnode_with_nops path_offset_aliases
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
LIBTREE_TESTS_L = truncated_property
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS)
DL_LIB_TESTS_L = asm_tree_dump value-labels
DL_LIB_TESTS = $(DL_LIB_TESTS_L:%=$(TESTS_PREFIX)%)
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS) $(DL_LIB_TESTS)
TESTS_TREES_L = test_tree1.dtb
TESTS_TREES = $(TESTS_TREES_L:%=$(TESTS_PREFIX)%)
@ -28,16 +34,19 @@ TESTS_DEPFILES = $(TESTS:%=%.d) \
$(addprefix $(TESTS_PREFIX),testutils.d trees.d dumptrees.d)
TESTS_CLEANFILES_L = *.output vglog.* vgcore.* *.dtb *.test.dts *.dtsv1 tmp.*
TESTS_CLEANFILES = $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
BIN += $(TESTS) $(TESTS_PREFIX)dumptrees
TESTS_CLEANFILES_L += dumptrees
TESTS_CLEANFILES = $(TESTS) $(TESTS_CLEANFILES_L:%=$(TESTS_PREFIX)%)
.PHONY: tests
tests: $(TESTS) $(TESTS_TREES)
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_lib)
$(LIB_TESTS): %: $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_lib)
$(DL_LIB_TESTS): %: %.o $(TESTS_PREFIX)testutils.o $(LIBFDT_archive)
@$(VECHO) LD [libdl] $@
$(LINK.c) -o $@ $^ -ldl
$(LIBTREE_TESTS): %: $(TESTS_PREFIX)testutils.o $(TESTS_PREFIX)trees.o $(LIBFDT_archive)
$(TESTS_PREFIX)dumptrees: $(TESTS_PREFIX)trees.o

21
tests/aliases.dts Normal file
View File

@ -0,0 +1,21 @@
/dts-v1/;
/ {
aliases {
s1 = &sub1;
ss1 = &subsub1;
sss1 = &subsubsub1;
};
sub1: subnode@1 {
compatible = "subnode1";
subsub1: subsubnode {
compatible = "subsubnode1", "subsubnode";
subsubsub1: subsubsubnode {
compatible = "subsubsubnode1", "subsubsubnode";
};
};
};
};

62
tests/asm_tree_dump.c Normal file
View File

@ -0,0 +1,62 @@
/*
* libfdt - Flat Device Tree manipulation
* Tests if an asm tree built into a shared object matches a given dtb
* Copyright (C) 2008 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <dlfcn.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
int main(int argc, char *argv[])
{
void *sohandle;
void *fdt;
int err;
test_init(argc, argv);
if (argc != 3)
CONFIG("Usage: %s <so file> <dtb file>", argv[0]);
sohandle = dlopen(argv[1], RTLD_NOW);
if (!sohandle)
FAIL("Couldn't dlopen() %s", argv[1]);
fdt = dlsym(sohandle, "dt_blob_start");
if (!fdt)
FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
argv[1]);
err = fdt_check_header(fdt);
if (err != 0)
FAIL("%s contains invalid tree: %s", argv[1],
fdt_strerror(err));
save_blob(argv[2], fdt);
PASS();
}

View File

@ -1,3 +1,5 @@
/dts-v1/;
/ {
model = "SomeModel";
compatible = "Nothing";
@ -6,26 +8,26 @@
memory@0 {
device_type = "memory";
reg = <00000000 00000000 00000000 20000000>;
reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
d10 = <d# 10>; // hex: 0xa
d23 = <d# 23>; // hex: 0x17
b101 = <b# 101>; // hex: 0x5
o17 = <o# 17>; // hex: 0xf
hd00d = <h# d00d>; // hex: 0xd00d
d10 = < 10>; // hex: 0xa
d23 = < 23>; // hex: 0x17
b101 = < 0x5>; // hex: 0x5
o17 = < 017>; // hex: 0xf
hd00d = < 0xd00d>; // hex: 0xd00d
// hex: 0x4d2 0x163e 0x2334 0xd80
stuff = <d# 1234 d# 5678 d# 9012 d# 3456>;
stuff = < 1234 5678 9012 3456>;
bad-d-1 = <d# abc123>; // Hrm. 0
bad-d-2 = <d# 123456789012345>;
bad-o-1 = <o# 891>;
bad-o-2 = <o# 123456123456>;
bad-d-1 = < 0>; // Hrm. 0
bad-d-2 = < 123456789012345>;
bad-o-1 = < 00>;
bad-o-2 = < 0123456123456>;
};
};

3
tests/data.S Normal file
View File

@ -0,0 +1,3 @@
/* Used in combination with dtc -Oasm output to embed
* a device tree in the data section of a .o */
.data

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void compare_mem_rsv(const void *fdt1, const void *fdt2)
static void compare_mem_rsv(const void *fdt1, const void *fdt2)
{
int i;
uint64_t addr1, size1, addr2, size2;
@ -56,7 +56,7 @@ void compare_mem_rsv(const void *fdt1, const void *fdt2)
}
}
void compare_structure(const void *fdt1, const void *fdt2)
static void compare_structure(const void *fdt1, const void *fdt2)
{
int nextoffset1 = 0, nextoffset2 = 0;
int offset1, offset2;

View File

@ -1,2 +1,4 @@
/dts-v1/;
/ {
};

View File

@ -1,3 +1,5 @@
/dts-v1/;
/ {
compatible = "test_string_escapes";
escape-str = "nastystring: \a\b\t\n\v\f\r\\\"";

View File

@ -0,0 +1,59 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for properties with more than one terminating null
* Copyright (C) 2009 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
void check_extranull(void *fdt, const char *prop, const char *str, int numnulls)
{
int len = strlen(str);
char checkbuf[len+numnulls];
memset(checkbuf, 0, sizeof(checkbuf));
memcpy(checkbuf, TEST_STRING_1, len);
check_getprop(fdt, 0, prop, len+numnulls, checkbuf);
}
int main(int argc, char *argv[])
{
void *fdt;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
check_extranull(fdt, "extranull0", TEST_STRING_1, 1);
check_extranull(fdt, "extranull1,1", TEST_STRING_1, 2);
check_extranull(fdt, "extranull1,2", TEST_STRING_1, 2);
check_extranull(fdt, "extranull2,1", TEST_STRING_1, 3);
check_extranull(fdt, "extranull2,2", TEST_STRING_1, 3);
check_extranull(fdt, "extranull2,3", TEST_STRING_1, 3);
check_extranull(fdt, "extranull2,4", TEST_STRING_1, 3);
PASS();
}

View File

@ -0,0 +1,11 @@
/dts-v1/;
/ {
extranull0 = "hello world";
extranull1,1 = "hello world\0";
extranull1,2 = "hello world", "";
extranull2,1 = "hello world\0\0";
extranull2,2 = "hello world", "", "";
extranull2,3 = "hello world\0", "";
extranull2,4 = "hello world", "\0";
};

58
tests/get_alias.c Normal file
View File

@ -0,0 +1,58 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_get_alias()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
void check_alias(void *fdt, const char *path, const char *alias)
{
const char *aliaspath;
aliaspath = fdt_get_alias(fdt, alias);
if (path && !aliaspath)
FAIL("fdt_get_alias(%s) failed\n", alias);
if (strcmp(aliaspath, path) != 0)
FAIL("fdt_get_alias(%s) returned %s instead of %s\n",
alias, aliaspath, path);
}
int main(int argc, char *argv[])
{
void *fdt;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
check_alias(fdt, "/subnode@1", "s1");
check_alias(fdt, "/subnode@1/subsubnode", "ss1");
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
PASS();
}

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_name(void *fdt, const char *path)
static void check_name(void *fdt, const char *path)
{
int offset;
const char *getname, *getname2, *checkname;

View File

@ -30,7 +30,7 @@
#define POISON ('\xff')
void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
static void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
{
int offset;
char buf[buflen+1];
@ -43,6 +43,8 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
memset(buf, POISON, sizeof(buf)); /* poison the buffer */
len = fdt_get_path(fdt, offset, buf, buflen);
verbose_printf("get_path() %s -> %d -> %s\n", path, offset, buf);
if (buflen <= pathlen) {
if (len != -FDT_ERR_NOSPACE)
FAIL("fdt_get_path([%d bytes]) returns %d with "
@ -51,9 +53,9 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
if (len < 0)
FAIL("fdt_get_path([%d bytes]): %s", buflen,
fdt_strerror(len));
if (len != pathlen)
FAIL("fdt_get_path([%d bytes]) reports length %d "
"instead of %d", buflen, len, pathlen);
if (len != 0)
FAIL("fdt_get_path([%d bytes]) returns %d "
"instead of 0", buflen, len);
if (strcmp(buf, path) != 0)
FAIL("fdt_get_path([%d bytes]) returns \"%s\" "
"instead of \"%s\"", buflen, buf, path);
@ -63,13 +65,15 @@ void check_path_buf(void *fdt, const char *path, int pathlen, int buflen)
FAIL("fdt_get_path([%d bytes]) overran buffer", buflen);
}
void check_path(void *fdt, const char *path)
static void check_path(void *fdt, const char *path)
{
int pathlen = strlen(path);
check_path_buf(fdt, path, pathlen, 1024);
check_path_buf(fdt, path, pathlen, pathlen+1);
check_path_buf(fdt, path, pathlen, pathlen);
check_path_buf(fdt, path, pathlen, 0);
check_path_buf(fdt, path, pathlen, 2);
}
int main(int argc, char *argv[])

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_phandle(void *fdt, const char *path, uint32_t checkhandle)
static void check_phandle(void *fdt, const char *path, uint32_t checkhandle)
{
int offset;
uint32_t phandle;

View File

@ -31,7 +31,7 @@
#define CHUNKSIZE 1024
char *load_file(const char *name, int *len)
static char *load_file(const char *name, int *len)
{
FILE *f;
char *buf = NULL;

View File

@ -15,9 +15,12 @@
prop-int = <123456789>;
/include/ "include8.dts"
linux,phandle = <0x2001>;
phandle = <0x2001>;
compatible = "subsubnode2", "subsubnode";
prop-int = <0726746425>;
};
ss2 {
};
};
};

View File

@ -6,4 +6,7 @@
compatible = "subsubnode1", "subsubnode";
prop-int = <0xdeadbeef>;
};
ss1 {
};
};

View File

@ -1,6 +1,8 @@
/memreserve/ 1000000000000000 0000000002000000;
memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
/memreserve/ 0-13;
/dts-v1/;
/memreserve/ 0x1000000000000000 0x0000000002000000;
memrsv2: /memreserve/ 0x2000000000000000 0x0100000000000000;
/memreserve/ 0x0000000000000000 0x0000000000000014;
/ {
model = "MyBoardName";
@ -9,28 +11,28 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
#size-cells = <2>;
cpus {
linux,phandle = <1>;
linux,phandle = <0x1>;
#address-cells = <1>;
#size-cells = <0>;
PowerPC,970@0 {
name = "PowerPC,970";
device_type = "cpu";
reg = <0>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
reg = <0x00000000>;
clock-frequency = <1600000000>;
timebase-frequency = <33333333>;
linux,boot-cpu;
i-cache-size = <10000>;
d-cache-size = <8000>;
i-cache-size = <65536>;
d-cache-size = <32768>;
};
PowerPC,970@1 {
name = "PowerPC,970";
device_type = "cpu";
reg = <1>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
i-cache-size = <10000>;
d-cache-size = <8000>;
reg = <0x00000001>;
clock-frequency = <1600000000>;
timebase-frequency = <33333333>;
i-cache-size = <65536>;
d-cache-size = <32768>;
};
};
@ -38,8 +40,8 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
node: randomnode {
prop: string = str: "foo", str_mid: "stuffstuff\t\t\t\n\n\n" str_end: ;
blob = [byte: 0a 0b 0c 0d byte_mid: de ea ad be ef byte_end: ];
ref = < cell: &/memory@0 0 cell_mid: ffffffff cell_end: >;
mixed = "abc", pre: [1234] post: , gap: < aligned: a b c>;
ref = < cell: &{/memory@0} 0x0 cell_mid: 0xffffffff cell_end: >;
mixed = "abc", pre: [1234] post: , gap: < aligned: 0xa 0xb 0xc>;
tricky1 = [61 lt1: 62 63 00];
subnode: child {
};
@ -49,12 +51,12 @@ memrsv2: /memreserve/ 2000000000000000-20ffffffffffffff;
memory@0 {
device_type = "memory";
memreg: reg = <00000000 00000000 00000000 20000000>;
memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
};
chosen {
bootargs = "root=/dev/sda2";
linux,platform = <00000600>;
linux,platform = <0x600>;
};
};

View File

@ -35,7 +35,7 @@ struct bufstate {
int size;
};
void expand_buf(struct bufstate *buf, int newsize)
static void expand_buf(struct bufstate *buf, int newsize)
{
buf->buf = realloc(buf->buf, newsize);
if (!buf->buf)
@ -43,7 +43,7 @@ void expand_buf(struct bufstate *buf, int newsize)
buf->size = newsize;
}
void new_header(struct bufstate *buf, int version, const void *fdt)
static void new_header(struct bufstate *buf, int version, const void *fdt)
{
int hdrsize;
@ -63,7 +63,7 @@ void new_header(struct bufstate *buf, int version, const void *fdt)
fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
}
void add_block(struct bufstate *buf, int version, char block, const void *fdt)
static void add_block(struct bufstate *buf, int version, char block, const void *fdt)
{
int align, size;
const void *src;

View File

@ -29,7 +29,8 @@
#include "tests.h"
#include "testdata.h"
void check_compatible(const void *fdt, const char *path, const char *compat)
static void check_compatible(const void *fdt, const char *path,
const char *compat)
{
int offset, err;

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void check_search(void *fdt, const char *compat, ...)
static void check_search(void *fdt, const char *compat, ...)
{
va_list ap;
int offset = -1, target;

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void check_search(void *fdt, uint32_t phandle, int target)
static void check_search(void *fdt, uint32_t phandle, int target)
{
int offset;

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
void vcheck_search(void *fdt, const char *propname, const void *propval,
static void vcheck_search(void *fdt, const char *propname, const void *propval,
int proplen, va_list ap)
{
int offset = -1, target;
@ -48,7 +48,7 @@ void vcheck_search(void *fdt, const char *propname, const void *propval,
} while (target >= 0);
}
void check_search(void *fdt, const char *propname, const void *propval,
static void check_search(void *fdt, const char *propname, const void *propval,
int proplen, ...)
{
va_list ap;
@ -58,7 +58,8 @@ void check_search(void *fdt, const char *propname, const void *propval,
va_end(ap);
}
void check_search_str(void *fdt, const char *propname, const char *propval, ...)
static void check_search_str(void *fdt, const char *propname,
const char *propval, ...)
{
va_list ap;

View File

@ -30,7 +30,7 @@
#include "tests.h"
#include "testdata.h"
int nopulate_struct(char *buf, const char *fdt)
static int nopulate_struct(char *buf, const char *fdt)
{
int offset, nextoffset = 0;
uint32_t tag;

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_error(const char *s, int err)
static void check_error(const char *s, int err)
{
if (err != -FDT_ERR_NOTFOUND)
FAIL("%s return error %s instead of -FDT_ERR_NOTFOUND", s,

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
int path_parent_len(const char *path)
static int path_parent_len(const char *path)
{
const char *p = strrchr(path, '/');
@ -40,7 +40,7 @@ int path_parent_len(const char *path)
return p - path;
}
void check_path(struct fdt_header *fdt, const char *path)
static void check_path(struct fdt_header *fdt, const char *path)
{
char *parentpath;
int nodeoffset, parentoffset, parentpathoffset, pathparentlen;

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_ref(const void *fdt, int node, const char *checkpath)
static void check_ref(const void *fdt, int node, const char *checkpath)
{
const char *p;
int len;

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
int check_subnode(void *fdt, int parent, const char *name)
static int check_subnode(void *fdt, int parent, const char *name)
{
int offset;
const struct fdt_node_header *nh;

View File

@ -0,0 +1,59 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_path_offset()
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2008 Kumar Gala, Freescale Semiconductor, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
void check_alias(void *fdt, const char *full_path, const char *alias_path)
{
int offset, offset_a;
offset = fdt_path_offset(fdt, full_path);
offset_a = fdt_path_offset(fdt, alias_path);
if (offset != offset_a)
FAIL("Mismatch between %s path_offset (%d) and %s path_offset alias (%d)",
full_path, offset, alias_path, offset_a);
}
int main(int argc, char *argv[])
{
void *fdt;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
check_alias(fdt, "/subnode@1", "s1");
check_alias(fdt, "/subnode@1/subsubnode", "ss1");
check_alias(fdt, "/subnode@1/subsubnode", "s1/subsubnode");
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "sss1");
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "ss1/subsubsubnode");
check_alias(fdt, "/subnode@1/subsubnode/subsubsubnode", "s1/subsubnode/subsubsubnode");
PASS();
}

78
tests/phandle_format.c Normal file
View File

@ -0,0 +1,78 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for phandle format options
* Copyright (C) 2009 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
#define PHANDLE_BOTH 0x3
int main(int argc, char *argv[])
{
void *fdt;
int phandle_format;
int n4;
uint32_t h4;
if (argc != 3)
CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
test_init(argc, argv);
fdt = load_blob(argv[1]);
if (streq(argv[2], "legacy"))
phandle_format = PHANDLE_LEGACY;
else if (streq(argv[2], "epapr"))
phandle_format = PHANDLE_EPAPR;
else if (streq(argv[2], "both"))
phandle_format = PHANDLE_BOTH;
else
CONFIG("Usage: %s <dtb file> <legacy|epapr|both>\n", argv[0]);
n4 = fdt_path_offset(fdt, "/node4");
if (n4 < 0)
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
h4 = fdt_get_phandle(fdt, n4);
if ((h4 == 0) || (h4 == -1))
FAIL("/node4 has bad phandle 0x%x\n", h4);
if (phandle_format & PHANDLE_LEGACY)
check_getprop_cell(fdt, n4, "linux,phandle", h4);
else
if (fdt_getprop(fdt, n4, "linux,phandle", NULL))
FAIL("linux,phandle property present in non-legacy mode");
if (phandle_format & PHANDLE_EPAPR)
check_getprop_cell(fdt, n4, "phandle", h4);
else
if (fdt_getprop(fdt, n4, "phandle", NULL))
FAIL("phandle property present in legacy-only mode");
PASS();
}

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_ref(const void *fdt, int node, uint32_t checkref)
static void check_ref(const void *fdt, int node, uint32_t checkref)
{
const uint32_t *p;
uint32_t ref;
@ -60,8 +60,8 @@ void check_ref(const void *fdt, int node, uint32_t checkref)
int main(int argc, char *argv[])
{
void *fdt;
int n1, n2, n3, n4;
uint32_t h1, h2, h4;
int n1, n2, n3, n4, n5;
uint32_t h1, h2, h4, h5;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
@ -78,10 +78,14 @@ int main(int argc, char *argv[])
n4 = fdt_path_offset(fdt, "/node4");
if (n4 < 0)
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
n5 = fdt_path_offset(fdt, "/node5");
if (n5 < 0)
FAIL("fdt_path_offset(/node5): %s", fdt_strerror(n5));
h1 = fdt_get_phandle(fdt, n1);
h2 = fdt_get_phandle(fdt, n2);
h4 = fdt_get_phandle(fdt, n4);
h5 = fdt_get_phandle(fdt, n5);
if (h1 != 0x2000)
FAIL("/node1 has wrong phandle, 0x%x instead of 0x%x",
@ -92,6 +96,11 @@ int main(int argc, char *argv[])
if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
FAIL("/node4 has bad phandle, 0x%x", h4);
if ((h5 == 0) || (h5 == -1))
FAIL("/node5 has bad phandle, 0x%x", h5);
if ((h5 == h4) || (h5 == h2) || (h5 == h1))
FAIL("/node5 has duplicate phandle, 0x%x", h5);
check_ref(fdt, n1, h2);
check_ref(fdt, n2, h1);
check_ref(fdt, n3, h4);

View File

@ -8,7 +8,7 @@
lref = <&n2>;
};
n2: node2 {
linux,phandle = <0x1>;
phandle = <0x1>;
ref = <&{/node1}>; /* reference after target */
lref = <&n1>;
};
@ -20,4 +20,15 @@
};
n4: node4 {
};
/* Explicit phandle with implicit value */
/* This self-reference is the standard way to tag a node as requiring
* a phandle (perhaps for reference by nodes that will be dynamically
* added) without explicitly allocating it a phandle.
* The self-reference requires some special internal handling, though
* so check it actually works */
n5: node5 {
linux,phandle = <&n5>;
phandle = <&n5>;
};
};

View File

@ -1,21 +1,26 @@
/dts-v1/;
/ {
/* Explicit phandles */
n1: node1 {
linux,phandle = <2000>;
ref = <&/node2>; /* reference precedes target */
linux,phandle = <0x2000>;
ref = <&{/node2}>; /* reference precedes target */
lref = <&n2>;
};
n2: node2 {
linux,phandle = <1>;
ref = <&/node1>; /* reference after target */
linux,phandle = <0x1>;
ref = <&{/node1}>; /* reference after target */
lref = <&n1>;
};
/* Implicit phandles */
n3: node3 {
ref = <&/node4>;
ref = <&{/node4}>;
lref = <&n4>;
};
n4: node4 {
};
n5: node5 {
linux,phandle = <&n5>;
};
};

View File

@ -2,6 +2,10 @@
. ./tests.sh
if [ -z "$CC" ]; then
CC=gcc
fi
export QUIET_TEST=1
export VALGRIND=
@ -71,11 +75,12 @@ run_dtc_test () {
base_run_test wrap_test $VALGRIND $DTC "$@"
}
CONVERT=../convert-dtsv0
asm_to_so () {
$CC -shared -o $1.test.so data.S $1.test.s
}
run_convert_test () {
echo -n "convert-dtsv0 $@: "
base_run_test wrap_test $VALGRIND $CONVERT "$@"
asm_to_so_test () {
run_wrap_test asm_to_so "$@"
}
tree1_tests () {
@ -201,6 +206,9 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o dtc_escapes.test.dtb escapes.dts
run_test string_escapes dtc_escapes.test.dtb
run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb extra-terminating-null.dts
run_test extra-terminating-null dtc_extra-terminating-null.test.dtb
run_dtc_test -I dts -O dtb -o dtc_references.test.dtb references.dts
run_test references dtc_references.test.dtb
@ -210,10 +218,21 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
run_test path-references dtc_path-references.test.dtb
run_test phandle_format dtc_references.test.dtb both
for f in legacy epapr both; do
run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb references.dts
run_test phandle_format dtc_references.test.$f.dtb $f
done
run_dtc_test -I dts -O dtb -o dtc_comments.test.dtb comments.dts
run_dtc_test -I dts -O dtb -o dtc_comments-cmp.test.dtb comments-cmp.dts
run_test dtbs_equal_ordered dtc_comments.test.dtb dtc_comments-cmp.test.dtb
# Check aliases support in fdt_path_offset
run_dtc_test -I dts -O dtb -o aliases.dtb aliases.dts
run_test get_alias aliases.dtb
run_test path_offset_aliases aliases.dtb
# Check /include/ directive
run_dtc_test -I dts -O dtb -o includes.test.dtb include0.dts
run_test dtbs_equal_ordered includes.test.dtb test_tree1.dtb
@ -230,8 +249,22 @@ dtc_tests () {
run_dtc_test -I dtb -O dtb -o boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
run_test dtbs_equal_ordered boot_cpuid_preserved_test_tree1.test.dtb boot_cpuid_test_tree1.test.dtb
# Check -Oasm mode
for tree in test_tree1.dts escapes.dts references.dts path-references.dts \
comments.dts aliases.dts include0.dts incbin.dts \
value-labels.dts ; do
run_dtc_test -I dts -O asm -o oasm_$tree.test.s $tree
asm_to_so_test oasm_$tree
run_dtc_test -I dts -O dtb -o $tree.test.dtb $tree
run_test asm_tree_dump ./oasm_$tree.test.so oasm_$tree.test.dtb
run_wrap_test cmp oasm_$tree.test.dtb $tree.test.dtb
done
run_test value-labels ./oasm_value-labels.dts.test.so
# Check -Odts mode preserve all dtb information
for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb ; do
for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb \
dtc_extra-terminating-null.test.dtb dtc_references.test.dtb; do
run_dtc_test -I dtb -O dts -o odts_$tree.test.dts $tree
run_dtc_test -I dts -O dtb -o odts_$tree.test.dtb odts_$tree.test.dts
run_test dtbs_equal_ordered $tree odts_$tree.test.dtb
@ -283,21 +316,6 @@ dtc_tests () {
run_sh_test dtc-fatal.sh -I fs -O dtb nosuchfile
}
convert_tests () {
V0_DTS="test_tree1_dts0.dts references_dts0.dts empty.dts escapes.dts \
test01.dts label01.dts"
for dts in $V0_DTS; do
run_dtc_test -I dts -O dtb -o cvtraw_$dts.test.dtb $dts
run_dtc_test -I dts -O dts -o cvtdtc_$dts.test.dts $dts
run_dtc_test -I dts -O dtb -o cvtdtc_$dts.test.dtb cvtdtc_$dts.test.dts
run_convert_test $dts
run_dtc_test -I dts -O dtb -o cvtcvt_$dts.test.dtb ${dts}v1
run_wrap_test cmp cvtraw_$dts.test.dtb cvtdtc_$dts.test.dtb
run_wrap_test cmp cvtraw_$dts.test.dtb cvtcvt_$dts.test.dtb
done
}
while getopts "vt:m" ARG ; do
case $ARG in
"v")
@ -313,7 +331,7 @@ while getopts "vt:m" ARG ; do
done
if [ -z "$TESTSETS" ]; then
TESTSETS="libfdt dtc convert"
TESTSETS="libfdt dtc"
fi
# Make sure we don't have stale blobs lying around
@ -327,20 +345,17 @@ for set in $TESTSETS; do
"dtc")
dtc_tests
;;
"convert")
convert_tests
;;
esac
done
echo -e "********** TEST SUMMARY"
echo -e "* Total testcases: $tot_tests"
echo -e "* PASS: $tot_pass"
echo -e "* FAIL: $tot_fail"
echo -e "* Bad configuration: $tot_config"
echo "********** TEST SUMMARY"
echo "* Total testcases: $tot_tests"
echo "* PASS: $tot_pass"
echo "* FAIL: $tot_fail"
echo "* Bad configuration: $tot_config"
if [ -n "$VALGRIND" ]; then
echo -e "* valgrind errors: $tot_vg"
echo "* valgrind errors: $tot_vg"
fi
echo -e "* Strange test result: $tot_strange"
echo -e "**********"
echo "* Strange test result: $tot_strange"
echo "**********"

View File

@ -50,7 +50,7 @@ int main(int argc, char *argv[])
{
void *fdt;
int err;
int offset;
int offset, s1, s2;
test_init(argc, argv);
@ -77,21 +77,25 @@ int main(int argc, char *argv[])
CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1"));
CHECK(fdt_setprop_string(fdt, offset, "compatible", "subnode1"));
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode"));
s1 = offset;
CHECK(fdt_setprop_string(fdt, s1, "compatible", "subnode1"));
CHECK(fdt_setprop_cell(fdt, s1, "prop-int", TEST_VALUE_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "subsubnode"));
CHECK(fdt_setprop(fdt, offset, "compatible",
"subsubnode1\0subsubnode", 23));
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1));
OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "ss1"));
OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2"));
CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_1));
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2));
OFF_CHECK(offset, fdt_add_subnode(fdt, offset, "subsubnode@0"));
s2 = offset;
CHECK(fdt_setprop_cell(fdt, s2, "linux,phandle", PHANDLE_1));
CHECK(fdt_setprop_cell(fdt, s2, "prop-int", TEST_VALUE_2));
OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "subsubnode@0"));
CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_2));
CHECK(fdt_setprop(fdt, offset, "compatible",
"subsubnode2\0subsubnode", 23));
CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2));
OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "ss2"));
CHECK(fdt_pack(fdt));

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
void check_set_name(void *fdt, const char *path, const char *newname)
static void check_set_name(void *fdt, const char *path, const char *newname)
{
int offset;
const char *getname, *oldname;

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
int check_subnode(struct fdt_header *fdt, int parent, const char *name)
static int check_subnode(struct fdt_header *fdt, int parent, const char *name)
{
int offset;
const struct fdt_node_header *nh;
@ -60,6 +60,7 @@ int main(int argc, char *argv[])
void *fdt;
int subnode1_offset, subnode2_offset;
int subsubnode1_offset, subsubnode2_offset, subsubnode2_offset2;
int ss11_off, ss12_off, ss21_off, ss22_off;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
@ -84,5 +85,15 @@ int main(int argc, char *argv[])
if (subsubnode2_offset != subsubnode2_offset2)
FAIL("Different offsets with and without unit address");
ss11_off = check_subnode(fdt, subnode1_offset, "ss1");
ss21_off = fdt_subnode_offset(fdt, subnode2_offset, "ss1");
if (ss21_off != -FDT_ERR_NOTFOUND)
FAIL("Incorrectly found ss1 in subnode2");
ss12_off = fdt_subnode_offset(fdt, subnode1_offset, "ss2");
if (ss12_off != -FDT_ERR_NOTFOUND)
FAIL("Incorrectly found ss2 in subnode1");
ss22_off = check_subnode(fdt, subnode2_offset, "ss2");
PASS();
}

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
int path_depth(const char *path)
static int path_depth(const char *path)
{
const char *p;
int depth = 0;
@ -49,7 +49,7 @@ int path_depth(const char *path)
return depth;
}
int path_prefix(const char *path, int depth)
static int path_prefix(const char *path, int depth)
{
const char *p;
int i;
@ -67,7 +67,7 @@ int path_prefix(const char *path, int depth)
return p - path;
}
void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
static void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
int depth)
{
int pdepth = path_depth(path);
@ -106,7 +106,7 @@ void check_supernode_atdepth(struct fdt_header *fdt, const char *path,
"instead of %d", nodedepth, pdepth);
}
void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
static void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
{
int pdepth = path_depth(path);
int nodeoffset, err;
@ -121,7 +121,7 @@ void check_supernode_overdepth(struct fdt_header *fdt, const char *path)
"of FDT_ERR_NOTFOUND", path, pdepth+1, err);
}
void check_path(struct fdt_header *fdt, const char *path)
static void check_path(struct fdt_header *fdt, const char *path)
{
int i;

View File

@ -66,17 +66,22 @@ int main(int argc, char *argv[])
23));
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "ss1"));
CHECK(fdt_end_node(fdt));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "subnode@2"));
CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_1));
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
CHECK(fdt_begin_node(fdt, "subsubnode@0"));
CHECK(fdt_property_cell(fdt, "linux,phandle", PHANDLE_2));
CHECK(fdt_property_cell(fdt, "phandle", PHANDLE_2));
CHECK(fdt_property(fdt, "compatible", "subsubnode2\0subsubnode",
23));
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_2));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "ss2"));
CHECK(fdt_end_node(fdt));
CHECK(fdt_end_node(fdt));
CHECK(fdt_end_node(fdt));

View File

@ -1,6 +1,8 @@
/memreserve/ 1000000000000000 0000000002000000;
/memreserve/ 2000000000000000-20ffffffffffffff;
/memreserve/ 0-13;
/dts-v1/;
/memreserve/ 0x1000000000000000 0x0000000002000000;
/memreserve/ 0x2000000000000000 0x0100000000000000;
/memreserve/ 0x0000000000000000 0x0000000000000014;
/ {
model = "MyBoardName";
@ -9,28 +11,28 @@
#size-cells = <2>;
cpus {
linux,phandle = <1>;
linux,phandle = <0x1>;
#address-cells = <1>;
#size-cells = <0>;
PowerPC,970@0 {
name = "PowerPC,970";
device_type = "cpu";
reg = <0>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
reg = <0x00000000>;
clock-frequency = <1600000000>;
timebase-frequency = <33333333>;
linux,boot-cpu;
i-cache-size = <10000>;
d-cache-size = <8000>;
i-cache-size = <65536>;
d-cache-size = <32768>;
};
PowerPC,970@1 {
name = "PowerPC,970";
device_type = "cpu";
reg = <1>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
i-cache-size = <10000>;
d-cache-size = <8000>;
reg = <0x00000001>;
clock-frequency = <1600000000>;
timebase-frequency = <33333333>;
i-cache-size = <65536>;
d-cache-size = <32768>;
};
};
@ -38,18 +40,18 @@
randomnode {
string = "\xff\0stuffstuff\t\t\t\n\n\n";
blob = [0a 0b 0c 0d de ea ad be ef];
ref = < &/memory@0 >;
mixed = "abc", [1234], <a b c>;
ref = < &{/memory@0} >;
mixed = "abc", [1234], <0xa 0xb 0xc>;
};
memory@0 {
device_type = "memory";
memreg: reg = <00000000 00000000 00000000 20000000>;
memreg: reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
};
chosen {
bootargs = "root=/dev/sda2";
linux,platform = <00000600>;
linux,platform = <0x600>;
};
};

View File

@ -16,6 +16,9 @@
compatible = "subsubnode1", "subsubnode";
prop-int = <0xdeadbeef>;
};
ss1 {
};
};
subnode@2 {
@ -23,9 +26,12 @@
prop-int = <123456789>;
subsubnode@0 {
linux,phandle = <0x2001>;
phandle = <0x2001>;
compatible = "subsubnode2", "subsubnode";
prop-int = <0726746425>;
};
ss2 {
};
};
};

View File

@ -1,9 +1,11 @@
/memreserve/ deadbeef00000000-deadbeef000fffff;
/memreserve/ 75bcd15 1000;
/dts-v1/;
/memreserve/ 0xdeadbeef00000000 0x0000000000100000;
/memreserve/ 0x00000000075bcd15 0x0000000000001000;
/ {
compatible = "test_tree1";
prop-int = <deadbeef>;
prop-int = <0xdeadbeef>;
prop-str = "hello world";
subnode@1 {
@ -12,18 +14,24 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
prop-int = <h# deadbeef>;
prop-int = < 0xdeadbeef>;
};
ss1 {
};
};
subnode@2 {
linux,phandle = <2000>;
prop-int = <d# 123456789>;
linux,phandle = <0x2000>;
prop-int = < 123456789>;
subsubnode@0 {
linux,phandle = <2001>;
linux,phandle = <0x2001>;
compatible = "subsubnode2", "subsubnode";
prop-int = <o# 0726746425>;
prop-int = < 0726746425>;
};
ss2 {
};
};
};

View File

@ -34,6 +34,7 @@ void test_init(int argc, char *argv[]);
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define streq(s1, s2) (strcmp((s1),(s2)) == 0)

View File

@ -96,10 +96,14 @@ test_tree1_struct:
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
END_NODE
BEGIN_NODE("ss1")
END_NODE
END_NODE
BEGIN_NODE("subnode@2")
PROP_INT(test_tree1, phandle, PHANDLE_1)
PROP_INT(test_tree1, linux_phandle, PHANDLE_1)
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
BEGIN_NODE("subsubnode@0")
@ -107,6 +111,10 @@ test_tree1_struct:
PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
END_NODE
BEGIN_NODE("ss2")
END_NODE
END_NODE
END_NODE
@ -117,7 +125,8 @@ test_tree1_strings:
STRING(test_tree1, compatible, "compatible")
STRING(test_tree1, prop_int, "prop-int")
STRING(test_tree1, prop_str, "prop-str")
STRING(test_tree1, phandle, "linux,phandle")
STRING(test_tree1, linux_phandle, "linux,phandle")
STRING(test_tree1, phandle, "phandle")
test_tree1_strings_end:
test_tree1_end:

128
tests/value-labels.c Normal file
View File

@ -0,0 +1,128 @@
/*
* libfdt - Flat Device Tree manipulation
* Test labels within values
* Copyright (C) 2008 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <dlfcn.h>
#include <fdt.h>
#include <libfdt.h>
#include "tests.h"
#include "testdata.h"
struct val_label {
const char *labelname;
int propoff;
};
struct val_label labels1[] = {
{ "start1", 0 },
{ "mid1", 2 },
{ "end1", -1 },
};
struct val_label labels2[] = {
{ "start2", 0 },
{ "innerstart2", 0 },
{ "innermid2", 4 },
{ "innerend2", -1 },
{ "end2", -1 },
};
struct val_label labels3[] = {
{ "start3", 0 },
{ "innerstart3", 0 },
{ "innermid3", 1 },
{ "innerend3", -1 },
{ "end3", -1 },
};
void check_prop_labels(void *sohandle, void *fdt, const char *name,
const struct val_label* labels, int n)
{
const struct fdt_property *prop;
const char *p;
int len;
int i;
prop = fdt_get_property(fdt, 0, name, &len);
if (!prop)
FAIL("Couldn't locate property \"%s\"", name);
p = dlsym(sohandle, name);
if (!p)
FAIL("Couldn't locate label symbol \"%s\"", name);
if (p != (const char *)prop)
FAIL("Label \"%s\" does not point to correct property", name);
for (i = 0; i < n; i++) {
int off = labels[i].propoff;
if (off == -1)
off = len;
p = dlsym(sohandle, labels[i].labelname);
if (!p)
FAIL("Couldn't locate label symbol \"%s\"", name);
if ((p - prop->data) != off)
FAIL("Label \"%s\" points to offset %ld instead of %d"
"in property \"%s\"", labels[i].labelname,
(long)(p - prop->data), off, name);
}
}
int main(int argc, char *argv[])
{
void *sohandle;
void *fdt;
int err;
test_init(argc, argv);
if (argc != 2)
CONFIG("Usage: %s <so file>", argv[0]);
sohandle = dlopen(argv[1], RTLD_NOW);
if (!sohandle)
FAIL("Couldn't dlopen() %s", argv[1]);
fdt = dlsym(sohandle, "dt_blob_start");
if (!fdt)
FAIL("Couldn't locate \"dt_blob_start\" symbol in %s",
argv[1]);
err = fdt_check_header(fdt);
if (err != 0)
FAIL("%s contains invalid tree: %s", argv[1],
fdt_strerror(err));
check_prop_labels(sohandle, fdt, "prop1", labels1, ARRAY_SIZE(labels1));
check_prop_labels(sohandle, fdt, "prop2", labels2, ARRAY_SIZE(labels2));
check_prop_labels(sohandle, fdt, "prop3", labels3, ARRAY_SIZE(labels3));
PASS();
}

8
tests/value-labels.dts Normal file
View File

@ -0,0 +1,8 @@
/dts-v1/;
/ {
prop1: prop1 = start1: "a", mid1: "b" end1:;
prop2: prop2 = start2: < innerstart2: 0xdeadbeef innermid2: 0xabcd1234 innerend2: > end2:;
prop3: prop3 = start3: [ innerstart3: ab innermid3: cd innerend3: ] end3:;
};

View File

@ -52,7 +52,7 @@ static void write_prefix(FILE *f, int level)
fputc('\t', f);
}
int isstring(char c)
static int isstring(char c)
{
return (isprint(c)
|| (c == '\0')
@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val)
{
const char *str = val.val;
int i;
int newchunk = 1;
struct marker *m = val.markers;
assert(str[val.len-1] == '\0');
while (m && (m->offset == 0)) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
m = m->next;
}
fprintf(f, "\"");
for (i = 0; i < (val.len-1); i++) {
char c = str[i];
if (newchunk) {
while (m && (m->offset <= i)) {
if (m->type == LABEL) {
assert(m->offset == i);
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "\"");
newchunk = 0;
}
switch (c) {
case '\a':
fprintf(f, "\\a");
@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val)
break;
case '\0':
fprintf(f, "\", ");
newchunk = 1;
while (m && (m->offset < i)) {
if (m->type == LABEL) {
assert(m->offset == (i+1));
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "\"");
break;
default:
if (isprint(c))

30
util.c Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
char *xstrdup(const char *s)
{
int len = strlen(s) + 1;
char *dup = xmalloc(len);
memcpy(dup, s, len);
return dup;
}

55
util.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _UTIL_H
#define _UTIL_H
/*
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
static inline void __attribute__((noreturn)) die(char * str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (!new)
die("malloc() failed\n");
return new;
}
static inline void *xrealloc(void *p, size_t len)
{
void *new = realloc(p, len);
if (!new)
die("realloc() failed (len=%d)\n", len);
return new;
}
extern char *xstrdup(const char *s);
#endif /* _UTIL_H */