Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Jun 2009 09:12:12 +0400
From:      Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To:        freebsd-acpi@freebsd.org
Subject:   [PATCH] acpidump: teach to disassemble arbitrary memory locations as AML code
Message-ID:  <W6QSpRPwDx1bM%2BckKMKVCUsLU5A@XX1fo6zQUfC4h0jjRC6IBz3oNH4>

next in thread | raw e-mail | index | archive | help
It is not uncommon when some chunks of the AML code are loaded by DSDT
=66rom the memory locations that aren't part of the DSDT itself, but one
wants to see what's inside.  It can be achieved with 'dd' and 'iasl',
but it is better to implement this machinery inside acpidump to ease the
life of both users and develepers that needs to see the full picture
of the ACPI stuff from foreign machines.

This commit also have some small fixes:

- verbose output (going to stderr) isn't mixed with normal output
  that goes to stdout -- the latter is made unbuffered;

- we're using IASL's logics to get the name of the output file and,
  moreover, we prevent two simultaneous invocations of acpidump
  to hose other's output;

- IASL exit code is checked and if disassembler exited abnormally
  or was failed to do its job, the warning is produced to give
  the reader an idea on what's going on.

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 usr.sbin/acpi/acpidump/acpi.c     |  165 ++++++++++++++++++++++++++++++++-=
----
 usr.sbin/acpi/acpidump/acpidump.8 |    5 +
 usr.sbin/acpi/acpidump/acpidump.c |   97 +++++++++++++++++++++-
 usr.sbin/acpi/acpidump/acpidump.h |    2 +
 4 files changed, 244 insertions(+), 25 deletions(-)

diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c
index fed0fb2..321f894 100644
--- a/usr.sbin/acpi/acpidump/acpi.c
+++ b/usr.sbin/acpi/acpidump/acpi.c
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 1998 Doug Rabson
  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * Copyright (c) 2009 Eygene Ryabinkin <rea-fbsd@codelabs.ru>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,10 +32,13 @@
 #include <sys/endian.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <assert.h>
 #include <err.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
=20
@@ -800,47 +804,166 @@ dsdt_save_file(char *outfile, struct ACPIsdt *rsdt, =
struct ACPIsdt *dsdp)
 	close(fd);
 }
=20
-void
-aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp)
-{
-	char tmpstr[32], buf[256];
-	FILE *fp;
-	int fd, len;
+#define	TMPIN	"/tmp/acpidump.XXXXXX.aml"
+#define	TMPSLEN	4
=20
-	strcpy(tmpstr, "/tmp/acpidump.XXXXXX");
-	fd =3D mkstemp(tmpstr);
-	if (fd < 0) {
-		perror("iasl tmp file");
+/*
+ * Disassembles contents of a given file and dumps them to the
+ * specified file descriptor.
+ */
+static void
+invoke_iasl(char *infile, FILE *outfp)
+{
+	char	buf[256], *outfile;
+	int	len, status;
+	FILE	*fp;
+	pid_t	child;
+
+	if (strlen(infile) <=3D TMPSLEN) {
+		warnx("bad input file name '%s', should be longer "
+		    "than " ##TMPSLEN " characters", infile);
 		return;
 	}
-	write_dsdt(fd, rsdt, dsdp);
-	close(fd);
+	if (strcmp(infile + strlen(infile) - TMPSLEN, ".aml")) {
+		warnx("bad input file name '%s', should end on '.aml'",
+		    infile);
+		return;
+	}
+	outfile =3D strdup(infile);
+	if (outfile =3D=3D NULL) {
+		perror("ASL tmp file");
+		return;
+	}
+	strcpy(outfile + strlen(outfile) - TMPSLEN, ".dsl");
=20
-	/* Run iasl -d on the temp file */
-	if (fork() =3D=3D 0) {
+	/* Run iasl -d on the input file */
+	child =3D fork();
+	if (child =3D=3D -1) {
+		warn("fork");
+		free(outfile);
+		return;
+	}
+	if (child =3D=3D 0) {
 		close(STDOUT_FILENO);
 		if (vflag =3D=3D 0)
 			close(STDERR_FILENO);
-		execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, (char *) 0);
+		execl("/usr/sbin/iasl", "iasl", "-d", "-p", outfile,
+		    infile, (char *) 0);
 		err(1, "exec");
 	}
=20
-	wait(NULL);
-	unlink(tmpstr);
+	if (waitpid(child, &status, 0) !=3D child) {
+		warn("waitpid(%lu)", (unsigned long)child);
+		unlink(outfile);
+		free(outfile);
+		return;
+	}
+
+	if (!WIFEXITED(status)) {
+		warnx("IASL exited abnormally: status =3D %d", status);
+		unlink(outfile);
+		free(outfile);
+		return;
+	}
+
+	if (WEXITSTATUS(status) !=3D 0) {
+		warnx("IASL was not able to disassemble the passed AML code");
+		unlink(outfile);
+		free(outfile);
+		return;
+	}
=20
 	/* Dump iasl's output to stdout */
-	fp =3D fopen("acpidump.dsl", "r");
-	unlink("acpidump.dsl");
+	fp =3D fopen(outfile, "r");
+	unlink(outfile);
+	free(outfile);
 	if (fp =3D=3D NULL) {
-		perror("iasl tmp file (read)");
+		perror("ASL tmp file (read)");
 		return;
 	}
 	while ((len =3D fread(buf, 1, sizeof(buf), fp)) > 0)
-		fwrite(buf, 1, len, stdout);
+		fwrite(buf, 1, len, outfp);
 	fclose(fp);
 }
=20
 void
+mem_disassemble(size_t dumpaddr, size_t dumplen)
+{
+	char	tmpstr[sizeof(TMPIN)];
+	char	buf[256];
+	int	fd, memfd, toread, towrite;
+
+	strcpy(tmpstr, TMPIN);
+	fd =3D mkstemps(tmpstr, TMPSLEN);
+	if (fd < 0) {
+		perror("AML tmp file");
+		return;
+	}
+	memfd =3D open("/dev/mem", O_RDONLY);
+	if (memfd =3D=3D -1) {
+		perror("open /dev/mem");
+		close(fd);
+		unlink(tmpstr);
+		return;
+	}
+	if (lseek(memfd, dumpaddr, SEEK_SET) =3D=3D -1) {
+		perror("seeking /dev/mem");
+		close(fd);
+		close(memfd);
+		unlink(tmpstr);
+		return;
+	}
+
+	while (dumplen > 0) {
+		toread =3D (dumplen > sizeof(buf) ? sizeof(buf) : dumplen);
+		towrite =3D read(memfd, buf, toread);
+		if (towrite =3D=3D -1) {
+			perror("reading /dev/mem");
+			close(fd);
+			close(memfd);
+			unlink(tmpstr);
+			return;
+		}
+		if (write(fd, buf, towrite) !=3D towrite) {
+			perror("writing to AML tmp file");
+			close(fd);
+			close(memfd);
+			unlink(tmpstr);
+			return;
+		}
+		dumplen -=3D towrite;
+	}
+
+	close(fd);
+	close(memfd);
+
+	invoke_iasl(tmpstr, stdout);
+	unlink(tmpstr);
+}
+
+void
+aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp)
+{
+	char	tmpstr[sizeof(TMPIN)];
+	int	fd;
+
+	strcpy(tmpstr, TMPIN);
+	fd =3D mkstemps(tmpstr, TMPSLEN);
+	if (fd < 0) {
+		perror("AML tmp file");
+		return;
+	}
+	write_dsdt(fd, rsdt, dsdp);
+	close(fd);
+
+	invoke_iasl(tmpstr, stdout);
+	unlink(tmpstr);
+}
+
+#undef TMPIN
+#undef TMPSLEN
+
+void
 sdt_print_all(struct ACPIsdt *rsdp)
 {
 	acpi_handle_rsdt(rsdp);
diff --git a/usr.sbin/acpi/acpidump/acpidump.8 b/usr.sbin/acpi/acpidump/acp=
idump.8
index 1401e38..ec16e4b 100644
--- a/usr.sbin/acpi/acpidump/acpidump.8
+++ b/usr.sbin/acpi/acpidump/acpidump.8
@@ -4,6 +4,7 @@
 .\" Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
 .\" Copyright (c) 2000 Yasuo YOKOYAMA <yokoyama@jp.FreeBSD.org>
 .\" Copyright (c) 2000 Hiroki Sato <hrs@FreeBSD.org>
+.\" Copyright (c) 2009 Eygene Ryabinkin <rea-fbsd@codelabs.ru>
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -43,6 +44,7 @@
 .Op Fl v
 .Op Fl f Ar dsdt_input
 .Op Fl o Ar dsdt_output
+.Op Fl a Ar address:length
 .Sh DESCRIPTION
 The
 .Nm
@@ -122,6 +124,9 @@ the DSDT consists of free-formatted AML data.
 The following options are supported by
 .Nm :
 .Bl -tag -width indent
+.It Fl d Ar address:length
+Disassemble the given block of physical memory to the standard output.
+This flag can be repeated: multiple blocks will be disassembled.
 .It Fl d
 Disassemble the DSDT into ASL using
 .Xr iasl 8
diff --git a/usr.sbin/acpi/acpidump/acpidump.c b/usr.sbin/acpi/acpidump/acp=
idump.c
index a601ac2..b10527a 100644
--- a/usr.sbin/acpi/acpidump/acpidump.c
+++ b/usr.sbin/acpi/acpidump/acpidump.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * Copyright (c) 2009 Eygene Ryabinkin <rea-fbsd@codelabs.ru>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sysexits.h>
 #include <unistd.h>
=20
 #include "acpidump.h"
@@ -40,23 +42,78 @@ int	dflag;	/* Disassemble AML using iasl(8) */
 int	tflag;	/* Dump contents of SDT tables */
 int	vflag;	/* Use verbose messages */
=20
+struct aflag {
+	size_t		addr;
+	size_t		size;
+	struct aflag	*next;
+};
+
 static void
 usage(const char *progname)
 {
=20
-	fprintf(stderr, "usage: %s [-d] [-t] [-h] [-v] [-f dsdt_input] "
+	fprintf(stderr, "usage: %s [-a addr:len] [-d] [-t] [-h] [-v] [-f dsdt_inp=
ut] "
 			"[-o dsdt_output]\n", progname);
 	fprintf(stderr, "To send ASL:\n\t%s -dt | gzip -c9 > foo.asl.gz\n",
 	    progname);
 	exit(1);
 }
=20
+/*
+ * Parses pair of address:length from the given string.
+ * Both numbers can be hexadecimal (prefixed by 0[xX])
+ * or plain decimal.
+ *
+ * Returns 0 for success, !=3D 0 otherwise.
+ */
+static int
+parse_addr(const char *arg, size_t *addr, size_t *len)
+{
+	char *c1, *c2, *a, *l;
+
+	c1 =3D strchr(arg, ':');
+	c2 =3D strrchr(arg, ':');
+	if (c1 !=3D c2 || c1 =3D=3D NULL) {
+		warnx ("argument to '-a' should have form 'addr:len'");
+		return 1;
+	}
+
+	l =3D c1 + 1;
+	a =3D strndup(arg, l - arg);
+	if (a =3D=3D NULL)
+		err(EX_OSERR, "can't parse address:size tuple");
+
+	if (sscanf(a, "%zi", addr) !=3D 1) {
+		warnx("Unable to parse address from argument to '-a'");
+		free(a);
+		return 1;
+	}
+	if (sscanf(l, "%zi", len) !=3D 1) {
+		warnx("Unable to parse length from argument to '-a'");
+		free(a);
+		return 1;
+	}
+
+	free(a);
+	return 0;
+}
+
 int
 main(int argc, char *argv[])
 {
 	char	c, *progname;
-	char	*dsdt_input_file, *dsdt_output_file;
-	struct	ACPIsdt *rsdt, *sdt;
+	char	*dsdt_input_file =3D NULL, *dsdt_output_file =3D NULL;
+	struct	ACPIsdt *rsdt =3D NULL, *sdt =3D NULL;
+	struct aflag	*aroot =3D NULL, *atmp;
+
+	/*
+	 * When stdin/stdout are sent to the same file, stdout shouldn't
+	 * be buffered to prevent mixing two outputs.  We won't try to
+	 * check it stdin/stdout are the same files, but will just
+	 * make stdout unbuffered unconditionally.  This is most
+	 * useful when we're running in verbose mode.
+	 */
+	setbuf(stdout, NULL);
=20
 	dsdt_input_file =3D dsdt_output_file =3D NULL;
 	progname =3D argv[0];
@@ -64,8 +121,17 @@ main(int argc, char *argv[])
 	if (argc < 2)
 		usage(progname);
=20
-	while ((c =3D getopt(argc, argv, "dhtvf:o:")) !=3D -1) {
+	while ((c =3D getopt(argc, argv, "a:dhtvf:o:")) !=3D -1) {
 		switch (c) {
+		case 'a':
+			atmp =3D (struct aflag *)malloc(sizeof(*atmp));
+			if (atmp =3D=3D NULL)
+				errx(EX_OSERR, "parsing arguments to '-a'");
+			if (parse_addr(optarg, &atmp->addr, &atmp->size))
+				usage(progname);
+			atmp->next =3D aroot;
+			aroot =3D atmp;
+			break;
 		case 'd':
 			dflag =3D 1;
 			break;
@@ -140,5 +206,28 @@ main(int argc, char *argv[])
 			warnx("iasl processing complete");
 	}
=20
+	if (aroot !=3D NULL) {
+		struct aflag *nroot =3D NULL;
+		/* Reverse list and disassemble each memory location */
+		while (aroot !=3D NULL) {
+			atmp =3D aroot->next;
+			aroot->next =3D nroot;
+			nroot =3D aroot;
+			aroot =3D atmp;
+		}
+		while (nroot !=3D NULL) {
+			if (vflag) {
+				warnx("disassembling memory at 0x%zx, "
+				    "0x%zx bytes", nroot->addr, nroot->size);
+			}
+			mem_disassemble(nroot->addr, nroot->size);
+			if (vflag)
+				warnx("finished disassembling");
+			atmp =3D nroot;
+			nroot =3D nroot->next;
+			free(atmp);
+		}
+	}
+
 	exit(0);
 }
diff --git a/usr.sbin/acpi/acpidump/acpidump.h b/usr.sbin/acpi/acpidump/acp=
idump.h
index 8d79168..8428b58 100644
--- a/usr.sbin/acpi/acpidump/acpidump.h
+++ b/usr.sbin/acpi/acpidump/acpidump.h
@@ -332,6 +332,8 @@ void		 sdt_print_all(struct ACPIsdt *);
=20
 /* Disassemble the AML in the DSDT */
 void		 aml_disassemble(struct ACPIsdt *, struct ACPIsdt *);
+/* Disassemble arbitrary memory chunk */
+void		 mem_disassemble(size_t dumpaddr, size_t dumplen);
=20
 /* Routines for accessing tables in physical memory */
 struct ACPIrsdp	*acpi_find_rsd_ptr(void);
--=20
1.6.3.1
--=20
Eygene
 _                ___       _.--.   #
 \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
 /  ' `         ,       __.--'      #  to read the on-line manual
 )/' _/     \   `-_,   /            #  while single-stepping the kernel.
 `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
     _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook
    {_.-``-'         {_/            #



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?W6QSpRPwDx1bM%2BckKMKVCUsLU5A>