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 <[email protected]>
---
 fdtdump.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/fdtdump.c b/fdtdump.c
index a29aa5e..d4480df 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -8,6 +8,14 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <alloca.h>
+#include <dirent.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include <libfdt.h>
 #include <libfdt_env.h>
@@ -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] <file>";
 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.7.12

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to