/** * @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 <stdio.h> #include <iostream> #include <fstream> #include <sstream> #include <string> #include <cstring> #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(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(bfd * nbfd, void * stream) { spu_elf * my_stream = (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(bfd * abfd, void * stream, void * buf, file_ptr nbytes, file_ptr offset) { spu_elf * my_stream = (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(string const name, int fd, uint64_t offset_to_spu_elf) { bfd * nbfd = NULL; spu_elf * spu_elf_stream = (spu_elf *)malloc(sizeof(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; }