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
32using namespace std;
33
34extern 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 */
41op_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
155find_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
176out:
177	add_symbols(symbols, symbol_filter);
178	return;
179out_fail:
180	ibfd.close();
181	dbfd.close();
182	file_size = -1;
183	goto out;
184}
185
186