/** * @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; }