18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * genelf_debug.c 48c2ecf20Sopenharmony_ci * Copyright (C) 2015, Google, Inc 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Contributed by: 78c2ecf20Sopenharmony_ci * Stephane Eranian <eranian@google.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * based on GPLv2 source code from Oprofile 108c2ecf20Sopenharmony_ci * @remark Copyright 2007 OProfile authors 118c2ecf20Sopenharmony_ci * @author Philippe Elie 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/compiler.h> 148c2ecf20Sopenharmony_ci#include <sys/types.h> 158c2ecf20Sopenharmony_ci#include <stdio.h> 168c2ecf20Sopenharmony_ci#include <getopt.h> 178c2ecf20Sopenharmony_ci#include <stddef.h> 188c2ecf20Sopenharmony_ci#include <libelf.h> 198c2ecf20Sopenharmony_ci#include <string.h> 208c2ecf20Sopenharmony_ci#include <stdlib.h> 218c2ecf20Sopenharmony_ci#include <inttypes.h> 228c2ecf20Sopenharmony_ci#include <limits.h> 238c2ecf20Sopenharmony_ci#include <fcntl.h> 248c2ecf20Sopenharmony_ci#include <err.h> 258c2ecf20Sopenharmony_ci#include <dwarf.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "genelf.h" 288c2ecf20Sopenharmony_ci#include "../util/jitdump.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define BUFFER_EXT_DFL_SIZE (4 * 1024) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_citypedef uint32_t uword; 338c2ecf20Sopenharmony_citypedef uint16_t uhalf; 348c2ecf20Sopenharmony_citypedef int32_t sword; 358c2ecf20Sopenharmony_citypedef int16_t shalf; 368c2ecf20Sopenharmony_citypedef uint8_t ubyte; 378c2ecf20Sopenharmony_citypedef int8_t sbyte; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct buffer_ext { 408c2ecf20Sopenharmony_ci size_t cur_pos; 418c2ecf20Sopenharmony_ci size_t max_sz; 428c2ecf20Sopenharmony_ci void *data; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void 468c2ecf20Sopenharmony_cibuffer_ext_dump(struct buffer_ext *be, const char *msg) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci size_t i; 498c2ecf20Sopenharmony_ci warnx("DUMP for %s", msg); 508c2ecf20Sopenharmony_ci for (i = 0 ; i < be->cur_pos; i++) 518c2ecf20Sopenharmony_ci warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline int 558c2ecf20Sopenharmony_cibuffer_ext_add(struct buffer_ext *be, void *addr, size_t sz) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci void *tmp; 588c2ecf20Sopenharmony_ci size_t be_sz = be->max_sz; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciretry: 618c2ecf20Sopenharmony_ci if ((be->cur_pos + sz) < be_sz) { 628c2ecf20Sopenharmony_ci memcpy(be->data + be->cur_pos, addr, sz); 638c2ecf20Sopenharmony_ci be->cur_pos += sz; 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (!be_sz) 688c2ecf20Sopenharmony_ci be_sz = BUFFER_EXT_DFL_SIZE; 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci be_sz <<= 1; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci tmp = realloc(be->data, be_sz); 738c2ecf20Sopenharmony_ci if (!tmp) 748c2ecf20Sopenharmony_ci return -1; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci be->data = tmp; 778c2ecf20Sopenharmony_ci be->max_sz = be_sz; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci goto retry; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void 838c2ecf20Sopenharmony_cibuffer_ext_init(struct buffer_ext *be) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci be->data = NULL; 868c2ecf20Sopenharmony_ci be->cur_pos = 0; 878c2ecf20Sopenharmony_ci be->max_sz = 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline size_t 918c2ecf20Sopenharmony_cibuffer_ext_size(struct buffer_ext *be) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci return be->cur_pos; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic inline void * 978c2ecf20Sopenharmony_cibuffer_ext_addr(struct buffer_ext *be) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return be->data; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct debug_line_header { 1038c2ecf20Sopenharmony_ci // Not counting this field 1048c2ecf20Sopenharmony_ci uword total_length; 1058c2ecf20Sopenharmony_ci // version number (2 currently) 1068c2ecf20Sopenharmony_ci uhalf version; 1078c2ecf20Sopenharmony_ci // relative offset from next field to 1088c2ecf20Sopenharmony_ci // program statement 1098c2ecf20Sopenharmony_ci uword prolog_length; 1108c2ecf20Sopenharmony_ci ubyte minimum_instruction_length; 1118c2ecf20Sopenharmony_ci ubyte default_is_stmt; 1128c2ecf20Sopenharmony_ci // line_base - see DWARF 2 specs 1138c2ecf20Sopenharmony_ci sbyte line_base; 1148c2ecf20Sopenharmony_ci // line_range - see DWARF 2 specs 1158c2ecf20Sopenharmony_ci ubyte line_range; 1168c2ecf20Sopenharmony_ci // number of opcode + 1 1178c2ecf20Sopenharmony_ci ubyte opcode_base; 1188c2ecf20Sopenharmony_ci /* follow the array of opcode args nr: ubytes [nr_opcode_base] */ 1198c2ecf20Sopenharmony_ci /* follow the search directories index, zero terminated string 1208c2ecf20Sopenharmony_ci * terminated by an empty string. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is 1238c2ecf20Sopenharmony_ci * the directory index entry, 0 means current directory, then mtime 1248c2ecf20Sopenharmony_ci * and filesize, last entry is followed by en empty string. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci /* follow the first program statement */ 1278c2ecf20Sopenharmony_ci} __packed; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* DWARF 2 spec talk only about one possible compilation unit header while 1308c2ecf20Sopenharmony_ci * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not 1318c2ecf20Sopenharmony_ci * related to the used arch, an ELF 32 can hold more than 4 Go of debug 1328c2ecf20Sopenharmony_ci * information. For now we handle only DWARF 2 32 bits comp unit. It'll only 1338c2ecf20Sopenharmony_ci * become a problem if we generate more than 4GB of debug information. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistruct compilation_unit_header { 1368c2ecf20Sopenharmony_ci uword total_length; 1378c2ecf20Sopenharmony_ci uhalf version; 1388c2ecf20Sopenharmony_ci uword debug_abbrev_offset; 1398c2ecf20Sopenharmony_ci ubyte pointer_size; 1408c2ecf20Sopenharmony_ci} __packed; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define DW_LNS_num_opcode (DW_LNS_set_isa + 1) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* field filled at run time are marked with -1 */ 1458c2ecf20Sopenharmony_cistatic struct debug_line_header const default_debug_line_header = { 1468c2ecf20Sopenharmony_ci .total_length = -1, 1478c2ecf20Sopenharmony_ci .version = 2, 1488c2ecf20Sopenharmony_ci .prolog_length = -1, 1498c2ecf20Sopenharmony_ci .minimum_instruction_length = 1, /* could be better when min instruction size != 1 */ 1508c2ecf20Sopenharmony_ci .default_is_stmt = 1, /* we don't take care about basic block */ 1518c2ecf20Sopenharmony_ci .line_base = -5, /* sensible value for line base ... */ 1528c2ecf20Sopenharmony_ci .line_range = -14, /* ... and line range are guessed statically */ 1538c2ecf20Sopenharmony_ci .opcode_base = DW_LNS_num_opcode 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic ubyte standard_opcode_length[] = 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci#if 0 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci [DW_LNS_advance_pc] = 1, 1638c2ecf20Sopenharmony_ci [DW_LNS_advance_line] = 1, 1648c2ecf20Sopenharmony_ci [DW_LNS_set_file] = 1, 1658c2ecf20Sopenharmony_ci [DW_LNS_set_column] = 1, 1668c2ecf20Sopenharmony_ci [DW_LNS_fixed_advance_pc] = 1, 1678c2ecf20Sopenharmony_ci [DW_LNS_set_isa] = 1, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci#endif 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* field filled at run time are marked with -1 */ 1728c2ecf20Sopenharmony_cistatic struct compilation_unit_header default_comp_unit_header = { 1738c2ecf20Sopenharmony_ci .total_length = -1, 1748c2ecf20Sopenharmony_ci .version = 2, 1758c2ecf20Sopenharmony_ci .debug_abbrev_offset = 0, /* we reuse the same abbrev entries for all comp unit */ 1768c2ecf20Sopenharmony_ci .pointer_size = sizeof(void *) 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void emit_uword(struct buffer_ext *be, uword data) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci buffer_ext_add(be, &data, sizeof(uword)); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void emit_string(struct buffer_ext *be, const char *s) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci buffer_ext_add(be, (void *)s, strlen(s) + 1); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void emit_unsigned_LEB128(struct buffer_ext *be, 1908c2ecf20Sopenharmony_ci unsigned long data) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci do { 1938c2ecf20Sopenharmony_ci ubyte cur = data & 0x7F; 1948c2ecf20Sopenharmony_ci data >>= 7; 1958c2ecf20Sopenharmony_ci if (data) 1968c2ecf20Sopenharmony_ci cur |= 0x80; 1978c2ecf20Sopenharmony_ci buffer_ext_add(be, &cur, 1); 1988c2ecf20Sopenharmony_ci } while (data); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void emit_signed_LEB128(struct buffer_ext *be, long data) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int more = 1; 2048c2ecf20Sopenharmony_ci int negative = data < 0; 2058c2ecf20Sopenharmony_ci int size = sizeof(long) * CHAR_BIT; 2068c2ecf20Sopenharmony_ci while (more) { 2078c2ecf20Sopenharmony_ci ubyte cur = data & 0x7F; 2088c2ecf20Sopenharmony_ci data >>= 7; 2098c2ecf20Sopenharmony_ci if (negative) 2108c2ecf20Sopenharmony_ci data |= - (1 << (size - 7)); 2118c2ecf20Sopenharmony_ci if ((data == 0 && !(cur & 0x40)) || 2128c2ecf20Sopenharmony_ci (data == -1l && (cur & 0x40))) 2138c2ecf20Sopenharmony_ci more = 0; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci cur |= 0x80; 2168c2ecf20Sopenharmony_ci buffer_ext_add(be, &cur, 1); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void emit_extended_opcode(struct buffer_ext *be, ubyte opcode, 2218c2ecf20Sopenharmony_ci void *data, size_t data_len) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci buffer_ext_add(be, (char *)"", 1); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, data_len + 1); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 2288c2ecf20Sopenharmony_ci buffer_ext_add(be, data, data_len); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void emit_opcode(struct buffer_ext *be, ubyte opcode) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void emit_opcode_signed(struct buffer_ext *be, 2378c2ecf20Sopenharmony_ci ubyte opcode, long data) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 2408c2ecf20Sopenharmony_ci emit_signed_LEB128(be, data); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode, 2448c2ecf20Sopenharmony_ci unsigned long data) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 2478c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, data); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void emit_advance_lineno(struct buffer_ext *be, long delta_lineno) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void emit_lne_end_of_sequence(struct buffer_ext *be) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void emit_set_file(struct buffer_ext *be, unsigned long idx) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci emit_opcode_unsigned(be, DW_LNS_set_file, idx); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void emit_lne_define_filename(struct buffer_ext *be, 2718c2ecf20Sopenharmony_ci const char *filename) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */ 2768c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, strlen(filename) + 5); 2778c2ecf20Sopenharmony_ci emit_opcode(be, DW_LNE_define_file); 2788c2ecf20Sopenharmony_ci emit_string(be, filename); 2798c2ecf20Sopenharmony_ci /* directory index 0=do not know */ 2808c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 2818c2ecf20Sopenharmony_ci /* last modification date on file 0=do not know */ 2828c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 2838c2ecf20Sopenharmony_ci /* filesize 0=do not know */ 2848c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void emit_lne_set_address(struct buffer_ext *be, 2888c2ecf20Sopenharmony_ci void *address) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long)); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic ubyte get_special_opcode(struct debug_entry *ent, 2948c2ecf20Sopenharmony_ci unsigned int last_line, 2958c2ecf20Sopenharmony_ci unsigned long last_vma) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci unsigned int temp; 2988c2ecf20Sopenharmony_ci unsigned long delta_addr; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * delta from line_base 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci temp = (ent->lineno - last_line) - default_debug_line_header.line_base; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (temp >= default_debug_line_header.line_range) 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* 3098c2ecf20Sopenharmony_ci * delta of addresses 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* This is not sufficient to ensure opcode will be in [0-256] but 3148c2ecf20Sopenharmony_ci * sufficient to ensure when summing with the delta lineno we will 3158c2ecf20Sopenharmony_ci * not overflow the unsigned long opcode */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (delta_addr <= 256 / default_debug_line_header.line_range) { 3188c2ecf20Sopenharmony_ci unsigned long opcode = temp + 3198c2ecf20Sopenharmony_ci (delta_addr * default_debug_line_header.line_range) + 3208c2ecf20Sopenharmony_ci default_debug_line_header.opcode_base; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return opcode <= 255 ? opcode : 0; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void emit_lineno_info(struct buffer_ext *be, 3288c2ecf20Sopenharmony_ci struct debug_entry *ent, size_t nr_entry, 3298c2ecf20Sopenharmony_ci unsigned long code_addr) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci size_t i; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Machine state at start of a statement program 3358c2ecf20Sopenharmony_ci * address = 0 3368c2ecf20Sopenharmony_ci * file = 1 3378c2ecf20Sopenharmony_ci * line = 1 3388c2ecf20Sopenharmony_ci * column = 0 3398c2ecf20Sopenharmony_ci * is_stmt = default_is_stmt as given in the debug_line_header 3408c2ecf20Sopenharmony_ci * basic block = 0 3418c2ecf20Sopenharmony_ci * end sequence = 0 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* start state of the state machine we take care of */ 3458c2ecf20Sopenharmony_ci unsigned long last_vma = 0; 3468c2ecf20Sopenharmony_ci char const *cur_filename = NULL; 3478c2ecf20Sopenharmony_ci unsigned long cur_file_idx = 0; 3488c2ecf20Sopenharmony_ci int last_line = 1; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci emit_lne_set_address(be, (void *)code_addr); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) { 3538c2ecf20Sopenharmony_ci int need_copy = 0; 3548c2ecf20Sopenharmony_ci ubyte special_opcode; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * check if filename changed, if so add it 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci if (!cur_filename || strcmp(cur_filename, ent->name)) { 3608c2ecf20Sopenharmony_ci emit_lne_define_filename(be, ent->name); 3618c2ecf20Sopenharmony_ci cur_filename = ent->name; 3628c2ecf20Sopenharmony_ci emit_set_file(be, ++cur_file_idx); 3638c2ecf20Sopenharmony_ci need_copy = 1; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci special_opcode = get_special_opcode(ent, last_line, last_vma); 3678c2ecf20Sopenharmony_ci if (special_opcode != 0) { 3688c2ecf20Sopenharmony_ci last_line = ent->lineno; 3698c2ecf20Sopenharmony_ci last_vma = ent->addr; 3708c2ecf20Sopenharmony_ci emit_opcode(be, special_opcode); 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * lines differ, emit line delta 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci if (last_line != ent->lineno) { 3768c2ecf20Sopenharmony_ci emit_advance_lineno(be, ent->lineno - last_line); 3778c2ecf20Sopenharmony_ci last_line = ent->lineno; 3788c2ecf20Sopenharmony_ci need_copy = 1; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * addresses differ, emit address delta 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (last_vma != ent->addr) { 3848c2ecf20Sopenharmony_ci emit_advance_pc(be, ent->addr - last_vma); 3858c2ecf20Sopenharmony_ci last_vma = ent->addr; 3868c2ecf20Sopenharmony_ci need_copy = 1; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * add new row to matrix 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci if (need_copy) 3928c2ecf20Sopenharmony_ci emit_opcode(be, DW_LNS_copy); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic void add_debug_line(struct buffer_ext *be, 3988c2ecf20Sopenharmony_ci struct debug_entry *ent, size_t nr_entry, 3998c2ecf20Sopenharmony_ci unsigned long code_addr) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct debug_line_header * dbg_header; 4028c2ecf20Sopenharmony_ci size_t old_size; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci old_size = buffer_ext_size(be); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci buffer_ext_add(be, (void *)&default_debug_line_header, 4078c2ecf20Sopenharmony_ci sizeof(default_debug_line_header)); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci buffer_ext_add(be, &standard_opcode_length, sizeof(standard_opcode_length)); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci // empty directory entry 4128c2ecf20Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci // empty filename directory 4158c2ecf20Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dbg_header = buffer_ext_addr(be) + old_size; 4188c2ecf20Sopenharmony_ci dbg_header->prolog_length = (buffer_ext_size(be) - old_size) - 4198c2ecf20Sopenharmony_ci offsetof(struct debug_line_header, minimum_instruction_length); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci emit_lineno_info(be, ent, nr_entry, code_addr); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci emit_lne_end_of_sequence(be); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci dbg_header = buffer_ext_addr(be) + old_size; 4268c2ecf20Sopenharmony_ci dbg_header->total_length = (buffer_ext_size(be) - old_size) - 4278c2ecf20Sopenharmony_ci offsetof(struct debug_line_header, version); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void 4318c2ecf20Sopenharmony_ciadd_debug_abbrev(struct buffer_ext *be) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 1); 4348c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, DW_TAG_compile_unit); 4358c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, DW_CHILDREN_yes); 4368c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, DW_AT_stmt_list); 4378c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, DW_FORM_data4); 4388c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 4398c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 4408c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 0); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void 4448c2ecf20Sopenharmony_ciadd_compilation_unit(struct buffer_ext *be, 4458c2ecf20Sopenharmony_ci size_t offset_debug_line) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct compilation_unit_header *comp_unit_header; 4488c2ecf20Sopenharmony_ci size_t old_size = buffer_ext_size(be); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci buffer_ext_add(be, &default_comp_unit_header, 4518c2ecf20Sopenharmony_ci sizeof(default_comp_unit_header)); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci emit_unsigned_LEB128(be, 1); 4548c2ecf20Sopenharmony_ci emit_uword(be, offset_debug_line); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci comp_unit_header = buffer_ext_addr(be) + old_size; 4578c2ecf20Sopenharmony_ci comp_unit_header->total_length = (buffer_ext_size(be) - old_size) - 4588c2ecf20Sopenharmony_ci offsetof(struct compilation_unit_header, version); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int 4628c2ecf20Sopenharmony_cijit_process_debug_info(uint64_t code_addr, 4638c2ecf20Sopenharmony_ci void *debug, int nr_debug_entries, 4648c2ecf20Sopenharmony_ci struct buffer_ext *dl, 4658c2ecf20Sopenharmony_ci struct buffer_ext *da, 4668c2ecf20Sopenharmony_ci struct buffer_ext *di) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct debug_entry *ent = debug; 4698c2ecf20Sopenharmony_ci int i; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci for (i = 0; i < nr_debug_entries; i++) { 4728c2ecf20Sopenharmony_ci ent->addr = ent->addr - code_addr; 4738c2ecf20Sopenharmony_ci ent = debug_entry_next(ent); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci add_compilation_unit(di, buffer_ext_size(dl)); 4768c2ecf20Sopenharmony_ci add_debug_line(dl, debug, nr_debug_entries, GEN_ELF_TEXT_OFFSET); 4778c2ecf20Sopenharmony_ci add_debug_abbrev(da); 4788c2ecf20Sopenharmony_ci if (0) buffer_ext_dump(da, "abbrev"); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciint 4848c2ecf20Sopenharmony_cijit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci Elf_Data *d; 4878c2ecf20Sopenharmony_ci Elf_Scn *scn; 4888c2ecf20Sopenharmony_ci Elf_Shdr *shdr; 4898c2ecf20Sopenharmony_ci struct buffer_ext dl, di, da; 4908c2ecf20Sopenharmony_ci int ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci buffer_ext_init(&dl); 4938c2ecf20Sopenharmony_ci buffer_ext_init(&di); 4948c2ecf20Sopenharmony_ci buffer_ext_init(&da); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di); 4978c2ecf20Sopenharmony_ci if (ret) 4988c2ecf20Sopenharmony_ci return -1; 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * setup .debug_line section 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci scn = elf_newscn(e); 5038c2ecf20Sopenharmony_ci if (!scn) { 5048c2ecf20Sopenharmony_ci warnx("cannot create section"); 5058c2ecf20Sopenharmony_ci return -1; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci d = elf_newdata(scn); 5098c2ecf20Sopenharmony_ci if (!d) { 5108c2ecf20Sopenharmony_ci warnx("cannot get new data"); 5118c2ecf20Sopenharmony_ci return -1; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci d->d_align = 1; 5158c2ecf20Sopenharmony_ci d->d_off = 0LL; 5168c2ecf20Sopenharmony_ci d->d_buf = buffer_ext_addr(&dl); 5178c2ecf20Sopenharmony_ci d->d_type = ELF_T_BYTE; 5188c2ecf20Sopenharmony_ci d->d_size = buffer_ext_size(&dl); 5198c2ecf20Sopenharmony_ci d->d_version = EV_CURRENT; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci shdr = elf_getshdr(scn); 5228c2ecf20Sopenharmony_ci if (!shdr) { 5238c2ecf20Sopenharmony_ci warnx("cannot get section header"); 5248c2ecf20Sopenharmony_ci return -1; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci shdr->sh_name = 52; /* .debug_line */ 5288c2ecf20Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 5298c2ecf20Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 5308c2ecf20Sopenharmony_ci shdr->sh_flags = 0; 5318c2ecf20Sopenharmony_ci shdr->sh_entsize = 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * setup .debug_info section 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci scn = elf_newscn(e); 5378c2ecf20Sopenharmony_ci if (!scn) { 5388c2ecf20Sopenharmony_ci warnx("cannot create section"); 5398c2ecf20Sopenharmony_ci return -1; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci d = elf_newdata(scn); 5438c2ecf20Sopenharmony_ci if (!d) { 5448c2ecf20Sopenharmony_ci warnx("cannot get new data"); 5458c2ecf20Sopenharmony_ci return -1; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci d->d_align = 1; 5498c2ecf20Sopenharmony_ci d->d_off = 0LL; 5508c2ecf20Sopenharmony_ci d->d_buf = buffer_ext_addr(&di); 5518c2ecf20Sopenharmony_ci d->d_type = ELF_T_BYTE; 5528c2ecf20Sopenharmony_ci d->d_size = buffer_ext_size(&di); 5538c2ecf20Sopenharmony_ci d->d_version = EV_CURRENT; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci shdr = elf_getshdr(scn); 5568c2ecf20Sopenharmony_ci if (!shdr) { 5578c2ecf20Sopenharmony_ci warnx("cannot get section header"); 5588c2ecf20Sopenharmony_ci return -1; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci shdr->sh_name = 64; /* .debug_info */ 5628c2ecf20Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 5638c2ecf20Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 5648c2ecf20Sopenharmony_ci shdr->sh_flags = 0; 5658c2ecf20Sopenharmony_ci shdr->sh_entsize = 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * setup .debug_abbrev section 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci scn = elf_newscn(e); 5718c2ecf20Sopenharmony_ci if (!scn) { 5728c2ecf20Sopenharmony_ci warnx("cannot create section"); 5738c2ecf20Sopenharmony_ci return -1; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci d = elf_newdata(scn); 5778c2ecf20Sopenharmony_ci if (!d) { 5788c2ecf20Sopenharmony_ci warnx("cannot get new data"); 5798c2ecf20Sopenharmony_ci return -1; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci d->d_align = 1; 5838c2ecf20Sopenharmony_ci d->d_off = 0LL; 5848c2ecf20Sopenharmony_ci d->d_buf = buffer_ext_addr(&da); 5858c2ecf20Sopenharmony_ci d->d_type = ELF_T_BYTE; 5868c2ecf20Sopenharmony_ci d->d_size = buffer_ext_size(&da); 5878c2ecf20Sopenharmony_ci d->d_version = EV_CURRENT; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci shdr = elf_getshdr(scn); 5908c2ecf20Sopenharmony_ci if (!shdr) { 5918c2ecf20Sopenharmony_ci warnx("cannot get section header"); 5928c2ecf20Sopenharmony_ci return -1; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci shdr->sh_name = 76; /* .debug_info */ 5968c2ecf20Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 5978c2ecf20Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 5988c2ecf20Sopenharmony_ci shdr->sh_flags = 0; 5998c2ecf20Sopenharmony_ci shdr->sh_entsize = 0; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * now we update the ELF image with all the sections 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci if (elf_update(e, ELF_C_WRITE) < 0) { 6058c2ecf20Sopenharmony_ci warnx("elf_update debug failed"); 6068c2ecf20Sopenharmony_ci return -1; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 610