Subject: file(1) patch to recognise ELF notes in executables
To: None <tech-userlevel@netbsd.org>
From: Ben Harris <bjh21@netbsd.org>
List: tech-userlevel
Date: 03/07/2002 19:46:12
This patch is intended as a partial fix for PR bin/12295, which points out
that file(1)'s output for ELF executables doesn't mention which OS they're
for.  It recognises both NetBSD and GNU executables, and produces output
like:

/usr/bin/printf: ELF 32-bit MSB executable, PowerPC or cisco 4500, version
1, for NetBSD, dynamically linked (uses shared libs), stripped
/opt/netbsd/citrix_ica/linuxarm/echo_cmd: ELF 32-bit LSB executable,
Advanced RISC Machines ARM, version 1, for GNU/Linux 2.0.0, dynamically
linked (uses shared libs), stripped

Any comments?  If not, I'll probably commit it myself.

Index: readelf.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/file/readelf.c,v
retrieving revision 1.10
diff -u -u -r1.10 readelf.c
--- readelf.c	2001/12/09 23:21:07	1.10
+++ readelf.c	2002/03/07 19:37:49
@@ -177,9 +177,14 @@
 	size_t size;
 {
 	Elf32_Phdr ph32;
+	Elf32_Nhdr *nh32;
 	Elf64_Phdr ph64;
+	Elf64_Nhdr *nh64;
 	char *linking_style = "statically";
 	char *shared_libraries = "";
+	char nbuf[BUFSIZ];
+	int bufsize;
+	size_t offset, nameoffset;

 	if (lseek(fd, off, SEEK_SET) == -1)
 		error("lseek failed (%s).\n", strerror(errno));
@@ -194,6 +199,80 @@
 			break;
 		case PT_INTERP:
 			shared_libraries = " (uses shared libs)";
+			break;
+		case PT_NOTE:
+			/*
+			 * This is a PT_NOTE section; loop through all the notes
+			 * in the section.
+			 */
+			if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1)
+				error("lseek failed (%s).\n", strerror(errno));
+			bufsize = read(fd, nbuf, BUFSIZ);
+			if (bufsize == -1)
+				error(": " "read failed (%s).\n",
+				    strerror(errno));
+			offset = 0;
+			for (;;) {
+				if (offset >= bufsize)
+					break;
+				if (class == ELFCLASS32)
+					nh32 = (Elf32_Nhdr *)&nbuf[offset];
+				else
+					nh64 = (Elf64_Nhdr *)&nbuf[offset];
+				offset += nh_size;
+
+				if (offset + nh_namesz >= bufsize) {
+					/*
+					 * We're past the end of the buffer.
+					 */
+					break;
+				}
+
+				nameoffset = offset;
+				offset += nh_namesz;
+				offset = ((offset + 3)/4)*4;
+
+				if (offset + nh_descsz >= bufsize)
+					break;
+
+				if (nh_namesz == 4 &&
+				    strcmp(&nbuf[nameoffset], "GNU") == 0 &&
+				    nh_type == NT_GNU_VERSION &&
+				    nh_descsz == 16) {
+					uint32_t *desc =
+					    (uint32_t *)&nbuf[offset];
+
+					printf(", for GNU/");
+					switch (getu32(swap, desc[0])) {
+					case GNU_OS_LINUX:
+						printf("Linux");
+						break;
+					case GNU_OS_HURD:
+						printf("Hurd");
+						break;
+					case GNU_OS_SOLARIS:
+						printf("Solaris");
+						break;
+					default:
+						printf("<unknown>");
+					}
+					printf(" %d.%d.%d",
+					    getu32(swap, desc[1]),
+					    getu32(swap, desc[2]),
+					    getu32(swap, desc[3]));
+				}
+
+				if (nh_namesz == 7 &&
+				    strcmp(&nbuf[nameoffset], "NetBSD") == 0 &&
+				    nh_type == NT_NETBSD_VERSION &&
+				    nh_descsz == 4) {
+					printf(", for NetBSD");
+					/*
+					 * Version number is stuck at 199905,
+					 * and hence is basically content-free.
+					 */
+				}
+			}
 			break;
 		}
 	}
Index: readelf.h
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/file/readelf.h,v
retrieving revision 1.6
diff -u -u -r1.6 readelf.h
--- readelf.h	2001/12/09 23:21:07	1.6
+++ readelf.h	2002/03/07 19:37:49
@@ -190,4 +190,16 @@
 #define	NT_PLATFORM	5
 #define	NT_AUXV		6

+/* Note types used in executables */
+/* NetBSD executables (name = "NetBSD") */
+#define NT_NETBSD_VERSION	1
+#define NT_NETBSD_EMULATION	2
+/* GNU executables (name = "GNU") */
+#define NT_GNU_VERSION		1
+
+/* GNU OS tags */
+#define GNU_OS_LINUX	0
+#define GNU_OS_HURD	1
+#define GNU_OS_SOLARIS	2
+
 #endif

-- 
Ben Harris                                                   <bjh21@netbsd.org>
Portmaster, NetBSD/arm26               <URL:http://www.netbsd.org/Ports/arm26/>