diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
commit | d635711daa98be86d4c7fd01499c34f566b54ccb (patch) | |
tree | aa5cc3760a27c3d57146498cb82fa549547de06c /scripts/dtc | |
parent | c91265cd0efb83778f015b4d4b1129bd2cfd075e (diff) |
Linux-libre 4.6.2-gnu
Diffstat (limited to 'scripts/dtc')
-rw-r--r-- | scripts/dtc/checks.c | 2 | ||||
-rw-r--r-- | scripts/dtc/dtc-lexer.l | 39 | ||||
-rw-r--r-- | scripts/dtc/dtc-lexer.lex.c_shipped | 101 | ||||
-rw-r--r-- | scripts/dtc/dtc-parser.tab.c_shipped | 84 | ||||
-rw-r--r-- | scripts/dtc/dtc-parser.y | 20 | ||||
-rw-r--r-- | scripts/dtc/dtc.c | 62 | ||||
-rwxr-xr-x | scripts/dtc/dtx_diff | 349 | ||||
-rw-r--r-- | scripts/dtc/libfdt/fdt.c | 13 | ||||
-rw-r--r-- | scripts/dtc/libfdt/fdt_ro.c | 100 | ||||
-rw-r--r-- | scripts/dtc/libfdt/fdt_rw.c | 2 | ||||
-rw-r--r-- | scripts/dtc/libfdt/libfdt.h | 73 | ||||
-rw-r--r-- | scripts/dtc/util.c | 3 | ||||
-rw-r--r-- | scripts/dtc/version_gen.h | 2 |
13 files changed, 739 insertions, 111 deletions
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index e81a8c74b..0c03ac915 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -560,7 +560,7 @@ static void check_reg_format(struct check *c, struct node *dt, size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); - if ((prop->val.len % entrylen) != 0) + if (!entrylen || (prop->val.len % entrylen) != 0) FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index 0ee1caf03..790fbf6cf 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -73,24 +73,32 @@ static void lexical_error(const char *fmt, ...); } <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { - char *line, *tmp, *fn; + char *line, *fnstart, *fnend; + struct data fn; /* skip text before line # */ line = yytext; while (!isdigit((unsigned char)*line)) line++; - /* skip digits in line # */ - tmp = line; - while (!isspace((unsigned char)*tmp)) - tmp++; - /* "NULL"-terminate line # */ - *tmp = '\0'; - /* start of filename */ - fn = strchr(tmp + 1, '"') + 1; - /* strip trailing " from filename */ - tmp = strchr(fn, '"'); - *tmp = 0; + + /* regexp ensures that first and list " + * in the whole yytext are those at + * beginning and end of the filename string */ + fnstart = memchr(yytext, '"', yyleng); + for (fnend = yytext + yyleng - 1; + *fnend != '"'; fnend--) + ; + assert(fnstart && fnend && (fnend > fnstart)); + + fn = data_copy_escape_string(fnstart + 1, + fnend - fnstart - 1); + + /* Don't allow nuls in filenames */ + if (memchr(fn.val, '\0', fn.len - 1)) + lexical_error("nul in line number directive"); + /* -1 since #line is the number of the next line */ - srcpos_set_line(xstrdup(fn), atoi(line) - 1); + srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); + data_free(fn); } <*><<EOF>> { @@ -153,7 +161,10 @@ static void lexical_error(const char *fmt, ...); errno = 0; yylval.integer = strtoull(yytext, &e, 0); - assert(!(*e) || !e[strspn(e, "UL")]); + if (*e && e[strspn(e, "UL")]) { + lexical_error("Bad integer literal '%s'", + yytext); + } if (errno == ERANGE) lexical_error("Integer literal '%s' out of range", diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 11cd78e72..ba525c2f9 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -951,31 +951,39 @@ case 2: YY_RULE_SETUP #line 75 "dtc-lexer.l" { - char *line, *tmp, *fn; + char *line, *fnstart, *fnend; + struct data fn; /* skip text before line # */ line = yytext; while (!isdigit((unsigned char)*line)) line++; - /* skip digits in line # */ - tmp = line; - while (!isspace((unsigned char)*tmp)) - tmp++; - /* "NULL"-terminate line # */ - *tmp = '\0'; - /* start of filename */ - fn = strchr(tmp + 1, '"') + 1; - /* strip trailing " from filename */ - tmp = strchr(fn, '"'); - *tmp = 0; + + /* regexp ensures that first and list " + * in the whole yytext are those at + * beginning and end of the filename string */ + fnstart = memchr(yytext, '"', yyleng); + for (fnend = yytext + yyleng - 1; + *fnend != '"'; fnend--) + ; + assert(fnstart && fnend && (fnend > fnstart)); + + fn = data_copy_escape_string(fnstart + 1, + fnend - fnstart - 1); + + /* Don't allow nuls in filenames */ + if (memchr(fn.val, '\0', fn.len - 1)) + lexical_error("nul in line number directive"); + /* -1 since #line is the number of the next line */ - srcpos_set_line(xstrdup(fn), atoi(line) - 1); + srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); + data_free(fn); } YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(BYTESTRING): case YY_STATE_EOF(PROPNODENAME): case YY_STATE_EOF(V1): -#line 96 "dtc-lexer.l" +#line 104 "dtc-lexer.l" { if (!pop_input_file()) { yyterminate(); @@ -985,7 +993,7 @@ case YY_STATE_EOF(V1): case 3: /* rule 3 can match eol */ YY_RULE_SETUP -#line 102 "dtc-lexer.l" +#line 110 "dtc-lexer.l" { DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, @@ -995,7 +1003,7 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 109 "dtc-lexer.l" +#line 117 "dtc-lexer.l" { DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; @@ -1005,7 +1013,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 116 "dtc-lexer.l" +#line 124 "dtc-lexer.l" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); @@ -1014,7 +1022,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 122 "dtc-lexer.l" +#line 130 "dtc-lexer.l" { DPRINT("Keyword: /bits/\n"); BEGIN_DEFAULT(); @@ -1023,7 +1031,7 @@ YY_RULE_SETUP YY_BREAK case 7: YY_RULE_SETUP -#line 128 "dtc-lexer.l" +#line 136 "dtc-lexer.l" { DPRINT("Keyword: /delete-property/\n"); DPRINT("<PROPNODENAME>\n"); @@ -1033,7 +1041,7 @@ YY_RULE_SETUP YY_BREAK case 8: YY_RULE_SETUP -#line 135 "dtc-lexer.l" +#line 143 "dtc-lexer.l" { DPRINT("Keyword: /delete-node/\n"); DPRINT("<PROPNODENAME>\n"); @@ -1043,7 +1051,7 @@ YY_RULE_SETUP YY_BREAK case 9: YY_RULE_SETUP -#line 142 "dtc-lexer.l" +#line 150 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -1053,7 +1061,7 @@ YY_RULE_SETUP YY_BREAK case 10: YY_RULE_SETUP -#line 149 "dtc-lexer.l" +#line 157 "dtc-lexer.l" { char *e; DPRINT("Integer Literal: '%s'\n", yytext); @@ -1061,7 +1069,10 @@ YY_RULE_SETUP errno = 0; yylval.integer = strtoull(yytext, &e, 0); - assert(!(*e) || !e[strspn(e, "UL")]); + if (*e && e[strspn(e, "UL")]) { + lexical_error("Bad integer literal '%s'", + yytext); + } if (errno == ERANGE) lexical_error("Integer literal '%s' out of range", @@ -1076,7 +1087,7 @@ YY_RULE_SETUP case 11: /* rule 11 can match eol */ YY_RULE_SETUP -#line 168 "dtc-lexer.l" +#line 179 "dtc-lexer.l" { struct data d; DPRINT("Character literal: %s\n", yytext); @@ -1100,7 +1111,7 @@ YY_RULE_SETUP YY_BREAK case 12: YY_RULE_SETUP -#line 189 "dtc-lexer.l" +#line 200 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); @@ -1109,7 +1120,7 @@ YY_RULE_SETUP YY_BREAK case 13: YY_RULE_SETUP -#line 195 "dtc-lexer.l" +#line 206 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -1119,7 +1130,7 @@ YY_RULE_SETUP YY_BREAK case 14: YY_RULE_SETUP -#line 202 "dtc-lexer.l" +#line 213 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); @@ -1128,7 +1139,7 @@ YY_RULE_SETUP YY_BREAK case 15: YY_RULE_SETUP -#line 208 "dtc-lexer.l" +#line 219 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); @@ -1137,7 +1148,7 @@ YY_RULE_SETUP YY_BREAK case 16: YY_RULE_SETUP -#line 214 "dtc-lexer.l" +#line 225 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); yylval.propnodename = xstrdup((yytext[0] == '\\') ? @@ -1148,7 +1159,7 @@ YY_RULE_SETUP YY_BREAK case 17: YY_RULE_SETUP -#line 222 "dtc-lexer.l" +#line 233 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; @@ -1157,64 +1168,64 @@ YY_RULE_SETUP case 18: /* rule 18 can match eol */ YY_RULE_SETUP -#line 227 "dtc-lexer.l" +#line 238 "dtc-lexer.l" /* eat whitespace */ YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP -#line 228 "dtc-lexer.l" +#line 239 "dtc-lexer.l" /* eat C-style comments */ YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 229 "dtc-lexer.l" +#line 240 "dtc-lexer.l" /* eat C++-style comments */ YY_BREAK case 21: YY_RULE_SETUP -#line 231 "dtc-lexer.l" +#line 242 "dtc-lexer.l" { return DT_LSHIFT; }; YY_BREAK case 22: YY_RULE_SETUP -#line 232 "dtc-lexer.l" +#line 243 "dtc-lexer.l" { return DT_RSHIFT; }; YY_BREAK case 23: YY_RULE_SETUP -#line 233 "dtc-lexer.l" +#line 244 "dtc-lexer.l" { return DT_LE; }; YY_BREAK case 24: YY_RULE_SETUP -#line 234 "dtc-lexer.l" +#line 245 "dtc-lexer.l" { return DT_GE; }; YY_BREAK case 25: YY_RULE_SETUP -#line 235 "dtc-lexer.l" +#line 246 "dtc-lexer.l" { return DT_EQ; }; YY_BREAK case 26: YY_RULE_SETUP -#line 236 "dtc-lexer.l" +#line 247 "dtc-lexer.l" { return DT_NE; }; YY_BREAK case 27: YY_RULE_SETUP -#line 237 "dtc-lexer.l" +#line 248 "dtc-lexer.l" { return DT_AND; }; YY_BREAK case 28: YY_RULE_SETUP -#line 238 "dtc-lexer.l" +#line 249 "dtc-lexer.l" { return DT_OR; }; YY_BREAK case 29: YY_RULE_SETUP -#line 240 "dtc-lexer.l" +#line 251 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -1232,10 +1243,10 @@ YY_RULE_SETUP YY_BREAK case 30: YY_RULE_SETUP -#line 255 "dtc-lexer.l" +#line 266 "dtc-lexer.l" ECHO; YY_BREAK -#line 1239 "dtc-lexer.lex.c" +#line 1250 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -2195,7 +2206,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 254 "dtc-lexer.l" +#line 265 "dtc-lexer.l" diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index 116458c8d..31cec50a1 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -499,9 +499,9 @@ static const yytype_uint16 yyrline[] = 298, 303, 322, 336, 343, 344, 345, 352, 356, 357, 361, 362, 366, 367, 371, 372, 376, 377, 381, 382, 386, 387, 388, 392, 393, 394, 395, 396, 400, 401, - 402, 406, 407, 408, 412, 413, 414, 415, 419, 420, - 421, 422, 427, 430, 434, 442, 445, 449, 457, 461, - 465 + 402, 406, 407, 408, 412, 413, 422, 431, 435, 436, + 437, 438, 443, 446, 450, 458, 461, 465, 473, 477, + 481 }; #endif @@ -1909,111 +1909,125 @@ yyreduce: break; case 65: -#line 413 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); } -#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 414 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].integer) != 0) { + (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); + } else { + ERROR(&(yyloc), "Division by zero"); + (yyval.integer) = 0; + } + } +#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 66: -#line 414 "dtc-parser.y" /* yacc.c:1646 */ - { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); } -#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 423 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].integer) != 0) { + (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); + } else { + ERROR(&(yyloc), "Division by zero"); + (yyval.integer) = 0; + } + } +#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 69: -#line 420 "dtc-parser.y" /* yacc.c:1646 */ +#line 436 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = -(yyvsp[0].integer); } -#line 1927 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 70: -#line 421 "dtc-parser.y" /* yacc.c:1646 */ +#line 437 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = ~(yyvsp[0].integer); } -#line 1933 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 71: -#line 422 "dtc-parser.y" /* yacc.c:1646 */ +#line 438 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = !(yyvsp[0].integer); } -#line 1939 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 72: -#line 427 "dtc-parser.y" /* yacc.c:1646 */ +#line 443 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = empty_data; } -#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 73: -#line 431 "dtc-parser.y" /* yacc.c:1646 */ +#line 447 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); } -#line 1955 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1969 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 74: -#line 435 "dtc-parser.y" /* yacc.c:1646 */ +#line 451 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); } -#line 1963 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1977 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 75: -#line 442 "dtc-parser.y" /* yacc.c:1646 */ +#line 458 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = NULL; } -#line 1971 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 76: -#line 446 "dtc-parser.y" /* yacc.c:1646 */ +#line 462 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); } -#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 77: -#line 450 "dtc-parser.y" /* yacc.c:1646 */ +#line 466 "dtc-parser.y" /* yacc.c:1646 */ { ERROR(&(yylsp[0]), "Properties must precede subnodes"); YYERROR; } -#line 1988 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 78: -#line 458 "dtc-parser.y" /* yacc.c:1646 */ +#line 474 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename)); } -#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2010 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 79: -#line 462 "dtc-parser.y" /* yacc.c:1646 */ +#line 478 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename)); } -#line 2004 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2018 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 80: -#line 466 "dtc-parser.y" /* yacc.c:1646 */ +#line 482 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[0].node); } -#line 2013 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */ break; -#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2031 "dtc-parser.tab.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2248,7 +2262,7 @@ yyreturn: #endif return yyresult; } -#line 472 "dtc-parser.y" /* yacc.c:1906 */ +#line 488 "dtc-parser.y" /* yacc.c:1906 */ void yyerror(char const *s) diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 5a897e365..000873f07 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -410,8 +410,24 @@ integer_add: integer_mul: integer_mul '*' integer_unary { $$ = $1 * $3; } - | integer_mul '/' integer_unary { $$ = $1 / $3; } - | integer_mul '%' integer_unary { $$ = $1 % $3; } + | integer_mul '/' integer_unary + { + if ($3 != 0) { + $$ = $1 / $3; + } else { + ERROR(&@$, "Division by zero"); + $$ = 0; + } + } + | integer_mul '%' integer_unary + { + if ($3 != 0) { + $$ = $1 % $3; + } else { + ERROR(&@$, "Division by zero"); + $$ = 0; + } + } | integer_unary ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 8c4add69a..5fa23c406 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -18,6 +18,8 @@ * USA */ +#include <sys/stat.h> + #include "dtc.h" #include "srcpos.h" @@ -104,11 +106,56 @@ static const char * const usage_opts_help[] = { NULL, }; +static const char *guess_type_by_name(const char *fname, const char *fallback) +{ + const char *s; + + s = strrchr(fname, '.'); + if (s == NULL) + return fallback; + if (!strcasecmp(s, ".dts")) + return "dts"; + if (!strcasecmp(s, ".dtb")) + return "dtb"; + return fallback; +} + +static const char *guess_input_format(const char *fname, const char *fallback) +{ + struct stat statbuf; + uint32_t magic; + FILE *f; + + if (stat(fname, &statbuf) != 0) + return fallback; + + if (S_ISDIR(statbuf.st_mode)) + return "fs"; + + if (!S_ISREG(statbuf.st_mode)) + return fallback; + + f = fopen(fname, "r"); + if (f == NULL) + return fallback; + if (fread(&magic, 4, 1, f) != 1) { + fclose(f); + return fallback; + } + fclose(f); + + magic = fdt32_to_cpu(magic); + if (magic == FDT_MAGIC) + return "dtb"; + + return guess_type_by_name(fname, fallback); +} + int main(int argc, char *argv[]) { struct boot_info *bi; - const char *inform = "dts"; - const char *outform = "dts"; + const char *inform = NULL; + const char *outform = NULL; const char *outname = "-"; const char *depname = NULL; bool force = false, sort = false; @@ -213,6 +260,17 @@ int main(int argc, char *argv[]) fprintf(depfile, "%s:", outname); } + if (inform == NULL) + inform = guess_input_format(arg, "dts"); + if (outform == NULL) { + outform = guess_type_by_name(outname, NULL); + if (outform == NULL) { + if (streq(inform, "dts")) + outform = "dtb"; + else + outform = "dts"; + } + } if (streq(inform, "dts")) bi = dt_from_source(arg); else if (streq(inform, "fs")) diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff new file mode 100755 index 000000000..959ab2646 --- /dev/null +++ b/scripts/dtc/dtx_diff @@ -0,0 +1,349 @@ +#! /bin/bash + +# Copyright (C) 2015 Frank Rowand +# +# 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; version 2 of the License. + + +usage() { + + # use spaces instead of tabs in the usage message + cat >&2 <<eod + +Usage: + + `basename $0` DTx + decompile DTx + + `basename $0` DTx_1 DTx_2 + diff DTx_1 and DTx_2 + + + -f print full dts in diff (--unified=99999) + -h synonym for --help + -help synonym for --help + --help print this message and exit + -s SRCTREE linux kernel source tree is at path SRCTREE + (default is current directory) + -S linux kernel source tree is at root of current git repo + -u unsorted, do not sort DTx + + +Each DTx is processed by the dtc compiler to produce a sorted dts source +file. If DTx is a dts source file then it is pre-processed in the same +manner as done for the compile of the dts source file in the Linux kernel +build system ('#include' and '/include/' directives are processed). + +If two DTx are provided, the resulting dts source files are diffed. + +If DTx is a directory, it is treated as a DT subtree, such as + /proc/device-tree. + +If DTx contains the binary blob magic value in the first four bytes, + it is treated as a binary blob (aka .dtb or FDT). + +Otherwise DTx is treated as a dts source file (aka .dts). + + If this script is not run from the root of the linux source tree, + and DTx utilizes '#include' or '/include/' then the path of the + linux source tree can be provided by '-s SRCTREE' or '-S' so that + include paths will be set properly. + + The shell variable \${ARCH} must provide the architecture containing + the dts source file for include paths to be set properly for '#include' + or '/include/' to be processed. + + If DTx_1 and DTx_2 are in different architectures, then this script + may not work since \${ARCH} is part of the include path. Two possible + workarounds: + + `basename $0` \\ + <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\ + <(ARCH=arch_of_dtx_2 `basename $0` DTx_2) + + `basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts + `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts + `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts + rm tmp_dtx_1.dts tmp_dtx_2.dts + + If DTx_1 and DTx_2 are in different directories, then this script will + add the path of DTx_1 and DTx_2 to the include paths. If DTx_2 includes + a local file that exists in both the path of DTx_1 and DTx_2 then the + file in the path of DTx_1 will incorrectly be included. Possible + workaround: + + `basename $0` DTx_1 >tmp_dtx_1.dts + `basename $0` DTx_2 >tmp_dtx_2.dts + `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts + rm tmp_dtx_1.dts tmp_dtx_2.dts + +eod +} + + +compile_to_dts() { + + dtx="$1" + + if [ -d "${dtx}" ] ; then + + # ----- input is file tree + + if ( ! ${DTC} -I fs ${dtx} ) ; then + exit 3 + fi + + elif [ -f "${dtx}" ] && [ -r "${dtx}" ] ; then + + magic=`hexdump -n 4 -e '/1 "%02x"' ${dtx}` + if [ "${magic}" = "d00dfeed" ] ; then + + # ----- input is FDT (binary blob) + + if ( ! ${DTC} -I dtb ${dtx} ) ; then + exit 3 + fi + + return + + fi + + # ----- input is DTS (source) + + if ( cpp ${cpp_flags} -x assembler-with-cpp ${dtx} \ + | ${DTC} -I dts ) ; then + return + fi + + echo "" >&2 + echo "Possible hints to resolve the above error:" >&2 + echo " (hints might not fix the problem)" >&2 + + hint_given=0 + + if [ "${ARCH}" = "" ] ; then + hint_given=1 + echo "" >&2 + echo " shell variable \$ARCH not set" >&2 + fi + + dtx_arch=`echo "/${dtx}" | sed -e 's|.*/arch/||' -e 's|/.*||'` + + if [ "${dtx_arch}" != "" -a "${dtx_arch}" != "${ARCH}" ] ; then + hint_given=1 + echo "" >&2 + echo " architecture ${dtx_arch} is in file path," >&2 + echo " but does not match shell variable \$ARCH" >&2 + echo " >>\$ARCH<< is: >>${ARCH}<<" >&2 + fi + + if [ ! -d ${srctree}/arch/${ARCH} ] ; then + hint_given=1 + echo "" >&2 + echo " ${srctree}/arch/${ARCH}/ does not exist" >&2 + echo " Is \$ARCH='${ARCH}' correct?" >&2 + echo " Possible fix: use '-s' option" >&2 + + git_root=`git rev-parse --show-toplevel 2>/dev/null` + if [ -d ${git_root}/arch/ ] ; then + echo " Possible fix: use '-S' option" >&2 + fi + fi + + if [ $hint_given = 0 ] ; then + echo "" >&2 + echo " No hints available." >&2 + fi + + echo "" >&2 + + exit 3 + + else + echo "" >&2 + echo "ERROR: ${dtx} does not exist or is not readable" >&2 + echo "" >&2 + exit 2 + fi + +} + + +# ----- start of script + +cmd_diff=0 +diff_flags="-u" +dtx_file_1="" +dtx_file_2="" +dtc_sort="-s" +help=0 +srctree="" + + +while [ $# -gt 0 ] ; do + + case $1 in + + -f ) + diff_flags="--unified=999999" + shift + ;; + + -h | -help | --help ) + help=1 + shift + ;; + + -s ) + srctree="$2" + shift 2 + ;; + + -S ) + git_root=`git rev-parse --show-toplevel 2>/dev/null` + srctree="${git_root}" + shift + ;; + + -u ) + dtc_sort="" + shift + ;; + + *) + if [ "${dtx_file_1}" = "" ] ; then + dtx_file_1="$1" + elif [ "${dtx_file_2}" = "" ] ; then + dtx_file_2="$1" + else + echo "" >&2 + echo "ERROR: Unexpected parameter: $1" >&2 + echo "" >&2 + exit 2 + fi + shift + ;; + + esac + +done + +if [ "${srctree}" = "" ] ; then + srctree="." +fi + +if [ "${dtx_file_2}" != "" ]; then + cmd_diff=1 +fi + +if (( ${help} )) ; then + usage + exit 1 +fi + +# this must follow check for ${help} +if [ "${dtx_file_1}" = "" ]; then + echo "" >&2 + echo "ERROR: parameter DTx required" >&2 + echo "" >&2 + exit 2 +fi + + +# ----- prefer dtc from linux kernel, allow fallback to dtc in $PATH + +if [ "${KBUILD_OUTPUT:0:2}" = ".." ] ; then + __KBUILD_OUTPUT="${srctree}/${KBUILD_OUTPUT}" +elif [ "${KBUILD_OUTPUT}" = "" ] ; then + __KBUILD_OUTPUT="." +else + __KBUILD_OUTPUT="${KBUILD_OUTPUT}" +fi + +DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc" + +if [ ! -x ${DTC} ] ; then + __DTC="dtc" + if grep -q "^CONFIG_DTC=y" ${__KBUILD_OUTPUT}/.config ; then + make_command=' + make scripts' + else + make_command=' + Enable CONFIG_DTC in the kernel configuration + make scripts' + fi + if ( ! which ${__DTC} >/dev/null ) ; then + + # use spaces instead of tabs in the error message + cat >&2 <<eod + +ERROR: unable to find a 'dtc' program + + Preferred 'dtc' (built from Linux kernel source tree) was not found or + is not executable. + + 'dtc' is: ${DTC} + + If it does not exist, create it from the root of the Linux source tree: +${make_command} + + If not at the root of the Linux kernel source tree -s SRCTREE or -S + may need to be specified to find 'dtc'. + + If 'O=\${dir}' is specified in your Linux builds, this script requires + 'export KBUILD_OUTPUT=\${dir}' or add \${dir}/scripts/dtc to \$PATH + before running. + + If \${KBUILD_OUTPUT} is a relative path, then '-s SRCDIR', -S, or run + this script from the root of the Linux kernel source tree is required. + + Fallback '${__DTC}' was also not in \${PATH} or is not executable. + +eod + exit 2 + fi + DTC=${__DTC} +fi + + +# ----- cpp and dtc flags same as for linux source tree build of .dtb files, +# plus directories of the dtx file(s) + +dtx_path_1_dtc_include="-i `dirname ${dtx_file_1}`" + +dtx_path_2_dtc_include="" +if (( ${cmd_diff} )) ; then + dtx_path_2_dtc_include="-i `dirname ${dtx_file_2}`" +fi + +cpp_flags="\ + -nostdinc \ + -I${srctree}/arch/${ARCH}/boot/dts \ + -I${srctree}/arch/${ARCH}/boot/dts/include \ + -I${srctree}/drivers/of/testcase-data \ + -undef -D__DTS__" + +dtc_flags="\ + -i ${srctree}/arch/${ARCH}/boot/dts/ \ + -i ${srctree}/kernel/dts \ + ${dtx_path_1_dtc_include} \ + ${dtx_path_2_dtc_include}" + +DTC="${DTC} ${dtc_flags} -O dts -qq -f ${dtc_sort} -o -" + + +# ----- do the diff or decompile + +if (( ${cmd_diff} )) ; then + + diff ${diff_flags} \ + <(compile_to_dts "${dtx_file_1}") \ + <(compile_to_dts "${dtx_file_2}") + +else + + compile_to_dts "${dtx_file_1}" + +fi diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 2ce6a4417..22286a1aa 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -76,18 +76,19 @@ int fdt_check_header(const void *fdt) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - const char *p; + unsigned absoffset = offset + fdt_off_dt_struct(fdt); + + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; - p = _fdt_offset_ptr(fdt, offset); - - if (p + len < p) - return NULL; - return p; + return _fdt_offset_ptr(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index a65e4b5b7..e5b313682 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -538,6 +538,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) return 0; } +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return -length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 70adec6c3..8be02b1f6 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -101,6 +101,8 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index ea35ac3c9..59ca33976 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -121,7 +121,12 @@ /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells * or similar property with a bad format or value */ -#define FDT_ERR_MAX 14 +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ + +#define FDT_ERR_MAX 15 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -457,8 +462,8 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * @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. + * Identical to fdt_get_property(), 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, @@ -868,6 +873,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); +/** + * fdt_stringlist_count - count the number of strings in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @return: + * the number of strings in the given property + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); + +/** + * fdt_stringlist_search - find a string in a string list and return its index + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @string: string to look up in the string list + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @return: + * the index of the string in the list of strings + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist or does not contain + * the given string + */ +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * @return: + * A pointer to the string at the given index in the string list or NULL on + * failure. On success the length of the string will be stored in the memory + * location pointed to by the lenp parameter, if non-NULL. On failure one of + * the following negative error codes will be returned in the lenp parameter + * (if non-NULL): + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int index, + int *lenp); + /**********************************************************************/ /* Read-only functions (addressing related) */ /**********************************************************************/ diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 9d65226df..fb124eea4 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -152,7 +152,6 @@ char get_escape_char(const char *s, int *i) int j = *i + 1; char val; - assert(c); switch (c) { case 'a': val = '\a'; @@ -349,7 +348,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) void utilfdt_print_data(const char *data, int len) { int i; - const char *p = data; const char *s; /* no data, don't print */ @@ -376,6 +374,7 @@ void utilfdt_print_data(const char *data, int len) i < (len - 1) ? " " : ""); printf(">"); } else { + const unsigned char *p = (const unsigned char *)data; printf(" = ["); for (i = 0; i < len; i++) printf("%02x%s", *p++, i < len - 1 ? " " : ""); diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 5b8c7d53d..11d93e6d8 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-g9d3649bd" +#define DTC_VERSION "DTC 1.4.1-gb06e55c8" |