xref: /openbmc/linux/tools/perf/util/genelf_debug.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
16d8a639aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2598b7c69SStephane Eranian /*
3598b7c69SStephane Eranian  * genelf_debug.c
4598b7c69SStephane Eranian  * Copyright (C) 2015, Google, Inc
5598b7c69SStephane Eranian  *
6598b7c69SStephane Eranian  * Contributed by:
7598b7c69SStephane Eranian  * 	Stephane Eranian <eranian@google.com>
8598b7c69SStephane Eranian  *
9598b7c69SStephane Eranian  * based on GPLv2 source code from Oprofile
10598b7c69SStephane Eranian  * @remark Copyright 2007 OProfile authors
11598b7c69SStephane Eranian  * @author Philippe Elie
12598b7c69SStephane Eranian  */
13c9f5da74SArnaldo Carvalho de Melo #include <linux/compiler.h>
14*e413f9f1SArnaldo Carvalho de Melo #include <linux/zalloc.h>
15598b7c69SStephane Eranian #include <sys/types.h>
16598b7c69SStephane Eranian #include <stdio.h>
17598b7c69SStephane Eranian #include <getopt.h>
18598b7c69SStephane Eranian #include <stddef.h>
19598b7c69SStephane Eranian #include <libelf.h>
20598b7c69SStephane Eranian #include <string.h>
21598b7c69SStephane Eranian #include <stdlib.h>
22598b7c69SStephane Eranian #include <inttypes.h>
23598b7c69SStephane Eranian #include <limits.h>
24598b7c69SStephane Eranian #include <fcntl.h>
25598b7c69SStephane Eranian #include <err.h>
26598b7c69SStephane Eranian #include <dwarf.h>
27598b7c69SStephane Eranian 
28598b7c69SStephane Eranian #include "genelf.h"
29598b7c69SStephane Eranian #include "../util/jitdump.h"
30598b7c69SStephane Eranian 
31598b7c69SStephane Eranian #define BUFFER_EXT_DFL_SIZE	(4 * 1024)
32598b7c69SStephane Eranian 
33598b7c69SStephane Eranian typedef uint32_t uword;
34598b7c69SStephane Eranian typedef uint16_t uhalf;
35598b7c69SStephane Eranian typedef int32_t  sword;
36598b7c69SStephane Eranian typedef int16_t  shalf;
37598b7c69SStephane Eranian typedef uint8_t  ubyte;
38598b7c69SStephane Eranian typedef int8_t   sbyte;
39598b7c69SStephane Eranian 
40598b7c69SStephane Eranian struct buffer_ext {
41598b7c69SStephane Eranian 	size_t cur_pos;
42598b7c69SStephane Eranian 	size_t max_sz;
43598b7c69SStephane Eranian 	void *data;
44598b7c69SStephane Eranian };
45598b7c69SStephane Eranian 
46598b7c69SStephane Eranian static void
buffer_ext_dump(struct buffer_ext * be,const char * msg)47598b7c69SStephane Eranian buffer_ext_dump(struct buffer_ext *be, const char *msg)
48598b7c69SStephane Eranian {
49598b7c69SStephane Eranian 	size_t i;
50598b7c69SStephane Eranian 	warnx("DUMP for %s", msg);
51598b7c69SStephane Eranian 	for (i = 0 ; i < be->cur_pos; i++)
52598b7c69SStephane Eranian 		warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
53598b7c69SStephane Eranian }
54598b7c69SStephane Eranian 
55598b7c69SStephane Eranian static inline int
buffer_ext_add(struct buffer_ext * be,void * addr,size_t sz)56598b7c69SStephane Eranian buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
57598b7c69SStephane Eranian {
58598b7c69SStephane Eranian 	void *tmp;
59598b7c69SStephane Eranian 	size_t be_sz = be->max_sz;
60598b7c69SStephane Eranian 
61598b7c69SStephane Eranian retry:
62598b7c69SStephane Eranian 	if ((be->cur_pos + sz) < be_sz) {
63598b7c69SStephane Eranian 		memcpy(be->data + be->cur_pos, addr, sz);
64598b7c69SStephane Eranian 		be->cur_pos += sz;
65598b7c69SStephane Eranian 		return 0;
66598b7c69SStephane Eranian 	}
67598b7c69SStephane Eranian 
68598b7c69SStephane Eranian 	if (!be_sz)
69598b7c69SStephane Eranian 		be_sz = BUFFER_EXT_DFL_SIZE;
70598b7c69SStephane Eranian 	else
71598b7c69SStephane Eranian 		be_sz <<= 1;
72598b7c69SStephane Eranian 
73598b7c69SStephane Eranian 	tmp = realloc(be->data, be_sz);
74598b7c69SStephane Eranian 	if (!tmp)
75598b7c69SStephane Eranian 		return -1;
76598b7c69SStephane Eranian 
77598b7c69SStephane Eranian 	be->data   = tmp;
78598b7c69SStephane Eranian 	be->max_sz = be_sz;
79598b7c69SStephane Eranian 
80598b7c69SStephane Eranian 	goto retry;
81598b7c69SStephane Eranian }
82598b7c69SStephane Eranian 
83598b7c69SStephane Eranian static void
buffer_ext_init(struct buffer_ext * be)84598b7c69SStephane Eranian buffer_ext_init(struct buffer_ext *be)
85598b7c69SStephane Eranian {
86598b7c69SStephane Eranian 	be->data = NULL;
87598b7c69SStephane Eranian 	be->cur_pos = 0;
88598b7c69SStephane Eranian 	be->max_sz = 0;
89598b7c69SStephane Eranian }
90598b7c69SStephane Eranian 
91dc67c783SIan Rogers static void
buffer_ext_exit(struct buffer_ext * be)92dc67c783SIan Rogers buffer_ext_exit(struct buffer_ext *be)
93dc67c783SIan Rogers {
94*e413f9f1SArnaldo Carvalho de Melo 	zfree(&be->data);
95dc67c783SIan Rogers }
96dc67c783SIan Rogers 
97598b7c69SStephane Eranian static inline size_t
buffer_ext_size(struct buffer_ext * be)98598b7c69SStephane Eranian buffer_ext_size(struct buffer_ext *be)
99598b7c69SStephane Eranian {
100598b7c69SStephane Eranian 	return be->cur_pos;
101598b7c69SStephane Eranian }
102598b7c69SStephane Eranian 
103598b7c69SStephane Eranian static inline void *
buffer_ext_addr(struct buffer_ext * be)104598b7c69SStephane Eranian buffer_ext_addr(struct buffer_ext *be)
105598b7c69SStephane Eranian {
106598b7c69SStephane Eranian 	return be->data;
107598b7c69SStephane Eranian }
108598b7c69SStephane Eranian 
109598b7c69SStephane Eranian struct debug_line_header {
110598b7c69SStephane Eranian 	// Not counting this field
111598b7c69SStephane Eranian 	uword total_length;
112598b7c69SStephane Eranian 	// version number (2 currently)
113598b7c69SStephane Eranian 	uhalf version;
114598b7c69SStephane Eranian 	// relative offset from next field to
115598b7c69SStephane Eranian 	// program statement
116598b7c69SStephane Eranian 	uword prolog_length;
117598b7c69SStephane Eranian 	ubyte minimum_instruction_length;
118598b7c69SStephane Eranian 	ubyte default_is_stmt;
119598b7c69SStephane Eranian 	// line_base - see DWARF 2 specs
120598b7c69SStephane Eranian 	sbyte line_base;
121598b7c69SStephane Eranian 	// line_range - see DWARF 2 specs
122598b7c69SStephane Eranian 	ubyte line_range;
123598b7c69SStephane Eranian 	// number of opcode + 1
124598b7c69SStephane Eranian 	ubyte opcode_base;
125598b7c69SStephane Eranian 	/* follow the array of opcode args nr: ubytes [nr_opcode_base] */
126598b7c69SStephane Eranian 	/* follow the search directories index, zero terminated string
127598b7c69SStephane Eranian 	 * terminated by an empty string.
128598b7c69SStephane Eranian 	 */
129598b7c69SStephane Eranian 	/* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
130598b7c69SStephane Eranian 	 * the directory index entry, 0 means current directory, then mtime
131598b7c69SStephane Eranian 	 * and filesize, last entry is followed by en empty string.
132598b7c69SStephane Eranian 	 */
133598b7c69SStephane Eranian 	/* follow the first program statement */
134c9f5da74SArnaldo Carvalho de Melo } __packed;
135598b7c69SStephane Eranian 
136598b7c69SStephane Eranian /* DWARF 2 spec talk only about one possible compilation unit header while
137598b7c69SStephane Eranian  * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
138598b7c69SStephane Eranian  * related to the used arch, an ELF 32 can hold more than 4 Go of debug
139598b7c69SStephane Eranian  * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
140598b7c69SStephane Eranian  * become a problem if we generate more than 4GB of debug information.
141598b7c69SStephane Eranian  */
142598b7c69SStephane Eranian struct compilation_unit_header {
143598b7c69SStephane Eranian 	uword total_length;
144598b7c69SStephane Eranian 	uhalf version;
145598b7c69SStephane Eranian 	uword debug_abbrev_offset;
146598b7c69SStephane Eranian 	ubyte pointer_size;
147c9f5da74SArnaldo Carvalho de Melo } __packed;
148598b7c69SStephane Eranian 
149598b7c69SStephane Eranian #define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
150598b7c69SStephane Eranian 
151598b7c69SStephane Eranian /* field filled at run time are marked with -1 */
152598b7c69SStephane Eranian static struct debug_line_header const default_debug_line_header = {
153598b7c69SStephane Eranian 	.total_length = -1,
154598b7c69SStephane Eranian 	.version = 2,
155598b7c69SStephane Eranian 	.prolog_length = -1,
156598b7c69SStephane Eranian 	.minimum_instruction_length = 1,	/* could be better when min instruction size != 1 */
157598b7c69SStephane Eranian 	.default_is_stmt = 1,	/* we don't take care about basic block */
158598b7c69SStephane Eranian 	.line_base = -5,	/* sensible value for line base ... */
159598b7c69SStephane Eranian 	.line_range = -14,     /* ... and line range are guessed statically */
160598b7c69SStephane Eranian 	.opcode_base = DW_LNS_num_opcode
161598b7c69SStephane Eranian };
162598b7c69SStephane Eranian 
163598b7c69SStephane Eranian static ubyte standard_opcode_length[] =
164598b7c69SStephane Eranian {
165598b7c69SStephane Eranian 	0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
166598b7c69SStephane Eranian };
167598b7c69SStephane Eranian #if 0
168598b7c69SStephane Eranian {
169598b7c69SStephane Eranian 	[DW_LNS_advance_pc]   = 1,
170598b7c69SStephane Eranian 	[DW_LNS_advance_line] = 1,
171598b7c69SStephane Eranian 	[DW_LNS_set_file] =  1,
172598b7c69SStephane Eranian 	[DW_LNS_set_column] = 1,
173598b7c69SStephane Eranian 	[DW_LNS_fixed_advance_pc] = 1,
174598b7c69SStephane Eranian 	[DW_LNS_set_isa] = 1,
175598b7c69SStephane Eranian };
176598b7c69SStephane Eranian #endif
177598b7c69SStephane Eranian 
178598b7c69SStephane Eranian /* field filled at run time are marked with -1 */
179598b7c69SStephane Eranian static struct compilation_unit_header default_comp_unit_header = {
180598b7c69SStephane Eranian 	.total_length = -1,
181598b7c69SStephane Eranian 	.version = 2,
182598b7c69SStephane Eranian 	.debug_abbrev_offset = 0,     /* we reuse the same abbrev entries for all comp unit */
183598b7c69SStephane Eranian 	.pointer_size = sizeof(void *)
184598b7c69SStephane Eranian };
185598b7c69SStephane Eranian 
emit_uword(struct buffer_ext * be,uword data)186598b7c69SStephane Eranian static void emit_uword(struct buffer_ext *be, uword data)
187598b7c69SStephane Eranian {
188598b7c69SStephane Eranian 	buffer_ext_add(be, &data, sizeof(uword));
189598b7c69SStephane Eranian }
190598b7c69SStephane Eranian 
emit_string(struct buffer_ext * be,const char * s)191598b7c69SStephane Eranian static void emit_string(struct buffer_ext *be, const char *s)
192598b7c69SStephane Eranian {
193598b7c69SStephane Eranian 	buffer_ext_add(be, (void *)s, strlen(s) + 1);
194598b7c69SStephane Eranian }
195598b7c69SStephane Eranian 
emit_unsigned_LEB128(struct buffer_ext * be,unsigned long data)196598b7c69SStephane Eranian static void emit_unsigned_LEB128(struct buffer_ext *be,
197598b7c69SStephane Eranian 				 unsigned long data)
198598b7c69SStephane Eranian {
199598b7c69SStephane Eranian 	do {
200598b7c69SStephane Eranian 		ubyte cur = data & 0x7F;
201598b7c69SStephane Eranian 		data >>= 7;
202598b7c69SStephane Eranian 		if (data)
203598b7c69SStephane Eranian 			cur |= 0x80;
204598b7c69SStephane Eranian 		buffer_ext_add(be, &cur, 1);
205598b7c69SStephane Eranian 	} while (data);
206598b7c69SStephane Eranian }
207598b7c69SStephane Eranian 
emit_signed_LEB128(struct buffer_ext * be,long data)208598b7c69SStephane Eranian static void emit_signed_LEB128(struct buffer_ext *be, long data)
209598b7c69SStephane Eranian {
210598b7c69SStephane Eranian 	int more = 1;
211598b7c69SStephane Eranian 	int negative = data < 0;
212598b7c69SStephane Eranian 	int size = sizeof(long) * CHAR_BIT;
213598b7c69SStephane Eranian 	while (more) {
214598b7c69SStephane Eranian 		ubyte cur = data & 0x7F;
215598b7c69SStephane Eranian 		data >>= 7;
216598b7c69SStephane Eranian 		if (negative)
217598b7c69SStephane Eranian 			data |= - (1 << (size - 7));
218598b7c69SStephane Eranian 		if ((data == 0 && !(cur & 0x40)) ||
219598b7c69SStephane Eranian 		    (data == -1l && (cur & 0x40)))
220598b7c69SStephane Eranian 			more = 0;
221598b7c69SStephane Eranian 		else
222598b7c69SStephane Eranian 			cur |= 0x80;
223598b7c69SStephane Eranian 		buffer_ext_add(be, &cur, 1);
224598b7c69SStephane Eranian 	}
225598b7c69SStephane Eranian }
226598b7c69SStephane Eranian 
emit_extended_opcode(struct buffer_ext * be,ubyte opcode,void * data,size_t data_len)227598b7c69SStephane Eranian static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
228598b7c69SStephane Eranian 				 void *data, size_t data_len)
229598b7c69SStephane Eranian {
230598b7c69SStephane Eranian 	buffer_ext_add(be, (char *)"", 1);
231598b7c69SStephane Eranian 
232598b7c69SStephane Eranian 	emit_unsigned_LEB128(be, data_len + 1);
233598b7c69SStephane Eranian 
234598b7c69SStephane Eranian 	buffer_ext_add(be, &opcode, 1);
235598b7c69SStephane Eranian 	buffer_ext_add(be, data, data_len);
236598b7c69SStephane Eranian }
237598b7c69SStephane Eranian 
emit_opcode(struct buffer_ext * be,ubyte opcode)238598b7c69SStephane Eranian static void emit_opcode(struct buffer_ext *be, ubyte opcode)
239598b7c69SStephane Eranian {
240598b7c69SStephane Eranian 	buffer_ext_add(be, &opcode, 1);
241598b7c69SStephane Eranian }
242598b7c69SStephane Eranian 
emit_opcode_signed(struct buffer_ext * be,ubyte opcode,long data)243598b7c69SStephane Eranian static void emit_opcode_signed(struct buffer_ext  *be,
244598b7c69SStephane Eranian 			       ubyte opcode, long data)
245598b7c69SStephane Eranian {
246598b7c69SStephane Eranian 	buffer_ext_add(be, &opcode, 1);
247598b7c69SStephane Eranian 	emit_signed_LEB128(be, data);
248598b7c69SStephane Eranian }
249598b7c69SStephane Eranian 
emit_opcode_unsigned(struct buffer_ext * be,ubyte opcode,unsigned long data)250598b7c69SStephane Eranian static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
251598b7c69SStephane Eranian 				 unsigned long data)
252598b7c69SStephane Eranian {
253598b7c69SStephane Eranian 	buffer_ext_add(be, &opcode, 1);
254598b7c69SStephane Eranian 	emit_unsigned_LEB128(be, data);
255598b7c69SStephane Eranian }
256598b7c69SStephane Eranian 
emit_advance_pc(struct buffer_ext * be,unsigned long delta_pc)257598b7c69SStephane Eranian static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
258598b7c69SStephane Eranian {
259598b7c69SStephane Eranian 	emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
260598b7c69SStephane Eranian }
261598b7c69SStephane Eranian 
emit_advance_lineno(struct buffer_ext * be,long delta_lineno)262598b7c69SStephane Eranian static void emit_advance_lineno(struct buffer_ext  *be, long delta_lineno)
263598b7c69SStephane Eranian {
264598b7c69SStephane Eranian 	emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
265598b7c69SStephane Eranian }
266598b7c69SStephane Eranian 
emit_lne_end_of_sequence(struct buffer_ext * be)267598b7c69SStephane Eranian static void emit_lne_end_of_sequence(struct buffer_ext *be)
268598b7c69SStephane Eranian {
269598b7c69SStephane Eranian 	emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
270598b7c69SStephane Eranian }
271598b7c69SStephane Eranian 
emit_set_file(struct buffer_ext * be,unsigned long idx)272598b7c69SStephane Eranian static void emit_set_file(struct buffer_ext *be, unsigned long idx)
273598b7c69SStephane Eranian {
274598b7c69SStephane Eranian 	emit_opcode_unsigned(be, DW_LNS_set_file, idx);
275598b7c69SStephane Eranian }
276598b7c69SStephane Eranian 
emit_lne_define_filename(struct buffer_ext * be,const char * filename)277598b7c69SStephane Eranian static void emit_lne_define_filename(struct buffer_ext *be,
278598b7c69SStephane Eranian 				     const char *filename)
279598b7c69SStephane Eranian {
280598b7c69SStephane Eranian 	buffer_ext_add(be, (void *)"", 1);
281598b7c69SStephane Eranian 
282598b7c69SStephane Eranian 	/* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
283598b7c69SStephane Eranian 	emit_unsigned_LEB128(be, strlen(filename) + 5);
284598b7c69SStephane Eranian 	emit_opcode(be, DW_LNE_define_file);
285598b7c69SStephane Eranian 	emit_string(be, filename);
286598b7c69SStephane Eranian 	/* directory index 0=do not know */
287598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
288598b7c69SStephane Eranian 	/* last modification date on file 0=do not know */
289598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
290598b7c69SStephane Eranian 	/* filesize 0=do not know */
291598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
292598b7c69SStephane Eranian }
293598b7c69SStephane Eranian 
emit_lne_set_address(struct buffer_ext * be,void * address)294598b7c69SStephane Eranian static void emit_lne_set_address(struct buffer_ext *be,
295598b7c69SStephane Eranian 				 void *address)
296598b7c69SStephane Eranian {
297598b7c69SStephane Eranian 	emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
298598b7c69SStephane Eranian }
299598b7c69SStephane Eranian 
get_special_opcode(struct debug_entry * ent,unsigned int last_line,unsigned long last_vma)300598b7c69SStephane Eranian static ubyte get_special_opcode(struct debug_entry *ent,
301598b7c69SStephane Eranian 				unsigned int last_line,
302598b7c69SStephane Eranian 				unsigned long last_vma)
303598b7c69SStephane Eranian {
304598b7c69SStephane Eranian 	unsigned int temp;
305598b7c69SStephane Eranian 	unsigned long delta_addr;
306598b7c69SStephane Eranian 
307598b7c69SStephane Eranian 	/*
308598b7c69SStephane Eranian 	 * delta from line_base
309598b7c69SStephane Eranian 	 */
310598b7c69SStephane Eranian 	temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
311598b7c69SStephane Eranian 
312598b7c69SStephane Eranian 	if (temp >= default_debug_line_header.line_range)
313598b7c69SStephane Eranian 		return 0;
314598b7c69SStephane Eranian 
315598b7c69SStephane Eranian 	/*
316598b7c69SStephane Eranian 	 * delta of addresses
317598b7c69SStephane Eranian 	 */
318598b7c69SStephane Eranian 	delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
319598b7c69SStephane Eranian 
320598b7c69SStephane Eranian 	/* This is not sufficient to ensure opcode will be in [0-256] but
321598b7c69SStephane Eranian 	 * sufficient to ensure when summing with the delta lineno we will
322598b7c69SStephane Eranian 	 * not overflow the unsigned long opcode */
323598b7c69SStephane Eranian 
324598b7c69SStephane Eranian 	if (delta_addr <= 256 / default_debug_line_header.line_range) {
325598b7c69SStephane Eranian 		unsigned long opcode = temp +
326598b7c69SStephane Eranian 			(delta_addr * default_debug_line_header.line_range) +
327598b7c69SStephane Eranian 			default_debug_line_header.opcode_base;
328598b7c69SStephane Eranian 
329598b7c69SStephane Eranian 		return opcode <= 255 ? opcode : 0;
330598b7c69SStephane Eranian 	}
331598b7c69SStephane Eranian 	return 0;
332598b7c69SStephane Eranian }
333598b7c69SStephane Eranian 
emit_lineno_info(struct buffer_ext * be,struct debug_entry * ent,size_t nr_entry,unsigned long code_addr)334598b7c69SStephane Eranian static void emit_lineno_info(struct buffer_ext *be,
335598b7c69SStephane Eranian 			     struct debug_entry *ent, size_t nr_entry,
336598b7c69SStephane Eranian 			     unsigned long code_addr)
337598b7c69SStephane Eranian {
338598b7c69SStephane Eranian 	size_t i;
339598b7c69SStephane Eranian 
340598b7c69SStephane Eranian 	/* as described in the jitdump format */
341598b7c69SStephane Eranian 	const char repeated_name_marker[] = {'\xff', '\0'};
342598b7c69SStephane Eranian 
343598b7c69SStephane Eranian 	/*
344598b7c69SStephane Eranian 	 * Machine state at start of a statement program
345598b7c69SStephane Eranian 	 * address = 0
346598b7c69SStephane Eranian 	 * file    = 1
347598b7c69SStephane Eranian 	 * line    = 1
348598b7c69SStephane Eranian 	 * column  = 0
349598b7c69SStephane Eranian 	 * is_stmt = default_is_stmt as given in the debug_line_header
350598b7c69SStephane Eranian 	 * basic block = 0
351598b7c69SStephane Eranian 	 * end sequence = 0
3521e4bd2aeSNick Gasson 	 */
353598b7c69SStephane Eranian 
354598b7c69SStephane Eranian 	/* start state of the state machine we take care of */
355598b7c69SStephane Eranian 	unsigned long last_vma = 0;
356598b7c69SStephane Eranian 	char const  *cur_filename = NULL;
357598b7c69SStephane Eranian 	unsigned long cur_file_idx = 0;
358598b7c69SStephane Eranian 	int last_line = 1;
359598b7c69SStephane Eranian 
360598b7c69SStephane Eranian 	emit_lne_set_address(be, (void *)code_addr);
361598b7c69SStephane Eranian 
362598b7c69SStephane Eranian 	for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
363598b7c69SStephane Eranian 		int need_copy = 0;
364598b7c69SStephane Eranian 		ubyte special_opcode;
365598b7c69SStephane Eranian 
366598b7c69SStephane Eranian 		/*
367598b7c69SStephane Eranian 		 * check if filename changed, if so add it
368598b7c69SStephane Eranian 		 */
369598b7c69SStephane Eranian 		if ((!cur_filename || strcmp(cur_filename, ent->name)) &&
370598b7c69SStephane Eranian 			strcmp(repeated_name_marker, ent->name)) {
371598b7c69SStephane Eranian 			emit_lne_define_filename(be, ent->name);
372598b7c69SStephane Eranian 			cur_filename = ent->name;
373598b7c69SStephane Eranian 			emit_set_file(be, ++cur_file_idx);
374598b7c69SStephane Eranian 			need_copy = 1;
375598b7c69SStephane Eranian 		}
376598b7c69SStephane Eranian 
377598b7c69SStephane Eranian 		special_opcode = get_special_opcode(ent, last_line, last_vma);
378598b7c69SStephane Eranian 		if (special_opcode != 0) {
379598b7c69SStephane Eranian 			last_line = ent->lineno;
380598b7c69SStephane Eranian 			last_vma  = ent->addr;
381598b7c69SStephane Eranian 			emit_opcode(be, special_opcode);
382598b7c69SStephane Eranian 		} else {
383598b7c69SStephane Eranian 			/*
384598b7c69SStephane Eranian 			 * lines differ, emit line delta
385598b7c69SStephane Eranian 			 */
386598b7c69SStephane Eranian 			if (last_line != ent->lineno) {
387598b7c69SStephane Eranian 				emit_advance_lineno(be, ent->lineno - last_line);
388598b7c69SStephane Eranian 				last_line = ent->lineno;
389598b7c69SStephane Eranian 				need_copy = 1;
390598b7c69SStephane Eranian 			}
391598b7c69SStephane Eranian 			/*
392598b7c69SStephane Eranian 			 * addresses differ, emit address delta
393598b7c69SStephane Eranian 			 */
394598b7c69SStephane Eranian 			if (last_vma != ent->addr) {
395598b7c69SStephane Eranian 				emit_advance_pc(be, ent->addr - last_vma);
396598b7c69SStephane Eranian 				last_vma = ent->addr;
397598b7c69SStephane Eranian 				need_copy = 1;
398598b7c69SStephane Eranian 			}
399598b7c69SStephane Eranian 			/*
400598b7c69SStephane Eranian 			 * add new row to matrix
401598b7c69SStephane Eranian 			 */
402598b7c69SStephane Eranian 			if (need_copy)
403598b7c69SStephane Eranian 				emit_opcode(be, DW_LNS_copy);
404598b7c69SStephane Eranian 		}
405598b7c69SStephane Eranian 	}
406598b7c69SStephane Eranian }
407598b7c69SStephane Eranian 
add_debug_line(struct buffer_ext * be,struct debug_entry * ent,size_t nr_entry,unsigned long code_addr)408598b7c69SStephane Eranian static void add_debug_line(struct buffer_ext *be,
409598b7c69SStephane Eranian 	struct debug_entry *ent, size_t nr_entry,
410598b7c69SStephane Eranian 	unsigned long code_addr)
411598b7c69SStephane Eranian {
412598b7c69SStephane Eranian 	struct debug_line_header * dbg_header;
413598b7c69SStephane Eranian 	size_t old_size;
414598b7c69SStephane Eranian 
415598b7c69SStephane Eranian 	old_size = buffer_ext_size(be);
416598b7c69SStephane Eranian 
417598b7c69SStephane Eranian 	buffer_ext_add(be, (void *)&default_debug_line_header,
418598b7c69SStephane Eranian 		 sizeof(default_debug_line_header));
419598b7c69SStephane Eranian 
420598b7c69SStephane Eranian 	buffer_ext_add(be, &standard_opcode_length,  sizeof(standard_opcode_length));
421598b7c69SStephane Eranian 
422598b7c69SStephane Eranian 	// empty directory entry
423598b7c69SStephane Eranian 	buffer_ext_add(be, (void *)"", 1);
424598b7c69SStephane Eranian 
425598b7c69SStephane Eranian 	// empty filename directory
426598b7c69SStephane Eranian 	buffer_ext_add(be, (void *)"", 1);
427598b7c69SStephane Eranian 
428598b7c69SStephane Eranian 	dbg_header = buffer_ext_addr(be) + old_size;
429598b7c69SStephane Eranian 	dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
430598b7c69SStephane Eranian 		offsetof(struct debug_line_header, minimum_instruction_length);
431598b7c69SStephane Eranian 
432598b7c69SStephane Eranian 	emit_lineno_info(be, ent, nr_entry, code_addr);
433598b7c69SStephane Eranian 
434598b7c69SStephane Eranian 	emit_lne_end_of_sequence(be);
435598b7c69SStephane Eranian 
436598b7c69SStephane Eranian 	dbg_header = buffer_ext_addr(be) + old_size;
437598b7c69SStephane Eranian 	dbg_header->total_length = (buffer_ext_size(be) - old_size) -
438598b7c69SStephane Eranian 		offsetof(struct debug_line_header, version);
439598b7c69SStephane Eranian }
440598b7c69SStephane Eranian 
441598b7c69SStephane Eranian static void
add_debug_abbrev(struct buffer_ext * be)442598b7c69SStephane Eranian add_debug_abbrev(struct buffer_ext *be)
443598b7c69SStephane Eranian {
444598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 1);
445598b7c69SStephane Eranian         emit_unsigned_LEB128(be, DW_TAG_compile_unit);
446598b7c69SStephane Eranian         emit_unsigned_LEB128(be, DW_CHILDREN_yes);
447598b7c69SStephane Eranian         emit_unsigned_LEB128(be, DW_AT_stmt_list);
448598b7c69SStephane Eranian         emit_unsigned_LEB128(be, DW_FORM_data4);
449598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
450598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
451598b7c69SStephane Eranian         emit_unsigned_LEB128(be, 0);
452598b7c69SStephane Eranian }
453598b7c69SStephane Eranian 
454598b7c69SStephane Eranian static void
add_compilation_unit(struct buffer_ext * be,size_t offset_debug_line)455598b7c69SStephane Eranian add_compilation_unit(struct buffer_ext *be,
456598b7c69SStephane Eranian 		     size_t offset_debug_line)
457598b7c69SStephane Eranian {
458598b7c69SStephane Eranian 	struct compilation_unit_header *comp_unit_header;
459598b7c69SStephane Eranian 	size_t old_size = buffer_ext_size(be);
460598b7c69SStephane Eranian 
461598b7c69SStephane Eranian 	buffer_ext_add(be, &default_comp_unit_header,
462598b7c69SStephane Eranian 		       sizeof(default_comp_unit_header));
463598b7c69SStephane Eranian 
464598b7c69SStephane Eranian 	emit_unsigned_LEB128(be, 1);
465598b7c69SStephane Eranian 	emit_uword(be, offset_debug_line);
466598b7c69SStephane Eranian 
467598b7c69SStephane Eranian 	comp_unit_header = buffer_ext_addr(be) + old_size;
468598b7c69SStephane Eranian 	comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
469598b7c69SStephane Eranian 		offsetof(struct compilation_unit_header, version);
470598b7c69SStephane Eranian }
471598b7c69SStephane Eranian 
472598b7c69SStephane Eranian static int
jit_process_debug_info(uint64_t code_addr,void * debug,int nr_debug_entries,struct buffer_ext * dl,struct buffer_ext * da,struct buffer_ext * di)473598b7c69SStephane Eranian jit_process_debug_info(uint64_t code_addr,
474598b7c69SStephane Eranian 		       void *debug, int nr_debug_entries,
475598b7c69SStephane Eranian 		       struct buffer_ext *dl,
476598b7c69SStephane Eranian 		       struct buffer_ext *da,
477598b7c69SStephane Eranian 		       struct buffer_ext *di)
478598b7c69SStephane Eranian {
479598b7c69SStephane Eranian 	struct debug_entry *ent = debug;
480598b7c69SStephane Eranian 	int i;
481598b7c69SStephane Eranian 
482598b7c69SStephane Eranian 	for (i = 0; i < nr_debug_entries; i++) {
4831e4bd2aeSNick Gasson 		ent->addr = ent->addr - code_addr;
484598b7c69SStephane Eranian 		ent = debug_entry_next(ent);
485598b7c69SStephane Eranian 	}
486598b7c69SStephane Eranian 	add_compilation_unit(di, buffer_ext_size(dl));
487598b7c69SStephane Eranian 	add_debug_line(dl, debug, nr_debug_entries, GEN_ELF_TEXT_OFFSET);
488598b7c69SStephane Eranian 	add_debug_abbrev(da);
489598b7c69SStephane Eranian 	if (0) buffer_ext_dump(da, "abbrev");
490598b7c69SStephane Eranian 
491598b7c69SStephane Eranian 	return 0;
492598b7c69SStephane Eranian }
493598b7c69SStephane Eranian 
494598b7c69SStephane Eranian int
jit_add_debug_info(Elf * e,uint64_t code_addr,void * debug,int nr_debug_entries)495598b7c69SStephane Eranian jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
496598b7c69SStephane Eranian {
497dc67c783SIan Rogers 	Elf_Data *d;
498598b7c69SStephane Eranian 	Elf_Scn *scn;
499598b7c69SStephane Eranian 	Elf_Shdr *shdr;
500598b7c69SStephane Eranian 	struct buffer_ext dl, di, da;
501598b7c69SStephane Eranian 	int ret = -1;
502598b7c69SStephane Eranian 
503dc67c783SIan Rogers 	buffer_ext_init(&dl);
504dc67c783SIan Rogers 	buffer_ext_init(&di);
505dc67c783SIan Rogers 	buffer_ext_init(&da);
506598b7c69SStephane Eranian 
507598b7c69SStephane Eranian 	if (jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di))
508598b7c69SStephane Eranian 		goto out;
509598b7c69SStephane Eranian 
510598b7c69SStephane Eranian 	/*
511598b7c69SStephane Eranian 	 * setup .debug_line section
512dc67c783SIan Rogers 	 */
513598b7c69SStephane Eranian 	scn = elf_newscn(e);
514598b7c69SStephane Eranian 	if (!scn) {
515598b7c69SStephane Eranian 		warnx("cannot create section");
516598b7c69SStephane Eranian 		goto out;
517598b7c69SStephane Eranian 	}
518dc67c783SIan Rogers 
519598b7c69SStephane Eranian 	d = elf_newdata(scn);
520598b7c69SStephane Eranian 	if (!d) {
521598b7c69SStephane Eranian 		warnx("cannot get new data");
522598b7c69SStephane Eranian 		goto out;
523598b7c69SStephane Eranian 	}
524598b7c69SStephane Eranian 
525598b7c69SStephane Eranian 	d->d_align = 1;
526598b7c69SStephane Eranian 	d->d_off = 0LL;
527598b7c69SStephane Eranian 	d->d_buf = buffer_ext_addr(&dl);
528598b7c69SStephane Eranian 	d->d_type = ELF_T_BYTE;
529598b7c69SStephane Eranian 	d->d_size = buffer_ext_size(&dl);
530598b7c69SStephane Eranian 	d->d_version = EV_CURRENT;
531dc67c783SIan Rogers 
532598b7c69SStephane Eranian 	shdr = elf_getshdr(scn);
533598b7c69SStephane Eranian 	if (!shdr) {
534598b7c69SStephane Eranian 		warnx("cannot get section header");
535598b7c69SStephane Eranian 		goto out;
536598b7c69SStephane Eranian 	}
537598b7c69SStephane Eranian 
538598b7c69SStephane Eranian 	shdr->sh_name = 52; /* .debug_line */
539598b7c69SStephane Eranian 	shdr->sh_type = SHT_PROGBITS;
540598b7c69SStephane Eranian 	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
541598b7c69SStephane Eranian 	shdr->sh_flags = 0;
542598b7c69SStephane Eranian 	shdr->sh_entsize = 0;
543598b7c69SStephane Eranian 
544598b7c69SStephane Eranian 	/*
545598b7c69SStephane Eranian 	 * setup .debug_info section
546dc67c783SIan Rogers 	 */
547598b7c69SStephane Eranian 	scn = elf_newscn(e);
548598b7c69SStephane Eranian 	if (!scn) {
549598b7c69SStephane Eranian 		warnx("cannot create section");
550598b7c69SStephane Eranian 		goto out;
551598b7c69SStephane Eranian 	}
552dc67c783SIan Rogers 
553598b7c69SStephane Eranian 	d = elf_newdata(scn);
554598b7c69SStephane Eranian 	if (!d) {
555598b7c69SStephane Eranian 		warnx("cannot get new data");
556598b7c69SStephane Eranian 		goto out;
557598b7c69SStephane Eranian 	}
558598b7c69SStephane Eranian 
559598b7c69SStephane Eranian 	d->d_align = 1;
560598b7c69SStephane Eranian 	d->d_off = 0LL;
561598b7c69SStephane Eranian 	d->d_buf = buffer_ext_addr(&di);
562598b7c69SStephane Eranian 	d->d_type = ELF_T_BYTE;
563598b7c69SStephane Eranian 	d->d_size = buffer_ext_size(&di);
564598b7c69SStephane Eranian 	d->d_version = EV_CURRENT;
565dc67c783SIan Rogers 
566598b7c69SStephane Eranian 	shdr = elf_getshdr(scn);
567598b7c69SStephane Eranian 	if (!shdr) {
568598b7c69SStephane Eranian 		warnx("cannot get section header");
569598b7c69SStephane Eranian 		goto out;
570598b7c69SStephane Eranian 	}
571598b7c69SStephane Eranian 
572598b7c69SStephane Eranian 	shdr->sh_name = 64; /* .debug_info */
573598b7c69SStephane Eranian 	shdr->sh_type = SHT_PROGBITS;
574598b7c69SStephane Eranian 	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
575598b7c69SStephane Eranian 	shdr->sh_flags = 0;
576598b7c69SStephane Eranian 	shdr->sh_entsize = 0;
577598b7c69SStephane Eranian 
578598b7c69SStephane Eranian 	/*
579598b7c69SStephane Eranian 	 * setup .debug_abbrev section
580dc67c783SIan Rogers 	 */
581598b7c69SStephane Eranian 	scn = elf_newscn(e);
582598b7c69SStephane Eranian 	if (!scn) {
583598b7c69SStephane Eranian 		warnx("cannot create section");
584598b7c69SStephane Eranian 		goto out;
585598b7c69SStephane Eranian 	}
586dc67c783SIan Rogers 
587598b7c69SStephane Eranian 	d = elf_newdata(scn);
588598b7c69SStephane Eranian 	if (!d) {
589598b7c69SStephane Eranian 		warnx("cannot get new data");
590598b7c69SStephane Eranian 		goto out;
591598b7c69SStephane Eranian 	}
592598b7c69SStephane Eranian 
593598b7c69SStephane Eranian 	d->d_align = 1;
594598b7c69SStephane Eranian 	d->d_off = 0LL;
595598b7c69SStephane Eranian 	d->d_buf = buffer_ext_addr(&da);
596598b7c69SStephane Eranian 	d->d_type = ELF_T_BYTE;
597598b7c69SStephane Eranian 	d->d_size = buffer_ext_size(&da);
598598b7c69SStephane Eranian 	d->d_version = EV_CURRENT;
599dc67c783SIan Rogers 
600598b7c69SStephane Eranian 	shdr = elf_getshdr(scn);
601598b7c69SStephane Eranian 	if (!shdr) {
602598b7c69SStephane Eranian 		warnx("cannot get section header");
603598b7c69SStephane Eranian 		goto out;
604598b7c69SStephane Eranian 	}
605598b7c69SStephane Eranian 
606598b7c69SStephane Eranian 	shdr->sh_name = 76; /* .debug_info */
607598b7c69SStephane Eranian 	shdr->sh_type = SHT_PROGBITS;
608598b7c69SStephane Eranian 	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
609598b7c69SStephane Eranian 	shdr->sh_flags = 0;
610598b7c69SStephane Eranian 	shdr->sh_entsize = 0;
611dc67c783SIan Rogers 
612598b7c69SStephane Eranian 	/*
613dc67c783SIan Rogers 	 * now we update the ELF image with all the sections
614dc67c783SIan Rogers 	 */
615dc67c783SIan Rogers 	if (elf_update(e, ELF_C_WRITE) < 0)
616dc67c783SIan Rogers 		warnx("elf_update debug failed");
617dc67c783SIan Rogers 	else
618dc67c783SIan Rogers 		ret = 0;
619dc67c783SIan Rogers 
620dc67c783SIan Rogers out:
621598b7c69SStephane Eranian 	buffer_ext_exit(&dl);
622 	buffer_ext_exit(&di);
623 	buffer_ext_exit(&da);
624 	return ret;
625 }
626