[PATCH] fdtdump: Add live tree dump capability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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 <pantelis.antoniou@xxxxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux