• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
op_bfd(uint64_t spu_offset,string const & fname,string_filter const & symbol_filter,extra_images const & extra_images,bool & ok)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