| /** |
| * @file libutil++/op_spu_bfd.cpp |
| * Encapsulation of bfd objects for Cell BE SPU |
| * |
| * @remark Copyright 2007 OProfile authors |
| * @remark Read the file COPYING |
| * |
| * @author Maynard Johnson |
| * (C) Copyright IBM Corporation 2007 |
| */ |
| |
| |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <cstdlib> |
| #include <cstring> |
| |
| #include <iostream> |
| #include <cstring> |
| #include <cstdlib> |
| |
| #include "op_bfd.h" |
| #include "locate_images.h" |
| #include "op_libiberty.h" |
| #include "string_filter.h" |
| #include "cverb.h" |
| |
| #define OP_SPU_DYN_FLAG 0x10000000 /* kernel module adds this offset */ |
| /* to SPU code it can't find in the map */ |
| #define OP_SPU_MEMSIZE 0x3ffff /* Physical memory size on an SPU */ |
| |
| using namespace std; |
| |
| extern verbose vbfd; |
| |
| /* |
| * 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), |
| anon_obj(false) |
| { |
| 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; |
| } |
| |