Home | History | Annotate | Download | only in libutil++
      1 /**
      2  * @file libutil++/bfd_spu_support.cpp
      3  * Special BFD functions for processing a Cell BE SPU profile
      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 #include "bfd_support.h"
     13 #include "op_bfd.h"
     14 #include "config.h"
     15 #include "cverb.h"
     16 
     17 #include <stdlib.h>
     18 #include <stdio.h>
     19 #include <iostream>
     20 #include <fstream>
     21 #include <sstream>
     22 #include <string>
     23 #include <cstring>
     24 #include <sys/types.h>
     25 
     26 struct spu_elf {
     27 	FILE * stream;
     28 	off_t spu_offset;
     29 };
     30 
     31 using namespace std;
     32 
     33 extern verbose vbfd;
     34 
     35 #ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS
     36 
     37 namespace {
     38 
     39 static void *
     40 spu_bfd_iovec_open(bfd * nbfd, void * open_closure)
     41 {
     42 	/* Checking nbfd isn't really necessary, except to silence
     43 	 * compile warning.  In fact, nbfd will always be non-NULL.
     44 	 */
     45 	if (nbfd)
     46 		return open_closure;
     47 	else
     48 		return NULL;
     49 }
     50 
     51 static int
     52 spu_bfd_iovec_close(bfd * nbfd, void * stream)
     53 {
     54 	spu_elf * my_stream = (spu_elf *) stream;
     55 
     56 	fclose(my_stream->stream);
     57 	free(my_stream);
     58 	/* Checking nbfd isn't really necessary, except to silence
     59 	 * compile warning.  In fact, nbfd will always be non-NULL.
     60 	 */
     61 	if (nbfd)
     62 		return 1;
     63 	else
     64 		return 0;
     65 }
     66 
     67 static file_ptr
     68 spu_bfd_iovec_pread(bfd * abfd, void * stream, void * buf,
     69 		    file_ptr nbytes, file_ptr offset)
     70 {
     71 	spu_elf * my_stream = (spu_elf *) stream;
     72 	fseek(my_stream->stream, my_stream->spu_offset + offset,
     73 	      SEEK_SET);
     74 	nbytes = fread(buf, sizeof(char), nbytes, my_stream->stream);
     75 	/* Checking abfd isn't really necessary, except to silence
     76 	 * compile warning.  In fact, abfd will always be non-NULL.
     77 	 */
     78 	if (abfd)
     79 		return nbytes;
     80 	else
     81 		return 0;
     82 }
     83 } // namespace anon
     84 #endif
     85 
     86 bfd *
     87 spu_open_bfd(string const name, int fd, uint64_t offset_to_spu_elf)
     88 {
     89 
     90 	bfd * nbfd = NULL;
     91 	spu_elf * spu_elf_stream = (spu_elf *)malloc(sizeof(spu_elf));
     92 
     93 	FILE * fp = fdopen(fd, "r");
     94 	spu_elf_stream->stream = fp;
     95 	spu_elf_stream->spu_offset = offset_to_spu_elf;
     96 #ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS
     97 	nbfd = bfd_openr_iovec(strdup(name.c_str()), "elf32-spu",
     98 			       spu_bfd_iovec_open, spu_elf_stream,
     99 			       spu_bfd_iovec_pread, spu_bfd_iovec_close, NULL);
    100 #else
    101 	ostringstream os;
    102 	os << "Attempt to process a Cell Broadband Engine SPU profile without"
    103 	   << "proper BFD support.\n"
    104 	   << "Rebuild the opreport utility with the correct BFD library.\n"
    105 	   << "See the OProfile user manual for more information.\n";
    106 	throw op_runtime_error(os.str());
    107 #endif
    108 	if (!nbfd) {
    109 		cverb << vbfd << "spu_open_bfd failed for " << name << endl;
    110 		return NULL;
    111 	}
    112 
    113 	bfd_check_format(nbfd, bfd_object);
    114 
    115 	return nbfd;
    116 }
    117