1/**
2 * @file create_bfd.c
3 * Routine to handle elf file creation
4 *
5 * @remark Copyright 2007 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Jens Wilke
9 * @Modifications Maynard Johnson
10 * @Modifications Philippe Elie
11 * @Modifications Daniel Hansel
12 *
13 * Copyright IBM Corporation 2007
14 *
15 */
16
17#include "opjitconv.h"
18#include "opd_printf.h"
19#include "op_libiberty.h"
20
21#include <bfd.h>
22#include <stdint.h>
23#include <stdio.h>
24
25/* Create the symbols and fill the syms array for all functions
26 * from start_idx to end_idx pointing into entries_address_ascending array */
27static int fill_symtab(void)
28{
29	int rc = OP_JIT_CONV_OK;
30	u32 i;
31	int r;
32	struct jitentry const * e;
33	asymbol * s;
34	asection * section = NULL;
35
36	/* Check for valid value of entry_count to avoid integer overflow. */
37	if (entry_count > UINT32_MAX - 1) {
38		bfd_perror("invalid entry_count value");
39		rc = OP_JIT_CONV_FAIL;
40		goto out;
41	}
42
43	syms = xmalloc(sizeof(asymbol *) * (entry_count+1));
44	syms[entry_count] = NULL;
45	for (i = 0; i < entry_count; i++) {
46		e = entries_address_ascending[i];
47		if (e->section)
48			section = e->section;
49		s = bfd_make_empty_symbol(cur_bfd);
50		if (!s) {
51			bfd_perror("bfd_make_empty_symbol");
52			rc = OP_JIT_CONV_FAIL;
53			goto out;
54		}
55		s->name = e->symbol_name;
56		s->section = section;
57		s->flags = BSF_GLOBAL | BSF_FUNCTION;
58		s->value = e->vma - section->vma;
59		verbprintf(debug,"add sym: name=%s, value=%llx\n", s->name,
60			   (unsigned long long)s->value);
61		syms[i] = s;
62	}
63	r = bfd_set_symtab(cur_bfd, syms, entry_count);
64	if (r == FALSE) {
65		bfd_perror("bfd_set_symtab");
66		rc = OP_JIT_CONV_FAIL;
67	}
68out:
69	return rc;
70}
71
72/*
73 * create a new section.
74 */
75asection * create_section(bfd * abfd, char const * section_name,
76			  size_t size, bfd_vma vma, flagword flags)
77{
78	asection * section;
79
80	verbprintf(debug, "create_section() %s\n", section_name);
81	section = bfd_make_section(abfd, section_name);
82	if (section == NULL)  {
83		bfd_perror("bfd_make_section");
84		goto error;
85	}
86	if (bfd_set_section_vma(abfd, section, vma) == FALSE) {
87		bfd_perror("bfd_set_section_vma");
88		goto error;
89	}
90	if (bfd_set_section_size(abfd, section, size) == FALSE) {
91		bfd_perror("bfd_set_section_size");
92		goto error;
93	}
94	if (bfd_set_section_flags(abfd, section, flags) == FALSE) {
95		bfd_perror("bfd_set_section_flags");
96		goto error;
97	}
98	return section;
99error:
100	return NULL;
101}
102
103
104/* create a .text section. end_idx: index last jitentry (inclusive!)  */
105static int create_text_section(int start_idx, int end_idx)
106{
107	int rc = OP_JIT_CONV_OK;
108
109	asection * section;
110	char const * section_name;
111	int idx = start_idx;
112	unsigned long long vma_start =
113		entries_address_ascending[start_idx]->vma;
114	struct jitentry * ee = entries_address_ascending[end_idx];
115	unsigned long long vma_end = ee->vma + ee->code_size;
116	int size = vma_end - vma_start;
117
118	section_name = bfd_get_unique_section_name(cur_bfd, ".text", &idx);
119	verbprintf(debug, "section idx=%i, name=%s, vma_start=%llx, size=%i\n",
120		   idx, section_name, vma_start, size);
121
122	section = create_section(cur_bfd, section_name, size, vma_start,
123               SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_CODE|SEC_HAS_CONTENTS);
124	if (section)
125		entries_address_ascending[start_idx]->section = section;
126	else
127		rc = OP_JIT_CONV_FAIL;
128
129	return rc;
130}
131
132/* fill a section contents at a given offset from the start of the section */
133int fill_section_content(bfd * abfd, asection * section,
134			 void const * b, file_ptr offset, size_t sz)
135{
136	if (bfd_set_section_contents(abfd, section, b, offset, sz) == FALSE) {
137		bfd_perror("bfd_set_section_contents");
138		return OP_JIT_CONV_FAIL;
139	}
140	return OP_JIT_CONV_OK;
141}
142
143/*
144 * Copy all code of the functions that are within start_idx and end_idx to
145 * the section.
146 */
147static int fill_text_section_content(asection * section, int start_idx,
148				     int end_idx)
149{
150	int rc = OP_JIT_CONV_OK;
151	unsigned long long vma_start =
152		entries_address_ascending[start_idx]->vma;
153	struct jitentry const * e;
154	int i;
155
156	for (i = start_idx; i <= end_idx; i++) {
157		e = entries_address_ascending[i];
158		verbprintf(debug, "section = %s, i = %i, code = %llx,"
159			   " vma = %llx, offset = %llx,"
160			   "size = %i, name = %s\n",
161			   section->name, i,
162			   (unsigned long long) (uintptr_t) e->code,
163			   e->vma, e->vma - vma_start,
164			   e->code_size, e->symbol_name);
165		/* the right part that is created by split_entry may
166		 * have no code; also, the agent may have passed NULL
167		 * for the code location.
168		 */
169		if (e->code) {
170			rc = fill_section_content(cur_bfd, section,
171				e->code, (file_ptr) (e->vma - vma_start),
172				(bfd_size_type)e->code_size);
173			if (rc != OP_JIT_CONV_OK)
174				break;
175		}
176	}
177	return rc;
178}
179
180
181/* Walk over the symbols sorted by address and create ELF sections. Whenever we
182 * have a gap greater or equal to 4096 make a new section.
183 */
184int partition_sections(void)
185{
186	int rc = OP_JIT_CONV_OK;
187	u32 i, j;
188	struct jitentry const * pred;
189	struct jitentry const * entry;
190	unsigned long long end_addr;
191
192	// i: start index of the section
193	i = 0;
194	for (j = 1; j < entry_count; j++) {
195		entry = entries_address_ascending[j];
196		pred = entries_address_ascending[j - 1];
197		end_addr = pred->vma + pred->code_size;
198		// calculate gap between code, if it is more than one page
199		// create an additional section
200		if ((entry->vma - end_addr) >= 4096) {
201			rc = create_text_section(i, j - 1);
202			if (rc == OP_JIT_CONV_FAIL)
203				goto out;
204			i = j;
205		}
206	}
207	// this holds always if we have at least one jitentry
208	if (i < entry_count)
209		rc = create_text_section(i, entry_count - 1);
210out:
211	return rc;
212}
213
214
215/* Fill the code content into the sections created by partition_sections() */
216int fill_sections(void)
217{
218	int rc = OP_JIT_CONV_OK;
219	u32 i, j;
220	asection * section;
221
222	rc = fill_symtab();
223	if (rc == OP_JIT_CONV_FAIL)
224		goto out;
225
226	verbprintf(debug, "opjitconv: fill_sections\n");
227	i = 0;
228	for (j = 1; j < entry_count; j++) {
229		if (entries_address_ascending[j]->section) {
230			section = entries_address_ascending[i]->section;
231			rc = fill_text_section_content(section, i,
232						       j - 1);
233			if (rc == OP_JIT_CONV_FAIL)
234				goto out;
235			i = j;
236		}
237	}
238	// this holds always if we have at least one jitentry
239	if (i < entry_count) {
240		section = entries_address_ascending[i]->section;
241		rc = fill_text_section_content(section,
242					       i, entry_count - 1);
243	}
244out:
245	return rc;
246}
247
248
249/* create the elf file */
250bfd * open_elf(char const * filename)
251{
252	bfd * abfd;
253
254	abfd = bfd_openw(filename, dump_bfd_target_name);
255	if (!abfd) {
256		bfd_perror("bfd_openw");
257		goto error1;
258	}
259	if (bfd_set_format(abfd, bfd_object) == FALSE) {
260		bfd_perror("bfd_set_format");
261		goto error;
262	}
263	if (bfd_set_arch_mach(abfd, dump_bfd_arch, dump_bfd_mach) == FALSE) {
264		bfd_perror("bfd_set_format");
265		goto error;
266	}
267	return abfd;
268error:
269	bfd_close(abfd);
270error1:
271	return NULL;
272}
273