由于实时打印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