From: Maynard J. <may...@us...> - 2007-05-10 23:54:35
|
Update of /cvsroot/oprofile/oprofile/libutil++ In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv28094/libutil++ Modified Files: Makefile.am bfd_support.h op_bfd.h Added Files: bfd_spu_support.cpp op_spu_bfd.cpp Log Message: Patch 3 of 3: Add support for Cell BE SPU profiling (post-processing) --- NEW FILE: bfd_spu_support.cpp --- /** * @file libutil++/bfd_spu_support.cpp * Special BFD functions for processing a Cell BE SPU profile * * @remark Copyright 2007 OProfile authors * @remark Read the file COPYING * * @author Maynard Johnson * (C) Copyright IBM Corporation 2007 */ #include "bfd_support.h" #include "op_bfd.h" #include "config.h" #include "cverb.h" #include <stdlib.h> #include <iostream> #include <fstream> #include <sstream> #include <string> #include <sys/types.h> struct spu_elf { FILE * stream; off_t spu_offset; }; using namespace std; extern verbose vbfd; #ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS namespace { static void * spu_bfd_iovec_open(struct bfd * nbfd, void * open_closure) { /* Checking nbfd isn't really necessary, except to silence * compile warning. In fact, nbfd will always be non-NULL. */ if (nbfd) return open_closure; else return NULL; } static int spu_bfd_iovec_close(struct bfd * nbfd, void * stream) { struct spu_elf * my_stream = (struct spu_elf *) stream; fclose(my_stream->stream); free(my_stream); /* Checking nbfd isn't really necessary, except to silence * compile warning. In fact, nbfd will always be non-NULL. */ if (nbfd) return 1; else return 0; } static file_ptr spu_bfd_iovec_pread(struct bfd * abfd, void * stream, void * buf, file_ptr nbytes, file_ptr offset) { struct spu_elf * my_stream = (struct spu_elf *) stream; fseek(my_stream->stream, my_stream->spu_offset + offset, SEEK_SET); nbytes = fread(buf, sizeof(char), nbytes, my_stream->stream); /* Checking abfd isn't really necessary, except to silence * compile warning. In fact, abfd will always be non-NULL. */ if (abfd) return nbytes; else return 0; } } // namespace anon #endif bfd * spu_open_bfd(std::string const name, int fd, uint64_t offset_to_spu_elf) { struct bfd * nbfd = NULL; struct spu_elf * spu_elf_stream = (struct spu_elf *) malloc(sizeof(struct spu_elf)); FILE * fp = fdopen(fd, "r"); spu_elf_stream->stream = fp; spu_elf_stream->spu_offset = offset_to_spu_elf; #ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS nbfd = bfd_openr_iovec(strdup(name.c_str()), "elf32-spu", spu_bfd_iovec_open, spu_elf_stream, spu_bfd_iovec_pread, spu_bfd_iovec_close, NULL); #else ostringstream os; os << "Attempt to process a Cell Broadband Engine SPU profile without" << "proper BFD support.\n" << "Rebuild the opreport utility with the correct BFD library.\n" << "See the OProfile user manual for more information.\n"; throw op_runtime_error(os.str()); #endif if (!nbfd) { cverb << vbfd << "spu_open_bfd failed for " << name << endl; return NULL; } bfd_check_format(nbfd, bfd_object); return nbfd; } --- NEW FILE: op_spu_bfd.cpp --- /** * @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 <iostream> #include "op_bfd.h" #include "op_libiberty.h" #include "string_filter.h" #include "cverb.h" 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(string const & archive, uint64_t spu_offset, string const & fname, string_filter const & symbol_filter, bool & ok) : archive_path(archive), 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; string const image_path = archive_path + fname; 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); out: add_symbols(symbols, symbol_filter); return; out_fail: ibfd.close(); dbfd.close(); file_size = -1; goto out; } Index: Makefile.am =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/Makefile.am,v retrieving revision 1.21 retrieving revision 1.22 diff -u -p -d -r1.21 -r1.22 --- Makefile.am 6 Feb 2007 17:00:55 -0000 1.21 +++ Makefile.am 10 May 2007 23:54:35 -0000 1.22 @@ -37,4 +37,6 @@ libutil___a_SOURCES = \ cached_value.h \ comma_list.h \ xml_output.h \ - xml_output.cpp + xml_output.cpp \ + bfd_spu_support.cpp \ + op_spu_bfd.cpp Index: bfd_support.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/bfd_support.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -p -d -r1.2 -r1.3 --- bfd_support.h 17 Aug 2005 00:15:58 -0000 1.2 +++ bfd_support.h 10 May 2007 23:54:35 -0000 1.3 @@ -93,6 +93,9 @@ bfd * open_bfd(std::string const & file) /// open the given BFD from the fd bfd * fdopen_bfd(std::string const & file, int fd); +/// Return a BFD for an SPU ELF embedded in PPE binary file +bfd * spu_open_bfd(std::string const name, int fd, uint64_t offset_to_spu_elf); + /// Return true if the symbol is worth looking at bool interesting_symbol(asymbol * sym); Index: op_bfd.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libutil++/op_bfd.h,v retrieving revision 1.40 retrieving revision 1.41 diff -u -p -d -r1.40 -r1.41 --- op_bfd.h 17 Nov 2006 23:47:29 -0000 1.40 +++ op_bfd.h 10 May 2007 23:54:35 -0000 1.41 @@ -101,6 +101,18 @@ public: string_filter const & symbol_filter, bool & ok); + /** + * This constructor is used when processing an SPU profile + * where the SPU ELF is embedded within the PPE binary. + */ + op_bfd(std::string const & archive_path, + uint64_t spu_offset, + std::string const & filename, + string_filter const & symbol_filter, + bool & ok); + + std::string get_embedding_filename() const { return embedding_filename; } + /// close an opened bfd image and free all related resources ~op_bfd(); @@ -252,6 +264,12 @@ private: typedef std::map<std::string, u32> filepos_map_t; // mapping of section names to filepos in the original binary filepos_map_t filepos_map; + + /** + * If spu_offset is non-zero, embedding_filename is the file containing + * the embedded SPU image. + */ + std::string embedding_filename; }; |