00001
00012 #include "op_file.h"
00013 #include "op_config.h"
00014 #include "config.h"
00015
00016 #include <fcntl.h>
00017 #include <cstring>
00018
00019 #include <sys/stat.h>
00020
00021 #include <cstdlib>
00022
00023 #include <algorithm>
00024 #include <iostream>
00025 #include <iomanip>
00026 #include <sstream>
00027
00028 #include "op_bfd.h"
00029 #include "locate_images.h"
00030 #include "string_filter.h"
00031 #include "stream_util.h"
00032 #include "cverb.h"
00033
00034 using namespace std;
00035
00036
00037 verbose vbfd("bfd");
00038
00039
00040 namespace {
00041
00043 struct remove_filter {
00044 remove_filter(string_filter const & filter)
00045 : filter_(filter) {}
00046
00047 bool operator()(op_bfd_symbol const & symbol) {
00048 return !filter_.match(symbol.name());
00049 }
00050
00051 string_filter filter_;
00052 };
00053
00054
00055 }
00056
00057
00058 op_bfd_symbol::op_bfd_symbol(asymbol const * a)
00059 : bfd_symbol(a), symb_value(a->value),
00060 section_filepos(a->section->filepos),
00061 section_vma(a->section->vma),
00062 symb_size(0), symb_hidden(false), symb_weak(false),
00063 symb_artificial(false)
00064 {
00065
00066
00067
00068
00069 if (a->name && a->name[0] != '\0') {
00070 symb_name = a->name;
00071 symb_weak = a->flags & BSF_WEAK;
00072 symb_hidden = (a->flags & BSF_LOCAL)
00073 && !(a->flags & BSF_GLOBAL);
00074 } else {
00075 symb_name = string("??") + a->section->name;
00076 }
00077 }
00078
00079
00080 op_bfd_symbol::op_bfd_symbol(bfd_vma vma, size_t size, string const & name)
00081 : bfd_symbol(0), symb_value(vma),
00082 section_filepos(0), section_vma(0),
00083 symb_size(size), symb_name(name),
00084 symb_artificial(true)
00085 {
00086 }
00087
00088
00089 bool op_bfd_symbol::operator<(op_bfd_symbol const & rhs) const
00090 {
00091 return filepos() < rhs.filepos();
00092 }
00093
00094 unsigned long op_bfd_symbol::symbol_endpos(void) const
00095 {
00096 return bfd_symbol->section->filepos + bfd_symbol->section->size;
00097 }
00098
00099
00100 op_bfd::op_bfd(string const & fname, string_filter const & symbol_filter,
00101 extra_images const & extra_images, bool & ok)
00102 :
00103 filename(fname),
00104 archive_path(extra_images.get_archive_path()),
00105 extra_found_images(extra_images),
00106 file_size(-1),
00107 anon_obj(false)
00108 {
00109 int fd;
00110 struct stat st;
00111
00112
00113
00114 symbols_found_t symbols;
00115 asection const * sect;
00116 string suf = ".jo";
00117
00118 image_error img_ok;
00119 string const image_path =
00120 extra_images.find_image_path(filename, img_ok, true);
00121
00122 cverb << vbfd << "op_bfd ctor for " << image_path << endl;
00123
00124
00125 if (!ok || img_ok != image_ok) {
00126 cverb << vbfd << "can't locate " << image_path << endl;
00127 goto out_fail;
00128 }
00129
00130 fd = open(image_path.c_str(), O_RDONLY);
00131 if (fd == -1) {
00132 cverb << vbfd << "open failed for " << image_path << endl;
00133 ok = false;
00134 goto out_fail;
00135 }
00136
00137 if (fstat(fd, &st)) {
00138 cverb << vbfd << "stat failed for " << image_path << endl;
00139 ok = false;
00140 goto out_fail;
00141 }
00142
00143 file_size = st.st_size;
00144
00145 ibfd.abfd = fdopen_bfd(image_path, fd);
00146
00147 if (!ibfd.valid()) {
00148 cverb << vbfd << "fdopen_bfd failed for " << image_path << endl;
00149 ok = false;
00150 goto out_fail;
00151 }
00152
00153 string::size_type pos;
00154 pos = filename.rfind(suf);
00155 if (pos != string::npos && pos == filename.size() - suf.size())
00156 anon_obj = true;
00157
00158
00159
00160 for (sect = ibfd.abfd->sections; sect; sect = sect->next) {
00161 if (sect->flags & SEC_CODE) {
00162 if (filepos_map[sect->name] != 0) {
00163 cerr << "Found section \"" << sect->name
00164 << "\" twice for " << get_filename()
00165 << endl;
00166 abort();
00167 }
00168
00169 filepos_map[sect->name] = sect->filepos;
00170
00171 if (sect->vma == 0 && strcmp(sect->name, ".text"))
00172 filtered_section.push_back(sect);
00173 }
00174 }
00175
00176 get_symbols(symbols);
00177
00178 out:
00179 add_symbols(symbols, symbol_filter);
00180 return;
00181 out_fail:
00182 ibfd.close();
00183 dbfd.close();
00184
00185 file_size = -1;
00186 goto out;
00187 }
00188
00189
00190 op_bfd::~op_bfd()
00191 {
00192 }
00193
00194
00195 unsigned long op_bfd::get_start_offset(bfd_vma vma) const
00196 {
00197 if (!vma || !ibfd.valid()) {
00198 filepos_map_t::const_iterator it = filepos_map.find(".text");
00199 if (it != filepos_map.end())
00200 return it->second;
00201 return 0;
00202 }
00203
00204 return 0;
00205 }
00206
00207
00208 void op_bfd::get_symbols(op_bfd::symbols_found_t & symbols)
00209 {
00210 ibfd.get_symbols();
00211
00212
00213
00214
00215
00216 has_debug_info();
00217
00218 dbfd.set_image_bfd_info(&ibfd);
00219 dbfd.get_symbols();
00220 if (dbfd.valid() && !ibfd.nr_syms)
00221 vma_adj = ibfd.abfd->start_address - dbfd.abfd->start_address;
00222 else
00223 vma_adj= 0;
00224
00225 size_t i;
00226 for (i = 0; i < ibfd.nr_syms; ++i) {
00227 if (!interesting_symbol(ibfd.syms[i]))
00228 continue;
00229 if (find(filtered_section.begin(), filtered_section.end(),
00230 ibfd.syms[i]->section) != filtered_section.end())
00231 continue;
00232 symbols.push_back(op_bfd_symbol(ibfd.syms[i]));
00233 }
00234
00235 for (i = 0; i < dbfd.nr_syms; ++i) {
00236 if (!interesting_symbol(dbfd.syms[i]))
00237 continue;
00238
00239
00240
00241
00242
00243 u32 filepos = filepos_map[dbfd.syms[i]->section->name];
00244 if (filepos != 0)
00245 dbfd.syms[i]->section->filepos = filepos;
00246 symbols.push_back(op_bfd_symbol(dbfd.syms[i]));
00247 }
00248
00249 symbols.sort();
00250
00251 symbols_found_t::iterator it = symbols.begin();
00252
00253
00254
00255 while (it != symbols.end()) {
00256 symbols_found_t::iterator temp = it;
00257 ++temp;
00258 if (temp != symbols.end() && (it->vma() == temp->vma()) &&
00259 (it->filepos() == temp->filepos())) {
00260 if (boring_symbol(*it, *temp)) {
00261 it = symbols.erase(it);
00262 } else {
00263 symbols.erase(temp);
00264 }
00265 } else {
00266 ++it;
00267 }
00268 }
00269
00270
00271
00272
00273 for (it = symbols.begin() ; it != symbols.end(); ++it) {
00274 op_bfd_symbol const * next = 0;
00275 symbols_found_t::iterator temp = it;
00276 ++temp;
00277 if (temp != symbols.end())
00278 next = &*temp;
00279 it->size(symbol_size(*it, next));
00280 }
00281 }
00282
00283
00284 void op_bfd::add_symbols(op_bfd::symbols_found_t & symbols,
00285 string_filter const & symbol_filter)
00286 {
00287
00288 if (symbols.empty())
00289 symbols.push_back(create_artificial_symbol());
00290
00291 cverb << vbfd << "number of symbols before filtering "
00292 << dec << symbols.size() << hex << endl;
00293
00294 symbols_found_t::iterator it;
00295 it = remove_if(symbols.begin(), symbols.end(),
00296 remove_filter(symbol_filter));
00297
00298 copy(symbols.begin(), it, back_inserter(syms));
00299
00300 cverb << vbfd << "number of symbols now "
00301 << dec << syms.size() << hex << endl;
00302 }
00303
00304
00305 bfd_vma op_bfd::offset_to_pc(bfd_vma offset) const
00306 {
00307 asection const * sect = ibfd.abfd->sections;
00308
00309 for (; sect; sect = sect->next) {
00310 if (offset >= bfd_vma(sect->filepos) &&
00311 (!sect->next || offset < bfd_vma(sect->next->filepos))) {
00312 return sect->vma + (offset - sect->filepos);
00313 }
00314 }
00315
00316 return 0;
00317 }
00318
00319 bool op_bfd::
00320 symbol_has_contents(symbol_index_t sym_idx)
00321 {
00322 op_bfd_symbol const & bfd_sym = syms[sym_idx];
00323 string const name = bfd_sym.name();
00324 if (name.size() == 0 || bfd_sym.artificial() || !ibfd.valid())
00325 return false;
00326 else
00327 return true;
00328 }
00329
00330 bool op_bfd::
00331 get_symbol_contents(symbol_index_t sym_index, unsigned char * contents) const
00332 {
00333 op_bfd_symbol const & bfd_sym = syms[sym_index];
00334 size_t size = bfd_sym.size();
00335
00336 if (!bfd_get_section_contents(ibfd.abfd, bfd_sym.symbol()->section,
00337 contents,
00338 static_cast<file_ptr>(bfd_sym.value()), size)) {
00339 return false;
00340 }
00341 return true;
00342 }
00343
00344 bool op_bfd::has_debug_info() const
00345 {
00346 if (debug_info.cached())
00347 return debug_info.get();
00348
00349 if (!ibfd.valid())
00350 return debug_info.reset(false);
00351
00352 if (ibfd.has_debug_info())
00353 return debug_info.reset(true);
00354
00355
00356
00357 if (find_separate_debug_file(ibfd.abfd, filename, debug_filename, extra_found_images)) {
00358 cverb << vbfd << "now loading: " << debug_filename << endl;
00359 dbfd.abfd = open_bfd(debug_filename);
00360 if (dbfd.has_debug_info())
00361 return debug_info.reset(true);
00362 }
00363
00364
00365 cverb << vbfd << "failed to process separate debug file "
00366 << debug_filename << endl;
00367
00368 return debug_info.reset(false);
00369 }
00370
00371
00372 bool op_bfd::get_linenr(symbol_index_t sym_idx, bfd_vma offset,
00373 string & source_filename, unsigned int & linenr) const
00374 {
00375 if (!has_debug_info())
00376 return false;
00377
00378 bfd_info const & b = dbfd.valid() ? dbfd : ibfd;
00379 op_bfd_symbol const & sym = syms[sym_idx];
00380
00381 linenr_info const info = find_nearest_line(b, sym, offset, anon_obj);
00382
00383 if (!info.found)
00384 return false;
00385
00386 source_filename = info.filename;
00387 linenr = info.line;
00388 return true;
00389 }
00390
00391
00392 size_t op_bfd::symbol_size(op_bfd_symbol const & sym,
00393 op_bfd_symbol const * next) const
00394 {
00395 unsigned long long start = sym.filepos();
00396 unsigned long long end;
00397
00398 if (next && (sym.section() != next->section()))
00399 end = sym.symbol_endpos();
00400 else
00401 end = next ? next->filepos() : sym.section()->filepos + file_size;
00402
00403 if (start > end)
00404 return 0;
00405
00406 return end - start;
00407 }
00408
00409
00410 void op_bfd::get_symbol_range(symbol_index_t sym_idx,
00411 unsigned long long & start, unsigned long long & end) const
00412 {
00413 op_bfd_symbol const & sym = syms[sym_idx];
00414
00415 bool const verbose = cverb << (vbfd & vlevel1);
00416
00417 if (anon_obj)
00418 start = sym.vma();
00419 else
00420 start = sym.filepos();
00421 end = start + sym.size();
00422
00423 if (!verbose)
00424 return;
00425
00426 io_state state(cverb << (vbfd & vlevel1));
00427
00428 cverb << (vbfd & vlevel1) << "symbol " << sym.name()
00429 << ", value " << hex << sym.value() << endl;
00430 cverb << (vbfd & vlevel1)
00431 << "start " << hex << start << ", end " << end << endl;
00432
00433 if (sym.symbol()) {
00434 cverb << (vbfd & vlevel1) << "in section "
00435 << sym.symbol()->section->name << ", filepos "
00436 << hex << sym.symbol()->section->filepos << endl;
00437 }
00438 }
00439
00440
00441 void op_bfd::get_vma_range(bfd_vma & start, bfd_vma & end) const
00442 {
00443 if (!syms.empty()) {
00444
00445
00446 op_bfd_symbol const & last_symb = syms[syms.size() - 1];
00447 start = syms[0].vma();
00448
00449 end = last_symb.vma() + last_symb.size() + (last_symb.size() != 0);
00450 } else {
00451 start = 0;
00452 end = file_size;
00453 }
00454 }
00455
00456
00457 op_bfd_symbol const op_bfd::create_artificial_symbol()
00458 {
00459
00460 bfd_vma start, end;
00461 get_vma_range(start, end);
00462 return op_bfd_symbol(start, end - start, get_filename());
00463 }
00464
00465
00466 string op_bfd::get_filename() const
00467 {
00468 return filename;
00469 }
00470
00471
00472 size_t op_bfd::bfd_arch_bits_per_address() const
00473 {
00474 if (ibfd.valid())
00475 return ::bfd_arch_bits_per_address(ibfd.abfd);
00476
00477
00478 return sizeof(bfd_vma);
00479 }