162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * genelf_debug.c 462306a36Sopenharmony_ci * Copyright (C) 2015, Google, Inc 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Contributed by: 762306a36Sopenharmony_ci * Stephane Eranian <eranian@google.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * based on GPLv2 source code from Oprofile 1062306a36Sopenharmony_ci * @remark Copyright 2007 OProfile authors 1162306a36Sopenharmony_ci * @author Philippe Elie 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/compiler.h> 1462306a36Sopenharmony_ci#include <linux/zalloc.h> 1562306a36Sopenharmony_ci#include <sys/types.h> 1662306a36Sopenharmony_ci#include <stdio.h> 1762306a36Sopenharmony_ci#include <getopt.h> 1862306a36Sopenharmony_ci#include <stddef.h> 1962306a36Sopenharmony_ci#include <libelf.h> 2062306a36Sopenharmony_ci#include <string.h> 2162306a36Sopenharmony_ci#include <stdlib.h> 2262306a36Sopenharmony_ci#include <inttypes.h> 2362306a36Sopenharmony_ci#include <limits.h> 2462306a36Sopenharmony_ci#include <fcntl.h> 2562306a36Sopenharmony_ci#include <err.h> 2662306a36Sopenharmony_ci#include <dwarf.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "genelf.h" 2962306a36Sopenharmony_ci#include "../util/jitdump.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define BUFFER_EXT_DFL_SIZE (4 * 1024) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_citypedef uint32_t uword; 3462306a36Sopenharmony_citypedef uint16_t uhalf; 3562306a36Sopenharmony_citypedef int32_t sword; 3662306a36Sopenharmony_citypedef int16_t shalf; 3762306a36Sopenharmony_citypedef uint8_t ubyte; 3862306a36Sopenharmony_citypedef int8_t sbyte; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct buffer_ext { 4162306a36Sopenharmony_ci size_t cur_pos; 4262306a36Sopenharmony_ci size_t max_sz; 4362306a36Sopenharmony_ci void *data; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void 4762306a36Sopenharmony_cibuffer_ext_dump(struct buffer_ext *be, const char *msg) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci size_t i; 5062306a36Sopenharmony_ci warnx("DUMP for %s", msg); 5162306a36Sopenharmony_ci for (i = 0 ; i < be->cur_pos; i++) 5262306a36Sopenharmony_ci warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline int 5662306a36Sopenharmony_cibuffer_ext_add(struct buffer_ext *be, void *addr, size_t sz) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci void *tmp; 5962306a36Sopenharmony_ci size_t be_sz = be->max_sz; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciretry: 6262306a36Sopenharmony_ci if ((be->cur_pos + sz) < be_sz) { 6362306a36Sopenharmony_ci memcpy(be->data + be->cur_pos, addr, sz); 6462306a36Sopenharmony_ci be->cur_pos += sz; 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (!be_sz) 6962306a36Sopenharmony_ci be_sz = BUFFER_EXT_DFL_SIZE; 7062306a36Sopenharmony_ci else 7162306a36Sopenharmony_ci be_sz <<= 1; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci tmp = realloc(be->data, be_sz); 7462306a36Sopenharmony_ci if (!tmp) 7562306a36Sopenharmony_ci return -1; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci be->data = tmp; 7862306a36Sopenharmony_ci be->max_sz = be_sz; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci goto retry; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void 8462306a36Sopenharmony_cibuffer_ext_init(struct buffer_ext *be) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci be->data = NULL; 8762306a36Sopenharmony_ci be->cur_pos = 0; 8862306a36Sopenharmony_ci be->max_sz = 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void 9262306a36Sopenharmony_cibuffer_ext_exit(struct buffer_ext *be) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci zfree(&be->data); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline size_t 9862306a36Sopenharmony_cibuffer_ext_size(struct buffer_ext *be) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return be->cur_pos; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline void * 10462306a36Sopenharmony_cibuffer_ext_addr(struct buffer_ext *be) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return be->data; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistruct debug_line_header { 11062306a36Sopenharmony_ci // Not counting this field 11162306a36Sopenharmony_ci uword total_length; 11262306a36Sopenharmony_ci // version number (2 currently) 11362306a36Sopenharmony_ci uhalf version; 11462306a36Sopenharmony_ci // relative offset from next field to 11562306a36Sopenharmony_ci // program statement 11662306a36Sopenharmony_ci uword prolog_length; 11762306a36Sopenharmony_ci ubyte minimum_instruction_length; 11862306a36Sopenharmony_ci ubyte default_is_stmt; 11962306a36Sopenharmony_ci // line_base - see DWARF 2 specs 12062306a36Sopenharmony_ci sbyte line_base; 12162306a36Sopenharmony_ci // line_range - see DWARF 2 specs 12262306a36Sopenharmony_ci ubyte line_range; 12362306a36Sopenharmony_ci // number of opcode + 1 12462306a36Sopenharmony_ci ubyte opcode_base; 12562306a36Sopenharmony_ci /* follow the array of opcode args nr: ubytes [nr_opcode_base] */ 12662306a36Sopenharmony_ci /* follow the search directories index, zero terminated string 12762306a36Sopenharmony_ci * terminated by an empty string. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is 13062306a36Sopenharmony_ci * the directory index entry, 0 means current directory, then mtime 13162306a36Sopenharmony_ci * and filesize, last entry is followed by en empty string. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci /* follow the first program statement */ 13462306a36Sopenharmony_ci} __packed; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* DWARF 2 spec talk only about one possible compilation unit header while 13762306a36Sopenharmony_ci * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not 13862306a36Sopenharmony_ci * related to the used arch, an ELF 32 can hold more than 4 Go of debug 13962306a36Sopenharmony_ci * information. For now we handle only DWARF 2 32 bits comp unit. It'll only 14062306a36Sopenharmony_ci * become a problem if we generate more than 4GB of debug information. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistruct compilation_unit_header { 14362306a36Sopenharmony_ci uword total_length; 14462306a36Sopenharmony_ci uhalf version; 14562306a36Sopenharmony_ci uword debug_abbrev_offset; 14662306a36Sopenharmony_ci ubyte pointer_size; 14762306a36Sopenharmony_ci} __packed; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define DW_LNS_num_opcode (DW_LNS_set_isa + 1) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* field filled at run time are marked with -1 */ 15262306a36Sopenharmony_cistatic struct debug_line_header const default_debug_line_header = { 15362306a36Sopenharmony_ci .total_length = -1, 15462306a36Sopenharmony_ci .version = 2, 15562306a36Sopenharmony_ci .prolog_length = -1, 15662306a36Sopenharmony_ci .minimum_instruction_length = 1, /* could be better when min instruction size != 1 */ 15762306a36Sopenharmony_ci .default_is_stmt = 1, /* we don't take care about basic block */ 15862306a36Sopenharmony_ci .line_base = -5, /* sensible value for line base ... */ 15962306a36Sopenharmony_ci .line_range = -14, /* ... and line range are guessed statically */ 16062306a36Sopenharmony_ci .opcode_base = DW_LNS_num_opcode 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic ubyte standard_opcode_length[] = 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci#if 0 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci [DW_LNS_advance_pc] = 1, 17062306a36Sopenharmony_ci [DW_LNS_advance_line] = 1, 17162306a36Sopenharmony_ci [DW_LNS_set_file] = 1, 17262306a36Sopenharmony_ci [DW_LNS_set_column] = 1, 17362306a36Sopenharmony_ci [DW_LNS_fixed_advance_pc] = 1, 17462306a36Sopenharmony_ci [DW_LNS_set_isa] = 1, 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci#endif 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* field filled at run time are marked with -1 */ 17962306a36Sopenharmony_cistatic struct compilation_unit_header default_comp_unit_header = { 18062306a36Sopenharmony_ci .total_length = -1, 18162306a36Sopenharmony_ci .version = 2, 18262306a36Sopenharmony_ci .debug_abbrev_offset = 0, /* we reuse the same abbrev entries for all comp unit */ 18362306a36Sopenharmony_ci .pointer_size = sizeof(void *) 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic void emit_uword(struct buffer_ext *be, uword data) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci buffer_ext_add(be, &data, sizeof(uword)); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void emit_string(struct buffer_ext *be, const char *s) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci buffer_ext_add(be, (void *)s, strlen(s) + 1); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void emit_unsigned_LEB128(struct buffer_ext *be, 19762306a36Sopenharmony_ci unsigned long data) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci do { 20062306a36Sopenharmony_ci ubyte cur = data & 0x7F; 20162306a36Sopenharmony_ci data >>= 7; 20262306a36Sopenharmony_ci if (data) 20362306a36Sopenharmony_ci cur |= 0x80; 20462306a36Sopenharmony_ci buffer_ext_add(be, &cur, 1); 20562306a36Sopenharmony_ci } while (data); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void emit_signed_LEB128(struct buffer_ext *be, long data) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int more = 1; 21162306a36Sopenharmony_ci int negative = data < 0; 21262306a36Sopenharmony_ci int size = sizeof(long) * CHAR_BIT; 21362306a36Sopenharmony_ci while (more) { 21462306a36Sopenharmony_ci ubyte cur = data & 0x7F; 21562306a36Sopenharmony_ci data >>= 7; 21662306a36Sopenharmony_ci if (negative) 21762306a36Sopenharmony_ci data |= - (1 << (size - 7)); 21862306a36Sopenharmony_ci if ((data == 0 && !(cur & 0x40)) || 21962306a36Sopenharmony_ci (data == -1l && (cur & 0x40))) 22062306a36Sopenharmony_ci more = 0; 22162306a36Sopenharmony_ci else 22262306a36Sopenharmony_ci cur |= 0x80; 22362306a36Sopenharmony_ci buffer_ext_add(be, &cur, 1); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void emit_extended_opcode(struct buffer_ext *be, ubyte opcode, 22862306a36Sopenharmony_ci void *data, size_t data_len) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci buffer_ext_add(be, (char *)"", 1); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci emit_unsigned_LEB128(be, data_len + 1); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 23562306a36Sopenharmony_ci buffer_ext_add(be, data, data_len); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void emit_opcode(struct buffer_ext *be, ubyte opcode) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void emit_opcode_signed(struct buffer_ext *be, 24462306a36Sopenharmony_ci ubyte opcode, long data) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 24762306a36Sopenharmony_ci emit_signed_LEB128(be, data); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode, 25162306a36Sopenharmony_ci unsigned long data) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci buffer_ext_add(be, &opcode, 1); 25462306a36Sopenharmony_ci emit_unsigned_LEB128(be, data); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void emit_advance_lineno(struct buffer_ext *be, long delta_lineno) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void emit_lne_end_of_sequence(struct buffer_ext *be) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void emit_set_file(struct buffer_ext *be, unsigned long idx) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci emit_opcode_unsigned(be, DW_LNS_set_file, idx); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void emit_lne_define_filename(struct buffer_ext *be, 27862306a36Sopenharmony_ci const char *filename) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */ 28362306a36Sopenharmony_ci emit_unsigned_LEB128(be, strlen(filename) + 5); 28462306a36Sopenharmony_ci emit_opcode(be, DW_LNE_define_file); 28562306a36Sopenharmony_ci emit_string(be, filename); 28662306a36Sopenharmony_ci /* directory index 0=do not know */ 28762306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 28862306a36Sopenharmony_ci /* last modification date on file 0=do not know */ 28962306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 29062306a36Sopenharmony_ci /* filesize 0=do not know */ 29162306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void emit_lne_set_address(struct buffer_ext *be, 29562306a36Sopenharmony_ci void *address) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long)); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic ubyte get_special_opcode(struct debug_entry *ent, 30162306a36Sopenharmony_ci unsigned int last_line, 30262306a36Sopenharmony_ci unsigned long last_vma) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci unsigned int temp; 30562306a36Sopenharmony_ci unsigned long delta_addr; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * delta from line_base 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci temp = (ent->lineno - last_line) - default_debug_line_header.line_base; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (temp >= default_debug_line_header.line_range) 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * delta of addresses 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* This is not sufficient to ensure opcode will be in [0-256] but 32162306a36Sopenharmony_ci * sufficient to ensure when summing with the delta lineno we will 32262306a36Sopenharmony_ci * not overflow the unsigned long opcode */ 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (delta_addr <= 256 / default_debug_line_header.line_range) { 32562306a36Sopenharmony_ci unsigned long opcode = temp + 32662306a36Sopenharmony_ci (delta_addr * default_debug_line_header.line_range) + 32762306a36Sopenharmony_ci default_debug_line_header.opcode_base; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return opcode <= 255 ? opcode : 0; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void emit_lineno_info(struct buffer_ext *be, 33562306a36Sopenharmony_ci struct debug_entry *ent, size_t nr_entry, 33662306a36Sopenharmony_ci unsigned long code_addr) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci size_t i; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* as described in the jitdump format */ 34162306a36Sopenharmony_ci const char repeated_name_marker[] = {'\xff', '\0'}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * Machine state at start of a statement program 34562306a36Sopenharmony_ci * address = 0 34662306a36Sopenharmony_ci * file = 1 34762306a36Sopenharmony_ci * line = 1 34862306a36Sopenharmony_ci * column = 0 34962306a36Sopenharmony_ci * is_stmt = default_is_stmt as given in the debug_line_header 35062306a36Sopenharmony_ci * basic block = 0 35162306a36Sopenharmony_ci * end sequence = 0 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* start state of the state machine we take care of */ 35562306a36Sopenharmony_ci unsigned long last_vma = 0; 35662306a36Sopenharmony_ci char const *cur_filename = NULL; 35762306a36Sopenharmony_ci unsigned long cur_file_idx = 0; 35862306a36Sopenharmony_ci int last_line = 1; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci emit_lne_set_address(be, (void *)code_addr); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) { 36362306a36Sopenharmony_ci int need_copy = 0; 36462306a36Sopenharmony_ci ubyte special_opcode; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* 36762306a36Sopenharmony_ci * check if filename changed, if so add it 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if ((!cur_filename || strcmp(cur_filename, ent->name)) && 37062306a36Sopenharmony_ci strcmp(repeated_name_marker, ent->name)) { 37162306a36Sopenharmony_ci emit_lne_define_filename(be, ent->name); 37262306a36Sopenharmony_ci cur_filename = ent->name; 37362306a36Sopenharmony_ci emit_set_file(be, ++cur_file_idx); 37462306a36Sopenharmony_ci need_copy = 1; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci special_opcode = get_special_opcode(ent, last_line, last_vma); 37862306a36Sopenharmony_ci if (special_opcode != 0) { 37962306a36Sopenharmony_ci last_line = ent->lineno; 38062306a36Sopenharmony_ci last_vma = ent->addr; 38162306a36Sopenharmony_ci emit_opcode(be, special_opcode); 38262306a36Sopenharmony_ci } else { 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * lines differ, emit line delta 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci if (last_line != ent->lineno) { 38762306a36Sopenharmony_ci emit_advance_lineno(be, ent->lineno - last_line); 38862306a36Sopenharmony_ci last_line = ent->lineno; 38962306a36Sopenharmony_ci need_copy = 1; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * addresses differ, emit address delta 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci if (last_vma != ent->addr) { 39562306a36Sopenharmony_ci emit_advance_pc(be, ent->addr - last_vma); 39662306a36Sopenharmony_ci last_vma = ent->addr; 39762306a36Sopenharmony_ci need_copy = 1; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci /* 40062306a36Sopenharmony_ci * add new row to matrix 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if (need_copy) 40362306a36Sopenharmony_ci emit_opcode(be, DW_LNS_copy); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void add_debug_line(struct buffer_ext *be, 40962306a36Sopenharmony_ci struct debug_entry *ent, size_t nr_entry, 41062306a36Sopenharmony_ci unsigned long code_addr) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct debug_line_header * dbg_header; 41362306a36Sopenharmony_ci size_t old_size; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci old_size = buffer_ext_size(be); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci buffer_ext_add(be, (void *)&default_debug_line_header, 41862306a36Sopenharmony_ci sizeof(default_debug_line_header)); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci buffer_ext_add(be, &standard_opcode_length, sizeof(standard_opcode_length)); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci // empty directory entry 42362306a36Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci // empty filename directory 42662306a36Sopenharmony_ci buffer_ext_add(be, (void *)"", 1); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci dbg_header = buffer_ext_addr(be) + old_size; 42962306a36Sopenharmony_ci dbg_header->prolog_length = (buffer_ext_size(be) - old_size) - 43062306a36Sopenharmony_ci offsetof(struct debug_line_header, minimum_instruction_length); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci emit_lineno_info(be, ent, nr_entry, code_addr); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci emit_lne_end_of_sequence(be); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci dbg_header = buffer_ext_addr(be) + old_size; 43762306a36Sopenharmony_ci dbg_header->total_length = (buffer_ext_size(be) - old_size) - 43862306a36Sopenharmony_ci offsetof(struct debug_line_header, version); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void 44262306a36Sopenharmony_ciadd_debug_abbrev(struct buffer_ext *be) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci emit_unsigned_LEB128(be, 1); 44562306a36Sopenharmony_ci emit_unsigned_LEB128(be, DW_TAG_compile_unit); 44662306a36Sopenharmony_ci emit_unsigned_LEB128(be, DW_CHILDREN_yes); 44762306a36Sopenharmony_ci emit_unsigned_LEB128(be, DW_AT_stmt_list); 44862306a36Sopenharmony_ci emit_unsigned_LEB128(be, DW_FORM_data4); 44962306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 45062306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 45162306a36Sopenharmony_ci emit_unsigned_LEB128(be, 0); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void 45562306a36Sopenharmony_ciadd_compilation_unit(struct buffer_ext *be, 45662306a36Sopenharmony_ci size_t offset_debug_line) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct compilation_unit_header *comp_unit_header; 45962306a36Sopenharmony_ci size_t old_size = buffer_ext_size(be); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci buffer_ext_add(be, &default_comp_unit_header, 46262306a36Sopenharmony_ci sizeof(default_comp_unit_header)); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci emit_unsigned_LEB128(be, 1); 46562306a36Sopenharmony_ci emit_uword(be, offset_debug_line); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci comp_unit_header = buffer_ext_addr(be) + old_size; 46862306a36Sopenharmony_ci comp_unit_header->total_length = (buffer_ext_size(be) - old_size) - 46962306a36Sopenharmony_ci offsetof(struct compilation_unit_header, version); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int 47362306a36Sopenharmony_cijit_process_debug_info(uint64_t code_addr, 47462306a36Sopenharmony_ci void *debug, int nr_debug_entries, 47562306a36Sopenharmony_ci struct buffer_ext *dl, 47662306a36Sopenharmony_ci struct buffer_ext *da, 47762306a36Sopenharmony_ci struct buffer_ext *di) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct debug_entry *ent = debug; 48062306a36Sopenharmony_ci int i; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci for (i = 0; i < nr_debug_entries; i++) { 48362306a36Sopenharmony_ci ent->addr = ent->addr - code_addr; 48462306a36Sopenharmony_ci ent = debug_entry_next(ent); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci add_compilation_unit(di, buffer_ext_size(dl)); 48762306a36Sopenharmony_ci add_debug_line(dl, debug, nr_debug_entries, GEN_ELF_TEXT_OFFSET); 48862306a36Sopenharmony_ci add_debug_abbrev(da); 48962306a36Sopenharmony_ci if (0) buffer_ext_dump(da, "abbrev"); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciint 49562306a36Sopenharmony_cijit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci Elf_Data *d; 49862306a36Sopenharmony_ci Elf_Scn *scn; 49962306a36Sopenharmony_ci Elf_Shdr *shdr; 50062306a36Sopenharmony_ci struct buffer_ext dl, di, da; 50162306a36Sopenharmony_ci int ret = -1; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci buffer_ext_init(&dl); 50462306a36Sopenharmony_ci buffer_ext_init(&di); 50562306a36Sopenharmony_ci buffer_ext_init(&da); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di)) 50862306a36Sopenharmony_ci goto out; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * setup .debug_line section 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci scn = elf_newscn(e); 51462306a36Sopenharmony_ci if (!scn) { 51562306a36Sopenharmony_ci warnx("cannot create section"); 51662306a36Sopenharmony_ci goto out; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci d = elf_newdata(scn); 52062306a36Sopenharmony_ci if (!d) { 52162306a36Sopenharmony_ci warnx("cannot get new data"); 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci d->d_align = 1; 52662306a36Sopenharmony_ci d->d_off = 0LL; 52762306a36Sopenharmony_ci d->d_buf = buffer_ext_addr(&dl); 52862306a36Sopenharmony_ci d->d_type = ELF_T_BYTE; 52962306a36Sopenharmony_ci d->d_size = buffer_ext_size(&dl); 53062306a36Sopenharmony_ci d->d_version = EV_CURRENT; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci shdr = elf_getshdr(scn); 53362306a36Sopenharmony_ci if (!shdr) { 53462306a36Sopenharmony_ci warnx("cannot get section header"); 53562306a36Sopenharmony_ci goto out; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci shdr->sh_name = 52; /* .debug_line */ 53962306a36Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 54062306a36Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 54162306a36Sopenharmony_ci shdr->sh_flags = 0; 54262306a36Sopenharmony_ci shdr->sh_entsize = 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* 54562306a36Sopenharmony_ci * setup .debug_info section 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci scn = elf_newscn(e); 54862306a36Sopenharmony_ci if (!scn) { 54962306a36Sopenharmony_ci warnx("cannot create section"); 55062306a36Sopenharmony_ci goto out; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci d = elf_newdata(scn); 55462306a36Sopenharmony_ci if (!d) { 55562306a36Sopenharmony_ci warnx("cannot get new data"); 55662306a36Sopenharmony_ci goto out; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci d->d_align = 1; 56062306a36Sopenharmony_ci d->d_off = 0LL; 56162306a36Sopenharmony_ci d->d_buf = buffer_ext_addr(&di); 56262306a36Sopenharmony_ci d->d_type = ELF_T_BYTE; 56362306a36Sopenharmony_ci d->d_size = buffer_ext_size(&di); 56462306a36Sopenharmony_ci d->d_version = EV_CURRENT; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci shdr = elf_getshdr(scn); 56762306a36Sopenharmony_ci if (!shdr) { 56862306a36Sopenharmony_ci warnx("cannot get section header"); 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci shdr->sh_name = 64; /* .debug_info */ 57362306a36Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 57462306a36Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 57562306a36Sopenharmony_ci shdr->sh_flags = 0; 57662306a36Sopenharmony_ci shdr->sh_entsize = 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * setup .debug_abbrev section 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci scn = elf_newscn(e); 58262306a36Sopenharmony_ci if (!scn) { 58362306a36Sopenharmony_ci warnx("cannot create section"); 58462306a36Sopenharmony_ci goto out; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci d = elf_newdata(scn); 58862306a36Sopenharmony_ci if (!d) { 58962306a36Sopenharmony_ci warnx("cannot get new data"); 59062306a36Sopenharmony_ci goto out; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci d->d_align = 1; 59462306a36Sopenharmony_ci d->d_off = 0LL; 59562306a36Sopenharmony_ci d->d_buf = buffer_ext_addr(&da); 59662306a36Sopenharmony_ci d->d_type = ELF_T_BYTE; 59762306a36Sopenharmony_ci d->d_size = buffer_ext_size(&da); 59862306a36Sopenharmony_ci d->d_version = EV_CURRENT; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci shdr = elf_getshdr(scn); 60162306a36Sopenharmony_ci if (!shdr) { 60262306a36Sopenharmony_ci warnx("cannot get section header"); 60362306a36Sopenharmony_ci goto out; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci shdr->sh_name = 76; /* .debug_info */ 60762306a36Sopenharmony_ci shdr->sh_type = SHT_PROGBITS; 60862306a36Sopenharmony_ci shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */ 60962306a36Sopenharmony_ci shdr->sh_flags = 0; 61062306a36Sopenharmony_ci shdr->sh_entsize = 0; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * now we update the ELF image with all the sections 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_ci if (elf_update(e, ELF_C_WRITE) < 0) 61662306a36Sopenharmony_ci warnx("elf_update debug failed"); 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci ret = 0; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ciout: 62162306a36Sopenharmony_ci buffer_ext_exit(&dl); 62262306a36Sopenharmony_ci buffer_ext_exit(&di); 62362306a36Sopenharmony_ci buffer_ext_exit(&da); 62462306a36Sopenharmony_ci return ret; 62562306a36Sopenharmony_ci} 626