Skip to content

Commit

Permalink
Support systems without qsort_r
Browse files Browse the repository at this point in the history
qsort_r is a non-standard glibc extension and turns out to be the only
thing that prevents drgn from working on a musl system. "Fix" the use of
qsort_r by switching it to qsort with a thread local variable for the
parameter.

Tested in a clean chroot install of musl voidlinux.

Signed-off-by: Boris Burkov <boris@bur.io>
  • Loading branch information
boryas authored and osandov committed Nov 3, 2022
1 parent 8eaf01f commit c8ff872
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 10 deletions.
10 changes: 6 additions & 4 deletions libdrgn/dwarf_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -7411,11 +7411,12 @@ static void drgn_debug_info_cache_sh_addr(struct drgn_module *module,
}
}

static int drgn_dwarf_fde_compar(const void *_a, const void *_b, void *arg)
static _Thread_local struct drgn_dwarf_cie *drgn_dwarf_fde_compar_cies;
static int drgn_dwarf_fde_compar(const void *_a, const void *_b)
{
const struct drgn_dwarf_fde *a = _a;
const struct drgn_dwarf_fde *b = _b;
const struct drgn_dwarf_cie *cies = arg;
const struct drgn_dwarf_cie *cies = drgn_dwarf_fde_compar_cies;
if (a->initial_location < b->initial_location)
return -1;
else if (a->initial_location > b->initial_location)
Expand Down Expand Up @@ -7453,8 +7454,9 @@ drgn_debug_info_parse_frames(struct drgn_module *module)
* Sort FDEs and remove duplicates, preferring .debug_frame over
* .eh_frame.
*/
qsort_r(fdes.data, fdes.size, sizeof(fdes.data[0]),
drgn_dwarf_fde_compar, cies.data);
drgn_dwarf_fde_compar_cies = cies.data;
qsort(fdes.data, fdes.size, sizeof(fdes.data[0]),
drgn_dwarf_fde_compar);
if (fdes.size > 0) {
size_t src = 1, dst = 1;
for (; src < fdes.size; src++) {
Expand Down
13 changes: 7 additions & 6 deletions libdrgn/orc_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ static inline uint64_t drgn_raw_orc_pc(struct drgn_module *module, size_t i)
return module->orc.pc_base + UINT64_C(4) * i + offset;
}

static int compare_orc_entries(const void *a, const void *b, void *arg)
static _Thread_local struct drgn_module *compare_orc_entries_module;
static int compare_orc_entries(const void *a, const void *b)
{
struct drgn_module *module = arg;
struct drgn_module *module = compare_orc_entries_module;
size_t index_a = *(size_t *)a;
size_t index_b = *(size_t *)b;

Expand Down Expand Up @@ -203,17 +204,17 @@ static struct drgn_error *drgn_debug_info_parse_orc(struct drgn_module *module)
for (size_t i = 0; i < num_entries; i++)
indices[i] = i;

compare_orc_entries_module = module;
/*
* Sort the ORC entries for binary search. Since Linux kernel commit
* f14bf6a350df ("x86/unwind/orc: Remove boot-time ORC unwind tables
* sorting") (in v5.6), this is already sorted for vmlinux, so only sort
* it if necessary.
*/
for (size_t i = 1; i < num_entries; i++) {
if (compare_orc_entries(&indices[i - 1], &indices[i],
module) > 0) {
qsort_r(indices, num_entries, sizeof(indices[0]),
compare_orc_entries, module);
if (compare_orc_entries(&indices[i - 1], &indices[i]) > 0) {
qsort(indices, num_entries, sizeof(indices[0]),
compare_orc_entries);
break;
}
}
Expand Down

0 comments on commit c8ff872

Please sign in to comment.