summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-07-31 11:28:55 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-07-31 11:28:55 +0000
commit315d6f9d060f93a9448925a4a38b709ac304319e (patch)
treefa69d22cdbf9f7cb18475a691fc6f8d877cc7f5d
parent423227a2d1f1f6c0cc0a702ec148071640dace05 (diff)
parent40f72ea90006954fb73dcb696e7fede2435c4cb9 (diff)
downloadillumos-joyent-315d6f9d060f93a9448925a4a38b709ac304319e.tar.gz
[illumos-gate merge]
commit 40f72ea90006954fb73dcb696e7fede2435c4cb9 12228 libctf could handle gcc dwarf4 commit 11551c95ce2b1db0e052ae7a25787421afdef4da 12226 libctf needs to handle DW_AT_count based array sizing commit da2b26b186539432c4bee88ce2f08f41574e009f 12999 MSR_AMD_DE_CFG is twice defined
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c92
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c14
-rw-r--r--usr/src/uts/intel/sys/controlregs.h8
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h7
4 files changed, 95 insertions, 26 deletions
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
index cbe1661003..388cb20489 100644
--- a/usr/src/lib/libctf/common/ctf_dwarf.c
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -209,6 +209,7 @@
#include <errno.h>
#define DWARF_VERSION_TWO 2
+#define DWARF_VERSION_FOUR 4
#define DWARF_VARARGS_NAME "..."
/*
@@ -262,6 +263,8 @@ typedef struct ctf_die {
Dwarf_Die cu_cu; /* libdwarf compilation unit */
Dwarf_Off cu_cuoff; /* cu's offset */
Dwarf_Off cu_maxoff; /* maximum offset */
+ Dwarf_Half cu_vers; /* Dwarf Version */
+ Dwarf_Half cu_addrsz; /* Dwarf Address Size */
ctf_file_t *cu_ctfp; /* output CTF file */
avl_tree_t cu_map; /* map die offsets to CTF types */
char *cu_errbuf; /* error message buffer */
@@ -576,6 +579,13 @@ ctf_dwarf_string(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, char **strp)
return (ECTF_CONVBKERR);
}
+/*
+ * The encoding of a DW_AT_data_member_location has changed between different
+ * revisions of the specification. It may be a general udata form or it may be
+ * location data information. In DWARF 2, it is only the latter. In later
+ * revisions of the spec, it may be either. To determine the form, we ask the
+ * class, which will be of type CONSTANT.
+ */
static int
ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp)
{
@@ -584,11 +594,49 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp)
Dwarf_Attribute attr;
Dwarf_Locdesc *loc;
Dwarf_Signed locnum;
+ Dwarf_Half form;
+ enum Dwarf_Form_Class class;
if ((ret = ctf_dwarf_attribute(cup, die, DW_AT_data_member_location,
&attr)) != 0)
return (ret);
+ if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) {
+ (void) snprintf(cup->cu_errbuf, cup->cu_errlen,
+ "failed to get dwarf attribute for for member location: %s",
+ dwarf_errmsg(derr));
+ dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ return (ECTF_CONVBKERR);
+ }
+
+ class = dwarf_get_form_class(cup->cu_vers, DW_AT_data_member_location,
+ cup->cu_addrsz, form);
+ if (class == DW_FORM_CLASS_CONSTANT) {
+ Dwarf_Signed sign;
+
+ /*
+ * We have a constant. We need to try to get both this as signed
+ * and unsigned data, as unfortunately, DWARF doesn't define the
+ * sign. Which is a joy. We try unsigned first. If neither
+ * match, fall through to the normal path.
+ */
+ if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ if (dwarf_formsdata(attr, &sign, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ if (sign < 0) {
+ (void) snprintf(cup->cu_errbuf, cup->cu_errlen,
+ "encountered negative member data "
+ "location: %d", sign);
+ }
+ *valp = (Dwarf_Unsigned)sign;
+ return (0);
+ }
+ }
+
if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to obtain location list for member offset: %s",
@@ -1464,21 +1512,37 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar)
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)
- return (0);
+ 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);
+ } else {
+ adj = 1;
+ }
}
if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) {
@@ -1520,14 +1584,14 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar)
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;
@@ -2970,7 +3034,11 @@ ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
return (ECTF_CONVBKERR);
}
- if (vers != DWARF_VERSION_TWO) {
+ switch (vers) {
+ case DWARF_VERSION_TWO:
+ case DWARF_VERSION_FOUR:
+ break;
+ default:
(void) snprintf(errbuf, errlen,
"unsupported DWARF version: %d\n", vers);
return (ECTF_CONVBKERR);
@@ -2987,11 +3055,11 @@ ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
{
int ret;
Dwarf_Unsigned hdrlen, abboff, nexthdr;
- Dwarf_Half addrsz;
+ Dwarf_Half addrsz, vers;
Dwarf_Unsigned offset = 0;
Dwarf_Error derr;
- while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, NULL,
+ while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, &vers,
&abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) {
char *name;
Dwarf_Die cu, child;
@@ -3012,6 +3080,8 @@ ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
cup->cu_longtid = CTF_ERR;
cup->cu_elf = elf;
cup->cu_maxoff = nexthdr - 1;
+ cup->cu_vers = vers;
+ cup->cu_addrsz = addrsz;
cup->cu_ctfp = ctf_fdcreate(fd, &ret);
if (cup->cu_ctfp == NULL)
return (ret);
diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c
index 8943a2d888..fc0cf6622f 100644
--- a/usr/src/uts/i86pc/os/cpuid.c
+++ b/usr/src/uts/i86pc/os/cpuid.c
@@ -2746,8 +2746,8 @@ cpuid_use_amd_retpoline(struct cpuid_info *cpi)
/*
* We need to determine whether or not lfence is serializing. It always
* is on families 0xf and 0x11. On others, it's controlled by
- * MSR_AMD_DECODE_CONFIG (MSRC001_1029). If some hypervisor gives us a
- * crazy old family, don't try and do anything.
+ * MSR_AMD_DE_CFG (MSRC001_1029). If some hypervisor gives us a crazy
+ * old family, don't try and do anything.
*/
if (cpi->cpi_family < 0xf)
return (B_FALSE);
@@ -2762,16 +2762,16 @@ cpuid_use_amd_retpoline(struct cpuid_info *cpi)
* for it.
*/
if (!on_trap(&otd, OT_DATA_ACCESS)) {
- val = rdmsr(MSR_AMD_DECODE_CONFIG);
- val |= AMD_DECODE_CONFIG_LFENCE_DISPATCH;
- wrmsr(MSR_AMD_DECODE_CONFIG, val);
- val = rdmsr(MSR_AMD_DECODE_CONFIG);
+ val = rdmsr(MSR_AMD_DE_CFG);
+ val |= AMD_DE_CFG_LFENCE_DISPATCH;
+ wrmsr(MSR_AMD_DE_CFG, val);
+ val = rdmsr(MSR_AMD_DE_CFG);
} else {
val = 0;
}
no_trap();
- if ((val & AMD_DECODE_CONFIG_LFENCE_DISPATCH) != 0)
+ if ((val & AMD_DE_CFG_LFENCE_DISPATCH) != 0)
return (B_TRUE);
return (B_FALSE);
}
diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h
index 0be7b3b650..9c02a4b809 100644
--- a/usr/src/uts/intel/sys/controlregs.h
+++ b/usr/src/uts/intel/sys/controlregs.h
@@ -238,9 +238,15 @@ extern "C" {
#define AMD_BU_CFG_E298 (UINT64_C(1) << 1)
+/*
+ * This MSR exists on families, 10h, 12h+ for AMD. This controls instruction
+ * decoding. Most notably, for the AMD variant of retpolines, we must improve
+ * the serializability of lfence for the lfence based method to work.
+ */
#define MSR_AMD_DE_CFG 0xc0011029
-#define AMD_DE_CFG_E721 (UINT64_C(1))
+#define AMD_DE_CFG_E721 (1UL << 0)
+#define AMD_DE_CFG_LFENCE_DISPATCH (1UL << 1)
/* AMD's osvw MSRs */
#define MSR_AMD_OSVW_ID_LEN 0xc0010140
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 0c20330297..f5e4a4b153 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -603,13 +603,6 @@ extern "C" {
#define IA32_PKG_THERM_INTERRUPT_TR2_IE 0x00800000
#define IA32_PKG_THERM_INTERRUPT_PL_NE 0x01000000
-/*
- * This MSR exists on families, 10h, 12h+ for AMD. This controls instruction
- * decoding. Most notably, for the AMD variant of retpolines, we must improve
- * the serializability of lfence for the lfence based method to work.
- */
-#define MSR_AMD_DECODE_CONFIG 0xc0011029
-#define AMD_DECODE_CONFIG_LFENCE_DISPATCH 0x02
#define MCI_CTL_VALUE 0xffffffff