18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file libutil++/bfd_spu_support.cpp
38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Special BFD functions for processing a Cell BE SPU profile
48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2007 OProfile authors
68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING
78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Maynard Johnson
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * (C) Copyright IBM Corporation 2007
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "bfd_support.h"
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_bfd.h"
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "config.h"
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "cverb.h"
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <stdlib.h>
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <stdio.h>
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <iostream>
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <fstream>
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sstream>
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <string>
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstring>
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sys/types.h>
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstruct spu_elf {
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	FILE * stream;
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	off_t spu_offset;
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd};
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddusing namespace std;
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddextern verbose vbfd;
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddnamespace {
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void *
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspu_bfd_iovec_open(bfd * nbfd, void * open_closure)
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* Checking nbfd isn't really necessary, except to silence
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * compile warning.  In fact, nbfd will always be non-NULL.
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (nbfd)
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return open_closure;
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	else
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return NULL;
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspu_bfd_iovec_close(bfd * nbfd, void * stream)
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spu_elf * my_stream = (spu_elf *) stream;
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fclose(my_stream->stream);
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	free(my_stream);
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* Checking nbfd isn't really necessary, except to silence
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * compile warning.  In fact, nbfd will always be non-NULL.
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (nbfd)
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 1;
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	else
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 0;
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic file_ptr
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspu_bfd_iovec_pread(bfd * abfd, void * stream, void * buf,
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		    file_ptr nbytes, file_ptr offset)
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spu_elf * my_stream = (spu_elf *) stream;
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	fseek(my_stream->stream, my_stream->spu_offset + offset,
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	      SEEK_SET);
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	nbytes = fread(buf, sizeof(char), nbytes, my_stream->stream);
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* Checking abfd isn't really necessary, except to silence
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 * compile warning.  In fact, abfd will always be non-NULL.
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	 */
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (abfd)
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return nbytes;
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	else
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 0;
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} // namespace anon
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddbfd *
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddspu_open_bfd(string const name, int fd, uint64_t offset_to_spu_elf)
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	bfd * nbfd = NULL;
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spu_elf * spu_elf_stream = (spu_elf *)malloc(sizeof(spu_elf));
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	FILE * fp = fdopen(fd, "r");
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spu_elf_stream->stream = fp;
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	spu_elf_stream->spu_offset = offset_to_spu_elf;
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HAVE_BFD_OPENR_IOVEC_WITH_7PARMS
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	nbfd = bfd_openr_iovec(strdup(name.c_str()), "elf32-spu",
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			       spu_bfd_iovec_open, spu_elf_stream,
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			       spu_bfd_iovec_pread, spu_bfd_iovec_close, NULL);
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ostringstream os;
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	os << "Attempt to process a Cell Broadband Engine SPU profile without"
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   << "proper BFD support.\n"
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   << "Rebuild the opreport utility with the correct BFD library.\n"
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	   << "See the OProfile user manual for more information.\n";
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	throw op_runtime_error(os.str());
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!nbfd) {
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		cverb << vbfd << "spu_open_bfd failed for " << name << endl;
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return NULL;
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	bfd_check_format(nbfd, bfd_object);
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return nbfd;
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
117