186 lines
4.9 KiB
C++
186 lines
4.9 KiB
C++
/**
|
|
* @file libutil++/op_spu_bfd.cpp
|
|
* Encapsulation of bfd objects for Cell BE SPU
|
|
*
|
|
* @remark Copyright 2007 OProfile authors
|
|
* @remark Read the file COPYING
|
|
*
|
|
* @author Maynard Johnson
|
|
* (C) Copyright IBM Corporation 2007
|
|
*/
|
|
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include <iostream>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
|
|
#include "op_bfd.h"
|
|
#include "locate_images.h"
|
|
#include "op_libiberty.h"
|
|
#include "string_filter.h"
|
|
#include "cverb.h"
|
|
|
|
#define OP_SPU_DYN_FLAG 0x10000000 /* kernel module adds this offset */
|
|
/* to SPU code it can't find in the map */
|
|
#define OP_SPU_MEMSIZE 0x3ffff /* Physical memory size on an SPU */
|
|
|
|
using namespace std;
|
|
|
|
extern verbose vbfd;
|
|
|
|
/*
|
|
* This overload of the op_bfd constructor is patterned after the
|
|
* constructor in libutil++/op_bfd.cpp, with the additional processing
|
|
* needed to handle an embedded spu offset.
|
|
*/
|
|
op_bfd::op_bfd(uint64_t spu_offset, string const & fname,
|
|
string_filter const & symbol_filter,
|
|
extra_images const & extra_images, bool & ok)
|
|
:
|
|
archive_path(extra_images.get_archive_path()),
|
|
extra_found_images(extra_images),
|
|
file_size(-1),
|
|
embedding_filename(fname),
|
|
anon_obj(false)
|
|
{
|
|
int fd;
|
|
struct stat st;
|
|
int notes_remaining;
|
|
bool spu_note_found = false;
|
|
size_t sec_size = 0;
|
|
unsigned int oct_per_byte;
|
|
asection * note = NULL;
|
|
|
|
symbols_found_t symbols;
|
|
asection const * sect;
|
|
|
|
image_error image_ok;
|
|
string const image_path =
|
|
extra_images.find_image_path(fname, image_ok, true);
|
|
|
|
cverb << vbfd << "op_bfd ctor for " << image_path << endl;
|
|
if (!ok)
|
|
goto out_fail;
|
|
|
|
fd = open(image_path.c_str(), O_RDONLY);
|
|
if (fd == -1) {
|
|
cverb << vbfd << "open failed for " << image_path << endl;
|
|
ok = false;
|
|
goto out_fail;
|
|
}
|
|
|
|
if (fstat(fd, &st)) {
|
|
cverb << vbfd << "stat failed for " << image_path << endl;
|
|
ok = false;
|
|
goto out_fail;
|
|
}
|
|
|
|
file_size = st.st_size;
|
|
ibfd.abfd = spu_open_bfd(image_path, fd, spu_offset);
|
|
|
|
if (!ibfd.valid()) {
|
|
cverb << vbfd << "fdopen_bfd failed for " << image_path << endl;
|
|
ok = false;
|
|
goto out_fail;
|
|
}
|
|
|
|
/* For embedded SPU ELF, a note section named '.note.spu_name'
|
|
* contains the name of the SPU binary image in the description
|
|
* field.
|
|
*/
|
|
note = bfd_get_section_by_name(ibfd.abfd, ".note.spu_name");
|
|
if (!note) {
|
|
cverb << vbfd << "No .note.spu-name section found" << endl;
|
|
goto find_sec_code;
|
|
}
|
|
cverb << vbfd << "found .note.spu_name section" << endl;
|
|
|
|
bfd_byte * sec_contents;
|
|
oct_per_byte = bfd_octets_per_byte(ibfd.abfd);
|
|
sec_size = bfd_section_size(ibfd.abfd, note)/oct_per_byte;
|
|
|
|
sec_contents = (bfd_byte *) xmalloc(sec_size);
|
|
if (!bfd_get_section_contents(ibfd.abfd, note, sec_contents,
|
|
0, sec_size)) {
|
|
cverb << vbfd << "bfd_get_section_contents with size "
|
|
<< sec_size << " returned an error" << endl;
|
|
ok = false;
|
|
goto out_fail;
|
|
}
|
|
notes_remaining = sec_size;
|
|
while (notes_remaining && !spu_note_found) {
|
|
unsigned int nsize, dsize, type;
|
|
nsize = *((unsigned int *) sec_contents);
|
|
dsize = *((unsigned int *) sec_contents +1);
|
|
type = *((unsigned int *) sec_contents +2);
|
|
int remainder, desc_start, name_pad_length, desc_pad_length;
|
|
name_pad_length = desc_pad_length = 0;
|
|
/* Calculate padding for 4-byte alignment */
|
|
remainder = nsize % 4;
|
|
if (remainder != 0)
|
|
name_pad_length = 4 - remainder;
|
|
desc_start = 12 + nsize + name_pad_length;
|
|
if (type != 1) {
|
|
int note_record_length;
|
|
if ((remainder = (dsize % 4)) != 0)
|
|
desc_pad_length = 4 - remainder;
|
|
note_record_length = 12 + nsize +
|
|
name_pad_length + dsize + desc_pad_length;
|
|
notes_remaining -= note_record_length;
|
|
sec_contents += note_record_length;
|
|
continue;
|
|
} else {
|
|
spu_note_found = true;
|
|
/* Must memcpy the data from sec_contents to a
|
|
* 'char *' first, then stringify it, since
|
|
* the type of sec_contents (bfd_byte *) cannot be
|
|
* used as input for creating a string.
|
|
*/
|
|
char * description = (char *) xmalloc(dsize);
|
|
memcpy(description, sec_contents + desc_start, dsize);
|
|
filename = description;
|
|
free(description);
|
|
}
|
|
}
|
|
free(sec_contents);
|
|
/* Default to app name for the image name */
|
|
if (spu_note_found == false)
|
|
filename = fname;
|
|
|
|
find_sec_code:
|
|
for (sect = ibfd.abfd->sections; sect; sect = sect->next) {
|
|
if (sect->flags & SEC_CODE) {
|
|
if (filepos_map[sect->name] != 0) {
|
|
cerr << "Found section \"" << sect->name
|
|
<< "\" twice for " << get_filename()
|
|
<< endl;
|
|
abort();
|
|
}
|
|
|
|
filepos_map[sect->name] = sect->filepos;
|
|
}
|
|
}
|
|
|
|
get_symbols(symbols);
|
|
|
|
/* In some cases the SPU library code generates code stubs on the stack. */
|
|
/* The kernel module remaps those addresses so add an entry to catch/report them. */
|
|
symbols.push_back(op_bfd_symbol(OP_SPU_DYN_FLAG, OP_SPU_MEMSIZE,
|
|
"__send_to_ppe(stack)"));
|
|
|
|
out:
|
|
add_symbols(symbols, symbol_filter);
|
|
return;
|
|
out_fail:
|
|
ibfd.close();
|
|
dbfd.close();
|
|
file_size = -1;
|
|
goto out;
|
|
}
|
|
|