diff options
author | Jason King <jason.king@joyent.com> | 2020-06-24 15:43:51 -0500 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2020-06-29 20:00:59 -0500 |
commit | 5f9772673df89384a3fa8f1cbfcccd8d331f83ff (patch) | |
tree | c8312f5b74c8f53c1a23fb84c43e39ded404d532 | |
parent | 3f764e121447070c490c9637dd5791f8c8823ee4 (diff) | |
download | illumos-joyent-5f9772673df89384a3fa8f1cbfcccd8d331f83ff.tar.gz |
10854 empty struct array confuses CTF
Reviewed by: Andy Fiddaman <omnios@citrus-it.co.uk>
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/lib/libctf/common/ctf_dwarf.c | 117 | ||||
-rw-r--r-- | usr/src/test/util-tests/tests/ctf/check-array.c | 10 | ||||
-rw-r--r-- | usr/src/test/util-tests/tests/ctf/test-array.c | 4 |
3 files changed, 104 insertions, 27 deletions
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c index 2f501a2334..3079831715 100644 --- a/usr/src/lib/libctf/common/ctf_dwarf.c +++ b/usr/src/lib/libctf/common/ctf_dwarf.c @@ -1456,13 +1456,102 @@ ctf_dwarf_create_sou(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, } static int +ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar) +{ + Dwarf_Attribute attr; + Dwarf_Unsigned uval; + Dwarf_Signed sval; + Dwarf_Half form; + Dwarf_Error derr; + const char *formstr = NULL; + 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. + */ + if (ret != 0) { + if (ret == ENOENT) + return (0); + return (ret); + } + + if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) { + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, + "failed to get DW_AT_upper_bound attribute form: %s\n", + dwarf_errmsg(derr)); + ret = ECTF_CONVBKERR; + goto done; + } + + /* + * Compilers can indicate array bounds using signed or unsigned values. + * Additionally, some compilers may also store the array bounds + * using as DW_FORM_data{1,2,4,8} (which DWARF treats as raw data and + * expects the caller to understand how to interpret the value). + * + * GCC 4.4.4 appears to always use unsigned values to encode the + * array size (using '(unsigned)-1' to represent a zero-length or + * unknown length array). Later versions of GCC use a signed value of + * -1 for zero/unknown length arrays, and unsigned values to encode + * known array sizes. + * + * Both dwarf_formsdata() and dwarf_formudata() will retrieve values + * as their respective signed/unsigned forms, but both will also + * retreive DW_FORM_data{1,2,4,8} values and treat them as signed or + * unsigned integers (i.e. dwarf_formsdata() treats DW_FORM_dataXX + * as signed integers and dwarf_formudata() treats DW_FORM_dataXX as + * unsigned integers). Both will return an error if the form is not + * their respective signed/unsigned form, or DW_FORM_dataXX. + * + * To obtain the upper bound, we use the appropriate + * dwarf_form[su]data() function based on the form of DW_AT_upper_bound. + * Additionally, we let dwarf_formudata() handle the DW_FORM_dataXX + * forms (via the default option in the switch). If the value is in an + * unexpected form (i.e. not DW_FORM_udata or DW_FORM_dataXX), + * dwarf_formudata() will return failure (i.e. not DW_DLV_OK) and set + * derr with the specific error value. + */ + switch (form) { + case DW_FORM_sdata: + if (dwarf_formsdata(attr, &sval, &derr) == DW_DLV_OK) { + ar->ctr_nelems = sval + 1; + goto done; + } + break; + case DW_FORM_udata: + default: + if (dwarf_formudata(attr, &uval, &derr) == DW_DLV_OK) { + ar->ctr_nelems = uval + 1; + goto done; + } + break; + } + + if (dwarf_get_FORM_name(form, &formstr) != DW_DLV_OK) + formstr = "unknown DWARF form"; + + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, + "failed to get %s (%hu) value for DW_AT_upper_bound: %s\n", + formstr, form, dwarf_errmsg(derr)); + ret = ECTF_CONVBKERR; + +done: + dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + return (ret); +} + +static int ctf_dwarf_create_array_range(ctf_cu_t *cup, Dwarf_Die range, ctf_id_t *idp, ctf_id_t base, int isroot) { int ret; Dwarf_Die sib; - Dwarf_Unsigned val; - Dwarf_Signed sval; ctf_arinfo_t ar; ctf_dprintf("creating array range\n"); @@ -1482,30 +1571,8 @@ ctf_dwarf_create_array_range(ctf_cu_t *cup, Dwarf_Die range, ctf_id_t *idp, if ((ar.ctr_index = ctf_dwarf_long(cup)) == CTF_ERR) return (ctf_errno(cup->cu_ctfp)); - /* - * Array bounds can be signed or unsigned, but there are several kinds - * of signless forms (data1, data2, etc) that take their sign from the - * routine that is trying to interpret them. That is, data1 can be - * either signed or unsigned, depending on whether you use the signed or - * unsigned accessor function. GCC will use the signless forms to store - * unsigned values which have their high bit set, so we need to try to - * read them first as unsigned to get positive values. We could also - * try signed first, falling back to unsigned if we got a negative - * value. - */ - if ((ret = ctf_dwarf_unsigned(cup, range, DW_AT_upper_bound, - &val)) == 0) { - ar.ctr_nelems = val + 1; - } else if (ret != ENOENT) { - return (ret); - } else if ((ret = ctf_dwarf_signed(cup, range, DW_AT_upper_bound, - &sval)) == 0) { - ar.ctr_nelems = sval + 1; - } else if (ret != ENOENT) { + if ((ret = ctf_dwarf_array_upper_bound(cup, range, &ar)) != 0) return (ret); - } else { - ar.ctr_nelems = 0; - } if ((*idp = ctf_add_array(cup->cu_ctfp, isroot, &ar)) == CTF_ERR) return (ctf_errno(cup->cu_ctfp)); diff --git a/usr/src/test/util-tests/tests/ctf/check-array.c b/usr/src/test/util-tests/tests/ctf/check-array.c index be7a192480..46be6332cb 100644 --- a/usr/src/test/util-tests/tests/ctf/check-array.c +++ b/usr/src/test/util-tests/tests/ctf/check-array.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2019, Joyent, Inc. + * Copyright 2020 Joyent, Inc. */ /* @@ -36,6 +36,7 @@ static check_symbol_t check_syms[] = { { "g", "int [4][5][6][7][8]" }, { "h", "int [4][5][6][7][8][9]" }, { "i", "int [4][5][6][7][8][9][10]" }, + { "empty", "int [0]" }, { NULL } }; @@ -72,11 +73,18 @@ static check_descent_t check_array_i[] = { { NULL }, }; +static check_descent_t check_array_empty[] = { + { "int [0]", CTF_K_ARRAY, "int", 0 }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + static check_descent_test_t descents[] = { { "a", check_array_a }, { "b", check_array_b }, { "c", check_array_c }, { "i", check_array_i }, + { "empty", check_array_empty }, { NULL } }; diff --git a/usr/src/test/util-tests/tests/ctf/test-array.c b/usr/src/test/util-tests/tests/ctf/test-array.c index 9c15771caf..14fc21d5dd 100644 --- a/usr/src/test/util-tests/tests/ctf/test-array.c +++ b/usr/src/test/util-tests/tests/ctf/test-array.c @@ -10,7 +10,7 @@ */ /* - * Copyright (c) 2019, Joyent, Inc. + * Copyright 2020 Joyent, Inc. */ /* @@ -27,3 +27,5 @@ int f[4][5][6][7]; int g[4][5][6][7][8]; int h[4][5][6][7][8][9]; int i[4][5][6][7][8][9][10]; + +int empty[] = { }; |