opannotate.cpp

Go to the documentation of this file.
00001 
00012 #include <iostream>
00013 #include <sstream>
00014 #include <algorithm>
00015 #include <iomanip>
00016 #include <fstream>
00017 #include <utility>
00018 
00019 #include "op_exception.h"
00020 #include "op_header.h"
00021 #include "profile.h"
00022 #include "populate.h"
00023 #include "op_sample_file.h"
00024 #include "cverb.h"
00025 #include "string_manip.h"
00026 #include "demangle_symbol.h"
00027 #include "child_reader.h"
00028 #include "op_file.h"
00029 #include "file_manip.h"
00030 #include "arrange_profiles.h"
00031 #include "opannotate_options.h"
00032 #include "profile_container.h"
00033 #include "symbol_sort.h"
00034 #include "image_errors.h"
00035 
00036 using namespace std;
00037 using namespace options;
00038 
00039 namespace {
00040 
00041 size_t nr_events;
00042 
00043 scoped_ptr<profile_container> samples;
00044 
00046 string cmdline;
00047 
00049 string annotation_fill;
00050 
00052 string const begin_comment("/* ");
00053 string const in_comment(" * ");
00054 string const end_comment(" */");
00055 
00057 unsigned int const count_width = 6;
00058 
00059 string get_annotation_fill()
00060 {
00061     string str;
00062 
00063     for (size_t i = 0; i < nr_events; ++i) {
00064         str += string(count_width, ' ') + ' ';
00065         str += string(percent_width, ' ');
00066     }
00067 
00068     for (size_t i = 1; i < nr_events; ++i)
00069         str += "  ";
00070 
00071     str += " :";
00072     return str;
00073 }
00074 
00075 
00076 symbol_entry const * find_symbol(string const & image_name,
00077                  string const & str_vma, bfd_vma vma_adj)
00078 {
00079     // do not use the bfd equivalent:
00080     //  - it does not skip space at begin
00081     //  - we does not need cross architecture compile so the native
00082     // strtoull must work, assuming unsigned long long can contain a vma
00083     // and on 32/64 bits box bfd_vma is 64 bits
00084     bfd_vma vma = strtoull(str_vma.c_str(), NULL, 16) - vma_adj;
00085 
00086     return samples->find_symbol(image_name, vma);
00087 }
00088 
00089 
00090 void output_info(ostream & out)
00091 {
00092     out << begin_comment << '\n';
00093 
00094     out << in_comment << "Command line: " << cmdline << '\n'
00095         << in_comment << '\n';
00096 
00097     out << in_comment << "Interpretation of command line:" << '\n';
00098 
00099     if (!assembly) {
00100         out << in_comment
00101             << "Output annotated source file with samples" << '\n';
00102 
00103         if (options::threshold != 0) {
00104             out << in_comment
00105                 << "Output files where samples count reach "
00106                 << options::threshold << "% of the samples\n";
00107         } else {
00108             out << in_comment << "Output all files" << '\n';
00109         }
00110     } else {
00111         out << in_comment
00112             << "Output annotated assembly listing with samples"
00113             << '\n';
00114 
00115         if (!objdump_params.empty()) {
00116             out << in_comment << "Passing the following "
00117                 "additional arguments to objdump ; \"";
00118             for (size_t i = 0 ; i < objdump_params.size() ; ++i)
00119                 out << objdump_params[i] << " ";
00120             out << "\"" << '\n';
00121         }
00122     }
00123 
00124     out << in_comment << '\n';
00125 
00126     out << in_comment << classes.cpuinfo << endl;
00127     if (!classes.event.empty())
00128         out << in_comment << classes.event << endl;
00129 
00130     for (size_t i = 0; i < classes.v.size(); ++i)
00131         out << in_comment << classes.v[i].longname << endl;
00132 
00133     out << end_comment << '\n';
00134 }
00135 
00136 
00137 string count_str(count_array_t const & count,
00138            count_array_t const & total)
00139 {
00140     ostringstream os;
00141     for (size_t i = 0; i < nr_events; ++i) {
00142         os << setw(count_width) << count[i] << ' ';
00143 
00144         os << format_percent(op_ratio(count[i], total[i]) * 100.0,
00145                     percent_int_width, percent_fract_width);
00146     }
00147     return os.str();
00148 }
00149 
00150 
00163 int asm_list_annotation(symbol_entry const * last_symbol,
00164             bfd_vma last_symbol_vma,
00165             list<string>::iterator sit,
00166             sample_container::samples_iterator & samp_it,
00167             list<string> & asm_lines, bfd_vma vma_adj)
00168 {
00169     int ret = 0;
00170 
00171     sample_entry const * sample = NULL;
00172 
00173     if (samp_it != samples->end())
00174         sample = &samp_it->second;
00175 
00176     // do not use the bfd equivalent:
00177     //  - it does not skip space at begin
00178     //  - we does not need cross architecture compile so the native
00179     // strtoull must work, assuming unsigned long long can contain a vma
00180     // and on 32/64 bits box bfd_vma is 64 bits
00181     // gcc 2.91.66 workaround
00182     bfd_vma vma = strtoull((*sit).c_str(), NULL, 16) - vma_adj;
00183 
00184     if (sample 
00185         && ((sample->vma < last_symbol_vma) || (sample->vma > vma))) {
00186         *sit = annotation_fill + *sit;
00187     } else if (sample && sample->vma == vma) {
00188         // Case 1 : Sample address match current line address.
00189         string str = count_str(sample->counts, samples->samples_count());
00190 
00191         // For each events
00192         for (size_t i = 1; i < nr_events; ++i)
00193             str += "  ";
00194 
00195         *sit = str + " :" + *sit;
00196         if (samp_it != samples->end())
00197             ++samp_it;
00198 
00199     } else  if (sample && sample->vma < vma) {
00200         // Case 2 : vma of the current line is greater than vma of the sample
00201 
00202         // Get the string of previous assembly line
00203         list<string>::iterator sit_prev = sit;
00204         string prev_line, prev_vma_str;
00205         string::size_type loc1 = string::npos, loc2 = string::npos;
00206         while (sit_prev != asm_lines.begin()) {
00207             --sit_prev;
00208             prev_line = *sit_prev;
00209 
00210             loc1 = prev_line.find(":", 0);
00211             if (loc1 != string::npos) {
00212                 loc2 = prev_line.find(":", loc1+1);
00213                 if (loc2 != string::npos) {
00214                     prev_vma_str = prev_line.substr(loc1+1, loc2);
00215                     break;
00216                 }
00217             }
00218         }
00219 
00220         bfd_vma prev_vma = strtoull(prev_vma_str.c_str(), NULL, 16);
00221 
00222         // Need to check if prev_vma < sample->vma
00223         if (prev_vma != 0 && prev_vma < sample->vma) {
00224             string str;
00225 
00226             // Get sample for previous line.
00227             sample_entry * prev_sample = (sample_entry *)samples->
00228                             find_sample(last_symbol, prev_vma);
00229             if (prev_sample) {
00230                 // Aggregate sample with previous line if it already has samples
00231                 prev_sample->counts += sample->counts;
00232                 str = count_str(prev_sample->counts, samples->samples_count());
00233             } else {
00234                 str = count_str(sample->counts, samples->samples_count());
00235             }
00236 
00237             // For each events
00238             for (size_t i = 1; i < nr_events; ++i)
00239                 str += "  ";
00240 
00241             *sit_prev = str + " :" + prev_line.substr(loc1+1);
00242             if (samp_it != samples->end())
00243                 ++samp_it;
00244             ret = -1;
00245         } else {
00246             // Failed to annotate the previous line. Skip sample.
00247             *sit = annotation_fill + *sit;
00248             if (samp_it != samples->end())
00249                 ++samp_it;
00250         }
00251     } else {
00252         // In case sample is NULL
00253         *sit = annotation_fill + *sit;
00254     }
00255 
00256     return ret;
00257 }
00258 
00259 
00260 string symbol_annotation(symbol_entry const * symbol)
00261 {
00262     if (!symbol)
00263         return string();
00264 
00265     string annot = count_str(symbol->sample.counts,
00266                              samples->samples_count());
00267 
00268     string const & symname = symbol_names.demangle(symbol->name);
00269 
00270     string str = " ";
00271     str += begin_comment + symname + " total: ";
00272     str += count_str(symbol->sample.counts, samples->samples_count());
00273     str += end_comment;
00274     return str;
00275 }
00276 
00277 
00281 bool is_symbol_line(string const & str, string::size_type pos)
00282 {
00283     if (str[pos] != ' ' || str[pos + 1] != '<')
00284         return false;
00285 
00286     return str[str.length() - 1] == ':';
00287 }
00288 
00289 
00290 void annotate_objdump_str_list(string const & app_name,
00291                    symbol_collection const & symbols,
00292                    list<string> & asm_lines)
00293 {
00294     symbol_entry const * last_symbol = 0;
00295     bfd_vma last_symbol_vma = 0;
00296     bfd_vma vma_adj;
00297     int ret = 0;
00298 
00299     // to filter output of symbols (filter based on command line options)
00300     bool do_output = true;
00301 
00302     vma_adj = symbols[0]->vma_adj;
00303 
00304     // We simultaneously walk the two structures (list and sample_container)
00305     // which are sorted by address. and do address comparision.
00306     list<string>::iterator sit  = asm_lines.begin();
00307     list<string>::iterator send = asm_lines.end();
00308     sample_container::samples_iterator samp_it = samples->begin();
00309 
00310     for (; sit != send; (!ret? sit++: sit)) {
00311         // output of objdump is a human readable form and can contain some
00312         // ambiguity so this code is dirty. It is also optimized a little bit
00313         // so it is difficult to simplify it without breaking something ...
00314 
00315         // line of interest are: "[:space:]*[:xdigit:]?[ :]", the last char of
00316         // this regexp dis-ambiguate between a symbol line and an asm line. If
00317         // source contain line of this form an ambiguity occur and we rely on
00318         // the robustness of this code.
00319         string str = *sit;
00320         size_t pos = 0;
00321         while (pos < str.length() && isspace(str[pos]))
00322             ++pos;
00323 
00324         if (pos == str.length() || !isxdigit(str[pos])) {
00325             if (do_output) {
00326                 *sit = annotation_fill + str;
00327                 continue;
00328             }
00329         }
00330 
00331         while (pos < str.length() && isxdigit(str[pos]))
00332             ++pos;
00333 
00334         if (pos == str.length() || (!isspace(str[pos]) && str[pos] != ':')) {
00335             if (do_output) {
00336                 *sit = annotation_fill + str;
00337                 continue;
00338             }
00339         }
00340 
00341         if (is_symbol_line(str, pos)) {
00342 
00343             last_symbol = find_symbol(app_name, str, vma_adj);
00344             last_symbol_vma = strtoull(str.c_str(), NULL, 16) - vma_adj;
00345 
00346             // ! complexity: linear in number of symbol must use sorted
00347             // by address vector and lower_bound ?
00348             // Note this use a pointer comparison. It work because symbols
00349             // pointer are unique
00350             if (find(symbols.begin(), symbols.end(), last_symbol)
00351                 != symbols.end())
00352                 do_output = true;
00353             else
00354                 do_output = false;
00355 
00356             if (do_output) {
00357                 *sit += symbol_annotation(last_symbol);
00358 
00359                 // Realign the sample iterator to
00360                 // the beginning of this symbols
00361                 samp_it = samples->begin(last_symbol);
00362             }
00363         } else {
00364             // not a symbol, probably an asm line.
00365             if (do_output)
00366                 ret = asm_list_annotation(last_symbol,
00367                               last_symbol_vma,
00368                               sit, samp_it,
00369                               asm_lines, vma_adj);
00370         }
00371 
00372         if (!do_output)
00373             *sit = "";
00374     }
00375 }
00376 
00377 
00378 void output_objdump_str_list(symbol_collection const & symbols,
00379             string const & app_name,
00380             list<string> & asm_lines)
00381 {
00382 
00383     annotate_objdump_str_list(app_name, symbols, asm_lines);
00384 
00385     // Printing objdump output to stdout
00386     list<string>::iterator sit  = asm_lines.begin();
00387     list<string>::iterator send = asm_lines.end();
00388     sit = asm_lines.begin();
00389     for (; sit != send; ++sit) {
00390         string str = *sit;
00391         if (str.length() != 0)
00392             cout << str << '\n';
00393     }
00394 }
00395 
00396 
00397 void do_one_output_objdump(symbol_collection const & symbols,
00398                string const & image_name, string const & app_name,
00399                bfd_vma start, bfd_vma end)
00400 {
00401     vector<string> args;
00402     list<string> asm_lines;
00403 
00404     args.push_back("-d");
00405     args.push_back("--no-show-raw-insn");
00406     if (source)
00407         args.push_back("-S");
00408 
00409     if (start || end != ~(bfd_vma)0) {
00410         ostringstream arg1, arg2;
00411         arg1 << "--start-address=" << start;
00412         arg2 << "--stop-address=" << end;
00413         args.push_back(arg1.str());
00414         args.push_back(arg2.str());
00415     }
00416 
00417     if (!objdump_params.empty()) {
00418         for (size_t i = 0 ; i < objdump_params.size() ; ++i)
00419             args.push_back(objdump_params[i]);
00420     }
00421 
00422     args.push_back(image_name);
00423     child_reader reader("objdump", args);
00424     if (reader.error()) {
00425         cerr << "An error occur during the execution of objdump:\n\n";
00426         cerr << reader.error_str() << endl;
00427         return;
00428     }
00429 
00430     // Read each output line from objdump and store in a list.
00431     string str;
00432     while (reader.getline(str))
00433         asm_lines.push_back(str);
00434 
00435     output_objdump_str_list(symbols, app_name, asm_lines);
00436 
00437     // objdump always returns SUCCESS so we must rely on the stderr state
00438     // of objdump. If objdump error message is cryptic our own error
00439     // message will be probably also cryptic
00440     ostringstream std_err;
00441     ostringstream std_out;
00442     reader.get_data(std_out, std_err);
00443     if (std_err.str().length()) {
00444         cerr << "An error occur during the execution of objdump:\n\n";
00445         cerr << std_err.str() << endl;
00446         return ;
00447     }
00448 
00449     // force error code to be acquired
00450     reader.terminate_process();
00451 
00452     // required because if objdump stop by signal all above things suceeed
00453     // (signal error message are not output through stdout/stderr)
00454     if (reader.error()) {
00455         cerr << "An error occur during the execution of objdump:\n\n";
00456         cerr << reader.error_str() << endl;
00457         return;
00458     }
00459 }
00460 
00461 
00462 void output_objdump_asm(symbol_collection const & symbols,
00463             string const & app_name)
00464 {
00465     image_error error;
00466     string image =
00467         classes.extra_found_images.find_image_path(app_name, error,
00468                                true);
00469 
00470     // this is only an optimisation, we can either filter output by
00471     // directly calling objdump and rely on the symbol filtering or
00472     // we can call objdump with the right parameter to just disassemble
00473     // the needed part. This is a real win only when calling objdump
00474     // a medium number of times, I dunno if the used threshold is optimal
00475     // but it is a conservative value.
00476     size_t const max_objdump_exec = 50;
00477     if (symbols.size() <= max_objdump_exec || error != image_ok) {
00478         symbol_collection::const_iterator cit = symbols.begin();
00479         symbol_collection::const_iterator end = symbols.end();
00480         for (; cit != end; ++cit) {
00481             bfd_vma start = (*cit)->sample.vma;
00482             bfd_vma end  = start + (*cit)->size;
00483             do_one_output_objdump(symbols, image, app_name,
00484                           start, end);
00485         }
00486     } else {
00487         do_one_output_objdump(symbols, image,
00488                       app_name, 0, ~bfd_vma(0));
00489     }
00490 }
00491 
00492 
00493 bool output_asm(string const & app_name)
00494 {
00495     profile_container::symbol_choice choice;
00496     choice.threshold = options::threshold;
00497     choice.image_name = app_name;
00498     choice.match_image = true;
00499     symbol_collection symbols = samples->select_symbols(choice);
00500 
00501     if (!symbols.empty()) {
00502         sort_options options;
00503         options.add_sort_option(sort_options::sample);
00504         options.sort(symbols, false, false);
00505 
00506         output_info(cout);
00507 
00508         output_objdump_asm(symbols, app_name);
00509 
00510         return true;
00511     }
00512 
00513     return false;
00514 }
00515 
00516 
00517 string const source_line_annotation(debug_name_id filename, size_t linenr)
00518 {
00519     string str;
00520 
00521     count_array_t counts = samples->samples_count(filename, linenr);
00522     if (!counts.zero()) {
00523         str += count_str(counts, samples->samples_count());
00524         for (size_t i = 1; i < nr_events; ++i)
00525             str += "  ";
00526         str += " :";
00527     } else {
00528         str = annotation_fill;
00529     }
00530 
00531     return str;
00532 }
00533 
00534 
00535 string source_symbol_annotation(debug_name_id filename, size_t linenr)
00536 {
00537     symbol_collection const symbols = samples->find_symbol(filename, linenr);
00538 
00539     if (symbols.empty())
00540         return string();
00541 
00542     string str = " " + begin_comment;
00543 
00544     count_array_t counts;
00545     for (size_t i = 0; i < symbols.size(); ++i) {
00546         str += symbol_names.demangle(symbols[i]->name);
00547         if (symbols.size() == 1)
00548             str += " total: ";
00549         else
00550             str += " ";
00551         str += count_str(symbols[i]->sample.counts,
00552                   samples->samples_count());
00553         if (symbols.size() != 1)
00554             str += ", ";
00555 
00556         counts += symbols[i]->sample.counts;
00557     }
00558 
00559     if (symbols.size() > 1)
00560         str += "total: " + count_str(counts, samples->samples_count());
00561     str += end_comment;
00562 
00563     return str;
00564 }
00565 
00566 
00567 void output_per_file_info(ostream & out, debug_name_id filename,
00568               count_array_t const & total_file_count)
00569 {
00570     out << begin_comment << '\n'
00571          << in_comment << "Total samples for file : "
00572          << '"' << debug_names.name(filename) << '"'
00573          << '\n';
00574     out << in_comment << '\n' << in_comment
00575         << count_str(total_file_count, samples->samples_count())
00576         << '\n';
00577     out << end_comment << '\n' << '\n';
00578 }
00579 
00580 
00581 string const line0_info(debug_name_id filename)
00582 {
00583     string annotation = source_line_annotation(filename, 0);
00584     if (trim(annotation, " \t:").empty())
00585         return string();
00586 
00587     string str = "<credited to line zero> ";
00588     str += annotation;
00589     return str;
00590 }
00591 
00592 
00593 void do_output_one_file(ostream & out, istream & in, debug_name_id filename,
00594                         bool header)
00595 {
00596     count_array_t count = samples->samples_count(filename);
00597 
00598     if (header) {
00599         output_per_file_info(out, filename, count);
00600         out << line0_info(filename) << '\n';
00601     }
00602 
00603 
00604     if (in) {
00605         string str;
00606 
00607         for (size_t linenr = 1 ; getline(in, str) ; ++linenr) {
00608             out << source_line_annotation(filename, linenr) << str
00609                 << source_symbol_annotation(filename, linenr)
00610                 << '\n';
00611         }
00612 
00613     } else {
00614         // source is not available but we can at least output all the
00615         // symbols belonging to this file. This make more visible the
00616         // problem of having less samples for a given file than the
00617         // sum of all symbols samples for this file due to inlining
00618         symbol_collection const symbols = samples->select_symbols(filename);
00619         for (size_t i = 0; i < symbols.size(); ++i)
00620             out << symbol_annotation(symbols[i]) << endl;
00621     }
00622 
00623     if (!header) {
00624         output_per_file_info(out, filename, count);
00625         out << line0_info(filename) << '\n';
00626     }
00627 }
00628 
00629 
00630 void output_one_file(istream & in, debug_name_id filename,
00631                      string const & source)
00632 {
00633     if (output_dir.empty()) {
00634         do_output_one_file(cout, in, filename, true);
00635         return;
00636     }
00637 
00638     string const out_file = op_realpath(output_dir + source);
00639 
00640     /* Just because you're paranoid doesn't mean they're not out to
00641      * get you ...
00642      *
00643      * This is just a lame final safety check. If we found the
00644      * source, then "source" should be canonical already, and
00645      * can't escape from the output dir. We can't use op_realpath()
00646      * alone as that needs the file to exist already.
00647      *
00648      * Let's not complain again if we couldn't find the file anyway.
00649      */
00650     if (out_file.find("/../") != string::npos) {
00651         if (in) {
00652             cerr << "refusing to create non-canonical filename "
00653                  << out_file  << endl;
00654         }
00655         return;
00656     } else if (!is_prefix(out_file, output_dir)) {
00657         if (in) {
00658             cerr << "refusing to create file " << out_file
00659                  << " outside of output directory " << output_dir
00660                  << endl;
00661         }
00662         return;
00663     }
00664 
00665     if (is_files_identical(out_file, source)) {
00666         cerr << "input and output files are identical: "
00667              << out_file << endl;
00668         return;
00669     }
00670 
00671     if (create_path(out_file.c_str())) {
00672         cerr << "unable to create file: "
00673              << '"' << op_dirname(out_file) << '"' << endl;
00674         return;
00675     }
00676 
00677     ofstream out(out_file.c_str());
00678     if (!out) {
00679         cerr << "unable to open output file "
00680              << '"' << out_file << '"' << endl;
00681     } else {
00682         do_output_one_file(out, in, filename, false);
00683         output_info(out);
00684     }
00685 }
00686 
00687 
00688 /* Locate a source file from debug info, which may be relative */
00689 string const locate_source_file(debug_name_id filename_id)
00690 {
00691     string const origfile = debug_names.name(filename_id);
00692     string file = origfile;
00693 
00694     if (file.empty())
00695         return file;
00696 
00697     /* Allow absolute paths to be relocated to a different directory */
00698     if (file[0] == '/') {
00699         vector<string>::const_iterator cit = base_dirs.begin();
00700         vector<string>::const_iterator end = base_dirs.end();
00701         for (; cit != end; ++cit) {
00702             string path = op_realpath(*cit);
00703 
00704             if (is_prefix(file, path)) {
00705                 file = file.substr(path.length());
00706                 break;
00707             }
00708         }
00709     }
00710 
00711     vector<string>::const_iterator cit = search_dirs.begin();
00712     vector<string>::const_iterator end = search_dirs.end();
00713 
00714     for (; cit != end; ++cit) {
00715         string const absfile = op_realpath(*cit + "/" + file);
00716 
00717         if (op_file_readable(absfile))
00718             return absfile;
00719     }
00720 
00721     /* We didn't find a relocated absolute file, or a relative file,
00722      * assume the original is correct, accounting for the
00723      * possibility it's relative the cwd
00724      */
00725     return op_realpath(origfile);
00726 }
00727 
00728 
00729 void output_source(path_filter const & filter)
00730 {
00731     bool const separate_file = !output_dir.empty();
00732 
00733     if (!separate_file)
00734         output_info(cout);
00735 
00736     vector<debug_name_id> filenames =
00737         samples->select_filename(options::threshold);
00738 
00739     for (size_t i = 0 ; i < filenames.size() ; ++i) {
00740         string const & source = locate_source_file(filenames[i]);
00741 
00742         if (!filter.match(source))
00743             continue;
00744 
00745         ifstream in(source.c_str());
00746 
00747         // it is common to have empty filename due to the lack
00748         // of debug info (eg _init function) so warn only
00749         // if the filename is non empty. The case: no debug
00750         // info at all has already been checked.
00751         if (!in && source.length()) {
00752             cerr << "opannotate (warning): unable to open for "
00753                  "reading: " << source << endl;
00754         }
00755 
00756         if (source.length())
00757             output_one_file(in, filenames[i], source);
00758     }
00759 }
00760 
00761 
00762 bool annotate_source(list<string> const & images)
00763 {
00764     annotation_fill = get_annotation_fill();
00765 
00766     if (!output_dir.empty()) {
00767 
00768         if (create_path(output_dir.c_str())) {
00769             cerr << "unable to create " << output_dir
00770                  << " directory: " << endl;
00771             return false;
00772         }
00773 
00774         // Make sure we have an absolute path.
00775         output_dir = op_realpath(output_dir);
00776         if (output_dir.length() &&
00777             output_dir[output_dir.length() - 1] != '/')
00778             output_dir += '/';
00779 
00780         /* Don't let the user stomp on their sources */
00781         if (output_dir == "/") {
00782             cerr << "Output path of / would over-write the "
00783                 "source files" << endl;
00784             return false;
00785         }
00786     }
00787 
00788     if (assembly) {
00789         bool some_output = false;
00790 
00791         list<string>::const_iterator it = images.begin();
00792         list<string>::const_iterator const end = images.end();
00793 
00794         for (; it != end; ++it) {
00795             if (output_asm(*it))
00796                 some_output = true;
00797         }
00798 
00799         if (!some_output) {
00800             // It's the only case we must care since we know the
00801             // selected image set is not empty
00802             cerr << "selected image set doesn't contain any of "
00803                  << "the selected symbol\n";
00804         }
00805     } else {
00806         output_source(file_filter);
00807     }
00808 
00809     return true;
00810 }
00811 
00812 
00813 int opannotate(options::spec const & spec)
00814 {
00815     handle_options(spec);
00816 
00817     nr_events = classes.v.size();
00818 
00819     samples.reset(new profile_container(true, true,
00820                         classes.extra_found_images));
00821 
00822     list<string> images;
00823 
00824     list<inverted_profile> iprofiles = invert_profiles(classes);
00825 
00826     report_image_errors(iprofiles, classes.extra_found_images);
00827 
00828     list<inverted_profile>::iterator it = iprofiles.begin();
00829     list<inverted_profile>::iterator const end = iprofiles.end();
00830 
00831     bool debug_info = false;
00832     for (; it != end; ++it) {
00833         bool tmp = false;
00834         populate_for_image(*samples, *it,
00835                    options::symbol_filter, &tmp);
00836         images.push_back(it->image);
00837         if (tmp)
00838             debug_info = true;
00839     }
00840 
00841     if (!debug_info && !options::assembly) {
00842         cerr << "opannotate (warning): no debug information available for binary "
00843              << it->image << ", and --assembly not requested\n";
00844     }
00845 
00846     annotate_source(images);
00847 
00848     return 0;
00849 }
00850 
00851 } // anonymous namespace
00852 
00853 
00854 int main(int argc, char const * argv[])
00855 {
00856     // set the invocation, for the file headers later
00857     for (int i = 0 ; i < argc ; ++i)
00858         cmdline += string(argv[i]) + " ";
00859 
00860     return run_pp_tool(argc, argv, opannotate);
00861 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1