[Cbe-oss-dev] SPU overlay DWARF DIE/CIE/FDE to program section/segment mapping?

John DelSignore jdelsign at totalviewtech.com
Wed Mar 25 08:56:12 EST 2009


Hi Folks,

I'm not sure if this is the correct forum, but I'm not sure who else to ask, and I'm hoping that the Cell tool chain maintainers respond to this posting...

Question: Is there a way to determine the program segment to which a particular DWARF DIE or CIE/FDE belongs, when multiple program segments are linked at the same address due to SPU overlays?

Here is the problem, as seen with a simple SPU overlay example. Taken from the Cell SDK and changed slightly. The source code inside in the overlaid sections looks like this:

------------------------------cut-here------------------------------
% more olay*/test*.c
::::::::::::::
olay1/test1.c
::::::::::::::
/* --------------------------------------------------------------- */
/* (C)Copyright 2006                                               */
/* International Business Machines Corporation,                    */
/* All Rights Reserved.                                            */
/*                                                                 */
/* This program is made available under the terms of the           */
/* Common Public License v1.0 which accompanies this distribution. */
/* --------------------------------------------------------------- */
/* PROLOG END TAG zYx                                              */
#include <stdio.h>

int o1_test1(int p)
{
        printf("o1_test1 prints %d\n", p);
        return 1;
}

int o1_test2(int p)
{
        printf("o1_test2 prints %d\n", p);
        return 2;
}
::::::::::::::
olay2/test2.c
::::::::::::::
/* --------------------------------------------------------------- */
/* (C)Copyright 2006                                               */
/* International Business Machines Corporation,                    */
/* All Rights Reserved.                                            */
/*                                                                 */
/* This program is made available under the terms of the           */
/* Common Public License v1.0 which accompanies this distribution. */
/* --------------------------------------------------------------- */
/* PROLOG END TAG zYx                                              */
#include <stdio.h>

int o2_test1(int p)
{
        printf("o2_test1 prints %d\n", p);
        return 11;
}

int o2_test2(int p)
{
        printf("o2_test2 prints %d\n", p);
        return 12;
}
------------------------------cut-here------------------------------

When the above SPU code is linked, multiple program segments are linked at the same virtual address (overlaid). The program header for a sample program looks like this:

------------------------------cut-here------------------------------
% spu-readelf -lS spu_main
There are 26 section headers, starting at offset 0x792c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .init             PROGBITS        00000000 000100 000024 00  AX  0   0  4
  [ 2] .text             PROGBITS        00000030 000130 000ad0 00 WAX  0   0 16
  [ 3] .segment1         PROGBITS        00000b00 000c00 000080 00  AX  0   0 16
  [ 4] .segment2         PROGBITS        00000b00 000c80 000080 00  AX  0   0 16
  [ 5] .fini             PROGBITS        00000b80 000d00 00001c 00  AX  0   0  4
  [ 6] .rodata           PROGBITS        00000ba0 000d20 0000d0 00   A  0   0 16
  [ 7] .ctors            PROGBITS        00000c80 000e00 000008 00  WA  0   0  4
  [ 8] .dtors            PROGBITS        00000c88 000e08 000008 00  WA  0   0  4
  [ 9] .jcr              PROGBITS        00000c90 000e10 000004 00  WA  0   0  4
  [10] .data             PROGBITS        00000ca0 000e20 000454 00  WA  0   0 16
  [11] .bss              NOBITS          00001100 001274 000010 00  WA  0   0 16
  [12] .comment          PROGBITS        00000000 001274 0000fc 00      0   0  1
  [13] .debug_aranges    PROGBITS        00000000 001370 000190 00      0   0  1
  [14] .debug_pubnames   PROGBITS        00000000 001500 0001b0 00      0   0  1
  [15] .debug_info       PROGBITS        00000000 0016b0 003eb5 00      0   0  1
  [16] .debug_abbrev     PROGBITS        00000000 005565 000b79 00      0   0  1
  [17] .debug_line       PROGBITS        00000000 0060de 000954 00      0   0  1
  [18] .debug_frame      PROGBITS        00000000 006a34 0001f0 00      0   0  4
  [19] .debug_str        PROGBITS        00000000 006c24 0008a6 00      0   0  1
  [20] .debug_loc        PROGBITS        00000000 0074ca 000351 00      0   0  1
  [21] .note.spu_name    PROGBITS        00000000 007820 000020 00      0   0 16
  [22] .toe              NOBITS          00001180 001270 000010 00  WA  0   0 16
  [23] .shstrtab         STRTAB          00000000 007840 0000ec 00      0   0  1
  [24] .symtab           SYMTAB          00000000 007d3c 000670 10     25  66  4
  [25] .strtab           STRTAB          00000000 0083ac 000472 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x30
There are 6 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000100 0x00000000 0x00000000 0x00b00 0x00b00 RWE 0x10
  LOAD           0x000c00 0x00000b00 0x00000b00 0x00080 0x00080 R E 0x10
  LOAD           0x000c80 0x00000b00 0x00000b80 0x00080 0x00080 R E 0x10
  LOAD           0x000d00 0x00000b80 0x00000c00 0x00580 0x00590 RWE 0x10
  LOAD           0x001270 0x00001180 0x00001200 0x00000 0x00010 RW  0x10
  NOTE           0x007820 0x00000000 0x00000000 0x00020 0x00020 R   0x10

 Section to Segment mapping:
  Segment Sections...
   00     .init .text 
   01     .segment1 .segment2 
   02     .segment1 .segment2 
   03     .fini .rodata .ctors .dtors .jcr .data .bss 
   04     .toe 
   05     .note.spu_name 
------------------------------cut-here------------------------------

Notice that .segment1 and .segment2 are both at virtual address 0x00000b00, but their file offsets are different (0x000c00 and 0x000c80, respectively).

Loader symbols which are associated with a particular program segment are defined together in a single file section, and the file section header includes a "phoff" field, which, as we understand it, indicates
the offset within the executable file of the associated program segment.  For example:

------------------------------cut-here------------------------------
% readelf -s spu_main | egrep Num\|_test
   Num:    Value  Size Type    Bind   Vis      Ndx Name
    66: 00000b00    60 FUNC    GLOBAL DEFAULT    3 o1_test1
    70: 00000b40    60 FUNC    GLOBAL DEFAULT    4 o2_test2
    86: 00000b40    60 FUNC    GLOBAL DEFAULT    3 o1_test2
    92: 00000b00    60 FUNC    GLOBAL DEFAULT    4 o2_test1
% 
------------------------------cut-here------------------------------

We can take the section index (in the Ndx column), get the section file offset, and then lookup the program header. That makes it straightforward to determine the overlay to which a particular loader symbol belongs.

However, the DWARF information does not seem to contain any direct indication of the program segment to which a particular symbol belongs. Only the link address of the symbol is provided in the DWARF information, and when multiple segments are linked at the same address, that's ambiguous.  That seems to make it impossible to determine which overlay a particular DWARF symbol belongs to. For example, here are some DWARF DIEs for the sample program functions o1_test1() and o2_test1(), both of which are at virtual address 0x00000b00:

------------------------------cut-here------------------------------
  Compilation Unit @ offset 0x18d:
   Length:        399
   Version:       2
   Abbrev Offset: 95
   Pointer Size:  4
 <0><198>: Abbrev Number: 1 (DW_TAG_compile_unit)
  <199>     DW_AT_stmt_list   : 0x5c	
  <19d>     DW_AT_high_pc     : 0xb7c	
  <1a1>     DW_AT_low_pc      : 0xb00	
  <1a5>     DW_AT_producer    : GNU C 4.1.1	
  <1b1>     DW_AT_language    : 1	(ANSI C)
  <1b2>     DW_AT_name        : test1.c	
  <1ba>     DW_AT_comp_dir    : /nfs/netapp0/user/home/slawrence/cell-sdk-copy2/prototype/src/samples/overlay/simple/spu_olay/olay1	
...
 <1><2c5>: Abbrev Number: 4 (DW_TAG_subprogram)
  <2c6>     DW_AT_sibling     : <2f4>	
  <2ca>     DW_AT_external    : 1	
  <2cb>     DW_AT_name        : o1_test1	
  <2d4>     DW_AT_decl_file   : 1	
  <2d5>     DW_AT_decl_line   : 13	
  <2d6>     DW_AT_prototyped  : 1	
  <2d7>     DW_AT_type        : <23b>	
  <2db>     DW_AT_low_pc      : 0xb00	
  <2df>     DW_AT_high_pc     : 0xb3c	
  <2e3>     DW_AT_frame_base  : 0x20	(location list)
...
  Compilation Unit @ offset 0x320:
   Length:        399
   Version:       2
   Abbrev Offset: 200
   Pointer Size:  4
 <0><32b>: Abbrev Number: 1 (DW_TAG_compile_unit)
  <32c>     DW_AT_stmt_list   : 0x9d	
  <330>     DW_AT_high_pc     : 0xb7c	
  <334>     DW_AT_low_pc      : 0xb00	
  <338>     DW_AT_producer    : GNU C 4.1.1	
  <344>     DW_AT_language    : 1	(ANSI C)
  <345>     DW_AT_name        : test2.c	
  <34d>     DW_AT_comp_dir    : /nfs/netapp0/user/home/slawrence/cell-sdk-copy2/prototype/src/samples/overlay/simple/spu_olay/olay2	
...
 <1><458>: Abbrev Number: 4 (DW_TAG_subprogram)
  <459>     DW_AT_sibling     : <487>	
  <45d>     DW_AT_external    : 1	
  <45e>     DW_AT_name        : o2_test1	
  <467>     DW_AT_decl_file   : 1	
  <468>     DW_AT_decl_line   : 13	
  <469>     DW_AT_prototyped  : 1	
  <46a>     DW_AT_type        : <3ce>	
  <46e>     DW_AT_low_pc      : 0xb00	
  <472>     DW_AT_high_pc     : 0xb3c	
  <476>     DW_AT_frame_base  : 0x5e	(location list)
------------------------------cut-here------------------------------

The DWARF frame information has a similar problem:

------------------------------cut-here------------------------------
...
00000028 0000000c ffffffff CIE
  Version:               1
  Augmentation:          ""
  Code alignment factor: 1
  Data alignment factor: -16
  Return address column: 0

  DW_CFA_def_cfa: r1 ofs 0

00000038 00000014 00000028 FDE cie=00000028 pc=00000b00..00000b3c
  DW_CFA_advance_loc: 12 to 00000b0c
  DW_CFA_def_cfa_offset: 48
  DW_CFA_offset_extended_sf: r0 at cfa+16
  DW_CFA_nop
  DW_CFA_nop

00000050 00000014 00000028 FDE cie=00000028 pc=00000b40..00000b7c
  DW_CFA_advance_loc: 12 to 00000b4c
  DW_CFA_def_cfa_offset: 48
  DW_CFA_offset_extended_sf: r0 at cfa+16
  DW_CFA_nop
  DW_CFA_nop

00000068 0000000c ffffffff CIE
  Version:               1
  Augmentation:          ""
  Code alignment factor: 1
  Data alignment factor: -16
  Return address column: 0

  DW_CFA_def_cfa: r1 ofs 0

00000078 00000014 00000068 FDE cie=00000068 pc=00000b00..00000b3c
  DW_CFA_advance_loc: 12 to 00000b0c
  DW_CFA_def_cfa_offset: 48
  DW_CFA_offset_extended_sf: r0 at cfa+16
  DW_CFA_nop
  DW_CFA_nop

00000090 00000014 00000068 FDE cie=00000068 pc=00000b40..00000b7c
  DW_CFA_advance_loc: 12 to 00000b4c
  DW_CFA_def_cfa_offset: 48
  DW_CFA_offset_extended_sf: r0 at cfa+16
  DW_CFA_nop
  DW_CFA_nop
------------------------------cut-here------------------------------

Notice that the FDE pc ranges overlap

Without the connection between the DWARF symbol and the segment, it's difficult or impossible to manage breakpoints within and properly back trace out of code which is in an overlay. The reason for this is that we want to be able to take each link address in the executable file and relocate it into separate provisional address space. Each program object (subroutine, variable, etc.) lives at a unique location in the provisional address space, which allows a unique mapping between provisional addresses and symbols.

What we need is a way to map an address in a DWARF DIE or CIE/FDE to a particular section or program segment so that we can determine the proper provisional relocation value.

Does such a mapping exist?

Finally, as far as we can tell, breakpoint handling in overlaid SPU segments in ppu-gdb just flat out doesn't work:

------------------------------cut-here------------------------------
% ppu-gdb overlay_simple
GNU gdb 6.6.50.20070623-cvs
Copyright (C) 2007 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "powerpc64-linux"...
Using host libthread_db library "/lib64/libthread_db.so.1".
(gdb) set spu stop-on-load
(gdb) start
Breakpoint 1 at 0x180172c: file overlay_simple.c, line 23.
Starting program: /nfs/netapp0/user/home/slawrence/cell-sdk-copy2/prototype/src/samples/overlay/simple/overlay_simple 
[Thread debugging using libthread_db enabled]
[New Thread 0xfff28a0 (LWP 22743)]
[Switching to Thread 0xfff28a0 (LWP 22743)]
main () at overlay_simple.c:23
23        unsigned int entry = SPE_DEFAULT_ENTRY;
(gdb) cont
Continuing.
Breakpoint 2 at 0x19c: file spu_main.c, line 33.
main (spuid=25296904, argp=0, envp=0) at spu_main.c:33
33        rc = o1_test1(101);
(gdb) b o2_test1
Breakpoint 3 at 0xb1c: file test2.c, line 14.
(gdb) b o2_test2
Breakpoint 4 at 0xb5c: file test2.c, line 20.
(gdb) cont
Continuing.
o1_test1 prints 101
o1_test2 prints 102
o2_test1 prints 201
o2_test2 prints 202
o1_test1 prints 301
o1_test2 prints 302
warning: Temporarily disabling breakpoints for unloaded shared library "spu_main at 0x1802000 <3>"

Program exited normally.
(gdb) start
Breakpoint 5 at 0x180172c: file overlay_simple.c, line 23.
Starting program: /nfs/netapp0/user/home/slawrence/cell-sdk-copy2/prototype/src/samples/overlay/simple/overlay_simple 
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
[Thread debugging using libthread_db enabled]
[New Thread 0xfff28a0 (LWP 22840)]
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
Error in re-setting breakpoint 3:
Function "o2_test1" not defined.
Error in re-setting breakpoint 4:
Function "o2_test2" not defined.
[Switching to Thread 0xfff28a0 (LWP 22840)]
main () at overlay_simple.c:23
23        unsigned int entry = SPE_DEFAULT_ENTRY;
(gdb) cont
Continuing.
Breakpoint 6 at 0x19c: file spu_main.c, line 33.
main (spuid=25296904, argp=0, envp=0) at spu_main.c:33
33        rc = o1_test1(101);
(gdb) cont
Continuing.
o1_test1 prints 101
o1_test2 prints 102
o2_test1 prints 201
o2_test2 prints 202
o1_test1 prints 301
o1_test2 prints 302
warning: Temporarily disabling breakpoints for unloaded shared library "spu_main at 0x1802000 <3>"

Program exited normally.
(gdb) 
------------------------------cut-here------------------------------

Notice that it didn't stop in o2_test1 or o2_test2, and it seems quite confused about when it should be plant breakpoint when the program is restarted.

Thanks much, and sorry for the long message!

Cheers, John D.




More information about the cbe-oss-dev mailing list