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
26struct spu_elf {
27	FILE * stream;
28	off_t spu_offset;
29};
30
31using namespace std;
32
33extern verbose vbfd;
34
35#ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS
36
37namespace {
38
39static void *
40spu_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
51static int
52spu_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
67static file_ptr
68spu_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
86bfd *
87spu_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