string const find_image_path(string const & archive_path, string const & image_name, extra_images const & extra_images, image_error & error) { error = image_ok; string const image = op_realpath(archive_path + image_name); // simplest case if (op_file_readable(image)) { error = image_ok; return image_name; } if (errno == EACCES) { error = image_unreadable; return image_name; } string const base = op_basename(image); vector<string> result = extra_images.find(base); // not found, try a module search if (result.empty()) result = extra_images.find(module_matcher(base + ".ko")); if (result.empty()) { error = image_not_found; return image_name; } if (result.size() > 1) { error = image_multiple_match; return image_name; } return result[0]; }
/* * valid filename are variations on: * * {kern}/name/event_spec * {root}/path/to/bin/{dep}/{root}/path/to/bin/event_spec * {root}/path/to/bin/{dep}/{anon:anon}/pid.start.end/event_spec * {root}/path/to/bin/{dep}/{anon:[vdso]}/pid.start.end/event_spec * {root}/path/to/bin/{dep}/{kern}/name/event_spec * {root}/path/to/bin/{dep}/{root}/path/to/bin/{cg}/{root}/path/to/bin/event_spec * * where /name/ denote a unique path component */ parsed_filename parse_filename(string const & filename, extra_images const & extra_found_images) { struct stat st; string::size_type pos = filename.find_last_of('/'); if (pos == string::npos) { throw invalid_argument("parse_filename() invalid filename: " + filename); } string event_spec = filename.substr(pos + 1); string filename_spec = filename.substr(0, pos); parsed_filename result = parse_event_spec(event_spec); result.filename = filename; vector<string> path = separate_token(filename_spec, '/'); remove_base_dir(path); // pp_interface PP:3.19 to PP:3.23 path must start either with {root} // or {kern} and we must found at least 2 component, remove_base_dir() // return an empty path if {root} or {kern} are not found if (path.size() < 2) { throw invalid_argument("parse_filename() invalid filename: " + filename); } size_t i; for (i = 1 ; i < path.size() ; ++i) { if (path[i] == "{dep}") break; result.image += "/" + path[i]; } if (i == path.size()) { throw invalid_argument("parse_filename() invalid filename: " + filename); } // skip "{dep}" ++i; // PP:3.19 {dep}/ must be followed by {kern}/, {root}/ or {anon}/ if (path[i] != "{kern}" && path[i] != "{root}" && path[i].find("{anon", 0) != 0) { throw invalid_argument("parse_filename() invalid filename: " + filename); } bool anon = path[i].find("{anon:", 0) == 0; // skip "{root}", "{kern}" or "{anon:.*}" ++i; for (; i < path.size(); ++i) { if (path[i] == "{cg}") break; if (anon) { pos = filename_spec.rfind('.'); pos = filename_spec.rfind('.', pos-1); if (pos == string::npos) { throw invalid_argument("parse_filename() pid.addr.addr name expected: " + filename_spec); } string jitdump = filename_spec.substr(0, pos) + ".jo"; // if a jitdump file exists, we point to this file if (!stat(jitdump.c_str(), &st)) { // later code assumes an optional prefix path // is stripped from the lib_image. result.lib_image = extra_found_images.strip_path_prefix(jitdump); result.jit_dumpfile_exists = true; } else { result.lib_image = parse_anon(path[i], path[i - 1]); } i++; break; } else { result.lib_image += "/" + path[i]; } } if (i == path.size()) return result; // skip "{cg}" ++i; if (i == path.size() || (path[i] != "{kern}" && path[i] != "{root}" && path[i].find("{anon", 0) != 0)) { throw invalid_argument("parse_filename() invalid filename: " + filename); } // skip "{root}", "{kern}" or "{anon}" anon = (path[i].find("{anon", 0) == 0); ++i; if (anon) { result.cg_image = parse_anon(path[i], path[i - 1]); i++; } else { for (; i < path.size(); ++i) result.cg_image += "/" + path[i]; } return result; }
/* * This overload of the op_bfd constructor is patterned after the * constructor in libutil++/op_bfd.cpp, with the additional processing * needed to handle an embedded spu offset. */ op_bfd::op_bfd(uint64_t spu_offset, string const & fname, string_filter const & symbol_filter, extra_images const & extra_images, bool & ok) : archive_path(extra_images.get_archive_path()), extra_found_images(extra_images), file_size(-1), embedding_filename(fname) { int fd; struct stat st; int notes_remaining; bool spu_note_found = false; size_t sec_size = 0; unsigned int oct_per_byte; asection * note = NULL; symbols_found_t symbols; asection const * sect; image_error image_ok; string const image_path = extra_images.find_image_path(fname, image_ok, true); cverb << vbfd << "op_bfd ctor for " << image_path << endl; if (!ok) goto out_fail; fd = open(image_path.c_str(), O_RDONLY); if (fd == -1) { cverb << vbfd << "open failed for " << image_path << endl; ok = false; goto out_fail; } if (fstat(fd, &st)) { cverb << vbfd << "stat failed for " << image_path << endl; ok = false; goto out_fail; } file_size = st.st_size; ibfd.abfd = spu_open_bfd(image_path, fd, spu_offset); if (!ibfd.valid()) { cverb << vbfd << "fdopen_bfd failed for " << image_path << endl; ok = false; goto out_fail; } /* For embedded SPU ELF, a note section named '.note.spu_name' * contains the name of the SPU binary image in the description * field. */ note = bfd_get_section_by_name(ibfd.abfd, ".note.spu_name"); if (!note) { cverb << vbfd << "No .note.spu-name section found" << endl; goto find_sec_code; } cverb << vbfd << "found .note.spu_name section" << endl; bfd_byte * sec_contents; oct_per_byte = bfd_octets_per_byte(ibfd.abfd); sec_size = bfd_section_size(ibfd.abfd, note)/oct_per_byte; sec_contents = (bfd_byte *) xmalloc(sec_size); if (!bfd_get_section_contents(ibfd.abfd, note, sec_contents, 0, sec_size)) { cverb << vbfd << "bfd_get_section_contents with size " << sec_size << " returned an error" << endl; ok = false; goto out_fail; } notes_remaining = sec_size; while (notes_remaining && !spu_note_found) { unsigned int nsize, dsize, type; nsize = *((unsigned int *) sec_contents); dsize = *((unsigned int *) sec_contents +1); type = *((unsigned int *) sec_contents +2); int remainder, desc_start, name_pad_length, desc_pad_length; name_pad_length = desc_pad_length = 0; /* Calculate padding for 4-byte alignment */ remainder = nsize % 4; if (remainder != 0) name_pad_length = 4 - remainder; desc_start = 12 + nsize + name_pad_length; if (type != 1) { int note_record_length; if ((remainder = (dsize % 4)) != 0) desc_pad_length = 4 - remainder; note_record_length = 12 + nsize + name_pad_length + dsize + desc_pad_length; notes_remaining -= note_record_length; sec_contents += note_record_length; continue; } else { spu_note_found = true; /* Must memcpy the data from sec_contents to a * 'char *' first, then stringify it, since * the type of sec_contents (bfd_byte *) cannot be * used as input for creating a string. */ char * description = (char *) xmalloc(dsize); memcpy(description, sec_contents + desc_start, dsize); filename = description; free(description); } } free(sec_contents); /* Default to app name for the image name */ if (spu_note_found == false) filename = fname; find_sec_code: for (sect = ibfd.abfd->sections; sect; sect = sect->next) { if (sect->flags & SEC_CODE) { if (filepos_map[sect->name] != 0) { cerr << "Found section \"" << sect->name << "\" twice for " << get_filename() << endl; abort(); } filepos_map[sect->name] = sect->filepos; } } get_symbols(symbols); /* In some cases the SPU library code generates code stubs on the stack. */ /* The kernel module remaps those addresses so add an entry to catch/report them. */ symbols.push_back(op_bfd_symbol(OP_SPU_DYN_FLAG, OP_SPU_MEMSIZE, "__send_to_ppe(stack)")); out: add_symbols(symbols, symbol_filter); return; out_fail: ibfd.close(); dbfd.close(); file_size = -1; goto out; }
op_bfd::op_bfd(string const & fname, string_filter const & symbol_filter, extra_images const & extra_images, bool & ok) : filename(fname), archive_path(extra_images.get_archive_path()), extra_found_images(extra_images), file_size(-1), anon_obj(false) { int fd; struct stat st; // after creating all symbol it's convenient for user code to access // symbols through a vector. We use an intermediate list to avoid a // O(N²) behavior when we will filter vector element below symbols_found_t symbols; asection const * sect; string suf = ".jo"; image_error img_ok; string const image_path = extra_images.find_image_path(filename, img_ok, true); cverb << vbfd << "op_bfd ctor for " << image_path << endl; // if there's a problem already, don't try to open it if (!ok || img_ok != image_ok) { cverb << vbfd << "can't locate " << image_path << endl; goto out_fail; } fd = open(image_path.c_str(), O_RDONLY); if (fd == -1) { cverb << vbfd << "open failed for " << image_path << endl; ok = false; goto out_fail; } if (fstat(fd, &st)) { cverb << vbfd << "stat failed for " << image_path << endl; ok = false; goto out_fail; } file_size = st.st_size; ibfd.abfd = fdopen_bfd(image_path, fd); if (!ibfd.valid()) { cverb << vbfd << "fdopen_bfd failed for " << image_path << endl; ok = false; goto out_fail; } string::size_type pos; pos = filename.rfind(suf); if (pos != string::npos && pos == filename.size() - suf.size()) anon_obj = true; // find .text and use it for (sect = ibfd.abfd->sections; sect; sect = sect->next) { if (sect->flags & SEC_CODE) { if (filepos_map[sect->name] != 0) { cerr << "Found section \"" << sect->name << "\" twice for " << get_filename() << endl; abort(); } filepos_map[sect->name] = sect->filepos; if (sect->vma == 0 && strcmp(sect->name, ".text")) filtered_section.push_back(sect); } } get_symbols(symbols); out: add_symbols(symbols, symbol_filter); return; out_fail: ibfd.close(); dbfd.close(); // make the fake symbol fit within the fake file file_size = -1; goto out; }