分析binutils之addr2line

由于实时打印bt缺少symbol信息,为了在arm板实时打印出file and function info, 减少手动使用addr2line工具,参数binutils中的addr2line源码实现实时打印出file and function 信息。如下步骤:

binutils-2.26 configure说明:
    build 就是你现在使用的机器。
    host 就是你编译好的程序能够运行的平台。
    target 编译程序能够处理的平台。一般都用在构建编译本身的时候(gcc), 才用target, 也就是说平时我们所说的交叉编译用不到target.

    比如: 在386的平台上编译可以运行在arm板的程序 ./configure –build=i386-linux,–host=arm-linux就可以了.
    因为一般我们都是编译程序而不是编译工具.
    如果我们编译工具,比如gcc,这个target就有用了.如果我们需要在一个我们的机器上为arm开发板编译一个可以处理 mips程序的gcc,那么target就是mips

1.下载binutils-2.26
2.编译binutils-2.26,当前arm工具链为:arm-linux-xxx。预先要export PATH=&PATH:xxxx,其中xxx代表arm交叉工具链(arm-linux-xxx)所在目录
cd binutils-2.26
./configure --build=i386-linux --host=arm-linux --prefix=/work/binutils/binutils-2.26_arm/out
make

3.在binutils-2.26/bfd/下找到找到目标库libbfd.a libiberty.a libz.a
root@libz:/work/binutils/binutils-2.26# find ./ -name \*.a
./opcodes/.libs/libopcodes.a
./opcodes/libopcodes.a
./libiberty/libiberty.a
./zlib/libz.a
./ld/.libs/libldtestplug3.a
./ld/.libs/libldtestplug.a
./ld/.libs/libldtestplug2.a
./bfd/libbfd.a
./bfd/.libs/libbfd.a

为了使用BFD,需要包括'bfd.h'并且连接的时候需要和静态库 libbfd.a libiberty.a libz.a

gcc test.c libbfd.a libiberty.a libz.a -ldl -I./


原理:遍历目标文件中的所有所查找的地址属于哪个SECTION。如下为一个SECTION,其开始地址为0x33855, 长度为0x4f8,如果所查找的目标地址属于此范围,那目标函数便是_ZL19translate_addressesP3bfdPKcPci:

00033855 l     F .text  000004f8              _ZL19translate_addressesP3bfdPKcPci

Addr2Line.cpp

#include <stdlib.h>
#include "config.h"
#include "bfd.h"
#include "libiberty.h"
#include "demangle.h"
#include "elf-bfd.h"
#include <string.h>

#include "Addr2Line.h"

///Symbol table
static asymbol **syms = NULL;
#define FATAL printf
///Read in the symbol table
static bfd_boolean
slurp_symtab (bfd *fbfd)
{
    long storage = 0;
    long symcount = 0;
    bfd_boolean dynamic = FALSE;

    if (0 == (bfd_get_file_flags (fbfd) & HAS_SYMS))
    {
        FATAL("unkonw symbol error(%s)\n", bfd_get_filename (fbfd));
        return FALSE;
    }

    storage = bfd_get_symtab_upper_bound(fbfd);
    if (storage == 0)
    {
        storage = bfd_get_dynamic_symtab_upper_bound (fbfd);
        dynamic = TRUE;
        storage = 1;
    }

    if (storage < 0)
    {
        FATAL("(-1)unkonw symbol error(%s)\n", bfd_get_filename (fbfd));
        return FALSE;
    }

    if (NULL == (syms = (asymbol **) xmalloc (storage)))
    {
        FATAL("can't malloc position to storage symbol info error\n");
        return FALSE;
    }

    if (dynamic)
    {
        symcount = bfd_canonicalize_dynamic_symtab (fbfd, syms);
    }
    else
    {
        symcount = bfd_canonicalize_symtab (fbfd, syms);
    }

    if (symcount < 0)
    {
        FATAL("can't get symbol from file(%s)\n", bfd_get_filename (fbfd));
    }

    ///try again
    if (symcount == 0 &&
        ! dynamic     &&
        (storage = bfd_get_dynamic_symtab_upper_bound (fbfd)) > 0)
    {
        free (syms);
        syms = NULL;
        if (NULL == (syms = (asymbol **) xmalloc (storage)))
        {
            FATAL("can't malloc position to storage symbol info error\n");
            return FALSE;
        }
        symcount = bfd_canonicalize_dynamic_symtab (fbfd, syms);
    }

    if (symcount <= 0)
    {
        free (syms);
        syms = NULL;
        return FALSE;
    }

    return TRUE;
}


static bfd_boolean
translate_addresses (bfd *fbfd, const char *str_addr, char *out_buf, const int buf_len)
{
    static char buf[1024];
    const char *filename = NULL;
    const char *functionname = NULL;
    unsigned int line = 0;
    unsigned int discriminator = 0;
    asection *sect = NULL;
    unsigned int i = 0;

    if ((NULL == str_addr) || (NULL == out_buf) || (0 >= buf_len))
    {
        FATAL("address is null error, str_addr(%p), out_buf(%p), buf_len(%d)\n", str_addr, out_buf, buf_len);
        return FALSE;
    }

    bfd_vma pc = bfd_scan_vma (str_addr, NULL, 16);
    if (bfd_get_flavour (fbfd) == bfd_target_elf_flavour)
    {
        const struct elf_backend_data *bed = (elf_backend_data *)(((fbfd)->xvec)->backend_data);
        bfd_vma sign = (bfd_vma) 1 << (bed->s->arch_size - 1);

        pc &= (sign << 1) - 1;
        if (bed->sign_extend_vma)
        pc = (pc ^ sign) - sign;
    }

    memset(buf, 0x0, sizeof(buf));
    bfd_sprintf_vma(fbfd, buf, pc);
    snprintf (out_buf, buf_len, "0x%s :", buf);

    ///check all sections to find out current address belony to which section
    for (sect = fbfd->sections; sect != NULL; i++, sect = sect->next)
    {
        bfd_vma vma;
        bfd_size_type size;

        if ((sect->flags & SEC_ALLOC) == 0)
        {
            continue;
        }

        ///section start position
        if (pc < sect->vma)
        {
            continue;
        }

        ///section end position
        if (pc >= sect->vma + sect->size)
        {
            continue;
        }

        if (TRUE == bfd_find_nearest_line_discriminator (fbfd, sect, syms, pc - sect->vma,
                                               &filename, &functionname,
                                               &line, &discriminator))
        {
            break;
        }
    }

    if (i > fbfd->section_count)
    {
        FATAL("(%d)can't find the address(%s) info in all section(%d)\n", i, str_addr, fbfd->section_count);
        strncpy(buf, out_buf, sizeof(buf));
        snprintf (out_buf, buf_len, "%s ?? ??:0", buf);
        return FALSE;
    }

    ///luckly, found the address infomation, to format the output string
    while (TRUE)
    {
        const char *name = functionname;
        char *alloc = NULL;

        ///format function name
        if (name == NULL)
        {
        	return FALSE;
        }
		
		if (*name == '\0')
		{
			return FALSE;
		}

		alloc = bfd_demangle (fbfd, name, DMGL_ANSI | DMGL_PARAMS);
		if (alloc != NULL)
		{
			name = alloc;
		}

        strncpy(buf, out_buf, sizeof(buf));
        snprintf (out_buf, buf_len, "%s %s  at", buf, (NULL != name) ? name : "??");

        if (alloc != NULL)
        {
            free (alloc);
        }

        strncpy(buf, out_buf, sizeof(buf));
        snprintf (out_buf, buf_len, "%s %s:", buf, (NULL != filename) ? filename : "??");

        strncpy(buf, out_buf, sizeof(buf));
        if (line != 0)
        {
            if (discriminator != 0)
            {
                snprintf (out_buf, buf_len, "%s%u (discriminator %u)", buf, line, discriminator);
            }
            else
            {
                snprintf (out_buf, buf_len, "%s%u", buf, line);
            }
        }
        else
        {
            snprintf (out_buf, buf_len, "%s?", buf);
        }

        if (FALSE == bfd_find_inliner_info (fbfd, &filename, &functionname, &line))
        {
            break;
        }

        ///inline info
        strncpy(buf, out_buf, sizeof(buf));
        snprintf (out_buf, buf_len, "%s (inlined by) ", buf);
    }

    return TRUE;
}

int
addr2line (const char *file_name, const char *str_addr, const int index)
{
    bfd *fbfd = NULL;
    bfd_boolean ret = FALSE;
#define LEN (2048)
    static char out_buf[LEN];
    const int buf_len = LEN;
#undef LEN

    if (NULL == file_name)
    {
        FATAL("file name is null error\n");
        return FALSE;
    }

    bfd_init();
    fbfd = bfd_openr (file_name, NULL);
    if (NULL == fbfd)
    {
        FATAL("faild to open bfd file(%s)\n", file_name);
        return FALSE;
    }

    ///check file format
    fbfd->flags |= BFD_DECOMPRESS;
    if (bfd_check_format (fbfd, bfd_archive))
    {
        FATAL("not support to analyse staic file(%s) error\n", file_name);
        goto __EXIT;
    }
    else if (!bfd_check_format (fbfd, bfd_object))
    {
        FATAL("file(%s) no symbol detech\n", file_name);
        goto __EXIT;
    }

    if (FALSE == slurp_symtab (fbfd))
    {
        FATAL("file(%s) start up symtab error\n", file_name);
        goto __EXIT;
    }

    memset(out_buf, 0x0, sizeof(out_buf));
    ret = translate_addresses (fbfd, str_addr, out_buf, buf_len);
    if (syms != NULL)
    {
      free (syms);
      syms = NULL;
    }

__EXIT:
    bfd_close (fbfd);
	if (TRUE == ret)
	{
		printf("#%d  %s\n", index, out_buf);
	}
    return ret;
}
#undef FATAL

#if (0)
main(int argc, char *argv[])  
{
    char *filename = NULL;
    char *str_addr = NULL;
    if (argc<3) exit(-1);

    filename = argv[1];
    str_addr = argv[2];
    process_file (filename, str_addr);
}
///http://www.mssl.ucl.ac.uk/swift/om/sw/help/man/bfd.html
///http://www.mssl.ucl.ac.uk/swift/om/sw/help/man/bfd_toc.html#TOC70
#endif

LOG:

all alloc memory info:
<<      (1) memory address:     0x946b2b0, size: 200, thread_id(0xb730f700), p_id(0x6f39)       >>
        (1) backtrace information(6):
#0  0x000314a9 : get_backtrace_info(char**&, unsigned int*)  at /work/memleak/CCheckMemoryLeak.cpp:85
#1  0x000315a5 : save_malloc_pointer_info(void const*, unsigned int)  at /work/memleak/CCheckMemoryLeak.cpp:119
#2  __wrap_realloc at (Unknow Source File):0
#3  main() at (Unknow Source File):0
#4  __libc_start_main() at (Unknow Source File):0
#5  ./TestChkMemLeak() [0x80488d1]() at (Unknow Source File):0
== all unfree memory time(1) size(0xc8) ==

源码:

http://download.csdn.net/detail/lbo4031/9546584

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值