Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: cf6eda1cab6a29159a15437766e9d9ed899194ec (plain) (tree)








































































































































































































                                                                                                                  
                       



                                            


                                          
                                             

                                                                                                   

                                                                                                           


                                                                                             
                                                                                         
                                                                                        



                                        





                                                   

                                          
                           
                             
                                





                                                          
                                                                                                                                 





                                                                    







































































                                                                                                        

                                                       











                                                                          

                                                           
























































































                                                                                                                                
                                    

























                                                             
                                












































































                                                                                                                              
                                     

























                                                                             
                                            










                                                         


                                                                               
                                                                   









                                                                                    
             


                  




                                    


                           
/*******************************************************************************
 * Copyright (c) 2010, 2011 Wind River Systems, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 * You may elect to redistribute this code under either of these licenses.
 *
 * Contributors:
 *     Wind River Systems - initial API and implementation
 *******************************************************************************/

/* Fake debug context API implementation. It used for testing symbol services. */

#include <tcf/config.h>

#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
#if !defined(WIN32) || defined(__CYGWIN__)
#  include <dirent.h>
#endif

#include <tcf/framework/context.h>
#include <tcf/framework/events.h>
#include <tcf/framework/myalloc.h>
#include <tcf/framework/exceptions.h>

#include <tcf/services/tcf_elf.h>
#include <tcf/services/symbols.h>
#include <tcf/services/linenumbers.h>
#include <tcf/services/memorymap.h>
#include <tcf/services/dwarfframe.h>

#include <tcf/backend/backend.h>

#ifndef S_ISDIR
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif

static Context * elf_ctx = NULL;
static MemoryMap mem_map;
static RegisterDefinition reg_defs[MAX_REGS];
static char reg_names[MAX_REGS][32];
static uint8_t reg_vals[MAX_REGS * 8];
static unsigned reg_size = 0;

static uint8_t frame_data[0x1000];
static ContextAddress frame_addr = 0x40000000u;

static const char * elf_file_name = NULL;
static int mem_region_pos = 0;
static ContextAddress pc = 0;
static unsigned pass_cnt = 0;
static int test_posted = 0;
static struct timespec time_start;

static char ** files = NULL;
static unsigned files_max = 0;
static unsigned files_cnt = 0;

RegisterDefinition * get_reg_definitions(Context * ctx) {
    return reg_defs;
}

RegisterDefinition * get_PC_definition(Context * ctx) {
    return reg_defs;
}

Context * id2ctx(const char * id) {
    if (id != NULL && strcmp(id, elf_ctx->id) == 0) return elf_ctx;
    return NULL;
}

unsigned context_word_size(Context * ctx) {
    return get_PC_definition(ctx)->size;
}

int context_has_state(Context * ctx) {
    return 1;
}

Context * context_get_group(Context * ctx, int group) {
    return ctx;
}

int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) {
    if (ctx != elf_ctx) {
        errno = ERR_INV_CONTEXT;
        return -1;
    }
    memcpy(buf, reg_vals + def->offset + offs, size);
    return 0;
}

int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) {
    if (ctx != elf_ctx) {
        errno = ERR_INV_CONTEXT;
        return -1;
    }
    memcpy(reg_vals + def->offset + offs, buf, size);
    return 0;
}

int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) {
    if (address >= frame_addr && address + size >= address && address + size <= frame_addr + sizeof(frame_data)) {
        memcpy(buf, frame_data + (address - frame_addr), size);
        return 0;
    }
    memset(buf, 0, size);
    return 0;
}

int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) {
    /* TODO: context_write_mem */
    errno = ERR_UNSUPPORTED;
    return -1;
}

int context_get_memory_map(Context * ctx, MemoryMap * map) {
    unsigned i;
    for (i = 0; i < mem_map.region_cnt; i++) {
        MemoryRegion * r = NULL;
        if (map->region_cnt >= map->region_max) {
            map->region_max += 8;
            map->regions = (MemoryRegion *)loc_realloc(map->regions, sizeof(MemoryRegion) * map->region_max);
        }
        r = map->regions + map->region_cnt++;
        *r = mem_map.regions[i];
        if (r->file_name) r->file_name = loc_strdup(r->file_name);
        if (r->sect_name) r->sect_name = loc_strdup(r->sect_name);
    }
    return 0;
}

int crawl_stack_frame(StackFrame * frame, StackFrame * down) {
    if (frame->is_top_frame) {
        frame->fp = frame_addr;
        return 0;
    }
    errno = ERR_INV_ADDRESS;
    return -1;
}

static void error(const char * func) {
    int err = errno;
    printf("File    : %s\n", elf_file_name);
    printf("Address : 0x%" PRIX64 "\n", (uint64_t)pc);
    printf("Function: %s\n", func);
    printf("Error   : %s\n", errno_to_str(err));
    fflush(stdout);
    exit(1);
}

static void line_numbers_callback(CodeArea * area, void * args) {
    CodeArea * dst = (CodeArea *)args;
    *dst = *area;
}

static void print_time(struct timespec time_start, int cnt) {
    struct timespec time_now;
    struct timespec time_diff;
    if (cnt == 0) return;
    clock_gettime(CLOCK_REALTIME, &time_now);
    time_diff.tv_sec = time_now.tv_sec - time_start.tv_sec;
    if (time_now.tv_nsec < time_start.tv_nsec) {
        time_diff.tv_sec--;
        time_diff.tv_nsec = time_now.tv_nsec + 1000000000 - time_start.tv_nsec;
    }
    else {
        time_diff.tv_nsec = time_now.tv_nsec - time_start.tv_nsec;
    }
    time_diff.tv_nsec /= cnt;
    time_diff.tv_nsec += (long)(((uint64_t)(time_diff.tv_sec % cnt) * 1000000000) / cnt);
    time_diff.tv_sec /= cnt;
    printf("search time: %ld.%06ld\n", (long)time_diff.tv_sec, time_diff.tv_nsec / 1000);
    fflush(stdout);
}

static void test(void * args);

static void loc_var_func(void * args, Symbol * sym) {
    int frame = 0;
    Context * ctx = NULL;
    RegisterDefinition * reg = NULL;
    ContextAddress addr = 0;
    ContextAddress size = 0;
    SYM_FLAGS flags = 0;
    int symbol_class = 0;
    int type_class = 0;
    Symbol * type = NULL;
    Symbol * index_type = NULL;
    Symbol * base_type = NULL;
    ContextAddress length = 0;
    int64_t lower_bound = 0;
    void * value = NULL;
    size_t value_size = 0;
    int value_big_endian = 0;
    char * name = NULL;

    if (get_symbol_flags(sym, &flags) < 0) {
        error("get_symbol_flags");
    }
    if (get_symbol_name(sym, &name) < 0) {
        error("get_symbol_name");
    }
    if (get_symbol_address(sym, &addr) < 0) {
        if ((get_symbol_register(sym, &ctx, &frame, &reg) < 0 || reg == NULL) &&
            (get_symbol_value(sym, &value, &value_size, &value_big_endian) < 0 || value == NULL)) {
            int err = errno;
            if (strncmp(errno_to_str(err), "Object location or value info not available", 43) == 0) return;
            if (strncmp(errno_to_str(err), "No object location info found", 29) == 0) return;
            if (strncmp(errno_to_str(err), "Object is not available", 23) == 0) return;
            if (strncmp(errno_to_str(err), "Object has no RT address", 24) == 0) return;
            if (strncmp(errno_to_str(err), "Division by zero in DWARF", 25) == 0) return;
            if (strncmp(errno_to_str(err), "Cannot find loader debug", 24) == 0) return;
            errno = err;
            error("get_symbol_address");
        }
    }
    if (get_symbol_class(sym, &symbol_class) < 0) {
        error("get_symbol_class");
    }
    if (get_symbol_type(sym, &type) < 0) {
        error("get_symbol_type");
    }
    if (get_symbol_size(sym, &size) < 0) {
        int ok = 0;
        if (type != NULL) {
            char * type_name;
            unsigned type_flags;
            if (get_symbol_name(type, &type_name) < 0) {
                error("get_symbol_name");
            }
            if (get_symbol_flags(type, &type_flags) < 0) {
                error("get_symbol_flags");
            }
            if (name == NULL && type_name != NULL && strcmp(type_name, "exception") == 0 && (type_flags & SYM_FLAG_CLASS_TYPE)) {
                /* GCC does not tell size of std::exception class */
                ok = 1;
            }
        }
        if (!ok) error("get_symbol_size");
    }
    if (type != NULL) {
        if (get_symbol_type_class(sym, &type_class) < 0) {
            error("get_symbol_type_class");
        }
        if (get_symbol_flags(type, &flags) < 0) {
            error("get_symbol_flags");
        }
        if (type_class == TYPE_CLASS_ARRAY) {
            if (get_symbol_index_type(type, &index_type) < 0) {
                error("get_symbol_index_type");
            }
            if (get_symbol_base_type(type, &base_type) < 0) {
                error("get_symbol_base_type");
            }
            if (get_symbol_length(type, &length) < 0) {
                error("get_symbol_length");
            }
            if (get_symbol_lower_bound(type, &lower_bound) < 0) {
                error("get_symbol_lower_bound");
            }
        }
        else if (type_class == TYPE_CLASS_POINTER) {
            if (get_symbol_base_type(type, &base_type) < 0) {
                error("get_symbol_base_type");
            }
        }
        else if (type_class == TYPE_CLASS_ENUMERATION) {
            int i;
            int count = 0;
            Symbol ** children = NULL;
            if (get_symbol_children(type, &children, &count) < 0) {
                error("get_symbol_children");
            }
            for (i = 0; i < count; i++) {
                void * value = NULL;
                size_t value_size = 0;
                int big_endian = 0;
                if (get_symbol_value(children[i], &value, &value_size, &big_endian) < 0) {
                    error("get_symbol_value");
                }
            }
        }
    }
}

static void next_pc(void) {
    Symbol * sym = NULL;
    CodeArea area;
    ContextAddress lt_addr;
    ELF_File * lt_file;
    ELF_Section * lt_sec;
    struct timespec time_now;
    Trap trap;
    int test_cnt = 0;
    int loaded = mem_region_pos < 0;

    for (;;) {
        if (mem_region_pos < 0) {
            mem_region_pos = 0;
            pc = mem_map.regions[mem_region_pos].addr;
        }
        else if (pc + 5 < mem_map.regions[mem_region_pos].addr + mem_map.regions[mem_region_pos].size) {
            pc += 5;
        }
        else if (mem_region_pos + 1 < (int)mem_map.region_cnt) {
            mem_region_pos++;
            pc = mem_map.regions[mem_region_pos].addr;
        }
        else {
            mem_region_pos++;
            pc = 0;
            print_time(time_start, test_cnt);
            post_event_with_delay(test, NULL, 1000000);
            test_posted = 1;
            return;
        }

        while ((mem_map.regions[mem_region_pos].flags & MM_FLAG_X) == 0) {
            if (mem_region_pos + 1 < (int)mem_map.region_cnt) {
                mem_region_pos++;
                pc = mem_map.regions[mem_region_pos].addr;
            }
            else {
                mem_region_pos++;
                pc = 0;
                print_time(time_start, test_cnt);
                post_event_with_delay(test, NULL, 1000000);
                test_posted = 1;
                return;
            }
        }

        set_regs_PC(elf_ctx, pc);
        send_context_changed_event(elf_ctx);

        if (find_symbol_by_addr(elf_ctx, STACK_NO_FRAME, pc, &sym) < 0) {
            if (get_error_code(errno) != ERR_SYM_NOT_FOUND) {
                error("find_symbol_by_addr");
            }
        }
        else {
            char * name = NULL;
            char name_buf[0x1000];
            if (get_symbol_name(sym, &name) < 0) {
                error("get_symbol_name");
            }
            if (name != NULL) {
                strcpy(name_buf, name);
                if (find_symbol_by_name(elf_ctx, STACK_TOP_FRAME, 0, name_buf, &sym) < 0) {
                    if (get_error_code(errno) != ERR_SYM_NOT_FOUND) {
                        error("find_symbol_by_name");
                    }
                }
                else {
                    if (get_symbol_name(sym, &name) < 0) {
                        error("get_symbol_name");
                    }
                    if (strcmp(name_buf, name) != 0) {
                        errno = ERR_OTHER;
                        error("strcmp(name_buf, name)");
                    }
                }
            }
        }

        if (find_symbol_by_name(elf_ctx, STACK_TOP_FRAME, 0, "@ non existing name @", &sym) < 0) {
            if (get_error_code(errno) != ERR_SYM_NOT_FOUND) {
                error("find_symbol_by_name");
            }
        }

        memset(&area, 0, sizeof(area));
        if (address_to_line(elf_ctx, pc, pc + 1, line_numbers_callback, &area) < 0) {
            error("address_to_line");
        }
        else if (area.start_line > 0) {
            char elf_file_name[0x1000];
            strlcpy(elf_file_name, area.file, sizeof(elf_file_name));
            if (line_to_address(elf_ctx, elf_file_name, area.start_line, area.start_column, line_numbers_callback, &area) < 0) {
                error("line_to_address");
            }
        }

        if (enumerate_symbols(elf_ctx, STACK_TOP_FRAME, loc_var_func, NULL) < 0) {
            error("enumerate_symbols");
        }

        lt_file = NULL;
        lt_sec = NULL;
        lt_addr = elf_map_to_link_time_address(elf_ctx, pc, &lt_file, &lt_sec);
        assert(lt_file != NULL);
        assert(pc == elf_map_to_run_time_address(elf_ctx, lt_file, lt_sec, lt_addr));
        if (set_trap(&trap)) {
            get_dwarf_stack_frame_info(elf_ctx, lt_file, lt_sec, lt_addr);
            clear_trap(&trap);
        }
        else {
            error("get_dwarf_stack_frame_info");
        }

        test_cnt++;
        if (loaded) {
            struct timespec time_diff;
            clock_gettime(CLOCK_REALTIME, &time_now);
            time_diff.tv_sec = time_now.tv_sec - time_start.tv_sec;
            if (time_now.tv_nsec < time_start.tv_nsec) {
                time_diff.tv_sec--;
                time_diff.tv_nsec = time_now.tv_nsec + 1000000000 - time_start.tv_nsec;
            }
            else {
                time_diff.tv_nsec = time_now.tv_nsec - time_start.tv_nsec;
            }
            printf("load time: %ld.%06ld\n", (long)time_diff.tv_sec, time_diff.tv_nsec / 1000);
            fflush(stdout);
            time_start = time_now;
            loaded = 0;
        }
        else if (test_cnt >= 1000) {
            print_time(time_start, test_cnt);
            clock_gettime(CLOCK_REALTIME, &time_start);
            test_posted = 1;
            post_event(test, NULL);
            return;
        }
    }
}

static void next_file(void) {
    unsigned j;
    ELF_File * f = NULL;
    struct stat st;

    if (pass_cnt == files_cnt) exit(0);
    elf_file_name = files[pass_cnt % files_cnt];

    printf("File: %s\n", elf_file_name);
    fflush(stdout);
    if (stat(elf_file_name, &st) < 0) {
        printf("Cannot stat ELF: %s\n", errno_to_str(errno));
        exit(1);
    }

    clock_gettime(CLOCK_REALTIME, &time_start);

    f = elf_open(elf_file_name);
    if (f == NULL) {
        printf("Cannot open ELF: %s\n", errno_to_str(errno));
        exit(1);
    }

    if (elf_ctx == NULL) {
        elf_ctx = create_context("test");
        elf_ctx->stopped = 1;
        elf_ctx->pending_intercept = 1;
        elf_ctx->mem = elf_ctx;
        elf_ctx->big_endian = f->big_endian;
        list_add_first(&elf_ctx->ctxl, &context_root);
        elf_ctx->ref_count++;
    }

    context_clear_memory_map(&mem_map);
    for (j = 0; j < f->pheader_cnt; j++) {
        MemoryRegion * r = NULL;
        ELF_PHeader * p = f->pheaders + j;
        if (p->type != PT_LOAD) continue;
        if (mem_map.region_cnt >= mem_map.region_max) {
            mem_map.region_max += 8;
            mem_map.regions = (MemoryRegion *)loc_realloc(mem_map.regions, sizeof(MemoryRegion) * mem_map.region_max);
        }
        r = mem_map.regions + mem_map.region_cnt++;
        memset(r, 0, sizeof(MemoryRegion));
        r->addr = p->address;
        r->file_name = loc_strdup(elf_file_name);
        r->file_offs = p->offset;
        r->size = p->file_size;
        r->flags = MM_FLAG_R | MM_FLAG_W;
        if (p->flags & PF_X) r->flags |= MM_FLAG_X;
        r->dev = st.st_dev;
        r->ino = st.st_ino;
    }
    if (mem_map.region_cnt == 0) {
        for (j = 0; j < f->section_cnt; j++) {
            ELF_Section * sec = f->sections + j;
            if (sec->size == 0) continue;
            if (sec->name == NULL) continue;
            if (strcmp(sec->name, ".text") == 0 ||
                strcmp(sec->name, ".data") == 0 ||
                strcmp(sec->name, ".bss") == 0) {
                MemoryRegion * r = NULL;
                if (mem_map.region_cnt >= mem_map.region_max) {
                    mem_map.region_max += 8;
                    mem_map.regions = (MemoryRegion *)loc_realloc(mem_map.regions, sizeof(MemoryRegion) * mem_map.region_max);
                }
                r = mem_map.regions + mem_map.region_cnt++;
                memset(r, 0, sizeof(MemoryRegion));
                r->addr = sec->addr + 0x10000;
                r->size = sec->size;
                r->file_offs = sec->offset;
                r->bss = strcmp(sec->name, ".bss") == 0;
                r->dev = st.st_dev;
                r->ino = st.st_ino;
                r->file_name = loc_strdup(elf_file_name);
                r->sect_name = loc_strdup(sec->name);
                r->flags = MM_FLAG_R | MM_FLAG_W;
                if (strcmp(sec->name, ".text") == 0) r->flags |= MM_FLAG_X;
            }
        }
    }
    if (mem_map.region_cnt == 0) {
        printf("File has no program headers.\n");
        exit(1);
    }
    memory_map_event_module_loaded(elf_ctx);
    mem_region_pos = -1;

    reg_size = 0;
    memset(reg_defs, 0, sizeof(reg_defs));
    memset(reg_vals, 0, sizeof(reg_vals));
    for (j = 0; j < MAX_REGS - 1; j++) {
        RegisterDefinition * r = reg_defs + j;
        r->big_endian = f->big_endian;
        r->dwarf_id = (int16_t)(j == 0 ? -1 : j - 1);
        r->eh_frame_id = r->dwarf_id;
        r->name = reg_names[j];
        snprintf(reg_names[j], sizeof(reg_names[j]), "R%d", j);
        r->offset = reg_size;
        r->size = f->elf64 ? 8 : 4;
        if (j == 0) r->role = "PC";
        reg_size += r->size;
    }

    pc = 0;
    pass_cnt++;

    test_posted = 1;
    post_event(test, NULL);
}

static void test(void * args) {
    assert(test_posted);
    test_posted = 0;
    if (elf_file_name == NULL || mem_region_pos >= (int)mem_map.region_cnt) {
        next_file();
    }
    else {
        next_pc();
    }
}

static void add_dir(const char * dir_name) {
    DIR * dir = opendir(dir_name);
    if (dir == NULL) {
        printf("Cannot open '%s' directory\n", dir_name);
        fflush(stdout);
        exit(1);
    }
    for (;;) {
        struct dirent * e = readdir(dir);
        char path[FILE_PATH_SIZE];
        struct stat st;
        if (e == NULL) break;
        if (strcmp(e->d_name, ".") == 0) continue;
        if (strcmp(e->d_name, "..") == 0) continue;
        if (strcmp(e->d_name + strlen(e->d_name) - 6, ".debug") == 0) continue;
        snprintf(path, sizeof(path), "%s/%s", dir_name, e->d_name);
        if (stat(path, &st) == 0) {
            if (S_ISDIR(st.st_mode)) {
                add_dir(path);
            }
            else {
                if (files_cnt >= files_max) {
                    files_max += 8;
                    files = (char **)loc_realloc(files, files_max * sizeof(char *));
                }
                files[files_cnt++] = loc_strdup(path);
            }
        }
    }
    closedir(dir);
}

void init_contexts_sys_dep(void) {
    const char * dir_name = "files";
    add_dir(dir_name);
    test_posted = 1;
    post_event(test, NULL);
}

Back to the top