Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame^] | 1 | /** |
| 2 | * @file libutil++/op_spu_bfd.cpp |
| 3 | * Encapsulation of bfd objects for Cell BE SPU |
| 4 | * |
| 5 | * @remark Copyright 2007 OProfile authors |
| 6 | * @remark Read the file COPYING |
| 7 | * |
| 8 | * @author Maynard Johnson |
| 9 | * (C) Copyright IBM Corporation 2007 |
| 10 | */ |
| 11 | |
| 12 | |
| 13 | #include <fcntl.h> |
| 14 | #include <sys/stat.h> |
| 15 | #include <cstdlib> |
| 16 | #include <cstring> |
| 17 | |
| 18 | #include <iostream> |
| 19 | #include <cstring> |
| 20 | #include <cstdlib> |
| 21 | |
| 22 | #include "op_bfd.h" |
| 23 | #include "locate_images.h" |
| 24 | #include "op_libiberty.h" |
| 25 | #include "string_filter.h" |
| 26 | #include "cverb.h" |
| 27 | |
| 28 | #define OP_SPU_DYN_FLAG 0x10000000 /* kernel module adds this offset */ |
| 29 | /* to SPU code it can't find in the map */ |
| 30 | #define OP_SPU_MEMSIZE 0x3ffff /* Physical memory size on an SPU */ |
| 31 | |
| 32 | using namespace std; |
| 33 | |
| 34 | extern verbose vbfd; |
| 35 | |
| 36 | /* |
| 37 | * This overload of the op_bfd constructor is patterned after the |
| 38 | * constructor in libutil++/op_bfd.cpp, with the additional processing |
| 39 | * needed to handle an embedded spu offset. |
| 40 | */ |
| 41 | op_bfd::op_bfd(uint64_t spu_offset, string const & fname, |
| 42 | string_filter const & symbol_filter, |
| 43 | extra_images const & extra_images, bool & ok) |
| 44 | : |
| 45 | archive_path(extra_images.get_archive_path()), |
| 46 | extra_found_images(extra_images), |
| 47 | file_size(-1), |
| 48 | embedding_filename(fname), |
| 49 | anon_obj(false) |
| 50 | { |
| 51 | int fd; |
| 52 | struct stat st; |
| 53 | int notes_remaining; |
| 54 | bool spu_note_found = false; |
| 55 | size_t sec_size = 0; |
| 56 | unsigned int oct_per_byte; |
| 57 | asection * note = NULL; |
| 58 | |
| 59 | symbols_found_t symbols; |
| 60 | asection const * sect; |
| 61 | |
| 62 | image_error image_ok; |
| 63 | string const image_path = |
| 64 | extra_images.find_image_path(fname, image_ok, true); |
| 65 | |
| 66 | cverb << vbfd << "op_bfd ctor for " << image_path << endl; |
| 67 | if (!ok) |
| 68 | goto out_fail; |
| 69 | |
| 70 | fd = open(image_path.c_str(), O_RDONLY); |
| 71 | if (fd == -1) { |
| 72 | cverb << vbfd << "open failed for " << image_path << endl; |
| 73 | ok = false; |
| 74 | goto out_fail; |
| 75 | } |
| 76 | |
| 77 | if (fstat(fd, &st)) { |
| 78 | cverb << vbfd << "stat failed for " << image_path << endl; |
| 79 | ok = false; |
| 80 | goto out_fail; |
| 81 | } |
| 82 | |
| 83 | file_size = st.st_size; |
| 84 | ibfd.abfd = spu_open_bfd(image_path, fd, spu_offset); |
| 85 | |
| 86 | if (!ibfd.valid()) { |
| 87 | cverb << vbfd << "fdopen_bfd failed for " << image_path << endl; |
| 88 | ok = false; |
| 89 | goto out_fail; |
| 90 | } |
| 91 | |
| 92 | /* For embedded SPU ELF, a note section named '.note.spu_name' |
| 93 | * contains the name of the SPU binary image in the description |
| 94 | * field. |
| 95 | */ |
| 96 | note = bfd_get_section_by_name(ibfd.abfd, ".note.spu_name"); |
| 97 | if (!note) { |
| 98 | cverb << vbfd << "No .note.spu-name section found" << endl; |
| 99 | goto find_sec_code; |
| 100 | } |
| 101 | cverb << vbfd << "found .note.spu_name section" << endl; |
| 102 | |
| 103 | bfd_byte * sec_contents; |
| 104 | oct_per_byte = bfd_octets_per_byte(ibfd.abfd); |
| 105 | sec_size = bfd_section_size(ibfd.abfd, note)/oct_per_byte; |
| 106 | |
| 107 | sec_contents = (bfd_byte *) xmalloc(sec_size); |
| 108 | if (!bfd_get_section_contents(ibfd.abfd, note, sec_contents, |
| 109 | 0, sec_size)) { |
| 110 | cverb << vbfd << "bfd_get_section_contents with size " |
| 111 | << sec_size << " returned an error" << endl; |
| 112 | ok = false; |
| 113 | goto out_fail; |
| 114 | } |
| 115 | notes_remaining = sec_size; |
| 116 | while (notes_remaining && !spu_note_found) { |
| 117 | unsigned int nsize, dsize, type; |
| 118 | nsize = *((unsigned int *) sec_contents); |
| 119 | dsize = *((unsigned int *) sec_contents +1); |
| 120 | type = *((unsigned int *) sec_contents +2); |
| 121 | int remainder, desc_start, name_pad_length, desc_pad_length; |
| 122 | name_pad_length = desc_pad_length = 0; |
| 123 | /* Calculate padding for 4-byte alignment */ |
| 124 | remainder = nsize % 4; |
| 125 | if (remainder != 0) |
| 126 | name_pad_length = 4 - remainder; |
| 127 | desc_start = 12 + nsize + name_pad_length; |
| 128 | if (type != 1) { |
| 129 | int note_record_length; |
| 130 | if ((remainder = (dsize % 4)) != 0) |
| 131 | desc_pad_length = 4 - remainder; |
| 132 | note_record_length = 12 + nsize + |
| 133 | name_pad_length + dsize + desc_pad_length; |
| 134 | notes_remaining -= note_record_length; |
| 135 | sec_contents += note_record_length; |
| 136 | continue; |
| 137 | } else { |
| 138 | spu_note_found = true; |
| 139 | /* Must memcpy the data from sec_contents to a |
| 140 | * 'char *' first, then stringify it, since |
| 141 | * the type of sec_contents (bfd_byte *) cannot be |
| 142 | * used as input for creating a string. |
| 143 | */ |
| 144 | char * description = (char *) xmalloc(dsize); |
| 145 | memcpy(description, sec_contents + desc_start, dsize); |
| 146 | filename = description; |
| 147 | free(description); |
| 148 | } |
| 149 | } |
| 150 | free(sec_contents); |
| 151 | /* Default to app name for the image name */ |
| 152 | if (spu_note_found == false) |
| 153 | filename = fname; |
| 154 | |
| 155 | find_sec_code: |
| 156 | for (sect = ibfd.abfd->sections; sect; sect = sect->next) { |
| 157 | if (sect->flags & SEC_CODE) { |
| 158 | if (filepos_map[sect->name] != 0) { |
| 159 | cerr << "Found section \"" << sect->name |
| 160 | << "\" twice for " << get_filename() |
| 161 | << endl; |
| 162 | abort(); |
| 163 | } |
| 164 | |
| 165 | filepos_map[sect->name] = sect->filepos; |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | get_symbols(symbols); |
| 170 | |
| 171 | /* In some cases the SPU library code generates code stubs on the stack. */ |
| 172 | /* The kernel module remaps those addresses so add an entry to catch/report them. */ |
| 173 | symbols.push_back(op_bfd_symbol(OP_SPU_DYN_FLAG, OP_SPU_MEMSIZE, |
| 174 | "__send_to_ppe(stack)")); |
| 175 | |
| 176 | out: |
| 177 | add_symbols(symbols, symbol_filter); |
| 178 | return; |
| 179 | out_fail: |
| 180 | ibfd.close(); |
| 181 | dbfd.close(); |
| 182 | file_size = -1; |
| 183 | goto out; |
| 184 | } |
| 185 | |