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 186