From 909ab234518e8d20eb4608ca1b89c252e74c9a6f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 30 Jan 2013 12:20:41 -0800 Subject: [PATCH] PR14705: Modify SDT semaphores in stapdyn For SDT probes which are guarded by a semaphore, stapdyn needs to update the value to show when the probes are active. * stapdyn/mutatee.h (mutatee::semaphores): New vector of variables in this mutatee which represent active semaphores. * stapdyn/mutatee.cxx (mutatee::update_semaphores): New, used to increment or decrement the value of semaphores in this mutatee. (mutatee::instrument_dynprobe_target): When a probe has a semaphore, create a variable representation of it. (mutatee::instrument_object_dynprobes): Increment semaphores in bulk. (mutatee::copy_forked_instrumentation): Copy semaphore variables too. (mutatee::remove_instrumentation): Decrement semaphores in bulk. * tapsets.cxx (sdt_query::handle_query_module): Calculate the difference in load addresses between .text and .data as semaphore_load_offset. (sdt_query::record_semaphore): Subtract the semaphore_load_offset for dyninst to get a file-based offset of the semaphore. --- stapdyn/mutatee.cxx | 57 ++++++++++++++++++++++++++++++++++++++++++++- stapdyn/mutatee.h | 4 ++++ tapsets.cxx | 25 +++++++++++++++++--- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/stapdyn/mutatee.cxx b/stapdyn/mutatee.cxx index 666e646d7..094a82731 100644 --- a/stapdyn/mutatee.cxx +++ b/stapdyn/mutatee.cxx @@ -126,6 +126,28 @@ mutatee::unload_stap_dso() } + +void +mutatee::update_semaphores(unsigned short delta, size_t start) +{ + if (!process || process->isTerminated()) + return; + + for (size_t i=start; i < semaphores.size(); ++i) + { + unsigned short value = 0; + BPatch_variableExpr* semaphore = semaphores[i]; + + // Read-modify-write the semaphore remotely. + semaphore->readValue(&value, (int)sizeof(value)); + value += delta; + semaphore->writeValue(&value, (int)sizeof(value)); + } + // NB: Alternatively, we could build up a oneTimeCode snippet to do them all + // at once within the target process. For now, remote seems good enough. +} + + void mutatee::call_utrace_dynprobe(const dynprobe_location& probe, BPatch_thread* thread) @@ -307,7 +329,22 @@ mutatee::instrument_dynprobe_target(BPatch_object* object, if (handle) snippets.push_back(handle); - // XXX write the semaphore too! + // Update SDT semaphores as needed. + if (probe.semaphore) + { + Dyninst::Address sem_address = object->fileOffsetToAddr(probe.semaphore); + if (sem_address == BPatch_object::E_OUT_OF_BOUNDS) + stapwarn() << "couldn't convert semaphore " << target.path << "+" + << lex_cast_hex(probe.offset) << " to an address" << endl; + else + { + // Create a variable to represent this semaphore + BPatch_type *sem_type = process->getImage()->findType("unsigned short"); + BPatch_variableExpr *semaphore = process->createVariable(sem_address, sem_type); + if (semaphore) + semaphores.push_back(semaphore); + } + } } } @@ -345,6 +382,8 @@ mutatee::instrument_object_dynprobes(BPatch_object* object, string path = resolve_path(object->pathName()); staplog(2) << "found object " << path << endl; + size_t semaphore_start = semaphores.size(); + // Match the object to our targets, and instrument matches. process->beginInsertionSet(); for (size_t i = 0; i < targets.size(); ++i) @@ -356,6 +395,9 @@ mutatee::instrument_object_dynprobes(BPatch_object* object, instrument_dynprobe_target(object, target); } process->finalizeInsertionSet(false); + + // Increment new semaphores + update_semaphores(1, semaphore_start); } @@ -519,6 +561,15 @@ mutatee::copy_forked_instrumentation(mutatee& other) snippets.push_back(handle); } + // Get new variable representations of semaphores + for (size_t i = 0; i < other.semaphores.size(); ++i) + { + BPatch_variableExpr *semaphore = + process->getInheritedVariable(*other.semaphores[i]); + if (semaphore) + semaphores.push_back(semaphore); + } + // Update utrace probes to match for (size_t i = 0; i < other.attached_probes.size(); ++i) instrument_utrace_dynprobe(other.attached_probes[i]); @@ -538,6 +589,10 @@ mutatee::remove_instrumentation() process->finalizeInsertionSet(false); snippets.clear(); + // Decrement all semaphores + update_semaphores(-1); + semaphores.clear(); + unload_stap_dso(); } diff --git a/stapdyn/mutatee.h b/stapdyn/mutatee.h index bfe14c5e1..b8917790d 100644 --- a/stapdyn/mutatee.h +++ b/stapdyn/mutatee.h @@ -33,6 +33,8 @@ class mutatee { std::vector snippets; // handles from insertSnippet + std::vector semaphores; // SDT semaphore variables + std::vector attached_probes; BPatch_function* utrace_enter_function; @@ -40,6 +42,8 @@ class mutatee { mutatee (const mutatee& other); mutatee& operator= (const mutatee& other); + void update_semaphores(unsigned short delta, size_t start=0); + void call_utrace_dynprobe(const dynprobe_location& probe, BPatch_thread* thread=NULL); void instrument_utrace_dynprobe(const dynprobe_location& probe); diff --git a/tapsets.cxx b/tapsets.cxx index acdfdbb74..535882ac2 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6090,6 +6090,7 @@ private: string arg_string; string probe_name; string provider_name; + GElf_Addr semaphore_load_offset; Dwarf_Addr semaphore; bool init_probe_scn(); @@ -6119,7 +6120,7 @@ sdt_query::sdt_query(probe * base_probe, probe_point * base_loc, probe_loc(unknown_section), base_probe(base_probe), base_loc(base_loc), params(params), results(results), user_lib(user_lib), probe_scn_offset(0), probe_scn_addr(0), arg_count(0), base(0), pc(0), - semaphore(0) + semaphore_load_offset(0), semaphore(0) { assert(get_string_param(params, TOK_MARK, pp_mark)); get_string_param(params, TOK_PROVIDER, pp_provider); // pp_provider == "" -> unspecified @@ -6253,10 +6254,22 @@ sdt_query::handle_query_module() GElf_Shdr shdr_mem; GElf_Shdr *shdr = dw.get_section (".stapsdt.base", &shdr_mem); + // The 'base' lets us adjust the hardcoded addresses in notes for prelink + // effects. The 'semaphore_load_offset' accounts for the difference in + // load addresses between text and data, so the semaphore can be + // converted to a file offset if needed. if (shdr) - base = shdr->sh_addr; + { + base = shdr->sh_addr; + GElf_Addr base_offset = shdr->sh_offset; + shdr = dw.get_section (".probes", &shdr_mem); + if (shdr) + semaphore_load_offset = + (shdr->sh_addr - shdr->sh_offset) - (base - base_offset); + } else - base = 0; + base = semaphore_load_offset = 0; + dw.iterate_over_notes ((void*) this, &sdt_query::setup_note_probe_entry_callback); } else if (probe_loc == probe_section) @@ -6479,6 +6492,12 @@ sdt_query::record_semaphore (vector & results, unsigned start) if (dwfl_module_relocations (dw.module) > 0) dwfl_module_relocate_address (dw.module, &addr); // XXX: relocation basis? + + // Dyninst needs the *file*-based offset for semaphores, + // so subtract the difference in load addresses between .text and .probes + if (dw.sess.runtime_usermode_p()) + addr -= semaphore_load_offset; + for (unsigned i = start; i < results.size(); ++i) results[i]->sdt_semaphore_addr = addr; if (sess.verbose > 2) -- 2.43.5