Home | History | Annotate | Download | only in libutil++
      1 /**
      2  * @file libutil++/op_spu_bfd.cpp
      3  * Encapsulation of bfd objects for Cell BE SPU
      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 
     13 #include <fcntl.h>
     14 #include <sys/stat.h>
     15 #include <cstdlib>
     16 #include <cstring>
     17 
     18 #include <iostream>
     19 #include <cstring>
     20 #include <cstdlib>
     21 
     22 #include "op_bfd.h"
     23 #include "locate_images.h"
     24 #include "op_libiberty.h"
     25 #include "string_filter.h"
     26 #include "cverb.h"
     27 
     28 #define OP_SPU_DYN_FLAG		0x10000000	/* kernel module adds this offset */
     29 						/* to SPU code it can't find in the map */
     30 #define OP_SPU_MEMSIZE		0x3ffff		/* Physical memory size on an SPU */
     31 
     32 using namespace std;
     33 
     34 extern verbose vbfd;
     35 
     36 /*
     37  * This overload of the op_bfd constructor is patterned after the
     38  * constructor in libutil++/op_bfd.cpp, with the additional processing
     39  * needed to handle an embedded spu offset.
     40  */
     41 op_bfd::op_bfd(uint64_t spu_offset, string const & fname,
     42 	       string_filter const & symbol_filter,
     43 	       extra_images const & extra_images, bool & ok)
     44 	:
     45 	archive_path(extra_images.get_archive_path()),
     46 	extra_found_images(extra_images),
     47 	file_size(-1),
     48 	embedding_filename(fname),
     49 	anon_obj(false)
     50 {
     51 	int fd;
     52 	struct stat st;
     53 	int notes_remaining;
     54 	bool spu_note_found = false;
     55 	size_t sec_size = 0;
     56 	unsigned int oct_per_byte;
     57 	asection * note = NULL;
     58 
     59 	symbols_found_t symbols;
     60 	asection const * sect;
     61 
     62 	image_error image_ok;
     63 	string const image_path =
     64 		extra_images.find_image_path(fname, image_ok, true);
     65 
     66 	cverb << vbfd << "op_bfd ctor for " << image_path << endl;
     67 	if (!ok)
     68 		goto out_fail;
     69 
     70 	fd = open(image_path.c_str(), O_RDONLY);
     71 	if (fd == -1) {
     72 		cverb << vbfd << "open failed for " << image_path << endl;
     73 		ok = false;
     74 		goto out_fail;
     75 	}
     76 
     77 	if (fstat(fd, &st)) {
     78 		cverb << vbfd << "stat failed for " << image_path << endl;
     79 		ok = false;
     80 		goto out_fail;
     81 	}
     82 
     83 	file_size = st.st_size;
     84 	ibfd.abfd = spu_open_bfd(image_path, fd, spu_offset);
     85 
     86 	if (!ibfd.valid()) {
     87 		cverb << vbfd << "fdopen_bfd failed for " << image_path << endl;
     88 		ok = false;
     89 		goto out_fail;
     90 	}
     91 
     92 	/* For embedded SPU ELF, a note section named '.note.spu_name'
     93 	 * contains the name of the SPU binary image in the description
     94 	 * field.
     95 	 */
     96 	note = bfd_get_section_by_name(ibfd.abfd, ".note.spu_name");
     97 	if (!note) {
     98 		cverb << vbfd << "No .note.spu-name section found" << endl;
     99 		goto find_sec_code;
    100 	}
    101 	cverb << vbfd << "found .note.spu_name section" << endl;
    102 
    103 	bfd_byte * sec_contents;
    104 	oct_per_byte = bfd_octets_per_byte(ibfd.abfd);
    105 	sec_size = bfd_section_size(ibfd.abfd, note)/oct_per_byte;
    106 
    107 	sec_contents = (bfd_byte *) xmalloc(sec_size);
    108 	if (!bfd_get_section_contents(ibfd.abfd, note, sec_contents,
    109 				      0, sec_size)) {
    110 		cverb << vbfd << "bfd_get_section_contents with size "
    111 		      << sec_size << " returned an error" << endl;
    112 		ok = false;
    113 		goto out_fail;
    114 	}
    115 	notes_remaining = sec_size;
    116 	while (notes_remaining && !spu_note_found) {
    117 		unsigned int  nsize, dsize, type;
    118 		nsize = *((unsigned int *) sec_contents);
    119 		dsize = *((unsigned int *) sec_contents +1);
    120 		type = *((unsigned int *) sec_contents +2);
    121 		int remainder, desc_start, name_pad_length, desc_pad_length;
    122 		name_pad_length = desc_pad_length = 0;
    123 		/* Calculate padding for 4-byte alignment */
    124 		remainder = nsize % 4;
    125 		if (remainder != 0)
    126 			name_pad_length = 4 - remainder;
    127 		desc_start = 12 + nsize + name_pad_length;
    128 		if (type != 1) {
    129 			int note_record_length;
    130 			if ((remainder = (dsize % 4)) != 0)
    131 				desc_pad_length = 4 - remainder;
    132 			note_record_length = 12 + nsize +
    133 				name_pad_length + dsize + desc_pad_length;
    134 			notes_remaining -= note_record_length;
    135 			sec_contents += note_record_length;
    136 			continue;
    137 		} else {
    138 			spu_note_found = true;
    139 			/* Must memcpy the data from sec_contents to a
    140 			 * 'char *' first, then stringify it, since
    141 			 * the type of sec_contents (bfd_byte *) cannot be
    142 			 * used as input for creating a string.
    143 			 */
    144 			char * description = (char *) xmalloc(dsize);
    145 			memcpy(description, sec_contents + desc_start, dsize);
    146 			filename = description;
    147 			free(description);
    148 		}
    149 	}
    150 	free(sec_contents);
    151 	/* Default to app name for the image name */
    152 	if (spu_note_found == false)
    153 		filename = fname;
    154 
    155 find_sec_code:
    156 	for (sect = ibfd.abfd->sections; sect; sect = sect->next) {
    157 		if (sect->flags & SEC_CODE) {
    158 			if (filepos_map[sect->name] != 0) {
    159 				cerr << "Found section \"" << sect->name
    160 				     << "\" twice for " << get_filename()
    161 				     << endl;
    162 				abort();
    163 			}
    164 
    165 			filepos_map[sect->name] = sect->filepos;
    166 		}
    167 	}
    168 
    169 	get_symbols(symbols);
    170 
    171 	/* In some cases the SPU library code generates code stubs on the stack. */
    172 	/* The kernel module remaps those addresses so add an entry to catch/report them. */
    173 	symbols.push_back(op_bfd_symbol(OP_SPU_DYN_FLAG, OP_SPU_MEMSIZE,
    174 			  "__send_to_ppe(stack)"));
    175 
    176 out:
    177 	add_symbols(symbols, symbol_filter);
    178 	return;
    179 out_fail:
    180 	ibfd.close();
    181 	dbfd.close();
    182 	file_size = -1;
    183 	goto out;
    184 }
    185 
    186