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 *
spu_bfd_iovec_open(bfd * nbfd,void * open_closure)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
spu_bfd_iovec_close(bfd * nbfd,void * stream)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
spu_bfd_iovec_pread(bfd * abfd,void * stream,void * buf,file_ptr nbytes,file_ptr offset)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 *
spu_open_bfd(string const name,int fd,uint64_t offset_to_spu_elf)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