changeset 25258:4076af232ed9

12226 libctf needs to handle DW_AT_count based array sizing Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Jason King <jason.king@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
author Robert Mustacchi <rm@fingolfin.org>
date Thu, 09 Jul 2020 09:08:47 -0700
parents b821679919bb
children 2d1e73c83a13
files usr/src/lib/libctf/common/ctf_dwarf.c
diffstat 1 files changed, 24 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libctf/common/ctf_dwarf.c	Wed Jul 29 22:37:40 2020 +0000
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c	Thu Jul 09 09:08:47 2020 -0700
@@ -1464,21 +1464,37 @@
 	Dwarf_Half form;
 	Dwarf_Error derr;
 	const char *formstr = NULL;
+	uint_t adj = 0;
 	int ret = 0;
 
 	ctf_dprintf("setting array upper bound\n");
 
 	ar->ctr_nelems = 0;
 
-	ret = ctf_dwarf_attribute(cup, range, DW_AT_upper_bound, &attr);
 	/*
-	 * Treat the lack of an upper bound attribute as a zero element array
-	 * and return success, otherwise return the error.
+	 * Different compilers use different attributes to indicate the size of
+	 * an array. GCC has traditionally used DW_AT_upper_bound, while Clang
+	 * uses DW_AT_count. They have slightly different semantics. DW_AT_count
+	 * indicates the total number of elements that are present, while
+	 * DW_AT_upper_bound indicates the last index, hence we need to add one
+	 * to that index to get the count.
+	 *
+	 * We first search for DW_AT_count and then for DW_AT_upper_bound. If we
+	 * find neither, then we treat the lack of this as a zero element array.
+	 * Our value is initialized assuming we find a DW_AT_count value.
 	 */
-	if (ret != 0) {
-		if (ret == ENOENT)
+	ret = ctf_dwarf_attribute(cup, range, DW_AT_count, &attr);
+	if (ret != 0 && ret != ENOENT) {
+		return (ret);
+	} else if (ret == ENOENT) {
+		ret = ctf_dwarf_attribute(cup, range, DW_AT_upper_bound, &attr);
+		if (ret != 0 && ret != ENOENT) {
+			return (ret);
+		} else if (ret == ENOENT) {
 			return (0);
-		return (ret);
+		} else {
+			adj = 1;
+		}
 	}
 
 	if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) {
@@ -1520,14 +1536,14 @@
 	switch (form) {
 	case DW_FORM_sdata:
 		if (dwarf_formsdata(attr, &sval, &derr) == DW_DLV_OK) {
-			ar->ctr_nelems = sval + 1;
+			ar->ctr_nelems = sval + adj;
 			goto done;
 		}
 		break;
 	case DW_FORM_udata:
 	default:
 		if (dwarf_formudata(attr, &uval, &derr) == DW_DLV_OK) {
-			ar->ctr_nelems = uval + 1;
+			ar->ctr_nelems = uval + adj;
 			goto done;
 		}
 		break;