dwarf2.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,670 行 · 第 1/3 页
C
1,670 行
case DW_FORM_data4: DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); info_ptr += 4; break; case DW_FORM_data8: DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); info_ptr += 8; break; case DW_FORM_string: DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_block: blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block)); blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_block1: blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block)); blk->size = read_1_byte (abfd, info_ptr); info_ptr += 1; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_data1: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_flag: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_sdata: DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_udata: DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_ref1: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_ref2: DW_UNSND (attr) = read_2_bytes (abfd, info_ptr); info_ptr += 2; break; case DW_FORM_ref4: DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); info_ptr += 4; break; case DW_FORM_ref8: DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); info_ptr += 8; break; case DW_FORM_ref_udata: DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_strp: case DW_FORM_indirect: default: (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %d."), abbrev->form); bfd_set_error (bfd_error_bad_value); } return info_ptr;}/* Source line information table routines. */#define FILE_ALLOC_CHUNK 5#define DIR_ALLOC_CHUNK 5struct line_info{ struct line_info* prev_line; bfd_vma address; char* filename; unsigned int line; unsigned int column; int end_sequence; /* End of (sequential) code sequence. */};struct fileinfo{ char *name; unsigned int dir; unsigned int time; unsigned int size;};struct line_info_table{ bfd* abfd; unsigned int num_files; unsigned int num_dirs; char* comp_dir; char** dirs; struct fileinfo* files; struct line_info* last_line;};static voidadd_line_info (table, address, filename, line, column, end_sequence) struct line_info_table* table; bfd_vma address; char* filename; unsigned int line; unsigned int column; int end_sequence;{ struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, sizeof (struct line_info)); info->prev_line = table->last_line; table->last_line = info; info->address = address; info->filename = filename; info->line = line; info->column = column; info->end_sequence = end_sequence;}static char *concat_filename (table, file) struct line_info_table* table; unsigned int file;{ char* filename; if (file - 1 >= table->num_files) { (*_bfd_error_handler) (_("Dwarf Error: mangled line number section (bad file number).")); return "<unknown>"; } filename = table->files[file - 1].name; if (IS_ABSOLUTE_PATH(filename)) return filename; else { char* dirname = (table->files[file - 1].dir ? table->dirs[table->files[file - 1].dir - 1] : table->comp_dir); return (char*) concat (dirname, "/", filename, NULL); }}static voidarange_add (unit, low_pc, high_pc) struct comp_unit *unit; bfd_vma low_pc; bfd_vma high_pc;{ struct arange *arange; /* First see if we can cheaply extend an existing range. */ arange = &unit->arange; do { if (low_pc == arange->high) { arange->high = high_pc; return; } if (high_pc == arange->low) { arange->low = low_pc; return; } arange = arange->next; } while (arange); if (unit->arange.high == 0) { /* This is the first address range: store it in unit->arange. */ unit->arange.next = 0; unit->arange.low = low_pc; unit->arange.high = high_pc; return; } /* Need to allocate a new arange and insert it into the arange list. */ arange = bfd_zalloc (unit->abfd, sizeof (*arange)); arange->low = low_pc; arange->high = high_pc; arange->next = unit->arange.next; unit->arange.next = arange;}/* Decode the line number information for UNIT. */static struct line_info_table*decode_line_info (unit, stash) struct comp_unit *unit; struct dwarf2_debug *stash;{ bfd *abfd = unit->abfd; struct line_info_table* table; char *line_ptr; char *line_end; struct line_head lh; unsigned int i, bytes_read; char *cur_file, *cur_dir; unsigned char op_code, extended_op, adj_opcode; if (! stash->dwarf_line_buffer) { asection *msec; msec = bfd_get_section_by_name (abfd, ".debug_line"); if (! msec) { (*_bfd_error_handler) (_("Dwarf Error: Can't find .debug_line section.")); bfd_set_error (bfd_error_bad_value); return 0; } stash->dwarf_line_size = msec->_raw_size; stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, stash->dwarf_line_size); if (! stash->dwarf_line_buffer) return 0; if (! bfd_get_section_contents (abfd, msec, stash->dwarf_line_buffer, 0, stash->dwarf_line_size)) return 0; /* FIXME: We ought to apply the relocs against this section before we process it... */ } /* Since we are using un-relocated data, it is possible to get a bad value for the line_offset. Validate it here so that we won't get a segfault below. */ if (unit->line_offset >= stash->dwarf_line_size) { (*_bfd_error_handler) (_("Dwarf Error: Line offset (%u) greater than or equal to line size (%u)."), unit->line_offset, stash->dwarf_line_size); bfd_set_error (bfd_error_bad_value); return 0; } table = (struct line_info_table*) bfd_alloc (abfd, sizeof (struct line_info_table)); table->abfd = abfd; table->comp_dir = unit->comp_dir; table->num_files = 0; table->files = NULL; table->num_dirs = 0; table->dirs = NULL; table->files = NULL; table->last_line = NULL; line_ptr = stash->dwarf_line_buffer + unit->line_offset; /* Read in the prologue. */ lh.total_length = read_4_bytes (abfd, line_ptr); line_ptr += 4; line_end = line_ptr + lh.total_length; lh.version = read_2_bytes (abfd, line_ptr); line_ptr += 2; lh.prologue_length = read_4_bytes (abfd, line_ptr); line_ptr += 4; lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); line_ptr += 1; lh.default_is_stmt = read_1_byte (abfd, line_ptr); line_ptr += 1; lh.line_base = read_1_signed_byte (abfd, line_ptr); line_ptr += 1; lh.line_range = read_1_byte (abfd, line_ptr); line_ptr += 1; lh.opcode_base = read_1_byte (abfd, line_ptr); line_ptr += 1; lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, lh.opcode_base * sizeof (unsigned char)); lh.standard_opcode_lengths[0] = 1; for (i = 1; i < lh.opcode_base; ++i) { lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); line_ptr += 1; } /* Read directory table. */ while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) { line_ptr += bytes_read; if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) { table->dirs = (char **) bfd_realloc (table->dirs, (table->num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *)); if (! table->dirs) return 0; } table->dirs[table->num_dirs++] = cur_dir; } line_ptr += bytes_read; /* Read file name table. */ while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) { line_ptr += bytes_read; if ((table->num_files % FILE_ALLOC_CHUNK) == 0) { table->files = (struct fileinfo *) bfd_realloc (table->files, (table->num_files + FILE_ALLOC_CHUNK) * sizeof (struct fileinfo)); if (! table->files) return 0; } table->files[table->num_files].name = cur_file; table->files[table->num_files].dir = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->files[table->num_files].time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->files[table->num_files].size = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->num_files++; } line_ptr += bytes_read; /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) { /* State machine registers. */ bfd_vma address = 0; char* filename = concat_filename (table, 1); unsigned int line = 1; unsigned int column = 0; int is_stmt = lh.default_is_stmt; int basic_block = 0; int end_sequence = 0, need_low_pc = 1; bfd_vma low_pc = 0; /* Decode the table. */ while (! end_sequence) { op_code = read_1_byte (abfd, line_ptr); line_ptr += 1; switch (op_code) { case DW_LNS_extended_op: line_ptr += 1; /* Ignore length. */ extended_op = read_1_byte (abfd, line_ptr); line_ptr += 1; switch (extended_op) { case DW_LNE_end_sequence: end_sequence = 1; add_line_info (table, address, filename, line, column, end_sequence); if (need_low_pc) { need_low_pc = 0; low_pc = address; } arange_add (unit, low_pc, address); break; case DW_LNE_set_address: address = read_address (unit, line_ptr); line_ptr += unit->addr_size; break; case DW_LNE_define_file: cur_file = read_string (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; if ((table->num_files % FILE_ALLOC_CHUNK) == 0) { table->files = (struct fileinfo *) bfd_realloc (table->files, (table->num_files + FILE_ALLOC_CHUNK) * sizeof (struct fileinfo)); if (! table->files) return 0; } table->files[table->num_files].name = cur_file; table->files[table->num_files].dir = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->files[table->num_files].time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->files[table->num_files].size = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; table->num_files++; break; default: (*_bfd_error_handler) (_("Dwarf Error: mangled line number section.")); bfd_set_error (bfd_error_bad_value); return 0; } break; case DW_LNS_copy: add_line_info (table, address, filename, line, column, 0); basic_block = 0; if (need_low_pc) { need_low_pc = 0; low_pc = address; } break; case DW_LNS_advance_pc: address += lh.minimum_instruction_length * read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_advance_line: line += read_signed_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_set_file: { unsigned int file; /* The file and directory tables are 0 based, the references are 1 based. */ file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; filename = concat_filename (table, file); break; } case DW_LNS_set_column: column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_negate_stmt: is_stmt = (!is_stmt); break; case DW_LNS_set_basic_block: basic_block = 1; break; case DW_LNS_const_add_pc: address += lh.minimum_instruction_length * ((255 - lh.opcode_base) / lh.line_range); break; case DW_LNS_fixed_advance_pc: address += read_2_bytes (abfd, line_ptr); line_ptr += 2; break; default: /* Special operand. */ adj_opcode = op_code - lh.opcode_base; address += (adj_opcode / lh.line_range) * lh.minimum_instruction_length; line += lh.line_base + (adj_opcode % lh.line_range); /* Append row to matrix using current values. */ add_line_info (table, address, filename, line, column, 0); basic_block = 1; if (need_low_pc) { need_low_pc = 0; low_pc = address; } } } } return table;}/* If ADDR is within TABLE set the output parameters and return true, otherwise return false. The output parameters, FILENAME_PTR and LINENUMBER_PTR, are pointers to the objects to be filled in. */static booleanlookup_address_in_line_info_table (table, addr, filename_ptr, linenumber_ptr) struct line_info_table* table; bfd_vma addr; const char **filename_ptr; unsigned int *linenumber_ptr;{ struct line_info* next_line = table->last_line; struct line_info* each_line; if (!next_line) return false; each_line = next_line->prev_line; while (each_line && next_line) { if (!each_line->end_sequence && addr >= each_line->address && addr < next_line->address) { *filename_ptr = each_line->filename; *linenumber_ptr = each_line->line; return true; } next_line = each_line; each_line = each_line->prev_line; } return false;}/* Function table functions. */struct funcinfo{ struct funcinfo *prev_func; char* name; bfd_vma low; bfd_vma high;};/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true. */static booleanlookup_address_in_function_table (table, addr, functionname_ptr) struct funcinfo* table; bfd_vma addr; const char **functionname_ptr;{ struct funcinfo* each_func; for (each_func = table; each_func; each_func = each_func->prev_func) { if (addr >= each_func->low && addr < each_func->high) { *functionname_ptr = each_func->name; return true; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?