summaryrefslogtreecommitdiffstats
path: root/translate.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'translate.cxx')
-rw-r--r--translate.cxx168
1 files changed, 128 insertions, 40 deletions
diff --git a/translate.cxx b/translate.cxx
index 87811e9f..518e5584 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;";
@@ -1240,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";
}
@@ -1359,6 +1376,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) || "
@@ -4409,45 +4431,61 @@ struct unwindsym_dump_context
systemtap_session& session;
ostream& output;
unsigned stp_module_index;
+ unsigned long stp_kretprobe_trampoline_addr;
set<string> undone_unwindsym_modules;
};
-// 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
@@ -4588,6 +4626,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,
@@ -4630,6 +4669,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)
{
@@ -4679,18 +4723,26 @@ 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.
- 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 = 0;
+ 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 +4750,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 < eh_len; i++)
+ {
+ int h = ((uint8_t *)eh_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 +4825,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 (unwind != NULL)
+ if (debug_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 << ".debug_frame = "
+ << "_stp_module_" << stpmod_idx << "_debug_frame, \n";
+ c->output << ".debug_frame_len = " << debug_len << ", \n";
c->output << "#else\n";
}
- c->output << ".unwind_data = NULL,\n";
- c->output << ".unwind_data_len = 0,\n";
+ c->output << ".debug_frame = NULL,\n";
+ c->output << ".debug_frame_len = 0,\n";
- if (unwind != NULL)
+ if (debug_frame != NULL)
+ c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n";
+
+ if (eh_frame != NULL)
+ {
+ c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\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 << ".eh_frame = NULL,\n";
+ c->output << ".eh_frame_len = 0,\n";
+
+ 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)/"
@@ -4826,7 +4911,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, ~0, s.unwindsym_modules };
// Micro optimization, mainly to speed up tiny regression tests
// using just begin probe.
@@ -4944,6 +5029,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<string>::iterator it = ctx->undone_unwindsym_modules.begin();
it != ctx->undone_unwindsym_modules.end();