You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
5.2 KiB

20 years ago
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
20 years ago
* 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
20 years ago
*/
#include "dtc.h"
void data_free(struct data d)
{
struct marker *m, *nm;
m = d.markers;
while (m) {
nm = m->next;
free(m->ref);
free(m);
m = nm;
}
20 years ago
if (d.val)
free(d.val);
}
struct data data_grow_for(struct data d, int xlen)
{
struct data nd;
int newsize;
if (xlen == 0)
return d;
nd = d;
20 years ago
newsize = xlen;
while ((d.len + xlen) > newsize)
newsize *= 2;
nd.val = xrealloc(d.val, newsize);
return nd;
}
struct data data_copy_mem(const char *mem, int len)
20 years ago
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
memcpy(d.val, mem, len);
return d;
}
struct data data_copy_escape_string(const char *s, int len)
20 years ago
{
int i = 0;
struct data d;
char *q;
d = data_add_marker(empty_data, TYPE_STRING, NULL);
d = data_grow_for(d, len + 1);
20 years ago
q = d.val;
while (i < len) {
char c = s[i++];
if (c == '\\')
c = get_escape_char(s, &i);
q[d.len++] = c;
20 years ago
}
q[d.len++] = '\0';
return d;
}
struct data data_copy_file(FILE *f, size_t maxlen)
20 years ago
{
struct data d = empty_data;
20 years ago
Kill bogus TYPE_BLOB marker type Since commit 32b9c6130762 "Preserve datatype markers when emitting dts format", we no longer try to guess the value type. Instead, we reuse the type of the datatype markers when they are present, if the type is either TYPE_UINT* or TYPE_STRING. This causes 'dtc -I fs' to crash: Starting program: /root/dtc -q -f -O dts -I fs /proc/device-tree /dts-v1/; / { Program received signal SIGSEGV, Segmentation fault. __strlen_power8 () at ../sysdeps/powerpc/powerpc64/power8/strlen.S:47 47 ld r12,0(r4) /* Load doubleword from memory. */ (gdb) bt #0 __strlen_power8 () at ../sysdeps/powerpc/powerpc64/power8/strlen.S:47 #1 0x00007ffff7de3d10 in __GI__IO_fputs (str=<optimized out>, fp=<optimized out>) at iofputs.c:33 #2 0x000000001000c7a0 in write_propval (prop=0x100525e0, f=0x7ffff7f718a0 <_IO_2_1_stdout_>) at treesource.c:245 The offending line is: fprintf(f, "%s", delim_start[emit_type]); where emit_type is TYPE_BLOB and: static const char *delim_start[] = { [TYPE_UINT8] = "[", [TYPE_UINT16] = "/bits/ 16 <", [TYPE_UINT32] = "<", [TYPE_UINT64] = "/bits/ 64 <", [TYPE_STRING] = "", }; /* Data blobs */ enum markertype { TYPE_NONE, REF_PHANDLE, REF_PATH, LABEL, TYPE_UINT8, TYPE_UINT16, TYPE_UINT32, TYPE_UINT64, TYPE_BLOB, TYPE_STRING, }; Because TYPE_BLOB < TYPE_STRING and delim_start[] is a static array, delim_start[emit_type] is 0x0. The glibc usually prints out "(null)" when one passes 0x0 to %s, but it seems to call fputs() internally if the format is exactly "%s", hence the crash. TYPE_BLOB basically means the data comes from a file and we don't know its type. We don't care for the former, and the latter is TYPE_NONE. So let's drop TYPE_BLOB completely and use TYPE_NONE instead when reading the file. Then, try to guess the data type at emission time, like the code already does for refs and labels. Instead of adding yet another check for TYPE_NONE, an helper is introduced to check if the data marker has type information, ie, >= TYPE_UINT8. Fixes: 32b9c61307629ac76c6ac0bead6f926d579b3d2c Suggested-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Greg Kurz <groug@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
6 years ago
d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
20 years ago
if (maxlen == -1)
chunksize = 4096;
else
chunksize = maxlen - d.len;
d = data_grow_for(d, chunksize);
ret = fread(d.val + d.len, 1, chunksize, f);
if (ferror(f))
die("Error reading file into data: %s", strerror(errno));
if (d.len + ret < d.len)
die("Overflow reading file into data\n");
d.len += ret;
}
20 years ago
return d;
}
struct data data_append_data(struct data d, const void *p, int len)
20 years ago
{
d = data_grow_for(d, len);
memcpy(d.val + d.len, p, len);
d.len += len;
return d;
}
struct data data_insert_at_marker(struct data d, struct marker *m,
const void *p, int len)
{
d = data_grow_for(d, len);
memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
memcpy(d.val + m->offset, p, len);
d.len += len;
/* Adjust all markers after the one we're inserting at */
m = m->next;
for_each_marker(m)
m->offset += len;
return d;
}
static struct data data_append_markers(struct data d, struct marker *m)
{
struct marker **mp = &d.markers;
/* Find the end of the markerlist */
while (*mp)
mp = &((*mp)->next);
*mp = m;
return d;
}
struct data data_merge(struct data d1, struct data d2)
{
struct data d;
struct marker *m2 = d2.markers;
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
/* Adjust for the length of d1 */
for_each_marker(m2)
m2->offset += d1.len;
d2.markers = NULL; /* So data_free() doesn't clobber them */
data_free(d2);
return d;
}
struct data data_append_integer(struct data d, uint64_t value, int bits)
20 years ago
{
uint8_t value_8;
fdt16_t value_16;
fdt32_t value_32;
fdt64_t value_64;
switch (bits) {
case 8:
value_8 = value;
return data_append_data(d, &value_8, 1);
case 16:
value_16 = cpu_to_fdt16(value);
return data_append_data(d, &value_16, 2);
case 32:
value_32 = cpu_to_fdt32(value);
return data_append_data(d, &value_32, 4);
case 64:
value_64 = cpu_to_fdt64(value);
return data_append_data(d, &value_64, 8);
default:
die("Invalid literal size (%d)\n", bits);
}
20 years ago
}
struct data data_append_re(struct data d, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry re;
re.address = cpu_to_fdt64(address);
re.size = cpu_to_fdt64(size);
return data_append_data(d, &re, sizeof(re));
}
struct data data_append_cell(struct data d, cell_t word)
{
return data_append_integer(d, word, sizeof(word) * 8);
}
struct data data_append_addr(struct data d, uint64_t addr)
{
return data_append_integer(d, addr, sizeof(addr) * 8);
}
20 years ago
struct data data_append_byte(struct data d, uint8_t byte)
{
return data_append_data(d, &byte, 1);
}
struct data data_append_zeroes(struct data d, int len)
{
d = data_grow_for(d, len);
memset(d.val + d.len, 0, len);
d.len += len;
return d;
}
struct data data_append_align(struct data d, int align)
{
int newlen = ALIGN(d.len, align);
return data_append_zeroes(d, newlen - d.len);
}
struct data data_add_marker(struct data d, enum markertype type, char *ref)
{
struct marker *m;
m = xmalloc(sizeof(*m));
m->offset = d.len;
m->type = type;
m->ref = ref;
m->next = NULL;
return data_append_markers(d, m);
}
bool data_is_one_string(struct data d)
20 years ago
{
int i;
int len = d.len;
if (len == 0)
return false;
20 years ago
for (i = 0; i < len-1; i++)
if (d.val[i] == '\0')
return false;
20 years ago
if (d.val[len-1] != '\0')
return false;
20 years ago
return true;
20 years ago
}