summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWenji Huang <wenji.huang@oracle.com>2008-10-06 03:07:09 -0400
committerWenji Huang <wenji.huang@oracle.com>2008-10-06 03:07:09 -0400
commit2949597251fea7f17a0e46c1c885e34b53395d18 (patch)
tree7628da32ea81a5bbaf10f31c7fd60006629db3d6
parent5311c037f83f66967f9de4cc66815f93940bb005 (diff)
downloadsystemtap-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--ChangeLog6
-rw-r--r--runtime/ChangeLog10
-rw-r--r--runtime/staprun/staprun.c5
-rw-r--r--runtime/sym.c66
-rw-r--r--runtime/sym.h10
-rw-r--r--runtime/transport/symbols.c11
-rw-r--r--translate.cxx40
7 files changed, 147 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index cc9dbd3d..8b1645e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);