⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 symbol.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * File symbol.c - management of symbols (lexical tree)
 *
 * Copyright (C) 1993, Eric Youngdale.
 *               2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <assert.h>
#define HAVE_REGEX_H 1
#ifdef HAVE_REGEX_H
# include "regex.h"
#endif

#include "wine/debug.h"
#include "dbghelp_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);

struct line_info
{
    unsigned long               is_first : 1,
                                is_last : 1,
                                is_source_file : 1,
                                line_number;
    union
    {
        unsigned long               pc_offset;   /* if is_source_file isn't set */
        unsigned                    source_file; /* if is_source_file is set */
    } u;
};

__inline static int cmp_addr(ULONG64 a1, ULONG64 a2)
{
    if (a1 > a2) return 1;
    if (a1 < a2) return -1;
    return 0;
}

__inline static int cmp_sorttab_addr(const struct module* module, int idx, ULONG64 addr)
{
    ULONG64     ref;

    symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_ADDRESS, &ref);
    return cmp_addr(ref, addr);
}

int symt_cmp_addr(const void* p1, const void* p2)
{
    const struct symt*  sym1 = *(const struct symt* const *)p1;
    const struct symt*  sym2 = *(const struct symt* const *)p2;
    ULONG64     a1, a2;

    symt_get_info(sym1, TI_GET_ADDRESS, &a1);
    symt_get_info(sym2, TI_GET_ADDRESS, &a2);
    return cmp_addr(a1, a2);
}

static __inline void re_append(char** mask, unsigned* len, char ch)
{
    *mask = HeapReAlloc(GetProcessHeap(), 0, *mask, ++(*len));
    (*mask)[*len - 2] = ch;
}

/* transforms a dbghelp's regular expression into a POSIX one
 * Here are the valid dbghelp reg ex characters:
 *      *       0 or more characters
 *      ?       a single character
 *      []      list
 *      #       0 or more of preceding char
 *      +       1 or more of preceding char
 *      escapes \ on #, ?, [, ], *, +. don't work on -
 */
static void compile_regex(const char* str, int numchar, regex_t* re)
{
    char*       mask = HeapAlloc(GetProcessHeap(), 0, 1);
    unsigned    len = 1;
    BOOL        in_escape = FALSE;

    re_append(&mask, &len, '^');

    while (*str && numchar--)
    {
        /* FIXME: this shouldn't be valid on '-' */
        if (in_escape)
        {
            re_append(&mask, &len, '\\');
            re_append(&mask, &len, *str);
            in_escape = FALSE;
        }
        else switch (*str)
        {
        case '\\': in_escape = TRUE; break;
        case '*':  re_append(&mask, &len, '.'); re_append(&mask, &len, '*'); break;
        case '?':  re_append(&mask, &len, '.'); break;
        case '#':  re_append(&mask, &len, '*'); break;
        /* escape some valid characters in dbghelp reg exp:s */
        case '$':  re_append(&mask, &len, '\\'); re_append(&mask, &len, '$'); break;
        /* +, [, ], - are the same in dbghelp & POSIX, use them as any other char */
        default:   re_append(&mask, &len, *str); break;
        }
        str++;
    }
    if (in_escape)
    {
        re_append(&mask, &len, '\\');
        re_append(&mask, &len, '\\');
    }
    re_append(&mask, &len, '$');
    mask[len - 1] = '\0';
    if (regcomp(re, mask, REG_NOSUB)) FIXME("Couldn't compile %s\n", mask);
    HeapFree(GetProcessHeap(), 0, mask);
}

struct symt_compiland* symt_new_compiland(struct module* module, const char* name)
{
    struct symt_compiland*    sym;

    TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n", 
                         module->module.ModuleName, name);
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagCompiland;
        sym->source   = source_new(module, name);
        vector_init(&sym->vchildren, sizeof(struct symt*), 32);
    }
    return sym;
}

struct symt_public* symt_new_public(struct module* module, 
                                    struct symt_compiland* compiland,
                                    const char* name,
                                    unsigned long address, unsigned size,
                                    BOOL in_code, BOOL is_func)
{
    struct symt_public* sym;
    struct symt**       p;

    TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%lx\n", 
                         module->module.ModuleName, name, address);
    if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) && 
        symt_find_nearest(module, address) != -1)
        return NULL;
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag      = SymTagPublicSymbol;
        sym->hash_elt.name = pool_strdup(&module->pool, name);
        hash_table_add(&module->ht_symbols, &sym->hash_elt);
        module->sortlist_valid = FALSE;
        sym->container     = compiland ? &compiland->symt : NULL;
        sym->address       = address;
        sym->size          = size;
        sym->in_code       = in_code;
        sym->is_function   = is_func;
        if (compiland)
        {
            p = vector_add(&compiland->vchildren, &module->pool);
            *p = &sym->symt;
        }
    }
    return sym;
}

struct symt_data* symt_new_global_variable(struct module* module, 
                                           struct symt_compiland* compiland, 
                                           const char* name, unsigned is_static,
                                           unsigned long addr, unsigned long size,
                                           struct symt* type)
{
    struct symt_data*   sym;
    struct symt**       p;
    DWORD               tsz;

    TRACE_(dbghelp_symt)("Adding global symbol %s:%s @%lx %p\n", 
                         module->module.ModuleName, name, addr, type);
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag      = SymTagData;
        sym->hash_elt.name = pool_strdup(&module->pool, name);
        hash_table_add(&module->ht_symbols, &sym->hash_elt);
        module->sortlist_valid = FALSE;
        sym->kind          = is_static ? DataIsFileStatic : DataIsGlobal;
        sym->container     = compiland ? &compiland->symt : NULL;
        sym->type          = type;
        sym->u.address     = addr;
        if (type && size && symt_get_info(type, TI_GET_LENGTH, &tsz))
        {
            if (tsz != size)
                FIXME("Size mismatch for %s.%s between type (%lu) and src (%lu)\n",
                      module->module.ModuleName, name, tsz, size);
        }
        if (compiland)
        {
            p = vector_add(&compiland->vchildren, &module->pool);
            *p = &sym->symt;
        }
    }
    return sym;
}

struct symt_function* symt_new_function(struct module* module, 
                                        struct symt_compiland* compiland, 
                                        const char* name,
                                        unsigned long addr, unsigned long size,
                                        struct symt* sig_type)
{
    struct symt_function*       sym;
    struct symt**               p;

    TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n", 
                         module->module.ModuleName, name, addr, addr + size - 1);

    assert(!sig_type || sig_type->tag == SymTagFunctionType);
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag  = SymTagFunction;
        sym->hash_elt.name = pool_strdup(&module->pool, name);
        hash_table_add(&module->ht_symbols, &sym->hash_elt);
        module->sortlist_valid = FALSE;
        sym->container = &compiland->symt;
        sym->address   = addr;
        sym->type      = sig_type;
        sym->size      = size;
        vector_init(&sym->vlines,  sizeof(struct line_info), 64);
        vector_init(&sym->vchildren, sizeof(struct symt*), 8);
        if (compiland)
        {
            p = vector_add(&compiland->vchildren, &module->pool);
            *p = &sym->symt;
        }
    }
    return sym;
}

void symt_add_func_line(struct module* module, struct symt_function* func,
                        unsigned source_idx, int line_num, unsigned long offset)
{
    struct line_info*   dli;
    BOOL                last_matches = FALSE;

    if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return;

    TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", 
                         func, func->hash_elt.name, offset, 
                         source_get(module, source_idx), line_num);

    assert(func->symt.tag == SymTagFunction);

    dli = NULL;
    while ((dli = vector_iter_down(&func->vlines, dli)))
    {
        if (dli->is_source_file)
        {
            last_matches = (source_idx == dli->u.source_file);
            break;
        }
    }

    if (!last_matches)
    {
        /* we shouldn't have line changes on first line of function */
        dli = vector_add(&func->vlines, &module->pool);
        dli->is_source_file = 1;
        dli->is_first       = dli->is_last = 0;
        dli->line_number    = 0;
        dli->u.source_file  = source_idx;
    }
    dli = vector_add(&func->vlines, &module->pool);
    dli->is_source_file = 0;
    dli->is_first       = dli->is_last = 0;
    dli->line_number    = line_num;
    dli->u.pc_offset    = func->address + offset;
}

struct symt_data* symt_add_func_local(struct module* module, 
                                      struct symt_function* func, 
                                      int regno, int offset, 
                                      struct symt_block* block, 
                                      struct symt* type, const char* name)
{
    struct symt_data*   locsym;
    struct symt**       p;

    assert(func);
    assert(func->symt.tag == SymTagFunction);

    TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n", 
                         module->module.ModuleName, func->hash_elt.name, 
                         name, type);
    locsym = pool_alloc(&module->pool, sizeof(*locsym));
    locsym->symt.tag      = SymTagData;
    locsym->hash_elt.name = pool_strdup(&module->pool, name);
    locsym->hash_elt.next = NULL;
    locsym->kind          = (offset < 0) ? DataIsParam : DataIsLocal;
    locsym->container     = &block->symt;
    locsym->type          = type;
    if (regno)
    {
        locsym->u.s.reg_id = regno;
        locsym->u.s.offset = 0;
        locsym->u.s.length = 0;
    }
    else
    {
        locsym->u.s.reg_id = 0;
        locsym->u.s.offset = offset * 8;
        locsym->u.s.length = 0;
    }
    if (block)
        p = vector_add(&block->vchildren, &module->pool);
    else
        p = vector_add(&func->vchildren, &module->pool);
    *p = &locsym->symt;
    return locsym;
}

struct symt_block* symt_open_func_block(struct module* module, 
                                        struct symt_function* func,
                                        struct symt_block* parent_block, 
                                        unsigned pc, unsigned len)
{
    struct symt_block*  block;
    struct symt**       p;

    assert(func);
    assert(func->symt.tag == SymTagFunction);

    assert(!parent_block || parent_block->symt.tag == SymTagBlock);
    block = pool_alloc(&module->pool, sizeof(*block));
    block->symt.tag = SymTagBlock;
    block->address  = func->address + pc;
    block->size     = len;
    block->container = parent_block ? &parent_block->symt : &func->symt;
    vector_init(&block->vchildren, sizeof(struct symt*), 4);
    if (parent_block)
        p = vector_add(&parent_block->vchildren, &module->pool);
    else
        p = vector_add(&func->vchildren, &module->pool);
    *p = &block->symt;

    return block;
}

struct symt_block* symt_close_func_block(struct module* module, 
                                         struct symt_function* func,
                                         struct symt_block* block, unsigned pc)
{
    assert(func->symt.tag == SymTagFunction);

    if (pc) block->size = func->address + pc - block->address;
    return (block->container->tag == SymTagBlock) ? 
        GET_ENTRY(block->container, struct symt_block, symt) : NULL;
}

struct symt_function_point* symt_add_function_point(struct module* module, 
                                                    struct symt_function* func,
                                                    enum SymTagEnum point, 
                                                    unsigned offset, const char* name)
{
    struct symt_function_point* sym;
    struct symt**               p;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = point;
        sym->parent   = func;
        sym->offset   = offset;
        sym->name     = name ? pool_strdup(&module->pool, name) : NULL;
        p = vector_add(&func->vchildren, &module->pool);
        *p = &sym->symt;
    }
    return sym;
}

BOOL symt_normalize_function(struct module* module, struct symt_function* func)
{
    unsigned            len;
    struct line_info*   dli;

    assert(func);
    /* We aren't adding any more locals or line numbers to this function.
     * Free any spare memory that we might have allocated.
     */
    assert(func->symt.tag == SymTagFunction);

/* EPP     vector_pool_normalize(&func->vlines,    &module->pool); */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -