From 4285dc9a58fbdae1516c4117a3f9297b822f27ff Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 20 May 2009 15:24:02 +0200 Subject: Fetch and store both debug_frame and eh_frame tables. * runtime/sym.h (_stp_module): Remove unwind_data, unwind_data_len and unwind_is_ehframe fields. Add debug_frame, eh_frame, debug_frame_len, eh_frame_len and eh_frame_addr fields. * runtime/unwind.c: Use debug_frame and debug_frame_len instead of unwind_data and unwind_data_len throughout. (cie_for_fde): Take unwind_data and is_ehframe as direct arguments. * runtime/unwind/unwind.h (cie_for_fde): New function declaration. * translate.cxx (get_unwind_data): Fetch and return both debug_frame and eh_frame tables. (dump_unwindsyms): Dump both debug_frame and eh_frame tables. --- translate.cxx | 130 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 39 deletions(-) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 87811e9f..eaa2e942 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4413,41 +4413,56 @@ struct unwindsym_dump_context }; -// Get the .debug_frame section for the given module. -// l will be set to the length of the size of the unwind data if found. -static void *get_unwind_data (Dwfl_Module *m, size_t *l) +// Get the .debug_frame end .eh_frame sections for the given module. +// Also returns the lenght of both sections when found, plus the section +// address of the eh_frame data. +static void get_unwind_data (Dwfl_Module *m, + void **debug_frame, void **eh_frame, + size_t *debug_len, size_t *eh_len, + Dwarf_Addr *eh_addr) { Dwarf_Addr bias = 0; - Dwarf *dw; GElf_Ehdr *ehdr, ehdr_mem; GElf_Shdr *shdr, shdr_mem; - Elf_Scn *scn = NULL; - Elf_Data *data = NULL; - - dw = dwfl_module_getdwarf(m, &bias); - if (dw != NULL) + Elf_Scn *scn; + Elf_Data *data; + Elf *elf; + + // fetch .eh_frame info preferably from main elf file. + elf = dwfl_module_getelf(m, &bias); + ehdr = gelf_getehdr(elf, &ehdr_mem); + scn = NULL; + while ((scn = elf_nextscn(elf, scn))) { - Elf *elf = dwarf_getelf(dw); - ehdr = gelf_getehdr(elf, &ehdr_mem); - while ((scn = elf_nextscn(elf, scn))) + shdr = gelf_getshdr(scn, &shdr_mem); + if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), + ".eh_frame") == 0) { - shdr = gelf_getshdr(scn, &shdr_mem); - if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), - ".debug_frame") == 0) - { - data = elf_rawdata(scn, NULL); - break; - } + data = elf_rawdata(scn, NULL); + *eh_frame = data->d_buf; + *eh_len = data->d_size; + *eh_addr = shdr->sh_addr; + break; } } - if (data != NULL) + // fetch .debug_frame info preferably from dwarf debuginfo file. + elf = (dwarf_getelf (dwfl_module_getdwarf (m, &bias)) + ?: dwfl_module_getelf (m, &bias)); + ehdr = gelf_getehdr(elf, &ehdr_mem); + scn = NULL; + while ((scn = elf_nextscn(elf, scn))) { - *l = data->d_size; - return data->d_buf; + shdr = gelf_getshdr(scn, &shdr_mem); + if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), + ".debug_frame") == 0) + { + data = elf_rawdata(scn, NULL); + *debug_frame = data->d_buf; + *debug_len = data->d_size; + break; + } } - - return NULL; } static int @@ -4680,17 +4695,21 @@ dump_unwindsyms (Dwfl_Module *m, } // Add unwind data to be included if it exists for this module. - size_t len = 0; - void *unwind = get_unwind_data (m, &len); - if (unwind != NULL) + void *debug_frame = NULL; + size_t debug_len = 0; + void *eh_frame = NULL; + size_t eh_len = 0; + Dwarf_Addr eh_addr = NULL; + get_unwind_data (m, &debug_frame, &eh_frame, &debug_len, &eh_len, &eh_addr); + if (debug_frame != NULL && debug_len > 0) { c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; c->output << "static uint8_t _stp_module_" << stpmod_idx - << "_unwind_data[] = \n"; + << "_debug_frame[] = \n"; c->output << " {"; - for (size_t i = 0; i < len; i++) + for (size_t i = 0; i < debug_len; i++) { - int h = ((uint8_t *)unwind)[i]; + int h = ((uint8_t *)debug_frame)[i]; c->output << "0x" << hex << h << dec << ","; if ((i + 1) % 16 == 0) c->output << "\n" << " "; @@ -4698,7 +4717,25 @@ dump_unwindsyms (Dwfl_Module *m, c->output << "};\n"; c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA */\n"; } - else + + if (eh_frame != NULL && eh_len > 0) + { + c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; + c->output << "static uint8_t _stp_module_" << stpmod_idx + << "_eh_frame[] = \n"; + c->output << " {"; + for (size_t i = 0; i < debug_len; i++) + { + int h = ((uint8_t *)debug_frame)[i]; + c->output << "0x" << hex << h << dec << ","; + if ((i + 1) % 16 == 0) + c->output << "\n" << " "; + } + c->output << "};\n"; + c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA */\n"; + } + + if (debug_frame == NULL && eh_frame == NULL) { // There would be only a small benefit to warning. A user // likely can't do anything about this; backtraces for the @@ -4755,25 +4792,40 @@ dump_unwindsyms (Dwfl_Module *m, c->output << ".path = " << lex_cast_qstring (mainfile) << ",\n"; c->output << ".dwarf_module_base = 0x" << hex << base << dec << ", \n"; + c->output << ".eh_frame_addr = 0x" << hex << eh_addr << dec << ", \n"; + + if (debug_frame != NULL) + { + c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; + c->output << ".debug_frame = " + << "_stp_module_" << stpmod_idx << "_debug_frame, \n"; + c->output << ".debug_frame_len = " << debug_len << ", \n"; + c->output << "#else\n"; + } + + c->output << ".debug_frame = NULL,\n"; + c->output << ".debug_frame_len = 0,\n"; + + if (debug_frame != NULL) + c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n"; - if (unwind != NULL) + if (eh_frame != NULL) { c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; - c->output << ".unwind_data = " - << "_stp_module_" << stpmod_idx << "_unwind_data, \n"; - c->output << ".unwind_data_len = " << len << ", \n"; + c->output << ".eh_frame = " + << "_stp_module_" << stpmod_idx << "_eh_frame, \n"; + c->output << ".eh_frame_len = " << eh_len << ", \n"; c->output << "#else\n"; } - c->output << ".unwind_data = NULL,\n"; - c->output << ".unwind_data_len = 0,\n"; + c->output << ".eh_frame = NULL,\n"; + c->output << ".eh_frame_len = 0,\n"; - if (unwind != NULL) + if (eh_frame != NULL) c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n"; c->output << ".unwind_hdr = NULL,\n"; c->output << ".unwind_hdr_len = 0,\n"; - c->output << ".unwind_is_ehframe = 0,\n"; c->output << ".sections = _stp_module_" << stpmod_idx << "_sections" << ",\n"; c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/" -- cgit From 7872a5b9d76dc78d8956de3d2a11757783121674 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 20 May 2009 23:11:43 +0200 Subject: Properly read eh_frame and pass is_ehframe correctly. * runtime/unwind.c (adjustStartLoc): Add extra dbug_unwind. (_stp_search_unwind_hdr): Always pass true for is_ehframe. (unwind_frame): Properly pass through is_ehframe to adjustStartLoc(). (unwind): Add extra dbug_unwind. * translate.cxx (dump_unwindsyms): Output and use correct eh_frame and eh_len. --- translate.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index eaa2e942..62c71aeb 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4724,9 +4724,9 @@ dump_unwindsyms (Dwfl_Module *m, c->output << "static uint8_t _stp_module_" << stpmod_idx << "_eh_frame[] = \n"; c->output << " {"; - for (size_t i = 0; i < debug_len; i++) + for (size_t i = 0; i < eh_len; i++) { - int h = ((uint8_t *)debug_frame)[i]; + int h = ((uint8_t *)eh_frame)[i]; c->output << "0x" << hex << h << dec << ","; if ((i + 1) % 16 == 0) c->output << "\n" << " "; -- cgit From 29e2616aeeb82605a6efe1dbc574b499781eafbe Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 20 May 2009 14:46:25 -0700 Subject: PR10177: init/kill time in sleepy context only Previously, _stp_init_time and _stp_kill_time were being called from begin/end/error probes, which will run with preemption disabled. The BUG reported on RT kernels showed that cpufreq_unregister_notifier can end up sleeping, which violates our preemption block. This patch moves the init/kill into systemtap_module_init/exit, where it is safe to sleep. The code maintains a new predicate with the define STAP_NEED_GETTIMEOFDAY, so we don't still incur any timer overhead if it's not used. --- translate.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 62c71aeb..9f45f5d1 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1133,6 +1133,15 @@ c_unparser::emit_module_init () o->newline(-1) << "}"; o->newline() << "if (rc) goto out;"; + // initialize gettimeofday (if needed) + o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; + o->newline() << "rc = _stp_init_time();"; // Kick off the Big Bang. + o->newline() << "if (rc) {"; + o->newline(1) << "_stp_error (\"couldn't initialize gettimeofday\");"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; + o->newline() << "#endif"; + o->newline() << "(void) probe_point;"; o->newline() << "(void) i;"; o->newline() << "(void) j;"; @@ -1359,6 +1368,11 @@ c_unparser::emit_module_exit () o->newline() << "#endif"; } + // teardown gettimeofday (if needed) + o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; + o->newline() << " _stp_kill_time();"; // Go to a beach. Drink a beer. + o->newline() << "#endif"; + // print final error/skipped counts if non-zero o->newline() << "if (atomic_read (& skipped_count) || " << "atomic_read (& error_count) || " -- cgit From 4acb6884cdfa8205a60b203aa9e48ab79efd9ea2 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 20 May 2009 23:59:26 +0200 Subject: Fix gcc warning about Dwarf_Addr initialization. * translate.cxx (dump_unwindsyms): Initialize eh_frame to 0, not NULL. --- translate.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 9f45f5d1..505c9fc6 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4713,7 +4713,7 @@ dump_unwindsyms (Dwfl_Module *m, size_t debug_len = 0; void *eh_frame = NULL; size_t eh_len = 0; - Dwarf_Addr eh_addr = NULL; + Dwarf_Addr eh_addr = 0; get_unwind_data (m, &debug_frame, &eh_frame, &debug_len, &eh_len, &eh_addr); if (debug_frame != NULL && debug_len > 0) { -- cgit From 6967e65ee23bf767fc45f3e190302656c11ddaea Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Thu, 28 May 2009 22:23:45 +0530 Subject: PR10206: Include NOTYPE symbols in stap-symbols.h On powerpc, function descriptors are in the .opd section as NO_TYPE. Include them in stap-symbols.h --- translate.cxx | 1 + 1 file changed, 1 insertion(+) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 505c9fc6..9631213e 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4617,6 +4617,7 @@ dump_unwindsyms (Dwfl_Module *m, // We omit symbols that have suspicious addresses (before base, // or after end). if ((GELF_ST_TYPE (sym.st_info) == STT_FUNC || + GELF_ST_TYPE (sym.st_info) == STT_NOTYPE || // PR10206 ppc fn-desc are in .opd GELF_ST_TYPE (sym.st_info) == STT_OBJECT) // PR10000: also need .data && !(sym.st_shndx == SHN_UNDEF // Value undefined, || shndxp == (GElf_Word) -1 // in a non-allocated section, -- cgit From 129de9ef18cd142e31ed509a7704d4faf0879f4c Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 3 Jun 2009 15:36:03 +0200 Subject: Detect kretprobe trampoline and use fallback unwinder. * runtime/sym.h (_stp_kretprobe_trampoline): Document. * translate.cxx (unwindsym_dump_context): Add stp_kretprobe_trampoline_addr. (dump_unwindsyms): Detect kretprobe_trampoline_holder symbol address. (emit_symbol_data): Initialize and emit _stp_kretprobe_trampoline. * runtime/transport/symbols.c (_stp_do_relocation): Detect kernel load address and adjust _stp_kretprobe_trampoline. * runtime/stack-i386.c (__stp_stack_print): Always use fallback unwinder when hitting kretprobe_trampoline_holder. * runtime/stack-x86_64.c (__stp_stack_print): Likewise. --- translate.cxx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 9631213e..76530cc4 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4423,6 +4423,7 @@ struct unwindsym_dump_context systemtap_session& session; ostream& output; unsigned stp_module_index; + unsigned long stp_kretprobe_trampoline_addr; set undone_unwindsym_modules; }; @@ -4660,6 +4661,11 @@ dump_unwindsyms (Dwfl_Module *m, secname = "_stext"; // NB: don't subtract session.sym_stext, which could be inconveniently NULL. // Instead, sym_addr will get compensated later via extra_offset. + + // We need to note this for the unwinder. + if (c->stp_kretprobe_trampoline_addr == (unsigned long) -1 + && ! strcmp (name, "kretprobe_trampoline_holder")) + c->stp_kretprobe_trampoline_addr = sym_addr; } else if (n > 0) { @@ -4709,6 +4715,10 @@ dump_unwindsyms (Dwfl_Module *m, } } + // Must be relative to actual kernel load address. + if (c->stp_kretprobe_trampoline_addr != (unsigned long) -1) + c->stp_kretprobe_trampoline_addr -= extra_offset; + // Add unwind data to be included if it exists for this module. void *debug_frame = NULL; size_t debug_len = 0; @@ -4893,7 +4903,7 @@ emit_symbol_data (systemtap_session& s) ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str()); - unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules }; + unwindsym_dump_context ctx = { s, kallsyms_out, 0, -1, s.unwindsym_modules }; // Micro optimization, mainly to speed up tiny regression tests // using just begin probe. @@ -5011,6 +5021,9 @@ emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s) ctx->output << "};\n"; ctx->output << "static unsigned _stp_num_modules = " << ctx->stp_module_index << ";\n"; + ctx->output << "static unsigned long _stp_kretprobe_trampoline = 0x" + << hex << ctx->stp_kretprobe_trampoline_addr << dec << ";\n"; + // Some nonexistent modules may have been identified with "-d". Note them. for (set::iterator it = ctx->undone_unwindsym_modules.begin(); it != ctx->undone_unwindsym_modules.end(); -- cgit From b608bb8322085893877078d76e3e50f7d9918c5a Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 9 Jun 2009 21:41:40 -0400 Subject: build compatibility fix for gcc 3.4 * translate.cxx (emit_symbol_data): Use ~0 instead of -1 for big unsigned constant --- translate.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 76530cc4..4e312f3e 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4903,7 +4903,7 @@ emit_symbol_data (systemtap_session& s) ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str()); - unwindsym_dump_context ctx = { s, kallsyms_out, 0, -1, s.unwindsym_modules }; + unwindsym_dump_context ctx = { s, kallsyms_out, 0, ~0, s.unwindsym_modules }; // Micro optimization, mainly to speed up tiny regression tests // using just begin probe. -- cgit From cc76db234897ff09eda098e786643506517b2175 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 10 Jun 2009 15:50:04 -0700 Subject: PR10260: Clean up all resources after init errors When anything in systemtap_module_init fails, and we return non-zero, then the module load is aborted. The normal module unload path (systemtap_module_exit) is not even attempted, so we need to make sure that all partially-allocated resources are returned. Our timer callbacks for the gettimeofday subsystem are a classic example of this error. If we don't unregister the timers before aborting init, they will later be called and cause a kernel fault. We also were neglecting to free the percpu context. A memory leak is less harmful, but that's fixed now too. --- translate.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'translate.cxx') diff --git a/translate.cxx b/translate.cxx index 4e312f3e..518e5584 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1249,6 +1249,14 @@ c_unparser::emit_module_init () o->newline() << "synchronize_sched();"; o->newline() << "#endif"; + // In case gettimeofday was started, it needs to be stopped + o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY"; + o->newline() << " _stp_kill_time();"; // An error is no cause to hurry... + o->newline() << "#endif"; + + // Free up the context memory after an error too + o->newline() << "free_percpu (contexts);"; + o->newline() << "return rc;"; o->newline(-1) << "}\n"; } -- cgit