From: Jeroen N. W. <jn...@xs...> - 2005-11-03 19:40:03
|
On Wed 2 november 2005, Nicholas Nethercote wrote: > On Wed, 2 Nov 2005, Jeroen N. Witmond wrote: > >> The approach taken by cachegrind, vcov and cover relies on debug >> information being present and correct. This approach determines the file >> name and line number of a guest instruction each time it is >> instrumented, >> and uses that information to group the coverage data. >> >> In the approach I am taking in blanket, the guest instructions are >> grouped >> by address into ranges. Each range had a single entry point at the first >> guest instruction and a single (conditional) exit at the last guest >> instruction in the range. During instrumentation, a table of ranges is >> built, and for each range one or two helpers are called to update the >> relevant entry in the table. > > It would be worth starting with the simple approach of one C call per > instruction, and then move to the more complex range approach, so that you > can measure how much of a speedup you get. With Cachegrind I've had > surprising experiences with this kind of optimization, sometimes they > don't work as well as you would expect. The grouping of guest instructions into ranges is intended to be an infrastructure that can be reused, for instance to create control flow graphs. blanket just happens to be the first tool to use this infrastructure. The advantage for the tools using this infrastructure is that they can treat the range as an atom. (This just happens to be the level of granularity blanket needs to produce correct results.) It may not optimize the execution of the tool, but it should (will) optimize the performance of the programmers using it. :-) >> In a perfect world, all translations of guest instruction addresses into >> source files and line numbers is done once for each guest instruction by >> bk_fini(). In the real world, for a shared object this translation must >> be >> done before the object is unloaded. The loading and unloading of shared >> objects, and the presence of self-modifying programs or generated guest >> instructions, will require the use of a versioning scheme in the table >> of >> ranges. > > Why wait until bk_fini() to do the debug info lookup? If you do it in > bk_instrument() you don't have to worry about the debug info having been > unloaded. A combination of motives: the entire concept of source location is irrelevant for the instrumentation loop and the helper functions; the (probabaly slight) performance increase by doing the lookup once for each guest instruction instead of each time it is instrumented; not having the debug information using space until after the execution of the guest program; and the feeling it is neater this way. >> If the debug information is sufficient, blanket will be able to report >> multiple execution counts and branch results for one source line, >> overcoming some of the problems mentioned in >> http://www.bullseye.com/coverage.html. If debug information is absent or >> incomplete, blanket can still report all coverage data collected, using >> executable/library names (from /proc/self/maps) and offset ranges to >> label >> the data. > > That sounds similar to Cachegrind/VCov, but for instructions that lack > debug info you are not putting them into a single "???" bucket, but rather > giving the location in the binary. How will a user utilise the binary > location? That depends on what you use blanket for. When blanket is a tool in an ordinary development process, the user does not need (and should not have to resort to) binary locations. However, when reverse engineering a module or library for which you do have the rights, but not the sources, blanket can help, for instance by determining entry and exit instruction sequences, or by determining which options activate which ranges of code. Anyway, I'm not saying that the binary locations will be output by default, just that they can be available. Jeroen. |