ELF Program Header Names

Ali Bahrami — Wednesday January 10, 2018

Surfing with the Linker-Aliens

The generic ELF format does not assign names to program headers. We've changed that with Solaris 11.4. This article describes how and why.

So much of ELF revolves around naming, particularly for sections and symbols. Today, noting that nearly everything else in an ELF object is explicitly named, and in particular, that sections have names, it seems like an odd oversight that program headers are nameless. However, when ELF was invented, it was always true that each object had only 2 mappings (text, data), and there were very few objects in a process (a.out, libc). As such, a given process had very few mappings, and experienced developers could easily tell them apart based on address, and access mode. In today's world with many mappings per object, many objects, and advanced virtual memory abilities, the lack of names creates an observability gap, where the human reader is required to apply educated guesswork to understand what a process is doing.

We're used to this, and generally don't notice, but last year, while puzzling over some mysterious (to me) pmap output, I realized how easy it would be to do better. That realization led to a project to add program header names to Solaris ELF objects, and to modify libproc, elfdump, elfedit, pmap, pmadvise, and mdb's ::mappings dcmd to use them. The ability to associate a mapping with its segment name takes some of the educated guesswork out of examining the mappings in a process, yielding clear and basic observability benefits. This additional information comes at very little cost: An additional 32-bit word per program header, and the addition of the name strings to the existing .dynstr string table. The overall effect of these changes is to add program header names to Solaris ELF objects, to make that added information available in the output of the utilities that examine mappings, and then to improve the display from those utilities such that the added information does not increase output line lengths unreasonably.

Implementation Details And Historical Context

The base memory mappings in a process come from program headers in ELF objects (PT_LOAD, PT_SUNW_RESERVE, PT_SUNW_SYSTAT, and PT_SUNW_SYSSTAT). These mappings are augmented by supporting mappings created by the kernel (anon, heap, stack, ...). ELF objects do not traditionally record names for the segments created from program headers. As such, when we look at pmap output for a process, we used to see something like this:
% pmap `pgrep zonestatd`
268:    /usr/lib/zones/zonestatd
00000008F1C2E000        388K rw-----    [ heap ]
00007FF5B39FF000          4K rw--R--    [ stack tid=5 ]
00007FF5B3BFE000          4K rw--R--    [ stack tid=4 ]
00007FF5B3C00000         28K r-x----  /lib/amd64/libcontract.so.1
00007FF5B3D07000          4K rw-----  /lib/amd64/libcontract.so.1
00007FF5B3FEE000          4K rw--R--    [ stack tid=3 ]
00007FF5B3FF0000         64K rw-----    [ anon ]
00007FF5B41FE000          4K rw--R--    [ stack tid=2 ]
00007FF5B4200000         68K r-x----  /lib/amd64/libuutil.so.1
00007FF5B4311000          4K rw-----  /lib/amd64/libuutil.so.1
00007FF5B4400000        340K r-x----  /lib/amd64/libscf.so.1
00007FF5B4555000          8K rw-----  /lib/amd64/libscf.so.1
00007FF5B4557000          4K rw-----  /lib/amd64/libscf.so.1
00007FF5B4600000       2048K r-x----  /lib/amd64/libc.so.1
00007FF5B4800000        616K r-x----  /lib/amd64/libc.so.1
00007FF5B499A000         80K rw-----  /lib/amd64/libc.so.1
00007FF5B49AE000         40K rw-----  /lib/amd64/libc.so.1
00007FF5B4A00000        144K r-x----  /lib/amd64/libumem.so.1
00007FF5B4B24000         32K rw-----  /lib/amd64/libumem.so.1
00007FF5B4B2C000         40K rw-----  /lib/amd64/libumem.so.1
00007FF5B4C00000        344K r-x----  /lib/amd64/ld.so.1
00007FF5B4D56000          4K r------  /lib/amd64/ld.so.1
00007FF5B4E57000         16K rwx----  /lib/amd64/ld.so.1
00007FF5B4E5B000          8K rwx----  /lib/amd64/ld.so.1
00007FF5B5000000         88K r-x----  /usr/lib/zones/zonestatd
00007FF5B5116000          4K rw-----  /usr/lib/zones/zonestatd
00007FF5B51AC000         64K rw-----    [ anon ]
00007FF5B51BD000        128K rw-----    [ anon ]
00007FF5B51DE000          4K rw-s---    [ anon ]
00007FF5B51E0000         24K rw-----    [ anon ]
00007FF5B51E9000          4K r-x----    [ anon ]
00007FF5B51ED000         64K rw-----    [ anon ]
00007FF5B51FE000         12K r--s---    [ anon ]
00007FF5B5202000          4K r--s---    [ anon ]
00007FF5B5204000          4K r--s---    [ anon ]
FFFF80E85A4C5000         12K rw-----    [ stack ]
         total         4708K
As OS developers, we're used to picking out the text and data segments, and the others, based on the permission flags and order, but sometimes, it isn't so obvious, and we have to take educated guesses. For instance, the output above might raise the following questions.

  1. Why does ld.so.1 have 4 mappings, why is one readonly, and what is that segment doing?
    00007FF5B4C00000        344K r-x----  /lib/amd64/ld.so.1
    00007FF5B4D56000          4K r------  /lib/amd64/ld.so.1
    00007FF5B4E57000         16K rwx----  /lib/amd64/ld.so.1
    00007FF5B4E5B000          8K rwx----  /lib/amd64/ld.so.1
    

  2. Here, we have 2 rw mappings adjacent to each other. We know from experience that the VM has probably fragmented the data segment into 2 mappings, but how can we really tell, other than using elfdump to manually match their addresses against the program headers?
    00007FF5B4A00000        144K r-x----  /lib/amd64/libumem.so.1
    00007FF5B4B24000         32K rw-----  /lib/amd64/libumem.so.1
    00007FF5B4B2C000         40K rw-----  /lib/amd64/libumem.so.1
    
And of course, programmers can create additional mappings using mapfiles. The reader of pmap output can only guess about that possibility.

It is interesting to note that the segments that come from ELF program headers start out with names. These names are assigned by the link-editor (ld) when the object is created. The segments automatically created by ld have names like 'text' and 'data', reflecting their purpose. When you create a segment or a memory reservation with a mapfile, the mapfile syntax requires you to supply a unique name by which they can be referenced. Segment names are used by the link-editor, but traditionally, when the ELF object is written, the segment name information is discarded, leaving the unnamed program headers described above.

Starting with Solaris 11.4, we preserve the segment names within ELF objects that have program headers (executables, shared objects).

To take advantage of this new information, related changes were made to other parts of the system:

The end result of these changes is that tools like pmap can now display segment names for all mappings. The example above becomes:

% pmap `pgrep zonestatd`
314:    /usr/lib/zones/zonestatd
000000042CC35000  384K rw-----  [ heap ]
00007FF6E7FFF000    4K rw--R--  [ stack tid=5 ]
00007FF6E81FE000    4K rw--R--  [ stack tid=4 ]
00007FF6E8200000   28K r-x----  [ text ] /lib/amd64/libcontract.so.1
00007FF6E8307000    4K rw-----  [ data ] /lib/amd64/libcontract.so.1
00007FF6E85EE000    4K rw--R--  [ stack tid=3 ]
00007FF6E85F0000   64K rw-----  [ anon ]
00007FF6E87FE000    4K rw--R--  [ stack tid=2 ]
00007FF6E8800000   68K r-x----  [ text ] /lib/amd64/libuutil.so.1
00007FF6E8911000    4K rw-----  [ data ] /lib/amd64/libuutil.so.1
00007FF6E8A00000  340K r-x----  [ text ] /lib/amd64/libscf.so.1
00007FF6E8B55000    8K rw-----  [ data ] /lib/amd64/libscf.so.1
00007FF6E8B57000    4K rw-----  [ data ] /lib/amd64/libscf.so.1
00007FF6E8C00000 2048K r-x----  [ text ] /lib/amd64/libc.so.1
00007FF6E8E00000  616K r-x----  [ text ] /lib/amd64/libc.so.1
00007FF6E8F9A000   80K rw-----  [ data ] /lib/amd64/libc.so.1
00007FF6E8FAE000   40K rw-----  [ data ] /lib/amd64/libc.so.1
00007FF6E9000000  144K r-x----  [ text ] /lib/amd64/libumem.so.1
00007FF6E9124000   32K rw-----  [ data ] /lib/amd64/libumem.so.1
00007FF6E912C000   40K rw-----  [ data ] /lib/amd64/libumem.so.1
00007FF6E9200000  344K r-x----  [ text ] /lib/amd64/ld.so.1
00007FF6E9356000    4K r------  [ dtrace ] /lib/amd64/ld.so.1
00007FF6E9457000   16K rwx----  [ data ] /lib/amd64/ld.so.1
00007FF6E945B000    8K rwx----  [ data ] /lib/amd64/ld.so.1
00007FF6E9600000   92K r-x----  [ text ] /usr/lib/zones/zonestatd
00007FF6E9717000    4K rw-----  [ data ] /usr/lib/zones/zonestatd
00007FF6E977E000   64K rw-----  [ anon ]
00007FF6E978F000  128K rw-----  [ anon ]
00007FF6E97B0000   24K rw-----  [ anon ]
00007FF6E97BC000    4K rw-s---  [ anon ]
00007FF6E97BE000    4K r-x----  [ anon ]
00007FF6E97C2000   64K rw-----  [ anon ]
00007FF6E97D3000   12K r--s---  [ anon ]
00007FF6E97D7000    4K r--s---  [ anon ]
00007FF6E97D9000    4K r--s---  [ anon ]
FFFF80CCF0817000   16K rw-----  [ stack ]
And the answers to our previous questions are a bit easier to answer:

  1. The extra mapping to ld.so.1 is named 'dtrace', an implementation detail of the runtime linker created via a mapfile to assist DTrace, and is not a text or data segment.

  2. The VM is indeed splitting some data segments into multiple mappings, presumably to apply more advantageous page sizes.

User Visible Changes (elfdump)

When elfdump displays program headers, it now includes the segment name, when available. The name is shown on the first line of output, similar to how section names are displayed.

When displaying program headers for older objects that lack name information, and for unnamed program headers in new object (those that do not directly create mappings), no name is shown. In this case, the output is unchanged relative to what was shown in the past.

Here, we examine hello world, and see that the PT_LOAD segments have been given the names 'text' and 'data':

% cc hello.c
% elfdump -pNLOAD a.out

Program Header[3]:  text
    p_vaddr:      0x8050000   p_flags:    [ PF_X PF_R ]
    p_paddr:      0           p_type:     [ PT_LOAD ]
    p_filesz:     0xb03       p_memsz:    0xb03
    p_offset:     0           p_align:    0x10000

Program Header[4]:  data
    p_vaddr:      0x8060b04   p_flags:    [ PF_X PF_W PF_R ]
    p_paddr:      0           p_type:     [ PT_LOAD ]
    p_filesz:     0x1d0       p_memsz:    0x1d0
    p_offset:     0xb04       p_align:    0x10000

User Visible Changes (elfedit)

The elfedit program is updated as follows:

User Visible Changes (pmap)

The pmap utility is modified to incorporate the new segment name information when available. This adds a small amount of extra information to every line. pmap output has traditionally been wasteful of horizontal space, and already suffers from long lines that exceed the width of a standard 80-column tty. The added segment name information exacerbated this situation. Therefore, I put additional effort into improving pmap's display to remove the unnecessary whitespace, with the result that pmap output will often be as compact, or more so, than in the past, despite the additional information.

The changes to pmap output are:

The changes can be easily seen in a comparison of old and new output. The following is from an older version of Solaris. Note the wasteful use of whitespace, and that segments are not named:

% pmap -x $$
19147:  -bash
         Address     Kbytes        RSS       Anon     Locked Mode   Mapped File
0000000000400000       1212       1120          -          - r-x----  bash
000000000062F000         40         40          8          - rw-----  bash
0000000000639000         40         28         12          - rw-----  bash
0000000DADD07000        408        404         40          - rw-----    [ heap ]
00007FF44EE00000         32         32          -          - r-x----  libgen.so.1
00007FF44EF08000          4          4          -          - rw-----  libgen.so.1
00007FF44F000000        420        260          -          - r-x----  libncurses.so.5.7
00007FF44F169000         20         20          -          - rw-----  libncurses.so.5.7
00007FF44F200000       2664       2664          -          - r-x----  libc.so.1
00007FF44F59A000         80         80          8          - rw-----  libc.so.1
00007FF44F5AE000         40         24          -          - rw-----  libc.so.1
00007FF44F600000        344        344          -          - r-x----  ld.so.1
00007FF44F756000          4          4          -          - r------  ld.so.1
00007FF44F857000         16         16          4          - rwx----  ld.so.1
00007FF44F85B000          8          8          4          - rwx----  ld.so.1
00007FF44F8B0000         64         16          -          - rw-----    [ anon ]
00007FF44F8D0000         64         64          -          - rw-----    [ anon ]
00007FF44F8F0000         24         12          4          - rw-----    [ anon ]
00007FF44F8FE000          4          4          -          - rw-s---    [ anon ]
00007FF44F900000         64         48         24          - rw-----    [ anon ]
00007FF44F911000         12         12          -          - r--s---    [ anon ]
00007FF44F915000          4          4          -          - r--s---    [ anon ]
00007FF44F917000          4          4          -          - r--s---    [ anon ]
00007FF44F919000          4          4          -          - r-x----    [ anon ]
FFFF80F932605000         28         28          8          - rw-----    [ stack ]
---------------- ---------- ---------- ---------- ----------
        total Kb       5604       5244        112          -
And here is the same output, produced by a current version of Solaris:
1611:   -bash
         Address Kbytes  RSS Anon Lock Mode     Mapped File
0000000000400000   1212 1112    -    - r-x----  [ text ] bash
000000000062F000     40   40    8    - rw-----  [ data ] bash
0000000000639000     40   28   12    - rw-----  [ data ] bash
0000000E6CC2C000    432  428   44    - rw-----  [ heap ]
00007FD15E400000     32   32    -    - r-x----  [ text ] libgen.so.1
00007FD15E508000      4    4    -    - rw-----  [ data ] libgen.so.1
00007FD15E600000    460  312    -    - r-x----  [ text ] libncursesw.so.5.9
00007FD15E773000     20   20    -    - rw-----  [ data ] libncursesw.so.5.9
00007FD15E800000   2660 2660    -    - r-x----  [ text ] libc.so.1
00007FD15EB99000     80   80    8    - rw-----  [ data ] libc.so.1
00007FD15EBAD000     40   24    -    - rw-----  [ data ] libc.so.1
00007FD15EC00000    348  348    -    - r-x----  [ text ] ld.so.1
00007FD15ED57000      4    4    -    - r------  [ dtrace ] ld.so.1
00007FD15EE58000     20   20    4    - rwx----  [ data ] ld.so.1
00007FD15EE5D000      4    4    4    - rwx----  [ data ] ld.so.1
00007FD15EF60000     64   16    -    - rw-----  [ anon ]
00007FD15EF80000     64   64    -    - rw-----  [ anon ]
00007FD15EF9E000      4    4    -    - rw-s---  [ anon ]
00007FD15EFA0000     24   20    4    - rw-----  [ anon ]
00007FD15EFA9000     64   52   28    - rw-----  [ anon ]
00007FD15EFBA000     12   12    -    - r--s---  [ anon ]
00007FD15EFBE000      4    4    -    - r--s---  [ anon ]
00007FD15EFC0000      4    4    -    - r--s---  [ anon ]
00007FD15EFC2000      4    4    -    - r-x----  [ anon ]
00007FDE270D3000     24   24    -    - rw-----  [ stack ]
00007FDE270D9000      4    4    4    - rw-----  [ stack ]
---------------- ------ ---- ---- ----
        total Kb   5668 5324  116    -
In addition to the changes described above, the existing pmap support for displaying PT_SUNW_RESERVE, PT_SUNW_SYSTAT, and PT_SUNW_SYSSTAT segments has been improved to show their specific types (rather than anon), as well as their mapfile assigned names. As an example, we apply the following mapfile to hello world:
% cat mapfile
$mapfile_version 2

RESERVE_SEGMENT locus {
        VADDR = 0x9000000;
        SIZE = 0x10000;
};

RESERVE_SEGMENT my_sysstat {
        TYPE = sysstat;
        VADDR = 0xa000000;
        SIZE = 0x100;
};

RESERVE_SEGMENT my_sysstat_zone {
        TYPE = sysstat_zone;
        VADDR = 0xb000000;
        SIZE = 0x100;
};
Prior to these changes, pmap would show the following output for this program:
% pmap -x 13652
13652:  a.out
         Address     Kbytes        RSS       Anon     Locked Mode   Mapped File
0000000000400000          4          4          -          - r-x----  a.out
0000000000500000          8          8          -          - rw-----  a.out
0000000009000000         64          -          -          - -------    [ reserved ]
000000000A000000          4          4          -          - r--s---    [ anon ]
000000000B000000          4          4          -          - r--s---    [ anon ]
FFFF80FFBF400000        344        344          -          - r-x----  ld.so.1
FFFF80FFBF556000          4          4          -          - r------  ld.so.1
FFFF80FFBF657000         16         16          4          - rwx----  ld.so.1
FFFF80FFBF65B000          8          -          -          - rwx----  ld.so.1
FFFF80FFBF7F5000         12         12          -          - r--s---    [ anon ]
FFFF80FFBF7F9000          4          4          -          - r--s---    [ anon ]
FFFF80FFBF7FB000          4          4          -          - r--s---    [ anon ]
FFFF80FFBF7FD000          4          4          -          - r-x----    [ anon ]
FFFF80FFBFFFE000          8          8          8          - rw-----    [ stack ]
---------------- ---------- ---------- ---------- ----------
        total Kb        488        416         12          -
With these changes:
% pmap -x 24305
24305:  a.out
 Address Kbytes RSS Anon Lock Mode     Mapped File
08050000      4   4    -    - r-x----  [ text ] a.out
08060000      4   4    -    - rwx----  [ data ] a.out
09000000     64   -    -    - -------  [ reserved name=locus ]
0A000000      4   4    -    - r--s---  [ sysstat name=my_sysstat ]
0B000000      4   4    -    - r--s---  [ sysstat_zone name=my_sysstat_zone ]
FE790000    236 236    -    - r-x----  [ text ] ld.so.1
FE7DB000      4   4    -    - r------  [ dtrace ] ld.so.1
FE7EC000     12  12    4    - rwx----  [ data ] ld.so.1
FE7EF000      4   -    -    - rwx----  [ data ] ld.so.1
FE7F4000     12  12    -    - r--s---  [ anon ]
FE7F8000      4   4    -    - r--s---  [ anon ]
FE7FA000      4   4    -    - r--s---  [ anon ]
FE7FC000      4   4    -    - r-x----  [ anon ]
FEFFE000      4   4    4    - rw-----  [ stack ]
-------- ------ --- ---- ----
total Kb    364 296    8    -
As shown above, the pmap -x and -S options automatically display the basename of the file that backs memory mappings, rather than the full file paths. When these options are not used, pmap displays full path names. The -b option has been added to allow basenames to be shown in these other modes as well. Often, the filename is all that is needed, and full paths create unnecessary clutter. This option was put to good use in the examples for the revised pmap manpage itself, where its use allowed the examples to fit in the allowed space without the need for artificial edits.

Here is an example of normal pmap output:

% pmap $$ | egrep 'bash|\.so'
1378:   -bash
0000000000400000 1212K r-x----  /usr/bin/bash
000000000062F000   40K rw-----  /usr/bin/bash
0000000000639000   40K rw-----  /usr/bin/bash
00007FFFBC800000   32K r-x----  [ text ] /lib/amd64/libgen.so.1
00007FFFBC908000    4K rw-----  [ data ] /lib/amd64/libgen.so.1
00007FFFBCA00000  420K r-x----  [ text ] /usr/lib/amd64/libncurses.so.5.7
00007FFFBCB69000   20K rw-----  [ data ] /usr/lib/amd64/libncurses.so.5.7
00007FFFBCC00000 2048K r-x----  [ text ] /lib/amd64/libc.so.1
00007FFFBCE00000  616K r-x----  [ text ] /lib/amd64/libc.so.1
00007FFFBCF9A000   80K rw-----  [ data ] /lib/amd64/libc.so.1
00007FFFBCFAE000   40K rw-----  [ data ] /lib/amd64/libc.so.1
00007FFFBD000000  344K r-x----  [ text ] /lib/amd64/ld.so.1
00007FFFBD156000    4K r------  [ dtrace ] /lib/amd64/ld.so.1
00007FFFBD257000   16K rwx----  [ data ] /lib/amd64/ld.so.1
00007FFFBD25B000    8K rwx----  [ data ] /lib/amd64/ld.so.1
And here is the same example, with the addition of -b:
% pmap -b $$ | egrep 'bash|\.so'
1378:   -bash
0000000000400000 1212K r-x----  bash
000000000062F000   40K rw-----  bash
0000000000639000   40K rw-----  bash
00007FFFBC800000   32K r-x----  [ text ] libgen.so.1
00007FFFBC908000    4K rw-----  [ data ] libgen.so.1
00007FFFBCA00000  420K r-x----  [ text ] libncurses.so.5.7
00007FFFBCB69000   20K rw-----  [ data ] libncurses.so.5.7
00007FFFBCC00000 2048K r-x----  [ text ] libc.so.1
00007FFFBCE00000  616K r-x----  [ text ] libc.so.1
00007FFFBCF9A000   80K rw-----  [ data ] libc.so.1
00007FFFBCFAE000   40K rw-----  [ data ] libc.so.1
00007FFFBD000000  344K r-x----  [ text ] ld.so.1
00007FFFBD156000    4K r------  [ dtrace ] ld.so.1
00007FFFBD257000   16K rwx----  [ data ] ld.so.1
00007FFFBD25B000    8K rwx----  [ data ] ld.so.1

User Visible Changes (pmadvise)

The pmadvise command, invoked with the -v option, produces the same output as pmap. To maintain this relationship, pmadvise has been updated with the same changes described for pmap above. As such, the example from the pmadvise manpage:
% pmadvise -o heap=access_lwp,stack=access_default -v $$
19147:  -bash
0000000000400000       1212K r-x----  /usr/bin/bash
000000000062F000         40K rw-----  /usr/bin/bash
0000000000639000         40K rw-----  /usr/bin/bash
0000000DADD07000        408K rw-----    [ heap ]        <= access_lwp
00007FF44EE00000         32K r-x----  /lib/amd64/libgen.so.1
00007FF44EF08000          4K rw-----  /lib/amd64/libgen.so.1
00007FF44F000000        420K r-x----  /usr/lib/amd64/libncurses.so.5.7
00007FF44F169000         20K rw-----  /usr/lib/amd64/libncurses.so.5.7
00007FF44F200000       2048K r-x----  /lib/amd64/libc.so.1
00007FF44F400000        616K r-x----  /lib/amd64/libc.so.1
00007FF44F59A000         80K rw-----  /lib/amd64/libc.so.1
00007FF44F5AE000         40K rw-----  /lib/amd64/libc.so.1
00007FF44F600000        344K r-x----  /lib/amd64/ld.so.1
00007FF44F756000          4K r------  /lib/amd64/ld.so.1
00007FF44F857000         16K rwx----  /lib/amd64/ld.so.1
00007FF44F85B000          8K rwx----  /lib/amd64/ld.so.1
00007FF44F8B0000         64K rw-----    [ anon ]
00007FF44F8D0000         64K rw-----    [ anon ]
00007FF44F8F0000         24K rw-----    [ anon ]
00007FF44F8FE000          4K rw-s---    [ anon ]
00007FF44F900000         64K rw-----    [ anon ]
00007FF44F911000         12K r--s---    [ anon ]
00007FF44F915000          4K r--s---    [ anon ]
00007FF44F917000          4K r--s---    [ anon ]
00007FF44F919000          4K r-x----    [ anon ]
FFFF80F932605000         28K rw-----    [ stack ]       <= access_default
becomes
% pmadvise -o heap=access_lwp,stack=access_default -v $$
23477:  -bash
0000000000400000 1212K r-x----  [ text ] /usr/bin/bash
000000000062F000   40K rw-----  [ data ] /usr/bin/bash
0000000000639000   40K rw-----  [ data ] /usr/bin/bash
0000000E3A310000  432K rw-----  [ heap ]        <= access_lwp
00007FF131600000   32K r-x----  [ text ] /lib/amd64/libgen.so.1
00007FF131708000    4K rw-----  [ data ] /lib/amd64/libgen.so.1
00007FF131800000  420K r-x----  [ text ] /usr/lib/amd64/libncurses.so.5.7
00007FF131969000   20K rw-----  [ data ] /usr/lib/amd64/libncurses.so.5.7
00007FF131A00000 2048K r-x----  [ text ] /lib/amd64/libc.so.1
00007FF131C00000  616K r-x----  [ text ] /lib/amd64/libc.so.1
00007FF131D9A000   80K rw-----  [ data ] /lib/amd64/libc.so.1
00007FF131DAE000   40K rw-----  [ data ] /lib/amd64/libc.so.1
00007FF131E00000  344K r-x----  [ text ] /lib/amd64/ld.so.1
00007FF131F56000    4K r------  [ dtrace ] /lib/amd64/ld.so.1
00007FF132057000   16K rwx----  [ data ] /lib/amd64/ld.so.1
00007FF13205B000    8K rwx----  [ data ] /lib/amd64/ld.so.1
00007FF132070000   64K rw-----  [ anon ]
00007FF132090000   64K rw-----  [ anon ]
00007FF1320AE000    4K rw-s---  [ anon ]
00007FF1320B0000   24K rw-----  [ anon ]
00007FF1320B7000   64K rw-----  [ anon ]
00007FF1320C8000   12K r--s---  [ anon ]
00007FF1320CC000    4K r--s---  [ anon ]
00007FF1320CE000    4K r--s---  [ anon ]
00007FF1320D0000    4K r-x----  [ anon ]
FFFF80EC736D0000   32K rw-----  [ stack ]       <= access_default

User Visible Changes (mdb ::mappings)

The mdb ::mappings dcmd provides pmap style mapping information for the process being debugged. It has also been updated to display the new segment name information. The preexisting output from ::mappings suffered from the same overly sparse layout issues as pmap, compounded by mdb's automatic line wrapping behavior. To mitigate this effect, the SIZE column is now dynamically sized to fit the actual data. Two options, -b (basename), and -s (suppress segment names) have also been added to give the end user additional control over the ::mappings output.

The following ::mappings output is from an older system:

% mdb a.out
a.out> main::bp
a.out> ::run
mdb: stop at main
mdb: target stopped at:
main:           pushq  %rbp
a.out:13622*> ::mappings
            BASE            LIMIT             SIZE NAME
          400000           401000             1000 /tmp/a.out
          500000           502000             2000 /tmp/a.out
         9000000          9010000            10000 [ reserved ]
         a000000          a001000             1000 [ anon ]
         b000000          b001000             1000 [ anon ]
ffff80ffbee00000 ffff80ffbf000000           200000 /lib/amd64/libc.so.1
ffff80ffbf000000 ffff80ffbf09a000            9a000 /lib/amd64/libc.so.1
ffff80ffbf19a000 ffff80ffbf1ae000            14000 /lib/amd64/libc.so.1
ffff80ffbf1ae000 ffff80ffbf1b8000             a000 /lib/amd64/libc.so.1
ffff80ffbf400000 ffff80ffbf456000            56000 /lib/amd64/ld.so.1
ffff80ffbf556000 ffff80ffbf557000             1000 /lib/amd64/ld.so.1
ffff80ffbf657000 ffff80ffbf65b000             4000 /lib/amd64/ld.so.1
ffff80ffbf65b000 ffff80ffbf65d000             2000 /lib/amd64/ld.so.1
ffff80ffbf7d0000 ffff80ffbf7d6000             6000 [ anon ]
ffff80ffbf7e4000 ffff80ffbf7f4000            10000 [ anon ]
ffff80ffbf7f5000 ffff80ffbf7f8000             3000 [ anon ]
ffff80ffbf7f9000 ffff80ffbf7fa000             1000 [ anon ]
ffff80ffbf7fb000 ffff80ffbf7fc000             1000 [ anon ]
ffff80ffbf7fd000 ffff80ffbf7fe000             1000 [ anon ]
ffff80ffbfffc000 ffff80ffc0000000             4000 [ stack ]
With the modifications described in this case, the same command produces the following:
a.out:1493*> ::mappings   
            BASE            LIMIT   SIZE NAME
          400000           401000   1000 [ text ] /tmp/a.out
          500000           502000   2000 [ data ] /tmp/a.out
         9000000          9010000  10000 [ reserved name=locus ]
         a000000          a001000   1000 [ sysstat name=my_sysstat ]
         b000000          b001000   1000 [ sysstat_zone name=my_sysstat_zone ]
ffff80ffbf000000 ffff80ffbf200000 200000 [ text ] /lib/amd64/libc.so.1
ffff80ffbf200000 ffff80ffbf29a000  9a000 [ text ] /lib/amd64/libc.so.1
ffff80ffbf39a000 ffff80ffbf3ae000  14000 [ data ] /lib/amd64/libc.so.1
ffff80ffbf3ae000 ffff80ffbf3b8000   a000 [ anon ]
ffff80ffbf400000 ffff80ffbf456000  56000 [ text ] /lib/amd64/ld.so.1
ffff80ffbf556000 ffff80ffbf557000   1000 [ dtrace ] /lib/amd64/ld.so.1
ffff80ffbf657000 ffff80ffbf65b000   4000 [ data ] /lib/amd64/ld.so.1
ffff80ffbf65b000 ffff80ffbf65d000   2000 [ anon ]
ffff80ffbf7d0000 ffff80ffbf7d6000   6000 [ anon ]
ffff80ffbf7e4000 ffff80ffbf7f4000  10000 [ anon ]
ffff80ffbf7f5000 ffff80ffbf7f8000   3000 [ anon ]
ffff80ffbf7f9000 ffff80ffbf7fa000   1000 [ anon ]
ffff80ffbf7fb000 ffff80ffbf7fc000   1000 [ anon ]
ffff80ffbf7fd000 ffff80ffbf7fe000   1000 [ anon ]
ffff80ffbfffd000 ffff80ffc0000000   3000 [ stack ]
The -b (basename) option can be used to remove extraneous path details:
a.out:1493*> ::mappings -b
            BASE            LIMIT   SIZE NAME
          400000           401000   1000 [ text ] a.out
          500000           502000   2000 [ data ] a.out
         9000000          9010000  10000 [ reserved name=locus ]
         a000000          a001000   1000 [ sysstat name=my_sysstat ]
         b000000          b001000   1000 [ sysstat_zone name=my_sysstat_zone ]
ffff80ffbf000000 ffff80ffbf200000 200000 [ text ] libc.so.1
ffff80ffbf200000 ffff80ffbf29a000  9a000 [ text ] libc.so.1
ffff80ffbf39a000 ffff80ffbf3ae000  14000 [ data ] libc.so.1
ffff80ffbf3ae000 ffff80ffbf3b8000   a000 [ anon ]
ffff80ffbf400000 ffff80ffbf456000  56000 [ text ] ld.so.1
ffff80ffbf556000 ffff80ffbf557000   1000 [ dtrace ] ld.so.1
ffff80ffbf657000 ffff80ffbf65b000   4000 [ data ] ld.so.1
ffff80ffbf65b000 ffff80ffbf65d000   2000 [ anon ]
ffff80ffbf7d0000 ffff80ffbf7d6000   6000 [ anon ]
ffff80ffbf7e4000 ffff80ffbf7f4000  10000 [ anon ]
ffff80ffbf7f5000 ffff80ffbf7f8000   3000 [ anon ]
ffff80ffbf7f9000 ffff80ffbf7fa000   1000 [ anon ]
ffff80ffbf7fb000 ffff80ffbf7fc000   1000 [ anon ]
ffff80ffbf7fd000 ffff80ffbf7fe000   1000 [ anon ]
ffff80ffbfffd000 ffff80ffc0000000   3000 [ stack ]
The -s option can be used to prevent the segment name information from being added at all:
a.out:1493*> ::mappings -bs
            BASE            LIMIT   SIZE NAME
          400000           401000   1000 a.out
          500000           502000   2000 a.out
         9000000          9010000  10000 [ reserved ]
         a000000          a001000   1000 [ sysstat ]
         b000000          b001000   1000 [ sysstat_zone ]
ffff80ffbf000000 ffff80ffbf200000 200000 libc.so.1
ffff80ffbf200000 ffff80ffbf29a000  9a000 libc.so.1
ffff80ffbf39a000 ffff80ffbf3ae000  14000 libc.so.1
ffff80ffbf3ae000 ffff80ffbf3b8000   a000 [ anon ]
ffff80ffbf400000 ffff80ffbf456000  56000 ld.so.1
ffff80ffbf556000 ffff80ffbf557000   1000 ld.so.1
ffff80ffbf657000 ffff80ffbf65b000   4000 ld.so.1
ffff80ffbf65b000 ffff80ffbf65d000   2000 [ anon ]
ffff80ffbf7d0000 ffff80ffbf7d6000   6000 [ anon ]
ffff80ffbf7e4000 ffff80ffbf7f4000  10000 [ anon ]
ffff80ffbf7f5000 ffff80ffbf7f8000   3000 [ anon ]
ffff80ffbf7f9000 ffff80ffbf7fa000   1000 [ anon ]
ffff80ffbf7fb000 ffff80ffbf7fc000   1000 [ anon ]
ffff80ffbf7fd000 ffff80ffbf7fe000   1000 [ anon ]
ffff80ffbfffd000 ffff80ffc0000000   3000 [ stack ]
Surfing with the Linker-Aliens

Published Elsewhere

https://blogs.oracle.com/ali/elf_phdr_names/

Surfing with the Linker-Aliens

[35] How To Strip An ELF Object
Blog Index (ali)
[37] Core File Enhancements for elfdump