From da5c33dd94949fa27243faf15cd87e98c53ccb29 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 5 Nov 2013 10:16:14 +0200 Subject: [PATCH] fdtdump: Add live tree dump capability Adds the capability to dump any point of the kernel's live tree which resides usually in /proc/device-tree. For example you can do this: # fdtdump /proc/device-tree/ocp/ethernet\@4a100000/ /* dump of live tree at /proc/device-tree/ocp/ethernet@4a100000 */ / { name = "ethernet"; pinctrl-1 = <0x0000000b>; pinctrl-0 = <0x0000000a>; pinctrl-names = "default", "sleep"; ranges; interrupts = <0x00000028 0x00000000 0x00000000 0x00000000>; interrupt-parent = <0x00000001>; #size-cells = <0x00000001>; #address-cells = <0x00000001>; reg = <0x4a100000 0x00000000 0x00000000 0x00000000>; cpts_clock_shift = <0x0000001d>; cpts_clock_mult = <0x80000000>; active_slave = <0x00000000>; slaves = <0x00000002>; mac_control = <0x00000020>; rx_descs = <0x00000040>; no_bd_ram = <0x00000000>; bd_ram_size = <0x00002000>; ale_entries = <0x00000400>; cpdma_channels = <0x00000008>; ti,hwmods = "cpgmac0"; compatible = "ti,cpsw"; slave@4a100300 { name = "slave"; phy-mode = "mii"; phy_id = <0x0000000e 0x00000000>; mac-address = [00 00 00 00 00 00]; }; slave@4a100200 { name = "slave"; phy-mode = "mii"; phy_id = <0x0000000e 0x00000000>; mac-address = [00 00 00 00 00 00]; }; mdio@4a101000 { name = "mdio"; phandle = <0x0000000e>; linux,phandle = <0x0000000e>; pinctrl-1 = <0x0000000d>; pinctrl-0 = <0x0000000c>; pinctrl-names = "default", "sleep"; reg = <0x4a101000 0x00000000>; bus_freq = <0x000f4240>; ti,hwmods = "davinci_mdio"; #size-cells = <0x00000000>; #address-cells = <0x00000001>; compatible = "ti,davinci_mdio"; }; }; This makes it much easier to see the state of the kernel's live tree. Signed-off-by: Pantelis Antoniou --- fdtdump.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/fdtdump.c b/fdtdump.c index 95a6a20..9183555 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -8,6 +8,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -143,6 +151,95 @@ static void dump_blob(void *blob, bool debug) } } +static void dump_live_internal(const char *path, bool debug, int depth) +{ + int maxsz = strlen(path) + 1 + PATH_MAX; + char *new_path = alloca(maxsz + 1); + struct stat sb; + struct dirent *de; + char *buf, *p; + int buf_alloc, shift, chunk, left, fd, ret; + DIR *d; + + shift = 4; + buf_alloc = 4 * 1024; /* 4K (maximum chunk) */ + buf = alloca(buf_alloc + sizeof(uint32_t)); + buf[buf_alloc] = '\0'; /* always terminate (just in case) */ + + d = opendir(path); + if (d == NULL) + die("Could not open %s directory\n", path); + + /* first dump the properties (files) */ + while ((de = readdir(d)) != NULL) { + /* properties are files */ + if (de->d_type != DT_REG) + continue; + snprintf(new_path, maxsz, "%s/%s", path, de->d_name); + new_path[maxsz] = '\0'; + printf("%*s%s", depth * shift, "", de->d_name); + + if (stat(new_path, &sb) != 0) + die("could not open: %s\n", new_path); + + fd = open(new_path, O_RDONLY); + if (fd == -1) + die("Could not open: %s\n", new_path); + + chunk = sb.st_size > buf_alloc ? buf_alloc : sb.st_size; + p = buf; + left = chunk; + while (left > 0) { + do { + ret = read(fd, p, left); + } while (ret == -1 && (errno == EAGAIN || errno == EINTR)); + if (ret == -1) + die("Read failed on: %s\n", new_path); + left -= ret; + p += ret; + } + close(fd); + + if (chunk < sb.st_size) + printf(" (trunc)"); + utilfdt_print_data(buf, chunk); + printf(";\n"); + } + + /* now recurse to the directories */ + rewinddir(d); + while ((de = readdir(d)) != NULL) { + /* properties are files */ + if (de->d_type != DT_DIR) + continue; + /* skip current and parent directories */ + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + snprintf(new_path, maxsz, "%s/%s", path, de->d_name); + new_path[maxsz] = '\0'; + printf("%*s%s {\n", depth * shift, "", de->d_name); + dump_live_internal(new_path, debug, depth + 1); + printf("%*s};\n", depth * shift, ""); + } +} + +static void dump_live(const char *path, bool debug) +{ + char *fixed_path = alloca(strlen(path) + 1); + char *p; + + /* strip trailing / */ + strcpy(fixed_path, path); + p = fixed_path + strlen(fixed_path) - 1; + while (*p == '/' && p > fixed_path) + *p-- = '\0'; + printf("/* dump of live tree at %s */\n", fixed_path); + printf("/ {\n"); + dump_live_internal(fixed_path, debug, 1); + printf("};\n"); +} + /* Usage related data. */ static const char usage_synopsis[] = "fdtdump [options] "; static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS; @@ -165,6 +262,7 @@ int main(int argc, char *argv[]) bool debug = false; bool scan = false; off_t len; + struct stat sb; while ((opt = util_getopt_long()) != EOF) { switch (opt) { @@ -182,6 +280,15 @@ int main(int argc, char *argv[]) usage("missing input filename"); file = argv[optind]; + if (stat(file, &sb) != 0) + die("could not open: %s\n", file); + + /* dump live tree if it's a directory */ + if (S_ISDIR(sb.st_mode)) { + dump_live(file, debug); + return 0; + } + buf = utilfdt_read_len(file, &len); if (!buf) die("could not read: %s\n", file); -- 1.9.1