diff options
author | Wenji Huang <wenji.huang@oracle.com> | 2008-10-06 03:07:09 -0400 |
---|---|---|
committer | Wenji Huang <wenji.huang@oracle.com> | 2008-10-06 03:07:09 -0400 |
commit | 2949597251fea7f17a0e46c1c885e34b53395d18 (patch) | |
tree | 7628da32ea81a5bbaf10f31c7fd60006629db3d6 | |
parent | 5311c037f83f66967f9de4cc66815f93940bb005 (diff) | |
download | systemtap-steved-2949597251fea7f17a0e46c1c885e34b53395d18.tar.gz systemtap-steved-2949597251fea7f17a0e46c1c885e34b53395d18.tar.xz systemtap-steved-2949597251fea7f17a0e46c1c885e34b53395d18.zip |
PR4886: check build-id if able.
This provides sanity check of debuginfo file based on build-id. Many cases are considered, whether build-id exists in debuginfo file or not, whether module is loaded or not, whether build-id exists in runtime kernel/module. It will do work when LD >= 2.18 and kernel >=2.6.23, otherwise no check.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | runtime/ChangeLog | 10 | ||||
-rw-r--r-- | runtime/staprun/staprun.c | 5 | ||||
-rw-r--r-- | runtime/sym.c | 66 | ||||
-rw-r--r-- | runtime/sym.h | 10 | ||||
-rw-r--r-- | runtime/transport/symbols.c | 11 | ||||
-rw-r--r-- | translate.cxx | 40 |
7 files changed, 147 insertions, 1 deletions
@@ -1,3 +1,9 @@ +2008-10-06 Wenji Huang <wenji.huang@oracle.com> + + PR 4886 + * translate.cxx (dump_unwindsyms): Extract build-id from debuginfo. + (emit_module_init): Check build-id if able. + 2008-10-03 Jim Keniston <jkenisto@us.ibm.com> PR 6850 diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 44147429..0a12c0d3 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,13 @@ +2008-10-06 Wenji Huang <wenji.huang@oracle.com> + + PR 4886 + * sym.h (_stp_module): Add several fields to store build-id. + * sym.c (_stp_module_check): New function to check build-id. + * staprun/staprun.c (send_relocation_kernel): Send build-id of runtime + kernel if there. + * transport/symbols.c (_stp_do_relocation): Update note section. + (_stp_section_is_interesting): No filter to .note.gnu.build-id. + 2008-10-03 Mark Wielaard <mjw@redhat.com> * procfs.c (_stp_rmdir_proc_module): Remove debug output from warning. diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index f8a08876..d23945e6 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -370,6 +370,11 @@ int send_relocation_kernel () } fclose (kallsyms); if (!done_with_kallsyms) srkrc = -1; + /* detect note section, send flag if there + * NB: address=2 represents existed note, the real one in _stp_module + */ + if (srkrc != -1 && !access("/sys/kernel/notes", R_OK)) + send_a_relocation ("kernel", ".note.gnu.build-id", 2); } return srkrc; diff --git a/runtime/sym.c b/runtime/sym.c index 1a9e26b2..97243929 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -160,6 +160,72 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo return NULL; } +/* Validate module/kernel based on build-id if there +* The completed case is the following combination: +* Debuginfo Module Kernel +* X X +* has build-id/not unloaded has build-id/not +* loaded && (has build-id/not) +* +* NB: build-id exists only if ld>=2.18 and kernel>= 2.6.23 +*/ +static int _stp_module_check(void) +{ + struct _stp_module *m = NULL; + unsigned long notes_addr, base_addr; + unsigned i,j; + + for (i = 0; i < _stp_num_modules; i++) + { + m = _stp_modules[i]; + + /* unloaded module */ + if (m->notes_sect == 0) { + _stp_warn("skip checking %s\n", m->name); + continue; + } + if (m->build_id_len > 0) { /* build-id in debuginfo file */ + dbug_sym(1, "validate %s based on build-id\n", m->name); + + /* loaded module/kernel, but without build-id */ + if (m->notes_sect == 1) { + _stp_error("missing build-id in %s\n", m->name); + return 1; + } + /* notes end address */ + if (!strcmp(m->name, "kernel")) { + notes_addr = m->build_id_offset; + base_addr = _stp_module_relocate("kernel", + "_stext", 0); + } else { + notes_addr = m->notes_sect + m->build_id_offset; + base_addr = m->notes_sect; + } + /* notes start address */ + notes_addr -= m->build_id_len; + if (notes_addr > base_addr) { + for (j = 0; j < m->build_id_len; j++) + if (*((unsigned char *) notes_addr+j) != + *(m->build_id_bits+j)) + { + _stp_error("inconsistent bit (0x%x [%s] vs 0x%x [debuginfo]) of build-id\n", *((unsigned char *) notes_addr+j), m->name, *(m->build_id_bits+j)); + return 1; + } + } else { /* bug, shouldn't come here */ + _stp_error("unknown failure in checking %s\n", + m->name); + return 1; + } /* end comparing */ + } else { + /* build-id in module/kernel, absent in debuginfo */ + if (m->notes_sect > 1) { + _stp_error("unexpected build-id in %s\n", m->name); + return 1; + } + } /* end checking */ + } /* end loop */ + return 0; +} /** Print an address symbolically. * @param address The address to lookup. diff --git a/runtime/sym.h b/runtime/sym.h index 5888d2c7..d23c1632 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -45,6 +45,16 @@ struct _stp_module { uint32_t unwind_data_len; uint32_t unwind_hdr_len; uint32_t unwind_is_ehframe; /* unwind data comes from .eh_frame */ + /* build-id information */ + unsigned char *build_id_bits; + unsigned long build_id_offset; + unsigned long notes_sect; /* kernel: 1 - no build-id + * 2 - has build-id + * module: 0 - unloaded + * 1 - loaded and no build-id + * Other - note section address + */ + int build_id_len; }; diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 4bdd0904..faba0986 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -51,8 +51,16 @@ static void _stp_do_relocation(const char __user *buf, size_t count) if (strcmp (_stp_modules[mi]->name, msg.module)) continue; + /* update note section to represent loaded */ + if (_stp_modules[mi]->notes_sect == 0) + _stp_modules[mi]->notes_sect = 1; for (si=0; si<_stp_modules[mi]->num_sections; si++) { + if (!strcmp (".note.gnu.build-id", msg.reloc)) { + _stp_modules[mi]->notes_sect = msg.address; + continue; + } + if (strcmp (_stp_modules[mi]->sections[si].name, msg.reloc)) continue; @@ -134,7 +142,8 @@ static int _stp_section_is_interesting(const char *name) { int ret = 1; if (!strncmp("__", name, 2) - || !strncmp(".note", name, 5) + || (!strncmp(".note", name, 5) + && strncmp(".note.gnu.build-id", name, 18)) || !strncmp(".gnu", name, 4) || !strncmp(".mod", name, 4)) ret = 0; diff --git a/translate.cxx b/translate.cxx index e92c8483..0ee51792 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1113,6 +1113,7 @@ c_unparser::emit_module_init () o->newline(-1) << "}"; // XXX: perform buildid-based checking if able + o->newline() << "if (_stp_module_check()) rc = -EINVAL;"; o->newline(-1) << "}"; o->newline() << "if (rc) goto out;"; @@ -4413,6 +4414,23 @@ dump_unwindsyms (Dwfl_Module *m, int syments = dwfl_module_getsymtab(m); assert(syments); + //extract build-id from debuginfo file + int build_id_len = 0; + unsigned char *build_id_bits; + GElf_Addr build_id_vaddr; + + if ((build_id_len=dwfl_module_build_id(m, + (const unsigned char **)&build_id_bits, + &build_id_vaddr)) > 0) + { + if (c->session.verbose > 1) { + clog << "Found build-id in " << name + << ", length " << build_id_len; + clog << ", end at 0x" << hex << build_id_vaddr + << dec << endl; + } + } + // Look up the relocation basis for symbols int n = dwfl_module_relocations (m); @@ -4581,6 +4599,28 @@ dump_unwindsyms (Dwfl_Module *m, c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/" << "sizeof(struct _stp_section), " << endl; + if (build_id_len > 0) { + c->output << ".build_id_bits = \"" ; + for (int j=0; j<build_id_len;j++) + c->output << "\\x" << hex + << (unsigned short) *(build_id_bits+j) << dec; + + c->output << "\", " << endl; + c->output << ".build_id_len = " << build_id_len << ", " << endl; + + if (modname == "kernel") + c->output << ".build_id_offset = 0x" << hex << build_id_vaddr + << dec << ", " << endl; + else + c->output << ".build_id_offset = 0x" << hex + << build_id_vaddr - base + << dec << ", " << endl; + } else + c->output << ".build_id_len = 0, " << endl; + + //initialize the note section representing unloaded + c->output << ".notes_sect = 0," << endl; + c->output << "};" << endl << endl; c->undone_unwindsym_modules.erase (modname); |