diff options
Diffstat (limited to 'translate.cxx')
-rw-r--r-- | translate.cxx | 88 |
1 files changed, 65 insertions, 23 deletions
diff --git a/translate.cxx b/translate.cxx index a22e9a5b..46fea6e7 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4532,9 +4532,14 @@ dump_unwindsyms (Dwfl_Module *m, } } - // Use end as sanity check when resolving symbol addresses. - Dwarf_Addr end; - dwfl_module_info (m, NULL, NULL, &end, NULL, NULL, NULL, NULL); + // Get the canonical path of the main file for comparison at runtime. + // When given directly by the user through -d or in case of the kernel + // name and path might differ. path should be used for matching. + // Use end as sanity check when resolving symbol addresses and to + // calculate size for .dynamic and .absolute sections. + const char *mainfile; + Dwarf_Addr start, end; + dwfl_module_info (m, NULL, &start, &end, NULL, NULL, &mainfile, NULL); // Look up the relocation basis for symbols int n = dwfl_module_relocations (m); @@ -4545,7 +4550,8 @@ dump_unwindsyms (Dwfl_Module *m, // XXX: unfortunate duplication with tapsets.cxx:emit_address() typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address - vector<string> seclist; // encountered relocation bases (section names) + vector<pair<string,unsigned> > seclist; // encountered relocation bases + // (section names and sizes) map<unsigned, addrmap_t> addrmap; // per-relocation-base sorted addrmap Dwarf_Addr extra_offset = 0; @@ -4588,11 +4594,11 @@ dump_unwindsyms (Dwfl_Module *m, || sym.st_value < base)) // before first section. { Dwarf_Addr sym_addr = sym.st_value; + Dwarf_Addr save_addr = sym_addr; const char *secname = NULL; if (n > 0) // only try to relocate if there exist relocation bases { - Dwarf_Addr save_addr = sym_addr; int ki = dwfl_module_relocate_address (m, &sym_addr); dwfl_assert ("dwfl_module_relocate_address", ki >= 0); secname = dwfl_module_relocation_info (m, ki, NULL); @@ -4645,10 +4651,31 @@ dump_unwindsyms (Dwfl_Module *m, // Compute our section number unsigned secidx; for (secidx=0; secidx<seclist.size(); secidx++) - if (seclist[secidx]==secname) break; + if (seclist[secidx].first==secname) break; if (secidx == seclist.size()) // new section name - seclist.push_back (secname); + { + // absolute, dynamic or kernel have just one relocation + // section, which covers the whole module address range. + unsigned size; + if (secidx == 0 + && (n == 0 + || (n == 1 + && (strcmp(secname, ".dynamic") == 0 + || strcmp(secname, "_stext") == 0)))) + size = end - start; + else + { + Dwarf_Addr b; + Elf_Scn *scn; + GElf_Shdr *shdr, shdr_mem; + scn = dwfl_module_address_section (m, &save_addr, &b); + assert (scn != NULL); + shdr = gelf_getshdr(scn, &shdr_mem); + size = shdr->sh_size; + } + seclist.push_back (make_pair(secname,size)); + } (addrmap[secidx])[sym_addr] = name; } @@ -4709,12 +4736,17 @@ dump_unwindsyms (Dwfl_Module *m, } c->output << "static struct _stp_section _stp_module_" << stpmod_idx<< "_sections[] = {\n"; + // For the kernel, executables (ET_EXEC) or shared libraries (ET_DYN) + // there is just one section that covers the whole address space of + // the module. For kernel modules (ET_REL) there can be multiple + // sections that get relocated separately. for (unsigned secidx = 0; secidx < seclist.size(); secidx++) { c->output << "{\n" - << ".name = " << lex_cast_qstring(seclist[secidx]) << ",\n" + << ".name = " << lex_cast_qstring(seclist[secidx].first) << ",\n" + << ".size = 0x" << hex << seclist[secidx].second << dec << ",\n" << ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << secidx << ",\n" - << ".num_symbols = sizeof(_stp_module_" << stpmod_idx << "_symbols_" << secidx << ")/sizeof(struct _stp_symbol)\n" + << ".num_symbols = " << addrmap[secidx].size() << "\n" << "},\n"; } c->output << "};\n"; @@ -4722,11 +4754,6 @@ dump_unwindsyms (Dwfl_Module *m, c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n"; c->output << ".name = " << lex_cast_qstring (modname) << ", \n"; - // Get the canonical path of the main file for comparison at runtime. - // When given directly by the user through -d or in case of the kernel - // name and path might differ. path should be used for matching. - const char *mainfile; - dwfl_module_info (m, NULL, NULL, NULL, NULL, NULL, &mainfile, NULL); mainfile = canonicalize_file_name(mainfile); c->output << ".path = " << lex_cast_qstring (mainfile) << ",\n"; @@ -4791,6 +4818,7 @@ dump_unwindsyms (Dwfl_Module *m, // Emit symbol table & unwind data, plus any calls needed to register // them with the runtime. +void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); void emit_symbol_data (systemtap_session& s) @@ -4803,6 +4831,14 @@ emit_symbol_data (systemtap_session& s) unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules }; + // Micro optimization, mainly to speed up tiny regression tests + // using just begin probe. + if (s.unwindsym_modules.size () == 0) + { + emit_symbol_data_done(&ctx, s); + return; + } + // XXX: copied from tapsets.cxx dwflpp::, sadly static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); @@ -4861,7 +4897,8 @@ emit_symbol_data (systemtap_session& s) { NULL, /* dwfl_linux_kernel_find_elf, */ dwfl_standard_find_debuginfo, - dwfl_offline_section_address, + NULL, /* ET_REL not supported for user space, only ET_EXEC and ET_DYN. + dwfl_offline_section_address, */ (char **) & debuginfo_path }; @@ -4894,20 +4931,25 @@ emit_symbol_data (systemtap_session& s) dwfl_end(dwfl); } + emit_symbol_data_done (&ctx, s); +} +void +emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s) +{ // Print out a definition of the runtime's _stp_modules[] globals. - kallsyms_out << "\n"; - kallsyms_out << "static struct _stp_module *_stp_modules [] = {\n"; - for (unsigned i=0; i<ctx.stp_module_index; i++) + ctx->output << "\n"; + ctx->output << "static struct _stp_module *_stp_modules [] = {\n"; + for (unsigned i=0; i<ctx->stp_module_index; i++) { - kallsyms_out << "& _stp_module_" << i << ",\n"; + ctx->output << "& _stp_module_" << i << ",\n"; } - kallsyms_out << "};\n"; - kallsyms_out << "static unsigned _stp_num_modules = " << ctx.stp_module_index << ";\n"; + ctx->output << "};\n"; + ctx->output << "static unsigned _stp_num_modules = " << ctx->stp_module_index << ";\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(); + for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin(); + it != ctx->undone_unwindsym_modules.end(); it ++) { s.print_warning ("missing unwind/symbol data for module '" + (*it) + "'"); |