26869ad14c
In standards such as LoPAPR, property names in excess of the usual 31 characters exist. This breaks property traversal. While in IEEE 1275-1994, nextprop is defined explicitly to work with a 32-byte region of memory, using a larger buffer should be fine. There is actually no way to pass a buffer length to the nextprop call in the OF client interface, so SLOF actually just blindly overflows the buffer. So we have to defensively make the buffer larger, to avoid memory corruption when reading out long properties on live OF systems. Note also that on real-mode OF, things are pretty tight because we are allocating against a static bounce buffer in low memory, so we can't just use a huge buffer to work around this without it being wasteful of our limited amount of 32-bit physical memory. This allows a patched ofwdump to operate properly on SLOF (i.e. pseries) systems, as well as any other PowerPC systems with overlength properties. Reviewed by: jhibbits MFC after: 2 weeks Sponsored by: Tag1 Consulting, Inc. Differential Revision: https://reviews.freebsd.org/D26669
251 lines
6.1 KiB
C
251 lines
6.1 KiB
C
/*-
|
|
* Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <dev/ofw/openfirm.h>
|
|
#include <dev/ofw/openfirmio.h>
|
|
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sysexits.h>
|
|
#include <unistd.h>
|
|
#include <vis.h>
|
|
|
|
#include "ofw_util.h"
|
|
|
|
/* Constants controlling the layout of the output. */
|
|
#define LVLINDENT 2
|
|
#define NAMEINDENT 2
|
|
#define DUMPINDENT 4
|
|
#define CHARSPERLINE 60
|
|
#define BYTESPERLINE (CHARSPERLINE / 3)
|
|
|
|
static void usage(void);
|
|
static void ofw_indent(int);
|
|
static void ofw_dump_properties(int, phandle_t, int, int, int);
|
|
static void ofw_dump_property(int fd, phandle_t n, int level,
|
|
const char *prop, int raw, int str);
|
|
static void ofw_dump(int, const char *, int, int, const char *, int, int);
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
|
|
fprintf(stderr,
|
|
"usage: ofwdump -a [-p | -P property] [-R | -S]\n"
|
|
" ofwdump [-p | -P property] [-r] [-R | -S] [--] nodes\n");
|
|
exit(EX_USAGE);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int opt, i, fd;
|
|
int aflag, pflag, rflag, Rflag, Sflag;
|
|
char *Parg;
|
|
|
|
aflag = pflag = rflag = Rflag = Sflag = 0;
|
|
Parg = NULL;
|
|
while ((opt = getopt(argc, argv, "-aprP:RS")) != -1) {
|
|
if (opt == '-')
|
|
break;
|
|
switch (opt) {
|
|
case 'a':
|
|
aflag = 1;
|
|
rflag = 1;
|
|
break;
|
|
case 'p':
|
|
if (Parg != NULL)
|
|
usage();
|
|
pflag = 1;
|
|
break;
|
|
case 'r':
|
|
rflag = 1;
|
|
break;
|
|
case 'P':
|
|
if (pflag)
|
|
usage();
|
|
pflag = 1;
|
|
Parg = optarg;
|
|
break;
|
|
case 'R':
|
|
if (Sflag)
|
|
usage();
|
|
Rflag = 1;
|
|
break;
|
|
case 'S':
|
|
if (Rflag)
|
|
usage();
|
|
Sflag = 1;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
fd = ofw_open(O_RDONLY);
|
|
if (aflag) {
|
|
if (argc != 0)
|
|
usage();
|
|
ofw_dump(fd, NULL, rflag, pflag, Parg, Rflag, Sflag);
|
|
} else {
|
|
/*
|
|
* For the sake of scripts, usage() is not called here if
|
|
* argc == 0.
|
|
*/
|
|
for (i = 0; i < argc; i++)
|
|
ofw_dump(fd, argv[i], rflag, pflag, Parg, Rflag, Sflag);
|
|
}
|
|
ofw_close(fd);
|
|
return (EX_OK);
|
|
}
|
|
|
|
static void
|
|
ofw_indent(int level)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < level; i++)
|
|
putchar(' ');
|
|
}
|
|
|
|
static void
|
|
ofw_dump_properties(int fd, phandle_t n, int level, int raw, int str)
|
|
{
|
|
int nlen;
|
|
char prop[OFIOCSUGGPROPNAMELEN];
|
|
|
|
for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
|
|
nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop)))
|
|
ofw_dump_property(fd, n, level, prop, raw, str);
|
|
}
|
|
|
|
static void
|
|
ofw_dump_property(int fd, phandle_t n, int level, const char *prop, int raw,
|
|
int str)
|
|
{
|
|
static void *pbuf = NULL;
|
|
static char *visbuf = NULL;
|
|
static char printbuf[CHARSPERLINE + 1];
|
|
static int pblen = 0, vblen = 0;
|
|
int len, i, j, max, vlen;
|
|
|
|
len = ofw_getprop_alloc(fd, n, prop, &pbuf, &pblen, 1);
|
|
if (len < 0)
|
|
return;
|
|
if (raw)
|
|
write(STDOUT_FILENO, pbuf, len);
|
|
else if (str)
|
|
printf("%.*s\n", len, (char *)pbuf);
|
|
else {
|
|
ofw_indent(level * LVLINDENT + NAMEINDENT);
|
|
printf("%s:\n", prop);
|
|
/* Print in hex. */
|
|
for (i = 0; i < len; i += BYTESPERLINE) {
|
|
max = len - i;
|
|
max = max > BYTESPERLINE ? BYTESPERLINE : max;
|
|
ofw_indent(level * LVLINDENT + DUMPINDENT);
|
|
for (j = 0; j < max; j++)
|
|
printf("%02x ",
|
|
((unsigned char *)pbuf)[i + j]);
|
|
printf("\n");
|
|
}
|
|
/*
|
|
* strvis() and print if it looks like it is
|
|
* zero-terminated.
|
|
*/
|
|
if (((char *)pbuf)[len - 1] == '\0' &&
|
|
strlen(pbuf) == (unsigned)len - 1) {
|
|
if (vblen < (len - 1) * 4 + 1) {
|
|
if (visbuf != NULL)
|
|
free(visbuf);
|
|
vblen = (OFIOCMAXVALUE + len) * 4 + 1;
|
|
if ((visbuf = malloc(vblen)) == NULL)
|
|
err(EX_OSERR,
|
|
"malloc() failed");
|
|
}
|
|
vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
|
|
for (i = 0; i < vlen; i += CHARSPERLINE) {
|
|
ofw_indent(level * LVLINDENT +
|
|
DUMPINDENT);
|
|
strlcpy(printbuf, &visbuf[i],
|
|
sizeof(printbuf));
|
|
printf("'%s'\n", printbuf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop,
|
|
const char *pmatch, int raw, int str)
|
|
{
|
|
static void *nbuf = NULL;
|
|
static int nblen = 0;
|
|
int plen;
|
|
phandle_t c;
|
|
|
|
if (!(raw || str)) {
|
|
ofw_indent(level * LVLINDENT);
|
|
printf("Node %#lx", (unsigned long)n);
|
|
plen = ofw_getprop_alloc(fd, n, "name", &nbuf, &nblen, 1);
|
|
if (plen > 0)
|
|
printf(": %.*s\n", (int)plen, (char *)nbuf);
|
|
else
|
|
putchar('\n');
|
|
}
|
|
if (prop) {
|
|
if (pmatch)
|
|
ofw_dump_property(fd, n, level, pmatch, raw, str);
|
|
else
|
|
ofw_dump_properties(fd, n, level, raw, str);
|
|
}
|
|
if (rec) {
|
|
for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
|
|
ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
|
|
raw, str);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
ofw_dump(int fd, const char *start, int rec, int prop, const char *pmatch,
|
|
int raw, int str)
|
|
{
|
|
phandle_t n;
|
|
|
|
n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
|
|
ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
|
|
}
|