Browse Source

Initital trace tests. Source-level stepping works! (but with a little secret)

master
A.Olokhtonov 3 years ago
commit
edd1067fde
  1. 2
      Makefile
  2. 675
      dwarf.c
  3. 375
      main.c
  4. 37
      project.4coder
  5. 586
      structs.h
  6. 5
      trace_include.c
  7. 23
      traceme.c

2
Makefile

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
debug:
gcc main.c -g -O0 -o build/trace -Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-switch

675
dwarf.c

@ -0,0 +1,675 @@ @@ -0,0 +1,675 @@
static u64
get_section_offset(u8 *file, char *name)
{
struct elf_header_x64 header = { 0 };
memcpy(&header, file, sizeof(header));
for (int i = 0; i < header.header_table_entry_count; ++i) {
struct elf_header_table_entry_x64 header_entry = { 0 };
u64 offset = header.header_table_offset + header.header_table_entry_size * i;
memcpy(&header_entry, file + offset, sizeof(header_entry));
int a = 1;
}
struct elf_section_table_entry_x64 shstrtab_header = { 0 };
u64 shstrtab_header_offset = header.section_table_offset + header.section_table_entry_size * header.section_names_table_index;
memcpy(&shstrtab_header, file + shstrtab_header_offset, sizeof(shstrtab_header));
u64 shstrtab_offset = shstrtab_header.offset_in_file;
u64 debug_info_offset = 0;
for (int i = 0; i < header.section_table_entry_count; ++i) {
struct elf_section_table_entry_x64 section_entry = { 0 };
u64 offset = header.section_table_offset + header.section_table_entry_size * i;
memcpy(&section_entry, file + offset, sizeof(section_entry));
u64 section_name_offset = shstrtab_offset + section_entry.name_offset;
if (strncmp((char *) file + section_name_offset, name, strlen(name) + 1) == 0) {
debug_info_offset = section_entry.offset_in_file;
}
}
return(debug_info_offset);
}
static int
dwarf_section_contribution_is_64(u8 *file, u64 offset)
{
u32 length;
memcpy(&length, file + offset, 4);
return(length >= 0xFFFFFFF0);
}
static int
decode_leb128(u8 *at, u32 *dest)
{
int offset = 0;
u64 result = 0;
u64 shift = 0;
while (1) {
u8 byte = at[offset++];
result |= ((byte & 127) << shift);
if ((byte & 128) == 0) {
break;
}
shift += 7;
}
if (dest) {
*dest = result;
}
return(offset);
}
static int
decode_leb128s(u8 *at, s32 *dest)
{
int offset = 0;
s64 result = 0;
u64 shift = 0;
u32 size = 32;
u8 byte;
while (1) {
byte = at[offset++];
result |= ((byte & 127) << shift);
if ((byte & 128) == 0) {
break;
}
shift += 7;
}
if ((shift < size) && (byte & 128)) {
result |= -(1 << shift);
}
if (dest) {
*dest = result;
}
return(offset);
}
static u64
abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code)
{
u32 code, tag;
u32 offset = 0;
do {
offset += decode_leb128(file + abbrev_offset + offset, &code);
offset += decode_leb128(file + abbrev_offset + offset, &tag);
u32 has_children = file[abbrev_offset + offset++];
if (code == requested_code) {
return(abbrev_offset);
}
if (code == 0) {
/* Abbreviation code not found, this should not happen */
assert(0);
return(0);
}
u32 attribute, form;
do {
offset += decode_leb128(file + abbrev_offset + offset, &form);
offset += decode_leb128(file + abbrev_offset + offset, &attribute);
} while (attribute != 0 || form != 0);
abbrev_offset += offset;
offset = 0;
} while (code != 0);
assert(0);
return(0);
}
static u64
find_subroutine_offset(u8 *file, u64 header_size, u8 address_size,
u64 string_offset, u64 abbrev_offset, u64 data_offset,
char *subroutine)
{
u32 code, tag;
u64 schema_offset;
u32 depth = 0;
u64 original_data_offset = data_offset;
int found_sr = 0;
do {
data_offset += decode_leb128(file + data_offset, &code);
if (code == 0) {
if (depth > 1) {
--depth;
continue;
} else {
break;
}
}
schema_offset = abbrev_entry_offset(file, abbrev_offset, code);
schema_offset += decode_leb128(file + schema_offset, NULL);
schema_offset += decode_leb128(file + schema_offset, &tag);
//printf("%d %s\n", code, tag_to_str(tag));
u32 has_children = file[schema_offset++];
if (has_children) {
++depth;
}
u32 attribute, form;
do {
schema_offset += decode_leb128(file + schema_offset, &attribute);
schema_offset += decode_leb128(file + schema_offset, &form);
if (attribute) {
//printf("\t%s ", attribute_to_str(attribute));
}
switch (form) {
case DW_FORM_sec_offset:
case DW_FORM_strp: {
u32 data = file[data_offset];
data_offset += 4; // 8 bytes for x64 DWARF!
if (form == DW_FORM_strp) {
char *str = (char *) file + string_offset + data;
//printf("(indirect string, offset: %#x): %s\n", data, str);
if (tag == DW_TAG_subprogram) {
if (strcmp(str, subroutine) == 0) {
found_sr = 1;
}
}
} else {
//printf("%#x\n", data);
}
break;
}
case DW_FORM_addr: {
u64 data = 0;
memcpy(&data, file + data_offset, address_size);
data_offset += address_size;
//printf("%#lx\n", data);
if (tag == DW_TAG_subprogram && found_sr == 1 && attribute == DW_AT_low_pc) {
return(data);
}
break;
};
case DW_FORM_string: {
char *data = (char *) file + data_offset;
data_offset += strlen(data) + 1;
//printf("%s\n", data);
break;
}
case DW_FORM_flag_present: {
int data = 1;
//printf("Flag = 1\n");
break;
}
case DW_FORM_ref4: {
u32 data = file[data_offset];
data_offset += 4;
//printf("%#x\n", data);
u32 referenced_data = file[original_data_offset - header_size + data];
break;
}
case DW_FORM_exprloc: {
u32 length;
data_offset += decode_leb128(file + data_offset, &length);
//printf("%d byte block:", length);
for (u32 i = 0; i < length; ++i) {
//printf(" %x", file[data_offset + i]);
}
//printf("\n");
data_offset += length;
break;
}
case DW_FORM_data1: {
u8 data = file[data_offset];
data_offset += 1;
//printf("%#x\n", data);
break;
};
case DW_FORM_data2: {
u16 data = file[data_offset];
data_offset += 2;
//printf("%#x\n", data);
break;
};
case DW_FORM_data4: {
u32 data = file[data_offset];
data_offset += 4;
//printf("%#x\n", data);
break;
};
case DW_FORM_data8: {
u64 data = file[data_offset];
data_offset += 8;
//printf("%#lx\n", data);
break;
};
default: {
if (form) {
//printf("unknown attribute form %d\n", form);
}
}
}
} while (attribute != 0 || form != 0);
} while (1);
return(0);
}
static u64
read_line_number_info(u8 *file, u64 dl_offset, u64 pc)
{
struct dwarf_debug_line_header_v3_x32 header = { 0 };
memcpy(&header, file + dl_offset, 15); /* all fixed-size info */
dl_offset += 15;
header.standard_opcode_lengths = malloc(header.opcode_base - 1);
memcpy(header.standard_opcode_lengths, file + dl_offset, header.opcode_base - 1);
dl_offset += header.opcode_base - 1;
/* "Each entry is a null-terminated string containing a full path name. The last entry
is followed by a single null byte." */
u8 ndirs = 0;
u8 nfiles = 0;
u8 *p = file + dl_offset;
while (*p != 0) {
++ndirs;
while (*p != 0) {
++p;
}
}
header.ndirs = ndirs;
header.include_directories = 0; // malloc(ndirs * sizeof(char *));
dl_offset += (p - (file + dl_offset)) + 1;
p = file + dl_offset;
while (*p != 0) {
++nfiles;
/* null-terminated string */
while (*p != 0) {
++p;
}
++p;
u64 offset = 0;
u32 dummy = 0;
offset += decode_leb128(p, &dummy);
offset += decode_leb128(p, &dummy);
offset += decode_leb128(p, &dummy);
p += offset;
}
header.files = malloc(nfiles * sizeof(struct dwarf_debug_line_file_info));
header.nfiles = nfiles;
struct dwarf_debug_line_file_info *f = header.files;
p = file + dl_offset;
while (*p != 0) {
/* null-terminated string */
f->name = (char *) p;
while (*p != 0) {
++p;
}
++p;
u64 offset = 0;
u32 dummy = 0;
offset += decode_leb128(p, &f->directory_index);
offset += decode_leb128(p, &f->time_modified);
offset += decode_leb128(p, &f->file_size);
p += offset;
++f;
}
dl_offset = p - file + 1;
u8 opcode;
enum dwarf_lnp_opcode opcode_regular;
enum dwarf_lnp_opcode_extended opcode_extended;
p = file + dl_offset;
struct dwarf_line_number_state state = { 0 };
state.file = 1;
state.line = 1;
state.is_stmt = header.default_is_stmt;
u64 last_line = 0;
do {
opcode = *p;
++p;
u8 nops = 0;
if (opcode) {
if (opcode <= header.opcode_base) {
/* standart opcode */
opcode_regular = opcode;
switch (opcode_regular) {
case DW_LNS_copy: {
state.basic_block = 0;
state.prologue_end = 0;
state.epilogue_begin = 0;
break;
}
case DW_LNS_advance_pc: {
u32 operand;
p += decode_leb128(p, &operand);
operand *= header.minimum_instruction_length;
state.pc += operand;
break;
}
case DW_LNS_advance_line: {
s32 operand;
p += decode_leb128s(p, &operand);
last_line = state.line;
state.line += operand;
break;
}
case DW_LNS_set_file: {
u32 operand;
p += decode_leb128(p, &operand);
operand *= header.minimum_instruction_length;
state.file = operand;
// printf("Switch to file %s in directory %d\n", header.files[state.file - 1].name, header.files[state.file - 1].directory_index);
break;
}
case DW_LNS_set_column: {
u32 operand;
p += decode_leb128(p, &operand);
operand *= header.minimum_instruction_length;
state.column = operand;
break;
}
case DW_LNS_negate_stmt: {
state.is_stmt = 1 - state.is_stmt;
break;
}
case DW_LNS_set_basic_block: {
state.basic_block = 1;
break;
}
case DW_LNS_const_add_pc: {
u8 adjusted = 255 - header.opcode_base;
s32 address_increment = (adjusted / header.line_range) * header.minimum_instruction_length;
state.pc += address_increment;
break;
}
case DW_LNS_fixed_advance_pc: {
u16 operand;
memcpy(&operand, p, 2);
p += 2;
state.pc += operand;
break;
}
case DW_LNS_set_prologue_end: {
state.prologue_end = 1;
break;
}
case DW_LNS_set_epilogue_begin: {
state.epilogue_begin = 1;
break;
}
case DW_LNS_set_isa: {
u32 operand;
p += decode_leb128(p, &operand);
operand *= header.minimum_instruction_length;
state.isa = operand;
break;
}
}
} else {
/* special opcode */
u8 adjusted = opcode - header.opcode_base;
s32 address_increment = (adjusted / header.line_range) * header.minimum_instruction_length;
s32 line_increment = header.line_base + (adjusted % header.line_range);
last_line = state.line;
state.pc += address_increment;
state.line += line_increment;
state.basic_block = 0;
state.prologue_end = 0;
state.epilogue_begin = 0;
state.discriminator = 0;
}
} else {
/* extended opcode */
u32 instruction_length;
p += decode_leb128(p, &instruction_length);
opcode = *p;
opcode_extended = opcode;
++p;
switch (opcode_extended) {
case DW_LNE_end_sequence: {
state.end_sequence = 1;
//printf("END: %lx -> %d\n", state.pc, state.line);
memset(&state, 0, sizeof(state));
state.file = 1;
state.line = 1;
state.is_stmt = header.default_is_stmt;
break;
}
case DW_LNE_set_address: {
u64 address;
memcpy(&address, p, 8);
state.pc = address;
p += 8;
break;
}
case DW_LNE_define_file: {
struct dwarf_debug_line_file_info f = { 0 };
f.name = (char *) p;
while (*p != 0) {
++p;
}
++p;
p += decode_leb128(p, &f.directory_index);
p += decode_leb128(p, &f.time_modified);
p += decode_leb128(p, &f.file_size);
break;
}
case DW_LNE_set_discriminator: {
u32 operand;
p += decode_leb128(p, &operand);
operand *= header.minimum_instruction_length;
state.discriminator = operand;
break;
break;
}
}
}
// TODO: this is off by one?
if (state.pc >= pc) {
return(last_line);
}
} while (opcode_extended != DW_LNE_end_sequence);
return(0);
}
static u64
get_executable_base_address(u8 *elf_file, int pid)
{
char path[256] = { 0 };
snprintf(path, 256, "/proc/%d/maps", pid);
FILE *maps_file = fopen(path, "rb");
if (!maps_file) {
DIE("proc map not found\n");
}
struct elf_header_x64 header = { 0 };
memcpy(&header, elf_file, sizeof(header));
u64 elf_offset = 0;
for (int i = 0; i < header.header_table_entry_count; ++i) {
struct elf_header_table_entry_x64 header_entry = { 0 };
u64 offset = header.header_table_offset + header.header_table_entry_size * i;
memcpy(&header_entry, elf_file + offset, sizeof(header_entry));
//printf("%#018lx %s\n", header_entry.segment_offset, header_entry.flags & PF_X ? "E" : "");
if (header_entry.flags & PF_X) {
elf_offset = header_entry.segment_offset;
break;
}
}
if (!elf_offset) {
return(0);
}
size_t len;
char *line = malloc(4096);
while ((len = getline(&line, &len, maps_file)) != -1UL) {
u64 base;
u64 end;
u64 offset;
char *at = line;
base = strtoll(at, &at, 16);
return(base);
end = strtoll(at + 1, &at, 16);
(void) end;
while (*at < '0' || *at > '9') ++at;
offset = strtoll(at, &at, 16);
if (offset == elf_offset) {
return(base);
}
}
free(line);
return(0);
}
static u64
get_address_of_subroutine(u8 *file, char *sr)
{
u64 debug_info_offset = get_section_offset(file, ".debug_info");
printf("Found .debug_info at offset %#lx\n", debug_info_offset);
u64 debug_line_offset = get_section_offset(file, ".debug_line");
printf("Found .debug_line at offset %#lx\n", debug_line_offset);
u64 debug_abbrev_offset = get_section_offset(file, ".debug_abbrev");
printf("Found .debug_abbrev at offset %#lx\n", debug_abbrev_offset);
u64 debug_str_offset = get_section_offset(file, ".debug_str");
printf("Found .debug_str at offset %#lx\n", debug_str_offset);
struct dwarf_debug_info_header_x32 di_header = { 0 };
memcpy(&di_header, file + debug_info_offset, sizeof(di_header));
u64 abbrev_offset = debug_abbrev_offset + di_header.debug_abbrev_offset;
u64 data_offset = debug_info_offset + sizeof(di_header);
u64 result = find_subroutine_offset(file, sizeof(di_header), di_header.address_size,
debug_str_offset, abbrev_offset, data_offset, sr);
//read_line_number_info(file, debug_line_offset);
return(result);
}
static u64
pc_to_line_number(u8 *file, u64 pc)
{
u64 debug_line_offset = get_section_offset(file, ".debug_line");
//printf("Found .debug_line at offset %#lx\n", debug_line_offset);
u64 result = read_line_number_info(file, debug_line_offset, pc);
return(result);
}

375
main.c

@ -0,0 +1,375 @@ @@ -0,0 +1,375 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <syscall.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/personality.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
#define NT_PRSTATUS 1
#define DIE(string) do { fprintf(stderr, string); exit(1); } while (0)
#include "structs.h"
struct mi_process {
pid_t pid;
char *source;
u64 source_size;
u8 *elf;
u64 elf_size;
u64 base_address;
u64 main_address;
};
struct mi_registers {
u64 rbp;
u64 rbx;
u64 rax;
u64 rcx;
u64 rdx;
u64 rsi;
u64 rdi;
u64 rip;
u64 rsp;
struct user_regs_struct _sys;
};
#include "dwarf.c"
static void
print_word_at_address(int child, u64 address)
{
long word = ptrace(PTRACE_PEEKDATA, child, address, NULL);
u8 nb[4];
memcpy(nb, &word, 4);
printf("word at %#018lx: {%x %x %x %x}\n", address, nb[0], nb[1], nb[2], nb[3]);
}
static void
print_current_line(struct mi_process proc, u64 line)
{
char *source = proc.source;
u64 size = proc.source_size;
u64 current_line = 1;
for (u32 i = 0; i < size; ++i) {
if (current_line == line) {
int len = 0;
int start = 0;
int leading = 1;
for (u32 j = i; j < size; ++j) {
if (leading && (source[j] == '\t' || source[j] == ' ')) {
++start;
} else {
leading = 0;
}
if (source[j] == '\n') {
break;
}
++len;
}
printf("%.*s\n", len - start, source + i + start);
return;
}
if (source[i] == '\n') {
current_line++;
}
}
}
static struct mi_process
process_create(char *path)
{
struct mi_process result = { 0 };
/* disable ASLR */
syscall(SYS_personality, ADDR_NO_RANDOMIZE);
pid_t pid = fork();
if (pid == -1) {
DIE("fork error\n");
}
if (pid == 0) {
int rt = ptrace(PTRACE_TRACEME, 0, 0, 0);
assert(rt == 0);
char *args[] = { path, NULL };
rt = execvp(path, args);
if (rt == -1) {
DIE("exevp error\n");
}
}
u64 source_size;
u64 elf_size;
u8 *elf;
char *source;
struct stat s;
int fd;
{
fd = open(path, O_RDONLY);
assert(fd != -1);
fstat(fd, &s);
elf_size = s.st_size;
elf = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
}
{
fd = open("/code/trace-test/traceme.c", O_RDONLY); // TODO
assert(fd != -1);
fstat(fd, &s);
source_size = s.st_size;
source = mmap(0, source_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
}
result.elf = elf;
result.elf_size = elf_size;
result.source = source;
result.source_size = source_size;
result.pid = pid;
return(result);
}
static struct mi_registers
get_process_registers(struct mi_process proc)
{
struct user_regs_struct regs = { 0 };
struct iovec iov = { &regs, sizeof(regs) };
struct mi_registers result = { 0 };
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov);
result.rax = regs.rax;
result.rip = regs.rip;
result.rbp = regs.rbp;
result.rbx = regs.rbx;
result.rcx = regs.rcx;
result.rdx = regs.rdx;
result.rsi = regs.rsi;
result.rdi = regs.rdi;
result.rsp = regs.rsp;
result._sys = regs;
return(result);
}
static void
set_process_registers(struct mi_process proc, struct mi_registers regs)
{
struct iovec iov = { &regs._sys, sizeof(regs._sys) };
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov);
}
static void
print_current_instruction(struct mi_process proc)
{
struct mi_registers regs = get_process_registers(proc);
long wordb = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip - 4, NULL);
long word = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL);
long worda = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip + 4, NULL);
u8 nb[12];
memcpy(nb, &wordb, 4);
memcpy(nb + 4, &word, 4);
memcpy(nb + 8, &worda, 4);
printf("PC = %#018lx: %x %x %x %x [%x] %x %x %x %x %x %x %x\n", regs.rip,
nb[0], nb[1], nb[2], nb[3], nb[4], nb[5], nb[6], nb[7],
nb[8], nb[9], nb[10], nb[11]);
}
static void
command_regs(struct mi_process proc)
{
struct mi_registers regs = get_process_registers(proc);
printf("rax = %#018lx rcx = %#018lx\n"
"rbp = %#018lx rbx = %#018lx\n"
"rdx = %#018lx rsi = %#018lx\n"
"rdi = %#018lx rip = %#018lx\n"
"rsp = %#018lx\n",
regs.rax, regs.rcx, regs.rbp, regs.rbx,
regs.rdx, regs.rsi, regs.rdi, regs.rip,
regs.rsp);
}
static void
command_step(struct mi_process proc)
{
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
#if 1
print_current_instruction(proc);
struct mi_registers regs = get_process_registers(proc);
u64 line_number = pc_to_line_number(proc.elf, regs.rip - proc.base_address);
print_current_line(proc, line_number);
#endif
}
static void
command_start(struct mi_process proc)
{
u64 main_address = proc.base_address + proc.main_address;
long saved_instruction = ptrace(PTRACE_PEEKDATA, proc.pid, main_address, NULL);
long int3_byte = 0x000000cc;
long int3_word = (saved_instruction & 0xFFFFFF00) | int3_byte;
/* write 0xcc */
ptrace(PTRACE_POKEDATA, proc.pid, main_address, int3_word);
/* wait till child hits the interrupt */
ptrace(PTRACE_CONT, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
/* restore original instrucion */
ptrace(PTRACE_POKEDATA, proc.pid, main_address, saved_instruction);
/* step back to original instruction */
struct mi_registers regs = get_process_registers(proc);
regs.rip -= 1;
set_process_registers(proc, regs);
}
static void
command_next(struct mi_process proc)
{
struct mi_registers regs = get_process_registers(proc);
u64 line_number = pc_to_line_number(proc.elf, regs.rip - proc.base_address);
u64 next_line_number;
do {
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
regs = get_process_registers(proc);
//printf("%#lx\n", regs.rip - proc.base_address);
next_line_number= pc_to_line_number(proc.elf, regs.rip - proc.base_address);
// TODO: skip call, repXXX, etc
} while (next_line_number == line_number);
print_current_line(proc, next_line_number);
}
static void
command_list(struct mi_process proc)
{
struct mi_registers regs = get_process_registers(proc);
u64 line_number = pc_to_line_number(proc.elf, regs.rip - proc.base_address);
print_current_line(proc, line_number);
}
static void
command_cont(struct mi_process proc)
{
ptrace(PTRACE_CONT, proc.pid, 0, 0);
// TODO
}
static void
command_stop(struct mi_process proc)
{
kill(proc.pid, SIGINT);
// TODO
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
printf("Usage: %s executable\n", argv[0]);
return(1);
}
struct mi_process process = process_create(argv[1]);
printf("pid of child = %d\n", process.pid);
size_t max_command_length = 1023;
int command_length = 0;
char *command = malloc(max_command_length + 1);
process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid);
process.main_address = get_address_of_subroutine(process.elf, "main");
printf("Base address: %#lx\n", process.base_address);
printf("Main address: %#lx\n", process.main_address);
printf("> ");
fflush(stdout);
while ((command_length = getline(&command, &max_command_length, stdin))) {
if (0 == strncmp(command, "exit\n", command_length) || 0 == strncmp(command, "q\n", command_length)) {
break;
} else if (strncmp(command, "regs\n", command_length) == 0) {
command_regs(process);
} else if (strncmp(command, "step\n", command_length) == 0) {
command_step(process);
} else if (strncmp(command, "start\n", command_length) == 0) {
command_start(process);
} else if (strncmp(command, "next\n", command_length) == 0) {
command_next(process);
} else if (strncmp(command, "line\n", command_length) == 0) {
command_list(process);
} else if (strncmp(command, "cont\n", command_length) == 0) {
command_cont(process);
} else if (strncmp(command, "stop\n", command_length) == 0) {
command_stop(process);
} else {
printf("Unknown command: %*s", command_length, command);
}
int wstatus;
int rt = waitpid(process.pid, &wstatus, WNOHANG);
if (rt > 0 && WIFEXITED(wstatus)) {
printf("Child exited\n");
break;
}
printf("> ");
}
return(0);
}

37
project.4coder

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
version(1);
project_name = "trace-test";
patterns = {
"*.c",
"*.h",
"*.4coder",
};
blacklist_patterns = {
".*",
"res",
"lib",
"build/*"
};
load_paths_base = {
{ ".", .relative = true, .recursive = true, }
};
load_paths = {
{ load_paths_base, .os = "linux", }
};
command_list = {
{
.name = "build debug",
.out = "*compilation*",
.footer_panel = false,
.save_dirty_files = true,
.cursor_at_end = true,
.cmd = {{ "make debug", .os = "linux" }},
},
};
fkey_command[1] = "build debug";

586
structs.h

@ -0,0 +1,586 @@ @@ -0,0 +1,586 @@
#define PF_X (1 << 0)
#define PF_W (1 << 1)
#define PF_R (1 << 2)
enum elf_abi {
SYSTEM_V = 0x00,
HP_UX = 0x01,
NETBSD = 0x02,
LINUX = 0x03,
GNU_HURD = 0x04,
SOLARIS = 0x06,
AIX = 0x07,
IRIX = 0x08,
FREEBSD = 0x09,
TRU64 = 0x0A,
NOVELL_MODESTO = 0x0B,
OPENBSD = 0x0D,
OPENVMS = 0x0E,
NONTSTOP_KERNEL = 0x0E,
AROS = 0x0F,
FENIX_OS = 0x10,
CLOUDABI = 0x11,
STRATUS_TECHNOLOGIES_OPENVOS = 0x12
};
enum elf_file_type {
ET_NONE = 0x00,
ET_REL = 0x01,
ET_EXEC = 0x02,
ET_DYN = 0x03,
ET_CORE = 0x04,
ET_LOOS = 0xFE00,
ET_HIOS = 0xFEFF,
ET_LOPROC = 0xFF00,
ET_HIPROC = 0xFFFF
};
enum elf_isa {
NO_SPECIFIC_INSTRUCTION_SET = 0x00,
ATNT_WE_32100 = 0x01,
SPARC = 0x02,
X86 = 0x03,
MOTOROLA_68000 = 0x04,
MOTOROLA_88000 = 0x05,
INTEL_MCU = 0x06,
INTEL_80860 = 0x07,
MIPS = 0x08,
IBM_SYSTEM_370 = 0x09,
MIPS_RS3000_LITTLE_ENDIAN = 0x0A,
HEWLETT_PACKARD_PA_RISC = 0x0E,
INTEL_80960 = 0x13,
POWERPC = 0x14,
POWERPC_64 = 0x15,
S390_S390X = 0x16,
ARM = 0x28,
SUPERH = 0x2A,
IA_64 = 0x32,
AMD64 = 0x3E,
TMS320C6000_FAMILY = 0x8C,
ARM_64 = 0xB7,
RISC_V = 0xF3,
BERKELEY_PACKET_FILTER = 0xF7,
WDC_65C816 = 0x10
};
enum elf_section_type {
SHT_NULL = 0, // No associated section (inactive entry).
SHT_PROGBITS = 1, // Program-defined contents.
SHT_SYMTAB = 2, // Symbol table.
SHT_STRTAB = 3, // String table.
SHT_RELA = 4, // Relocation entries; explicit addends.
SHT_HASH = 5, // Symbol hash table.
SHT_DYNAMIC = 6, // Information for dynamic linking.
SHT_NOTE = 7, // Information about the file.
SHT_NOBITS = 8, // Data occupies no space in the file.
SHT_REL = 9, // Relocation entries; no explicit addends.
SHT_SHLIB = 10, // Reserved.
SHT_DYNSYM = 11, // Symbol table.
SHT_INIT_ARRAY = 14, // Pointers to initialization functions.
SHT_FINI_ARRAY = 15, // Pointers to termination functions.
SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions.
SHT_GROUP = 17, // Section group.
SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries.
SHT_RELR = 19, // Relocation entries; only offsets.
SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
SHT_HIOS = 0x6fffffff, // Highest operating system-specific type.
SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type.
SHT_HEX_ORDERED = 0x70000000,
SHT_X86_64_UNWIND = 0x70000001, // Unwind information
SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type.
SHT_LOUSER = 0x80000000, // Lowest type reserved for applications.
SHT_HIUSER = 0xffffffff // Highest type reserved for applications.
};
enum dwarf_die_tag {
DW_TAG_array_type = 0x01,
DW_TAG_class_type = 0x02,
DW_TAG_entry_point = 0x03,
DW_TAG_enumeration_type = 0x04,
DW_TAG_formal_parameter = 0x05,
DW_TAG_imported_declaration = 0x08,
DW_TAG_label = 0x0a,
DW_TAG_lexical_block = 0x0b,
DW_TAG_member = 0x0d,
DW_TAG_pointer_type = 0x0f,
DW_TAG_reference_type = 0x10,
DW_TAG_compile_unit = 0x11,
DW_TAG_string_type = 0x12,
DW_TAG_structure_type = 0x13,
DW_TAG_subroutine_type = 0x15,
DW_TAG_typedef = 0x16,
DW_TAG_union_type = 0x17,
DW_TAG_unspecified_parameters = 0x18,
DW_TAG_variant = 0x19,
DW_TAG_common_block = 0x1a,
DW_TAG_common_inclusion = 0x1b,
DW_TAG_inheritance = 0x1c,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_module = 0x1e,
DW_TAG_ptr_to_member_type = 0x1f,
DW_TAG_set_type = 0x20,
DW_TAG_subrange_type = 0x21,
DW_TAG_with_stmt = 0x22,
DW_TAG_access_declaration = 0x23,
DW_TAG_base_type = 0x24,
DW_TAG_catch_block = 0x25,
DW_TAG_const_type = 0x26,
DW_TAG_constant = 0x27,
DW_TAG_enumerator = 0x28,
DW_TAG_file_type = 0x29,
DW_TAG_friend = 0x2a,
DW_TAG_namelist = 0x2b,
DW_TAG_namelist_item = 0x2c,
DW_TAG_namelist_items = 0x2c,
DW_TAG_packed_type = 0x2d,
DW_TAG_subprogram = 0x2e,
DW_TAG_thrown_type = 0x31,
DW_TAG_try_block = 0x32,
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
DW_TAG_lo_user = 0x4080,
DW_TAG_MIPS_loop = 0x4081,
DW_TAG_hi_user = 0xffff
};
enum dwarf_die_attribute {
DW_AT_sibling = 0x01,
DW_AT_location = 0x02,
DW_AT_name = 0x03,
DW_AT_ordering = 0x09,
DW_AT_subscr_data = 0x0a,
DW_AT_byte_size = 0x0b,
DW_AT_bit_offset = 0x0c,
DW_AT_bit_size = 0x0d,
DW_AT_element_list = 0x0f,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_language = 0x13,
DW_AT_member = 0x14,
DW_AT_discr = 0x15,
DW_AT_discr_value = 0x16,
DW_AT_visibility = 0x17,
DW_AT_import = 0x18,
DW_AT_string_length = 0x19,
DW_AT_common_reference = 0x1a,
DW_AT_comp_dir = 0x1b,
DW_AT_const_value = 0x1c,
DW_AT_containing_type = 0x1d,
DW_AT_default_value = 0x1e,
DW_AT_inline = 0x20,
DW_AT_is_optional = 0x21,
DW_AT_lower_bound = 0x22,
DW_AT_producer = 0x25,
DW_AT_prototyped = 0x27,
DW_AT_return_addr = 0x2a,
DW_AT_start_scope = 0x2c,
DW_AT_upper_bound = 0x2f,
DW_AT_abstract_origin = 0x31,
DW_AT_accessibility = 0x32,
DW_AT_address_class = 0x33,
DW_AT_artificial = 0x34,
DW_AT_base_types = 0x35,
DW_AT_calling_convention = 0x36,
DW_AT_count = 0x37,
DW_AT_data_member_location = 0x38,
DW_AT_decl_column = 0x39,
DW_AT_decl_file = 0x3a,
DW_AT_decl_line = 0x3b,
DW_AT_declaration = 0x3c,
DW_AT_encoding = 0x3e,
DW_AT_external = 0x3f,
DW_AT_frame_base = 0x40,
DW_AT_friend = 0x41,
DW_AT_identifier_case = 0x42,
DW_AT_macro_info = 0x43,
DW_AT_namelist_item = 0x44,
DW_AT_priority = 0x45,
DW_AT_segment = 0x46,
DW_AT_specification = 0x47,
DW_AT_static_link = 0x48,
DW_AT_type = 0x49,
DW_AT_use_location = 0x4a,
DW_AT_variable_parameter = 0x4b,
DW_AT_virtuality = 0x4c,
DW_AT_vtable_elem_location = 0x4d,
DW_AT_signature = 0x69,
DW_AT_main_subprogram = 0x6a,
DW_AT_data_bit_offset = 0x6b,
DW_AT_const_expr = 0x6c,
DW_AT_enum_class = 0x6d,
DW_AT_linkage_name = 0x6e,
DW_AT_string_length_bit_size = 0x6f,
DW_AT_string_length_byte_size = 0x70,
DW_AT_rank = 0x71,
DW_AT_str_offsets_base = 0x72,
DW_AT_addr_base = 0x73,
DW_AT_rnglists_base = 0x74,
DW_AT_dwo_id = 0x75,
DW_AT_dwo_name = 0x76,
DW_AT_reference = 0x77,
DW_AT_rvalue_reference = 0x78,
DW_AT_macros = 0x79,
DW_AT_call_all_calls = 0x7a,
DW_AT_call_all_source_calls = 0x7b,
DW_AT_call_all_tail_calls = 0x7c,
DW_AT_call_return_pc = 0x7d,
DW_AT_call_value = 0x7e,
DW_AT_call_origin = 0x7f,
DW_AT_call_parameter = 0x80,
DW_AT_call_pc = 0x81,
DW_AT_call_tail_call = 0x82,
DW_AT_call_target = 0x83,
DW_AT_call_target_clobbered = 0x84,
DW_AT_call_data_location = 0x85,
DW_AT_call_data_value = 0x86,
DW_AT_noreturn = 0x87,
DW_AT_alignment = 0x88,
DW_AT_export_symbols = 0x89,
DW_AT_deleted = 0x8a,
DW_AT_defaulted = 0x8b,
DW_AT_loclists_base = 0x8c
};
enum dwarf_attribute_form {
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0a,
DW_FORM_data1 = 0x0b,
DW_FORM_flag = 0x0c,
DW_FORM_sdata = 0x0d,
DW_FORM_strp = 0x0e,
DW_FORM_udata = 0x0f,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16,
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
DW_FORM_strx = 0x1a,
DW_FORM_addrx = 0x1b,
DW_FORM_ref_sup4 = 0x1c,
DW_FORM_strp_sup = 0x1d,
DW_FORM_data16 = 0x1e,
DW_FORM_line_strp = 0x1f,
DW_FORM_ref_sig8 = 0x20,
DW_FORM_implicit_const = 0x21,
DW_FORM_loclistx = 0x22,
DW_FORM_rnglistx = 0x23,
DW_FORM_ref_sup8 = 0x24,
DW_FORM_strx1 = 0x25,
DW_FORM_strx2 = 0x26,
DW_FORM_strx3 = 0x27,
DW_FORM_strx4 = 0x28,
DW_FORM_addrx1 = 0x29,
DW_FORM_addrx2 = 0x2a,
DW_FORM_addrx3 = 0x2b,
DW_FORM_addrx4 = 0x2c
};
enum dwarf_lnp_opcode {
DW_LNS_copy = 0x01,
DW_LNS_advance_pc = 0x02,
DW_LNS_advance_line = 0x03,
DW_LNS_set_file = 0x04,
DW_LNS_set_column = 0x05,
DW_LNS_negate_stmt = 0x06,
DW_LNS_set_basic_block = 0x07,
DW_LNS_const_add_pc = 0x08,
DW_LNS_fixed_advance_pc = 0x09,
DW_LNS_set_prologue_end = 0x0a,
DW_LNS_set_epilogue_begin = 0x0b,
DW_LNS_set_isa = 0x0c,
};
enum dwarf_lnp_opcode_extended {
DW_LNE_end_sequence = 0x01,
DW_LNE_set_address = 0x02,
DW_LNE_define_file = 0x03,
DW_LNE_set_discriminator = 0x04,
};
#pragma pack(1)
struct elf_header_x64 {
char magic[4];
u8 bitness;
u8 endianness;
u8 ei_version;
u8 abi;
u8 abi_version;
u8 pad[7];
u16 file_type;
u16 isa;
u32 version;
u64 entry_point_offset;
u64 header_table_offset;
u64 section_table_offset;
u32 flags;
u16 this_header_size;
u16 header_table_entry_size;
u16 header_table_entry_count;
u16 section_table_entry_size;
u16 section_table_entry_count;
u16 section_names_table_index;
};
#pragma pack(1)
struct elf_header_table_entry_x64 {
u32 type;
u32 flags;
u64 segment_offset;
u64 virtual_address;
u64 reserved_physical_address;
u64 segment_file_size;
u64 segment_memory_size;
u64 alignment;
};
#pragma pack(1)
struct elf_section_table_entry_x64 {
u32 name_offset;
u32 type;
u64 flags;
u64 virtual_address;
u64 offset_in_file;
u64 size;
u32 link;
u32 info;
u64 alignment;
u64 entry_size;
};
#pragma pack(1)
struct dwarf_debug_info_header_x64 {
u32 pad;
u64 length;
u16 version;
u64 debug_abbrev_offset;
u8 adress_size;
};
#pragma pack(1)
struct dwarf_debug_info_header_x32 {
u32 length;
u16 version;
u32 debug_abbrev_offset;
u8 address_size;
};
struct dwarf_debug_line_file_info {
char *name;
u32 directory_index;
u32 time_modified;
u32 file_size;
};
#pragma pack(1)
struct dwarf_debug_line_header_v3_x32 {
u32 length;
u16 version;
u32 header_length;
u8 minimum_instruction_length;
u8 default_is_stmt;
s8 line_base;
u8 line_range;
u8 opcode_base;
u8 *standard_opcode_lengths;
u8 ndirs;
u8 nfiles;
char *include_directories;
struct dwarf_debug_line_file_info *files;
};
struct dwarf_line_number_state {
u64 pc;
u32 file;
u32 line;
u32 column;
u8 is_stmt;
u8 basic_block;
u8 end_sequence;
u8 prologue_end;
u8 epilogue_begin;
u32 isa;
u32 discriminator;
};
static char *
attribute_to_str(enum dwarf_die_tag attr)
{
switch (attr) {
case DW_AT_sibling: { return "DW_AT_sibling"; }
case DW_AT_location: { return "DW_AT_location"; }
case DW_AT_name: { return "DW_AT_name"; }
case DW_AT_ordering: { return "DW_AT_ordering"; }
case DW_AT_subscr_data: { return "DW_AT_subscr_data"; }
case DW_AT_byte_size: { return "DW_AT_byte_size"; }
case DW_AT_bit_offset: { return "DW_AT_bit_offset"; }
case DW_AT_bit_size: { return "DW_AT_bit_size"; }
case DW_AT_element_list: { return "DW_AT_element_list"; }
case DW_AT_stmt_list: { return "DW_AT_stmt_list"; }
case DW_AT_low_pc: { return "DW_AT_low_pc"; }
case DW_AT_high_pc: { return "DW_AT_high_pc"; }
case DW_AT_language: { return "DW_AT_language"; }
case DW_AT_member: { return "DW_AT_member"; }
case DW_AT_discr: { return "DW_AT_discr"; }
case DW_AT_discr_value: { return "DW_AT_discr_value"; }
case DW_AT_visibility: { return "DW_AT_visibility"; }
case DW_AT_import: { return "DW_AT_import"; }
case DW_AT_string_length: { return "DW_AT_string_length"; }
case DW_AT_common_reference: { return "DW_AT_common_reference"; }
case DW_AT_comp_dir: { return "DW_AT_comp_dir"; }
case DW_AT_const_value: { return "DW_AT_const_value"; }
case DW_AT_containing_type: { return "DW_AT_containing_type"; }
case DW_AT_default_value: { return "DW_AT_default_value"; }
case DW_AT_inline: { return "DW_AT_inline"; }
case DW_AT_is_optional: { return "DW_AT_is_optional"; }
case DW_AT_lower_bound: { return "DW_AT_lower_bound"; }
case DW_AT_producer: { return "DW_AT_producer"; }
case DW_AT_prototyped: { return "DW_AT_prototyped"; }
case DW_AT_return_addr: { return "DW_AT_return_addr"; }
case DW_AT_start_scope: { return "DW_AT_start_scope"; }
case DW_AT_upper_bound: { return "DW_AT_upper_bound"; }
case DW_AT_abstract_origin: { return "DW_AT_abstract_origin"; }
case DW_AT_accessibility: { return "DW_AT_accessibility"; }
case DW_AT_address_class: { return "DW_AT_address_class"; }
case DW_AT_artificial: { return "DW_AT_artificial"; }
case DW_AT_base_types: { return "DW_AT_base_types"; }
case DW_AT_calling_convention: { return "DW_AT_calling_convention"; }
case DW_AT_count: { return "DW_AT_count"; }
case DW_AT_data_member_location: { return "DW_AT_data_member_location"; }
case DW_AT_decl_column: { return "DW_AT_decl_column"; }
case DW_AT_decl_file: { return "DW_AT_decl_file"; }
case DW_AT_decl_line: { return "DW_AT_decl_line"; }
case DW_AT_declaration: { return "DW_AT_declaration"; }
case DW_AT_encoding: { return "DW_AT_encoding"; }
case DW_AT_external: { return "DW_AT_external"; }
case DW_AT_frame_base: { return "DW_AT_frame_base"; }
case DW_AT_friend: { return "DW_AT_friend"; }
case DW_AT_identifier_case: { return "DW_AT_identifier_case"; }
case DW_AT_macro_info: { return "DW_AT_macro_info"; }
case DW_AT_namelist_item: { return "DW_AT_namelist_item"; }
case DW_AT_priority: { return "DW_AT_priority"; }
case DW_AT_segment: { return "DW_AT_segment"; }
case DW_AT_specification: { return "DW_AT_specification"; }
case DW_AT_static_link: { return "DW_AT_static_link"; }
case DW_AT_type: { return "DW_AT_type"; }
case DW_AT_use_location: { return "DW_AT_use_location"; }
case DW_AT_variable_parameter: { return "DW_AT_variable_parameter"; }
case DW_AT_virtuality: { return "DW_AT_virtuality"; }
case DW_AT_vtable_elem_location: { return "DW_AT_vtable_elem_location"; }
case DW_AT_signature: { return "DW_AT_signature"; }
case DW_AT_main_subprogram: { return "DW_AT_main_subprogram"; }
case DW_AT_data_bit_offset: { return "DW_AT_data_bit_offset"; }
case DW_AT_const_expr: { return "DW_AT_const_expr"; }
case DW_AT_enum_class: { return "DW_AT_enum_class"; }
case DW_AT_linkage_name: { return "DW_AT_linkage_name"; }
case DW_AT_string_length_bit_size: { return "DW_AT_string_length_bit_size"; }
case DW_AT_string_length_byte_size: { return "DW_AT_string_length_byte_size"; }
case DW_AT_rank: { return "DW_AT_rank"; }
case DW_AT_str_offsets_base: { return "DW_AT_str_offsets_base"; }
case DW_AT_addr_base: { return "DW_AT_addr_base"; }
case DW_AT_rnglists_base: { return "DW_AT_rnglists_base"; }
case DW_AT_dwo_id: { return "DW_AT_dwo_id"; }
case DW_AT_dwo_name: { return "DW_AT_dwo_name"; }
case DW_AT_reference: { return "DW_AT_reference"; }
case DW_AT_rvalue_reference: { return "DW_AT_rvalue_reference"; }
case DW_AT_macros: { return "DW_AT_macros"; }
case DW_AT_call_all_calls: { return "DW_AT_call_all_calls"; }
case DW_AT_call_all_source_calls: { return "DW_AT_call_all_source_calls"; }
case DW_AT_call_all_tail_calls: { return "DW_AT_call_all_tail_calls"; }
case DW_AT_call_return_pc: { return "DW_AT_call_return_pc"; }
case DW_AT_call_value: { return "DW_AT_call_value"; }
case DW_AT_call_origin: { return "DW_AT_call_origin"; }
case DW_AT_call_parameter: { return "DW_AT_call_parameter"; }
case DW_AT_call_pc: { return "DW_AT_call_pc"; }
case DW_AT_call_tail_call: { return "DW_AT_call_tail_call"; }
case DW_AT_call_target: { return "DW_AT_call_target"; }
case DW_AT_call_target_clobbered: { return "DW_AT_call_target_clobbered"; }
case DW_AT_call_data_location: { return "DW_AT_call_data_location"; }
case DW_AT_call_data_value: { return "DW_AT_call_data_value"; }
case DW_AT_noreturn: { return "DW_AT_noreturn"; }
case DW_AT_alignment: { return "DW_AT_alignment"; }
case DW_AT_export_symbols: { return "DW_AT_export_symbols"; }
case DW_AT_deleted: { return "DW_AT_deleted"; }
case DW_AT_defaulted: { return "DW_AT_defaulted"; }
case DW_AT_loclists_base: { return "DW_AT_loclists_base"; }
}
return(NULL);
}
static char *
tag_to_str(enum dwarf_die_tag tag) {
switch (tag) {
case DW_TAG_array_type: { return "DW_TAG_array_type"; }
case DW_TAG_class_type: { return "DW_TAG_class_type"; }
case DW_TAG_entry_point: { return "DW_TAG_entry_point"; }
case DW_TAG_enumeration_type: { return "DW_TAG_enumeration_type"; }
case DW_TAG_formal_parameter: { return "DW_TAG_formal_parameter"; }
case DW_TAG_imported_declaration: { return "DW_TAG_imported_declaration"; }
case DW_TAG_label: { return "DW_TAG_label"; }
case DW_TAG_lexical_block: { return "DW_TAG_lexical_block"; }
case DW_TAG_member: { return "DW_TAG_member"; }
case DW_TAG_pointer_type: { return "DW_TAG_pointer_type"; }
case DW_TAG_reference_type: { return "DW_TAG_reference_type"; }
case DW_TAG_compile_unit: { return "DW_TAG_compile_unit"; }
case DW_TAG_string_type: { return "DW_TAG_string_type"; }
case DW_TAG_structure_type: { return "DW_TAG_structure_type"; }
case DW_TAG_subroutine_type: { return "DW_TAG_subroutine_type"; }
case DW_TAG_typedef: { return "DW_TAG_typedef"; }
case DW_TAG_union_type: { return "DW_TAG_union_type"; }
case DW_TAG_unspecified_parameters: { return "DW_TAG_unspecified_parameters"; }
case DW_TAG_variant: { return "DW_TAG_variant"; }
case DW_TAG_common_block: { return "DW_TAG_common_block"; }
case DW_TAG_common_inclusion: { return "DW_TAG_common_inclusion"; }
case DW_TAG_inheritance: { return "DW_TAG_inheritance"; }
case DW_TAG_inlined_subroutine: { return "DW_TAG_inlined_subroutine"; }
case DW_TAG_module: { return "DW_TAG_module"; }
case DW_TAG_ptr_to_member_type: { return "DW_TAG_ptr_to_member_type"; }
case DW_TAG_set_type: { return "DW_TAG_set_type"; }
case DW_TAG_subrange_type: { return "DW_TAG_subrange_type"; }
case DW_TAG_with_stmt: { return "DW_TAG_with_stmt"; }
case DW_TAG_access_declaration: { return "DW_TAG_access_declaration"; }
case DW_TAG_base_type: { return "DW_TAG_base_type"; }
case DW_TAG_catch_block: { return "DW_TAG_catch_block"; }
case DW_TAG_const_type: { return "DW_TAG_const_type"; }
case DW_TAG_constant: { return "DW_TAG_constant"; }
case DW_TAG_enumerator: { return "DW_TAG_enumerator"; }
case DW_TAG_file_type: { return "DW_TAG_file_type"; }
case DW_TAG_friend: { return "DW_TAG_friend"; }
case DW_TAG_namelist: { return "DW_TAG_namelist"; }
case DW_TAG_namelist_item: { return "DW_TAG_namelist_item"; }
case DW_TAG_packed_type: { return "DW_TAG_packed_type"; }
case DW_TAG_subprogram: { return "DW_TAG_subprogram"; }
case DW_TAG_thrown_type: { return "DW_TAG_thrown_type"; }
case DW_TAG_try_block: { return "DW_TAG_try_block"; }
case DW_TAG_variant_part: { return "DW_TAG_variant_part"; }
case DW_TAG_variable: { return "DW_TAG_variable"; }
case DW_TAG_volatile_type: { return "DW_TAG_volatile_type"; }
case DW_TAG_lo_user: { return "DW_TAG_lo_user"; }
case DW_TAG_MIPS_loop: { return "DW_TAG_MIPS_loop"; }
default: { return "unknown tag"; }
}
assert(0);
return(NULL);
}

5
trace_include.c

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
int foo(int a)
{
int b = a + 1;
return(b / 10);
}

23
traceme.c

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
#include <stdio.h>
#include <unistd.h>
#include "trace_include.c"
int main()
{
int i;
int arr[10];
for(i = 0;i < 10; ++i) {
arr[i] = i * i * i / 10;
}
int pipa = 0;
int boba = 1;
int peppa = pipa / boba + 2 * (boba / 2) - 1
+ pipa * pipa / boba;
foo(3);
return 0;
}
Loading…
Cancel
Save