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