在uclinux中调试dxe文件

来源:互联网 发布:无锡中老年网络征婚 编辑:程序博客网 时间:2024/05/29 16:45
 
本文的开发环境为:bf561, uclinux-2.6(已移植到VDSP下),VDSP 5.0
日前看到一篇文章《Implementation of Dynamically Loaded Software Modules》,原始文件可从http://www.analog.com/ee-notes下载到(EE-323)。这篇文章的目标是从Flash中动态加载一个DXE文件,调用其中的函数并可用VDSP进行调试。其基本方法是将DXE由ELF格式转换为FLT格式并存储在FLASH中,使用时将这个FLT文件读取到内存的指定区域,再查找需要的函数所在的位置并进行调用。如果需要对调用的函数进行调试,则通过VDSP中的File -> Load Symbols加载原始的DXE文件中的调试信息即可。在调用完成后再加载调用程序的符号文件切换回来。
由此得到启发,uClinux本身不就支持FLT格式吗,这种方法是否也可以应用在uClinux中呢?
1   在VDSP中建立要调试的程序
1、利用VDSP5的向导在VDSP中建立一个要调试的DXE程序,注意不生成crt代码和LDF文件。
2、添加主程序main.c
/* Function prototypes */
 
int mean ( int *pArray, const unsigned int dwSize );
 
 
int g_iTimesCalled = 0;
 
/* Calculate the mean of an array pArray of length dwSize */
 
int mean ( int *pArray, const unsigned int dwSize )
{
       unsigned int sum = 0;
       unsigned int i;
      
       ++g_iTimesCalled;
      
       for ( i = 0 ; i < dwSize; ++i )
              sum += pArray[ i ];
             
       return sum / dwSize;
}
 
 
void main(void)
{
    int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int n = mean(array, 10);
    array[0] = n;
    return;
}
这是很简单的一个求平均数的程序。我们希望能够由uclinux加载这一程序并在VDSP中进行调试。
3、添加一个LDF文件,内容如下:
#ifndef __NO_STD_LIB
SEARCH_DIR( $ADI_DSP/Blackfin/lib )
#endif
 
$OBJECTS = $COMMAND_LINE_OBJECTS;
$LIBRARIES = libdsp561.dlb;
 
#define DBG_TEXT_BEGIN   0x10000
#define DBG_TEXT_END     0x20000
#define DBG_DATA_BEGIN   0x30000
#define DBG_DATA_END     0x40000
#define DBG_BSS_BEGIN    0x50000
#define DBG_BSS_END      0x60000
 
MEMORY
{
       // The sizes here are arbitrary and should be large enough to hold the inputs
       // sections they will contain. Specific START and END are unimportant as these
       // addresses will be "abstracted" away by elf2flt.
 
       MEM_TEXT { START(DBG_TEXT_BEGIN) END (DBG_TEXT_END) TYPE(RAM) WIDTH(8) }
       MEM_DATA   { START(DBG_DATA_BEGIN) END (DBG_DATA_END) TYPE(RAM) WIDTH(8) }
       MEM_BSZ            { START(DBG_BSS_BEGIN) END (DBG_BSS_END) TYPE(RAM) WIDTH(8) }
}
 
DYNAMIC p0
{
    OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
 
    SECTIONS
    {
          
           // Note the presence of three, and only three, output sections. They must
           // be called .text, .data, and .bsz. .bsz must be a zero-fill section
           // (ZERO_INIT keyword)
          
        .text
        {
            INPUT_SECTION_ALIGN(4)
            INPUT_SECTIONS( $OBJECTS(program) $LIBRARIES(program))
           
        } >MEM_TEXT
       
        .data
           {
            INPUT_SECTION_ALIGN(4)
            INPUT_SECTIONS( $OBJECTS(data1) $LIBRARIES(data1))
        } >MEM_DATA
 
        .bss ZERO_INIT
           {
            INPUT_SECTION_ALIGN(4)
            INPUT_SECTIONS( $OBJECTS(bsz) $LIBRARIES(bsz))
        } >MEM_BSZ
    }
}
注意以上的存储区域的定义,由于我们事先并不知道uclinux会把我们的程序放到哪个位置,因此这只是一个粗略的定义。
4、编译生成dxe文件。
5、利用VDSP5提供的elf2flt工具将这个dxe文件转换成flt格式。
2   在uclinux中加载FLT文件
1、将生成的flt格式文件放到uclinux的rootfs中。
2、为了在VDSP中调试这个文件,我们需要知道uclinux将这个文件加载到内存中的位置。在uclinux中,对FLT文件的加载是由fs/binfmt_flat.c这个文件来完成的,我们所需要做的是在这个文件的合适位置断下来,并取得相关的指针。
经过对此文件的分析,我们可以在load_flat_file这个函数中设置断点,并进行单步跟踪。在此过程中还发现VDSP 5.0转换生成的flt格式文件将rev设置为5,而uclinux只支持2和4的版本,在此处还需要将rev的值改为4。
跟踪到以下语句时(671行):
       /* The main program needs a little extra setup in the task structure */
       start_code = textpos + sizeof (struct flat_hdr);
       end_code = textpos + text_len;
       if (id == 0) {
              current->mm->start_code = start_code;
              current->mm->end_code = end_code;
              current->mm->start_data = datapos;
              current->mm->end_data = datapos + data_len;
              /*
               * set up the brk stuff, uses any slack left in data/bss/stack
               * allocation. We put the brk after the bss (between the bss
               * and stack) like other platforms.
               */
              current->mm->start_brk = datapos + data_len + bss_len;
              current->mm->brk = (current->mm->start_brk + 3) & ~3;
              current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
              current->mm->context.stack_start = current->mm->context.end_brk;
       }
我们就可以取得这个FLT文件在内存中的分布位置了,将code,data,bss这三个段的起始位置和结束位置记录下来。
3、在code的起始位置设置断点并运行,直到VDSP在此位置中断下来,就进入了我们需要调试的程序。
3   加载调试信息
为了保证VDSP中生成的DXE文件中的调试信息地址与uclinux加载的地址一致,还需要回过头修改LDF文件中的几个地址。
#define DBG_TEXT_BEGIN   0x10000
#define DBG_TEXT_END     0x20000
#define DBG_DATA_BEGIN   0x30000
#define DBG_DATA_END     0x40000
#define DBG_BSS_BEGIN    0x50000
#define DBG_BSS_END      0x60000
中的几个值改为uclinux实际加载的地址,并重新编译生成一个DXE文件。
在VDSP中选择File -> Load Symbols,并加载这个刚刚生成的DXE文件。哈哈,看到了吗,在汇编窗口出现了mean和main函数的符号。再打开变量监视器,输入g_iTimesCalled,马上就看到这个变量的值了。单步执行程序,VDSP自动打开main.c文件并将光标定位在mean函数的第一行语句上。
至此就意味着这种方法基本上是成功的。之所以只是基本,是因为这个程序还只能加载符号信息,但还无法运行。因为在uclinux下的用户程序要正常运行,它需要做一些初始化的工作,这部分工作是由uClibc来完成的,显然我们没有进行这样的过程,这个程序不能运行也就是理所当然的了。
下一步工作就是将uClibc移植到VDSP上,开发应用程序时链接进来应该就OK了!
 
原创粉丝点击