Blob Blame History Raw
From 493e2676626b530a45fcc17040915f34fa0c5dd3 Mon Sep 17 00:00:00 2001
From: Vincent Mihalkovic <vmihalko@redhat.com>
Date: Mon, 6 Feb 2023 14:39:29 +0100
Subject: [PATCH] add parsing for dynamic sections

9109a696f3289ba00eaa222fd432755ec4287e28
---
 src/readelf.c | 295 +++++++++++++++++++++++++++++++-------------------
 src/readelf.h | 103 ++++++++++++++++++
 2 files changed, 289 insertions(+), 109 deletions(-)

diff --git a/src/readelf.c b/src/readelf.c
index c101483..cdc211f 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -62,13 +62,12 @@ private uint64_t getu64(int, uint64_t);
 
 #define MAX_PHNUM	128
 #define	MAX_SHNUM	32768
-#define SIZE_UNKNOWN	((off_t)-1)
+#define SIZE_UNKNOWN	CAST(off_t, -1)
 
 private int
 toomany(struct magic_set *ms, const char *name, uint16_t num)
 {
-	if (file_printf(ms, ", too many %s (%u)", name, num
-	    ) == -1)
+	if (file_printf(ms, ", too many %s (%u)", name, num) == -1)
 		return -1;
 	return 0;
 }
@@ -143,54 +142,55 @@ getu64(int swap, uint64_t value)
 #define elf_getu64(swap, value) getu64(swap, value)
 
 #define xsh_addr	(clazz == ELFCLASS32			\
-			 ? (void *)&sh32			\
-			 : (void *)&sh64)
+			 ? CAST(void *, &sh32)			\
+			 : CAST(void *, &sh64))
 #define xsh_sizeof	(clazz == ELFCLASS32			\
 			 ? sizeof(sh32)				\
 			 : sizeof(sh64))
-#define xsh_size	(size_t)(clazz == ELFCLASS32		\
+#define xsh_size	CAST(size_t, (clazz == ELFCLASS32	\
 			 ? elf_getu32(swap, sh32.sh_size)	\
-			 : elf_getu64(swap, sh64.sh_size))
-#define xsh_offset	(off_t)(clazz == ELFCLASS32		\
+			 : elf_getu64(swap, sh64.sh_size)))
+#define xsh_offset	CAST(off_t, (clazz == ELFCLASS32	\
 			 ? elf_getu32(swap, sh32.sh_offset)	\
-			 : elf_getu64(swap, sh64.sh_offset))
+			 : elf_getu64(swap, sh64.sh_offset)))
 #define xsh_type	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, sh32.sh_type)	\
 			 : elf_getu32(swap, sh64.sh_type))
 #define xsh_name    	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, sh32.sh_name)	\
 			 : elf_getu32(swap, sh64.sh_name))
+
 #define xph_addr	(clazz == ELFCLASS32			\
-			 ? (void *) &ph32			\
-			 : (void *) &ph64)
+			 ? CAST(void *, &ph32)			\
+			 : CAST(void *, &ph64))
 #define xph_sizeof	(clazz == ELFCLASS32			\
 			 ? sizeof(ph32)				\
 			 : sizeof(ph64))
 #define xph_type	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, ph32.p_type)	\
 			 : elf_getu32(swap, ph64.p_type))
-#define xph_offset	(off_t)(clazz == ELFCLASS32		\
+#define xph_offset	CAST(off_t, (clazz == ELFCLASS32	\
 			 ? elf_getu32(swap, ph32.p_offset)	\
-			 : elf_getu64(swap, ph64.p_offset))
-#define xph_align	(size_t)((clazz == ELFCLASS32		\
-			 ? (off_t) (ph32.p_align ? 		\
-			    elf_getu32(swap, ph32.p_align) : 4) \
-			 : (off_t) (ph64.p_align ?		\
-			    elf_getu64(swap, ph64.p_align) : 4)))
-#define xph_vaddr	(size_t)((clazz == ELFCLASS32		\
-			 ? (off_t) (ph32.p_vaddr ? 		\
-			    elf_getu32(swap, ph32.p_vaddr) : 4) \
-			 : (off_t) (ph64.p_vaddr ?		\
-			    elf_getu64(swap, ph64.p_vaddr) : 4)))
-#define xph_filesz	(size_t)((clazz == ELFCLASS32		\
+			 : elf_getu64(swap, ph64.p_offset)))
+#define xph_align	CAST(size_t, (clazz == ELFCLASS32	\
+			 ? CAST(off_t, (ph32.p_align ? 		\
+			    elf_getu32(swap, ph32.p_align) : 4))\
+			 : CAST(off_t, (ph64.p_align ?		\
+			    elf_getu64(swap, ph64.p_align) : 4))))
+#define xph_vaddr	CAST(size_t, (clazz == ELFCLASS32	\
+			 ? CAST(off_t, (ph32.p_vaddr ? 		\
+			    elf_getu32(swap, ph32.p_vaddr) : 4))\
+			 : CAST(off_t, (ph64.p_vaddr ?		\
+			    elf_getu64(swap, ph64.p_vaddr) : 4))))
+#define xph_filesz	CAST(size_t, (clazz == ELFCLASS32	\
 			 ? elf_getu32(swap, ph32.p_filesz)	\
 			 : elf_getu64(swap, ph64.p_filesz)))
-#define xnh_addr	(clazz == ELFCLASS32			\
-			 ? (void *)&nh32			\
-			 : (void *)&nh64)
-#define xph_memsz	(size_t)((clazz == ELFCLASS32		\
+#define xph_memsz	CAST(size_t, ((clazz == ELFCLASS32	\
 			 ? elf_getu32(swap, ph32.p_memsz)	\
-			 : elf_getu64(swap, ph64.p_memsz)))
+			 : elf_getu64(swap, ph64.p_memsz))))
+#define xnh_addr	(clazz == ELFCLASS32			\
+			 ? CAST(void *, &nh32)			\
+			 : CAST(void *, &nh64))
 #define xnh_sizeof	(clazz == ELFCLASS32			\
 			 ? sizeof(nh32)				\
 			 : sizeof(nh64))
@@ -203,24 +203,36 @@ getu64(int swap, uint64_t value)
 #define xnh_descsz	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, nh32.n_descsz)	\
 			 : elf_getu32(swap, nh64.n_descsz))
-#define prpsoffsets(i)	(clazz == ELFCLASS32			\
-			 ? prpsoffsets32[i]			\
-			 : prpsoffsets64[i])
+
+#define xdh_addr	(clazz == ELFCLASS32			\
+			 ? CAST(void *, &dh32)			\
+			 : CAST(void *, &dh64))
+#define xdh_sizeof	(clazz == ELFCLASS32			\
+			 ? sizeof(dh32)				\
+			 : sizeof(dh64))
+#define xdh_tag		(clazz == ELFCLASS32			\
+			 ? elf_getu32(swap, dh32.d_tag)		\
+			 : elf_getu64(swap, dh64.d_tag))
+#define xdh_val		(clazz == ELFCLASS32			\
+			 ? elf_getu32(swap, dh32.d_un.d_val)	\
+			 : elf_getu64(swap, dh64.d_un.d_val))
+
 #define xcap_addr	(clazz == ELFCLASS32			\
-			 ? (void *)&cap32			\
-			 : (void *)&cap64)
+			 ? CAST(void *, &cap32)			\
+			 : CAST(void *, &cap64))
 #define xcap_sizeof	(clazz == ELFCLASS32			\
-			 ? sizeof cap32				\
-			 : sizeof cap64)
+			 ? sizeof(cap32)			\
+			 : sizeof(cap64))
 #define xcap_tag	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, cap32.c_tag)	\
 			 : elf_getu64(swap, cap64.c_tag))
 #define xcap_val	(clazz == ELFCLASS32			\
 			 ? elf_getu32(swap, cap32.c_un.c_val)	\
 			 : elf_getu64(swap, cap64.c_un.c_val))
+
 #define xauxv_addr	(clazz == ELFCLASS32			\
-			 ? (void *)&auxv32			\
-			 : (void *)&auxv64)
+			 ? CAST(void *, &auxv32)		\
+			 : CAST(void *, &auxv64))
 #define xauxv_sizeof	(clazz == ELFCLASS32			\
 			 ? sizeof(auxv32)			\
 			 : sizeof(auxv64))
@@ -231,6 +243,10 @@ getu64(int swap, uint64_t value)
 			 ? elf_getu32(swap, auxv32.a_v)		\
 			 : elf_getu64(swap, auxv64.a_v))
 
+#define prpsoffsets(i)	(clazz == ELFCLASS32			\
+			 ? prpsoffsets32[i]			\
+			 : prpsoffsets64[i])
+
 #ifdef ELFCORE
 /*
  * Try larger offsets first to avoid false matches
@@ -269,8 +285,8 @@ static const size_t	prpsoffsets64[] = {
 	16,		/* FreeBSD, 64-bit */
 };
 
-#define	NOFFSETS32	(sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
-#define NOFFSETS64	(sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
+#define	NOFFSETS32	(sizeof(prpsoffsets32) / sizeof(prpsoffsets32[0]))
+#define NOFFSETS64	(sizeof(prpsoffsets64) / sizeof(prpsoffsets64[0]))
 
 #define NOFFSETS	(clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
 
@@ -349,7 +365,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 	 * Loop through all the program headers.
 	 */
 	for ( ; num; num--) {
-		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+		if (pread(fd, xph_addr, xph_sizeof, off) <
+		    CAST(ssize_t, xph_sizeof)) {
 			file_badread(ms);
 			return -1;
 		}
@@ -392,7 +409,7 @@ static void
 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
 {
 	uint32_t desc;
-	(void)memcpy(&desc, v, sizeof(desc));
+	memcpy(&desc, v, sizeof(desc));
 	desc = elf_getu32(swap, desc);
 
 	if (file_printf(ms, ", for NetBSD") == -1)
@@ -438,7 +455,7 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
 {
 	uint32_t desc;
 
-	(void)memcpy(&desc, v, sizeof(desc));
+	memcpy(&desc, v, sizeof(desc));
 	desc = elf_getu32(swap, desc);
 	if (file_printf(ms, ", for FreeBSD") == -1)
 		return;
@@ -536,7 +553,7 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		}
 		if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
 			return 1;
-		(void)memcpy(desc, &nbuf[doff], descsz);
+		memcpy(desc, &nbuf[doff], descsz);
 		for (i = 0; i < descsz; i++)
 		    if (file_printf(ms, "%02x", desc[i]) == -1)
 			return 1;
@@ -560,7 +577,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
 	    type == NT_GNU_VERSION && descsz == 16) {
 		uint32_t desc[4];
-		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
+		memcpy(desc, &nbuf[doff], sizeof(desc));
 
 		*flags |= FLAGS_DID_OS_NOTE;
 		if (file_printf(ms, ", for GNU/") == -1)
@@ -627,7 +644,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		*flags |= FLAGS_DID_OS_NOTE;
 		if (file_printf(ms, ", for DragonFly") == -1)
 			return 1;
-		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+		memcpy(&desc, &nbuf[doff], sizeof(desc));
 		desc = elf_getu32(swap, desc);
 		if (file_printf(ms, " %d.%d.%d", desc / 100000,
 		    desc / 10000 % 10, desc % 10000) == -1)
@@ -657,7 +674,7 @@ do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		int did = 0;
 
 		*flags |= FLAGS_DID_NETBSD_PAX;
-		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+		memcpy(&desc, &nbuf[doff], sizeof(desc));
 		desc = elf_getu32(swap, desc);
 
 		if (desc && file_printf(ms, ", PaX: ") == -1)
@@ -957,7 +974,7 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 
 	nval = 0;
 	for (size_t off = 0; off + elsize <= descsz; off += elsize) {
-		(void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
+		memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
 		/* Limit processing to 50 vector entries to prevent DoS */
 		if (nval++ >= 50) {
 			file_error(ms, 0, "Too many ELF Auxv elements");
@@ -1021,6 +1038,38 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 #endif
 }
 
+private size_t
+dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
+    int clazz, int swap)
+{
+	Elf32_Dyn dh32;
+	Elf64_Dyn dh64;
+	unsigned char *dbuf = CAST(unsigned char *, vbuf);
+
+	if (xdh_sizeof + offset > size) {
+		/*
+		 * We're out of note headers.
+		 */
+		return xdh_sizeof + offset;
+	}
+
+	memcpy(xdh_addr, &dbuf[offset], xdh_sizeof);
+	offset += xdh_sizeof;
+
+	switch (xdh_tag) {
+	case DT_FLAGS_1:
+		if (xdh_val == DF_1_PIE)
+			ms->mode |= 0111;
+		else
+			ms->mode &= ~0111;
+		break;
+	default:
+		break;
+	}
+	return offset;
+}
+
+
 private size_t
 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
@@ -1043,7 +1092,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 		return xnh_sizeof + offset;
 	}
 
-	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
+	memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
 	offset += xnh_sizeof;
 
 	namesz = xnh_namesz;
@@ -1057,14 +1106,14 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 	}
 
 	if (namesz & 0x80000000) {
-	    (void)file_printf(ms, ", bad note name size %#lx",
-		(unsigned long)namesz);
+	    file_printf(ms, ", bad note name size %#lx",
+		CAST(unsigned long, namesz));
 	    return 0;
 	}
 
 	if (descsz & 0x80000000) {
-	    (void)file_printf(ms, ", bad note description size %#lx",
-		(unsigned long)descsz);
+	    file_printf(ms, ", bad note description size %#lx",
+		CAST(unsigned long, descsz));
 	    return 0;
 	}
 
@@ -1118,35 +1167,25 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 			return offset;
 	}
 
-	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+	if (namesz == 7 && strcmp(CAST(char *, &nbuf[noff]), "NetBSD") == 0) {
+		int descw, flag;
+		const char *str, *tag;
 		if (descsz > 100)
 			descsz = 100;
 		switch (xnh_type) {
 	    	case NT_NETBSD_VERSION:
 			return offset;
 		case NT_NETBSD_MARCH:
-			if (*flags & FLAGS_DID_NETBSD_MARCH)
-				return offset;
-			*flags |= FLAGS_DID_NETBSD_MARCH;
-			if (file_printf(ms, ", compiled for: %.*s",
-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
-				return offset;
+			flag = FLAGS_DID_NETBSD_MARCH;
+			tag = "compiled for";
 			break;
 		case NT_NETBSD_CMODEL:
-			if (*flags & FLAGS_DID_NETBSD_CMODEL)
-				return offset;
-			*flags |= FLAGS_DID_NETBSD_CMODEL;
-			if (file_printf(ms, ", compiler model: %.*s",
-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
-				return offset;
+			flag = FLAGS_DID_NETBSD_CMODEL;
+			tag = "compiler model";
 			break;
 		case NT_NETBSD_EMULATION:
-			if (*flags & FLAGS_DID_NETBSD_EMULATION)
-				return offset;
-			*flags |= FLAGS_DID_NETBSD_EMULATION;
-			if (file_printf(ms, ", emulation: %.*s",
-			    (int)descsz, (const char *)&nbuf[doff]) == -1)
-				return offset;
+			flag = FLAGS_DID_NETBSD_EMULATION;
+			tag = "emulation:";
 			break;
 		default:
 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
@@ -1154,8 +1193,15 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
 			if (file_printf(ms, ", note=%u", xnh_type) == -1)
 				return offset;
-			break;
+			return offset;
 		}
+
+		if (*flags & flag)
+			return offset;
+		str = CAST(const char *, &nbuf[doff]);
+		descw = CAST(int, descsz);
+		*flags |= flag;
+		file_printf(ms, ", %s: %.*s", tag, descw, str);
 		return offset;
 	}
 
@@ -1236,7 +1282,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 
 	/* Read offset of name section to be able to read section names later */
 	if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
-	    < (ssize_t)xsh_sizeof) {
+	    < CAST(ssize_t, xsh_sizeof)) {
 		if (file_printf(ms, ", missing section headers") == -1)
 			return -1;
 		return 0;
@@ -1245,7 +1291,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 
 	for ( ; num; num--) {
 		/* Read the name of this section. */
-		if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
+		if ((namesize = pread(fd, name, sizeof(name) - 1,
+		    name_off + xsh_name)) == -1) {
 			file_badread(ms);
 			return -1;
 		}
@@ -1255,7 +1302,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 			stripped = 0;
 		}
 
-		if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
+		if (pread(fd, xsh_addr, xsh_sizeof, off) <
+		    CAST(ssize_t, xsh_sizeof)) {
 			file_badread(ms);
 			return -1;
 		}
@@ -1281,14 +1329,15 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 		/* Things we can determine when we seek */
 		switch (xsh_type) {
 		case SHT_NOTE:
-			if ((uintmax_t)(xsh_size + xsh_offset) >
-			    (uintmax_t)fsize) {
+			if (CAST(uintmax_t, (xsh_size + xsh_offset)) >
+			    CAST(uintmax_t, fsize)) {
 				if (file_printf(ms,
 				    ", note offset/size %#" INTMAX_T_FORMAT
 				    "x+%#" INTMAX_T_FORMAT "x exceeds"
 				    " file size %#" INTMAX_T_FORMAT "x",
-				    (uintmax_t)xsh_offset, (uintmax_t)xsh_size,
-				    (uintmax_t)fsize) == -1)
+				    CAST(uintmax_t, xsh_offset),
+				    CAST(uintmax_t, xsh_size),
+				    CAST(uintmax_t, fsize)) == -1)
 					return -1;
 				return 0; 
 			}
@@ -1298,7 +1347,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 				return -1;
 			}
 			if (pread(fd, nbuf, xsh_size, xsh_offset) <
-			    (ssize_t)xsh_size) {
+			    CAST(ssize_t, xsh_size)) {
 				file_badread(ms);
 				free(nbuf);
 				return -1;
@@ -1306,9 +1355,9 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 
 			noff = 0;
 			for (;;) {
-				if (noff >= (off_t)xsh_size)
+				if (noff >= CAST(off_t, xsh_size))
 					break;
-				noff = donote(ms, nbuf, (size_t)noff,
+				noff = donote(ms, nbuf, CAST(size_t, noff),
 				    xsh_size, clazz, swap, 4, flags, notecount,
 				    fd, 0, 0, 0);
 				if (noff == 0)
@@ -1330,7 +1379,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 
 			if (nbadcap > 5)
 				break;
-			if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
+			if (lseek(fd, xsh_offset, SEEK_SET)
+			    == CAST(off_t, -1)) {
 				file_badseek(ms);
 				return -1;
 			}
@@ -1339,11 +1389,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 				Elf32_Cap cap32;
 				Elf64_Cap cap64;
 				char cbuf[/*CONSTCOND*/
-				    MAX(sizeof cap32, sizeof cap64)];
-				if ((coff += xcap_sizeof) > (off_t)xsh_size)
+				    MAX(sizeof(cap32), sizeof(cap64))];
+				if ((coff += xcap_sizeof) >
+				    CAST(off_t, xsh_size))
 					break;
-				if (read(fd, cbuf, (size_t)xcap_sizeof) !=
-				    (ssize_t)xcap_sizeof) {
+				if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) !=
+				    CAST(ssize_t, xcap_sizeof)) {
 					file_badread(ms);
 					return -1;
 				}
@@ -1377,7 +1428,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 #endif
 					break;
 				}
-				(void)memcpy(xcap_addr, cbuf, xcap_sizeof);
+				memcpy(xcap_addr, cbuf, xcap_sizeof);
 				switch (xcap_tag) {
 				case CA_SUNW_NULL:
 					break;
@@ -1392,8 +1443,9 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 					    ", with unknown capability "
 					    "%#" INT64_T_FORMAT "x = %#"
 					    INT64_T_FORMAT "x",
-					    (unsigned long long)xcap_tag,
-					    (unsigned long long)xcap_val) == -1)
+					    CAST(unsigned long long, xcap_tag),
+					    CAST(unsigned long long, xcap_val))
+					    == -1)
 						return -1;
 					if (nbadcap++ > 2)
 						coff = xsh_size;
@@ -1446,12 +1498,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 				if (file_printf(ms,
 				    " unknown hardware capability %#"
 				    INT64_T_FORMAT "x",
-				    (unsigned long long)cap_hw1) == -1)
+				    CAST(unsigned long long, cap_hw1)) == -1)
 					return -1;
 		} else {
 			if (file_printf(ms,
 			    " hardware capability %#" INT64_T_FORMAT "x",
-			    (unsigned long long)cap_hw1) == -1)
+			    CAST(unsigned long long, cap_hw1)) == -1)
 				return -1;
 		}
 	}
@@ -1468,7 +1520,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 			if (file_printf(ms,
 			    ", with unknown software capability %#"
 			    INT64_T_FORMAT "x",
-			    (unsigned long long)cap_sf1) == -1)
+			    CAST(unsigned long long, cap_sf1)) == -1)
 				return -1;
 	}
 	return 0;
@@ -1487,9 +1539,9 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 	Elf32_Phdr ph32;
 	Elf64_Phdr ph64;
 	const char *linking_style = "statically";
-	const char *interp = "";
 	unsigned char nbuf[BUFSIZ];
 	char ibuf[BUFSIZ];
+	char interp[BUFSIZ];
 	ssize_t bufsize;
 	size_t offset, align, len;
 	
@@ -1499,8 +1551,11 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		return 0;
 	}
 
+	interp[0] = '\0';
   	for ( ; num; num--) {
-		if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+		int doread;
+		if (pread(fd, xph_addr, xph_sizeof, off) <
+		    CAST(ssize_t, xph_sizeof)) {
 			file_badread(ms);
 			return -1;
 		}
@@ -1513,6 +1568,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		switch (xph_type) {
 		case PT_DYNAMIC:
 			linking_style = "dynamically";
+			doread = 1;
 			break;
 		case PT_NOTE:
 			if (sh_num)	/* Did this through section headers */
@@ -1521,21 +1577,16 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 			    align < 4) {
 				if (file_printf(ms, 
 				    ", invalid note alignment %#lx",
-				    (unsigned long)align) == -1)
+				    CAST(unsigned long, align)) == -1)
 					return -1;
 				align = 4;
 			}
 			/*FALLTHROUGH*/
 		case PT_INTERP:
-			len = xph_filesz < sizeof(nbuf) ? xph_filesz
-			    : sizeof(nbuf);
-			bufsize = pread(fd, nbuf, len, xph_offset);
-			if (bufsize == -1) {
-				file_badread(ms);
-				return -1;
-			}
+			doread = 1;
 			break;
 		default:
+			doread = 0;
 			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
 				/* Maybe warn here? */
 				continue;
@@ -1543,14 +1594,39 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 			break;
 		}
 
+		if (doread) {
+			len = xph_filesz < sizeof(nbuf) ? xph_filesz
+			    : sizeof(nbuf);
+			bufsize = pread(fd, nbuf, len, xph_offset);
+			if (bufsize == -1) {
+				file_badread(ms);
+				return -1;
+			}
+		} else
+			len = 0;
+
 		/* Things we can determine when we seek */
 		switch (xph_type) {
+		case PT_DYNAMIC:
+			offset = 0;
+			for (;;) {
+				if (offset >= (size_t)bufsize)
+					break;
+				offset = dodynamic(ms, nbuf, offset,
+				    CAST(size_t, bufsize), clazz, swap);
+				if (offset == 0)
+					break;
+			}
+                        if (ms->flags & MAGIC_MIME)
+                                continue;
+			break;
+
 		case PT_INTERP:
 			if (bufsize && nbuf[0]) {
 				nbuf[bufsize - 1] = '\0';
-				interp = (const char *)nbuf;
+				memcpy(interp, nbuf, bufsize);
 			} else
-				interp = "*empty*";
+				strlcpy(interp, "*empty*", sizeof(interp));
 			break;
 		case PT_NOTE:
 			/*
@@ -1562,7 +1638,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 				if (offset >= (size_t)bufsize)
 					break;
 				offset = donote(ms, nbuf, offset,
-				    (size_t)bufsize, clazz, swap, align,
+				    CAST(size_t, bufsize), clazz, swap, align,
 				    flags, notecount, fd, 0, 0, 0);
 				if (offset == 0)
 					break;
@@ -1591,7 +1667,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b)
 	size_t nbytes = b->flen;
 	union {
 		int32_t l;
-		char c[sizeof (int32_t)];
+		char c[sizeof(int32_t)];
 	} u;
 	int clazz;
 	int swap;
@@ -1619,7 +1695,8 @@ file_tryelf(struct magic_set *ms, const struct buffer *b)
 	/*
 	 * If we cannot seek, it must be a pipe, socket or fifo.
 	 */
-	if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
+	if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1))
+	    && (errno == ESPIPE))
 		fd = file_pipe2file(ms, fd, buf, nbytes);
 
 	if (fstat(fd, &st) == -1) {
diff --git a/src/readelf.h b/src/readelf.h
index ef880b9..f2f3dc3 100644
--- a/src/readelf.h
+++ b/src/readelf.h
@@ -430,4 +430,107 @@ typedef struct {
 #define	AV_386_SSE4_1		0x00800000
 #define	AV_386_SSE4_2		0x01000000
 
+/*
+ * Dynamic Section structure array
+ */
+typedef struct {
+	Elf32_Word		d_tag;	/* entry tag value */
+	union {
+		Elf32_Addr	d_ptr;
+		Elf32_Word	d_val;
+	} d_un;
+} Elf32_Dyn;
+
+typedef struct {
+	Elf64_Xword		d_tag;	/* entry tag value */
+	union {
+		Elf64_Addr	d_ptr;
+		Elf64_Xword	d_val;
+	} d_un;
+} Elf64_Dyn;
+
+/* d_tag */
+#define DT_NULL		0	/* Marks end of dynamic array */
+#define DT_NEEDED	1	/* Name of needed library (DT_STRTAB offset) */
+#define DT_PLTRELSZ	2	/* Size, in bytes, of relocations in PLT */
+#define DT_PLTGOT	3	/* Address of PLT and/or GOT */
+#define DT_HASH		4	/* Address of symbol hash table */
+#define DT_STRTAB	5	/* Address of string table */
+#define DT_SYMTAB	6	/* Address of symbol table */
+#define DT_RELA		7	/* Address of Rela relocation table */
+#define DT_RELASZ	8	/* Size, in bytes, of DT_RELA table */
+#define DT_RELAENT	9	/* Size, in bytes, of one DT_RELA entry */
+#define DT_STRSZ	10	/* Size, in bytes, of DT_STRTAB table */
+#define DT_SYMENT	11	/* Size, in bytes, of one DT_SYMTAB entry */
+#define DT_INIT		12	/* Address of initialization function */
+#define DT_FINI		13	/* Address of termination function */
+#define DT_SONAME	14	/* Shared object name (DT_STRTAB offset) */
+#define DT_RPATH	15	/* Library search path (DT_STRTAB offset) */
+#define DT_SYMBOLIC	16	/* Start symbol search within local object */
+#define DT_REL		17	/* Address of Rel relocation table */
+#define DT_RELSZ	18	/* Size, in bytes, of DT_REL table */
+#define DT_RELENT	19	/* Size, in bytes, of one DT_REL entry */
+#define DT_PLTREL	20	/* Type of PLT relocation entries */
+#define DT_DEBUG	21	/* Used for debugging; unspecified */
+#define DT_TEXTREL	22	/* Relocations might modify non-writable seg */
+#define DT_JMPREL	23	/* Address of relocations associated with PLT */
+#define DT_BIND_NOW	24	/* Process all relocations at load-time */
+#define DT_INIT_ARRAY	25	/* Address of initialization function array */
+#define DT_FINI_ARRAY	26	/* Size, in bytes, of DT_INIT_ARRAY array */
+#define DT_INIT_ARRAYSZ 27	/* Address of termination function array */
+#define DT_FINI_ARRAYSZ 28	/* Size, in bytes, of DT_FINI_ARRAY array*/
+#define DT_RUNPATH	29	/* overrides DT_RPATH */
+#define DT_FLAGS	30	/* Encodes ORIGIN, SYMBOLIC, TEXTREL, BIND_NOW, STATIC_TLS */
+#define DT_ENCODING	31	/* ??? */
+#define DT_PREINIT_ARRAY 32	/* Address of pre-init function array */
+#define DT_PREINIT_ARRAYSZ 33	/* Size, in bytes, of DT_PREINIT_ARRAY array */
+#define DT_NUM		34
+
+#define DT_LOOS		0x60000000	/* Operating system specific range */
+#define DT_VERSYM	0x6ffffff0	/* Symbol versions */
+#define DT_FLAGS_1	0x6ffffffb	/* ELF dynamic flags */
+#define DT_VERDEF	0x6ffffffc	/* Versions defined by file */
+#define DT_VERDEFNUM	0x6ffffffd	/* Number of versions defined by file */
+#define DT_VERNEED	0x6ffffffe	/* Versions needed by file */
+#define DT_VERNEEDNUM	0x6fffffff	/* Number of versions needed by file */
+#define DT_HIOS		0x6fffffff
+#define DT_LOPROC	0x70000000	/* Processor-specific range */
+#define DT_HIPROC	0x7fffffff
+
+/* Flag values for DT_FLAGS */
+#define DF_ORIGIN	0x00000001	/* uses $ORIGIN */
+#define DF_SYMBOLIC	0x00000002	/* */
+#define DF_TEXTREL	0x00000004	/* */
+#define DF_BIND_NOW	0x00000008	/* */
+#define DF_STATIC_TLS	0x00000010	/* */
+
+/* Flag values for DT_FLAGS_1 */
+#define	DF_1_NOW	0x00000001	/* Same as DF_BIND_NOW */
+#define	DF_1_GLOBAL	0x00000002	/* Unused */
+#define	DF_1_GROUP	0x00000004	/* Is member of group */
+#define	DF_1_NODELETE	0x00000008	/* Cannot be deleted from process */
+#define	DF_1_LOADFLTR	0x00000010	/* Immediate loading of filters */
+#define	DF_1_INITFIRST	0x00000020	/* init/fini takes priority */
+#define	DF_1_NOOPEN	0x00000040	/* Do not allow loading on dlopen() */
+#define	DF_1_ORIGIN	0x00000080 	/* Require $ORIGIN processing */
+#define	DF_1_DIRECT	0x00000100	/* Enable direct bindings */
+#define	DF_1_INTERPOSE 	0x00000400	/* Is an interposer */
+#define	DF_1_NODEFLIB	0x00000800 	/* Ignore default library search path */
+#define	DF_1_NODUMP	0x00001000 	/* Cannot be dumped with dldump(3C) */
+#define	DF_1_CONFALT	0x00002000 	/* Configuration alternative */
+#define	DF_1_ENDFILTEE	0x00004000	/* Filtee ends filter's search */
+#define	DF_1_DISPRELDNE	0x00008000	/* Did displacement relocation */
+#define	DF_1_DISPRELPND 0x00010000	/* Pending displacement relocation */
+#define	DF_1_NODIRECT	0x00020000 	/* Has non-direct bindings */
+#define	DF_1_IGNMULDEF	0x00040000	/* Used internally */
+#define	DF_1_NOKSYMS	0x00080000	/* Used internally */
+#define	DF_1_NOHDR	0x00100000	/* Used internally */
+#define	DF_1_EDITED	0x00200000	/* Has been modified since build */
+#define	DF_1_NORELOC	0x00400000 	/* Used internally */
+#define	DF_1_SYMINTPOSE 0x00800000 	/* Has individual symbol interposers */
+#define	DF_1_GLOBAUDIT	0x01000000	/* Require global auditing */
+#define	DF_1_SINGLETON	0x02000000	/* Has singleton symbols */
+#define	DF_1_STUB	0x04000000	/* Stub */
+#define	DF_1_PIE	0x08000000	/* Position Independent Executable */
+
 #endif
-- 
2.39.1