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