From afb933a7cac8e510d5f808bc50736ffedf7c0dcc Mon Sep 17 00:00:00 2001 From: Sergey Korolev Date: Sat, 23 Jun 2018 09:27:57 +0300 Subject: [PATCH] dwarf: allocate a debug frame index table with mmap() By analogy with "dwarf: do not allocate in load_debug_frame (#72)" avoid to call realloc(). An index table is also created infrequently and freed in unw_flush_cache() only. The main idea of the patch is to calculate an index table size first and then allocate a whole memory region. --- src/dwarf/Gfind_proc_info-lsb.c | 307 +++++++++++++++++++--------------------- src/mi/flush_cache.c | 2 +- 2 files changed, 149 insertions(+), 160 deletions(-) diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c index 58fa51d0..18819e6a 100644 --- a/src/dwarf/Gfind_proc_info-lsb.c +++ b/src/dwarf/Gfind_proc_info-lsb.c @@ -223,43 +223,8 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname, return fdesc; } -struct debug_frame_tab - { - struct table_entry *tab; - uint32_t length; - uint32_t size; - }; - -static void -debug_frame_tab_append (struct debug_frame_tab *tab, - unw_word_t fde_offset, unw_word_t start_ip) -{ - unsigned int length = tab->length; - - if (length == tab->size) - { - tab->size *= 2; - tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size); - } - - tab->tab[length].fde_offset = fde_offset; - tab->tab[length].start_ip_offset = start_ip; - - tab->length = length + 1; -} - -static void -debug_frame_tab_shrink (struct debug_frame_tab *tab) -{ - if (tab->size > tab->length) - { - tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length); - tab->size = tab->length; - } -} - static int -debug_frame_tab_compare (const void *a, const void *b) +debug_frame_index_compare (const void *a, const void *b) { const struct table_entry *fa = a, *fb = b; @@ -271,18 +236,102 @@ debug_frame_tab_compare (const void *a, const void *b) return 0; } +static size_t +debug_frame_index_make (struct unw_debug_frame_list *fdesc) +{ + unw_accessors_t *a = unw_get_accessors_int (unw_local_addr_space); + char *buf = fdesc->debug_frame; + size_t bufsize = fdesc->debug_frame_size; + unw_word_t addr = (unw_word_t) (uintptr_t) buf; + size_t count = 0; + + while (addr < (unw_word_t) (uintptr_t) (buf + bufsize)) + { + unw_word_t item_start = addr, item_end = 0; + uint32_t u32val = 0; + uint64_t cie_id = 0; + uint64_t id_for_cie; + + dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL); + + if (u32val == 0) + break; + + if (u32val != 0xffffffff) + { + uint32_t cie_id32 = 0; + + item_end = addr + u32val; + dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, NULL); + cie_id = cie_id32; + id_for_cie = 0xffffffff; + } + else + { + uint64_t u64val = 0; + + /* Extended length. */ + dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL); + item_end = addr + u64val; + + dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL); + id_for_cie = 0xffffffffffffffffull; + } + + /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/ + + if (cie_id == id_for_cie) + { + ; + /*Debug (1, "Found CIE at %.8x.\n", item_start);*/ + } + else + { + unw_word_t fde_addr = item_start; + unw_proc_info_t this_pi; + int err; + + /*Debug (1, "Found FDE at %.8x\n", item_start);*/ + + err = dwarf_extract_proc_info_from_fde (unw_local_addr_space, + a, &fde_addr, + &this_pi, + (uintptr_t) buf, 0, 1, + NULL); + + if (!err) + { + Debug (15, "start_ip = %lx, end_ip = %lx\n", + (long) this_pi.start_ip, (long) this_pi.end_ip); + + if (fdesc->index) + { + struct table_entry *e = &fdesc->index[count]; + + e->fde_offset = item_start - (unw_word_t) (uintptr_t) buf; + e->start_ip_offset = this_pi.start_ip; + } + + count++; + } + /*else + Debug (1, "FDE parse failed\n");*/ + } + + addr = item_end; + } + return count; +} + int dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip, unw_word_t segbase, const char* obj_name, unw_word_t start, unw_word_t end) { - unw_dyn_info_t *di; - struct unw_debug_frame_list *fdesc = 0; - unw_accessors_t *a; - unw_word_t addr; + unw_dyn_info_t *di = di_debug; + struct unw_debug_frame_list *fdesc; Debug (15, "Trying to find .debug_frame for %s\n", obj_name); - di = di_debug; fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end); @@ -291,130 +340,70 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip, Debug (15, "couldn't load .debug_frame\n"); return found; } - else + + Debug (15, "loaded .debug_frame\n"); + + if (fdesc->debug_frame_size == 0) { - char *buf; - size_t bufsize; - unw_word_t item_start, item_end = 0; - uint32_t u32val = 0; - uint64_t cie_id = 0; - struct debug_frame_tab tab; + Debug (15, "zero-length .debug_frame\n"); + return found; + } - Debug (15, "loaded .debug_frame\n"); + /* Now create a binary-search table, if it does not already exist. */ - buf = fdesc->debug_frame; - bufsize = fdesc->debug_frame_size; + if (!fdesc->index) + { + /* Find all FDE entries in debug_frame, and make into a sorted + index. First determine an index element count. */ - if (bufsize == 0) - { - Debug (15, "zero-length .debug_frame\n"); - return found; - } + size_t count = debug_frame_index_make (fdesc); + + if (!count) + { + Debug (15, "no CIE/FDE found in .debug_frame\n"); + return found; + } + + fdesc->index_size = count * sizeof (*fdesc->index); + GET_MEMORY (fdesc->index, fdesc->index_size); - /* Now create a binary-search table, if it does not already exist. */ if (!fdesc->index) - { - addr = (unw_word_t) (uintptr_t) buf; - - a = unw_get_accessors_int (unw_local_addr_space); - - /* Find all FDE entries in debug_frame, and make into a sorted - index. */ - - tab.length = 0; - tab.size = 16; - tab.tab = calloc (tab.size, sizeof (struct table_entry)); - - while (addr < (unw_word_t) (uintptr_t) (buf + bufsize)) - { - uint64_t id_for_cie; - item_start = addr; - - dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL); - - if (u32val == 0) - break; - else if (u32val != 0xffffffff) - { - uint32_t cie_id32 = 0; - item_end = addr + u32val; - dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, - NULL); - cie_id = cie_id32; - id_for_cie = 0xffffffff; - } - else - { - uint64_t u64val = 0; - /* Extended length. */ - dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL); - item_end = addr + u64val; - - dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL); - id_for_cie = 0xffffffffffffffffull; - } - - /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/ - - if (cie_id == id_for_cie) - ; - /*Debug (1, "Found CIE at %.8x.\n", item_start);*/ - else - { - unw_word_t fde_addr = item_start; - unw_proc_info_t this_pi; - int err; - - /*Debug (1, "Found FDE at %.8x\n", item_start);*/ - - err = dwarf_extract_proc_info_from_fde (unw_local_addr_space, - a, &fde_addr, - &this_pi, - (uintptr_t) buf, 0, 1, - NULL); - if (err == 0) - { - Debug (15, "start_ip = %lx, end_ip = %lx\n", - (long) this_pi.start_ip, (long) this_pi.end_ip); - debug_frame_tab_append (&tab, - item_start - (unw_word_t) (uintptr_t) buf, - this_pi.start_ip); - } - /*else - Debug (1, "FDE parse failed\n");*/ - } - - addr = item_end; - } - - debug_frame_tab_shrink (&tab); - qsort (tab.tab, tab.length, sizeof (struct table_entry), - debug_frame_tab_compare); - /* for (i = 0; i < tab.length; i++) - { - fprintf (stderr, "ip %x, fde offset %x\n", - (int) tab.tab[i].start_ip_offset, - (int) tab.tab[i].fde_offset); - }*/ - fdesc->index = tab.tab; - fdesc->index_size = tab.length; - } - - di->format = UNW_INFO_FORMAT_TABLE; - di->start_ip = fdesc->start; - di->end_ip = fdesc->end; - di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name; - di->u.ti.table_data = (unw_word_t *) fdesc; - di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t); - di->u.ti.segbase = segbase; - - found = 1; - Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, " - "gp=0x%lx, table_data=0x%lx\n", - (char *) (uintptr_t) di->u.ti.name_ptr, - (long) di->u.ti.segbase, (long) di->u.ti.table_len, - (long) di->gp, (long) di->u.ti.table_data); + { + Debug (15, "couldn't allocate a frame index table\n"); + fdesc->index_size = 0; + return found; + } + + /* Then fill and sort the index. */ + + debug_frame_index_make (fdesc); + qsort (fdesc->index, count, sizeof (struct table_entry), + debug_frame_index_compare); + + /*for (i = 0; i < count; i++) + { + const struct table_entry *e = &fdesc->index[i]; + + Debug (15, "ip %x, FDE offset %x\n", + e->start_ip_offset, e->fde_offset); + }*/ } + + di->format = UNW_INFO_FORMAT_TABLE; + di->start_ip = fdesc->start; + di->end_ip = fdesc->end; + di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name; + di->u.ti.table_data = (unw_word_t *) fdesc; + di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t); + di->u.ti.segbase = segbase; + + found = 1; + Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, " + "gp=0x%lx, table_data=0x%lx\n", + (char *) (uintptr_t) di->u.ti.name_ptr, + (long) di->u.ti.segbase, (long) di->u.ti.table_len, + (long) di->gp, (long) di->u.ti.table_data); + return found; } @@ -843,7 +832,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, endianness is the target one. */ as = unw_local_addr_space; table = fdesc->index; - table_len = fdesc->index_size * sizeof (struct table_entry); + table_len = fdesc->index_size; debug_frame_base = (uintptr_t) fdesc->debug_frame; #endif } diff --git a/src/mi/flush_cache.c b/src/mi/flush_cache.c index 9a344c0d..f2b01158 100644 --- a/src/mi/flush_cache.c +++ b/src/mi/flush_cache.c @@ -36,7 +36,7 @@ unw_flush_cache (unw_addr_space_t as, unw_word_t lo, unw_word_t hi) struct unw_debug_frame_list *n = w->next; if (w->index) - free (w->index); + munmap (w->index, w->index_size); munmap (w->debug_frame, w->debug_frame_size); munmap (w, sizeof (*w)); -- 2.11.0