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.
- 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
- 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
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).
- The names are added to the dynamic string table (.dynstr).
- A new ELF section, .SUNW_phname (SHT_SUNW_phname) is added to provide program header names. This section contains an array of 32-bit words, one per program header, each containing the offset of the string giving that program header’s name within the dynamic string table (.dynstr), or containing a 0 in the case of unnamed program headers.
- A new ELF dynamic section tag (DT_SUNW_PHNAME) is added to provide access to the .SUNW_phname section at runtime. This dynamic element allows applications to access the program header names from a live process or core file. The primary consumer of this is expected to be libproc.
To take advantage of this new information, related changes were made to other parts of the system:
- Extend the existing code in libproc that reads program header information to associate them with memory mappings to also retrieve the segment names.
- Modify elfdump, elfedit, pmap, pmadvise, and mdb’s ::mappings output, to display the segment names when available.
- In the case of pmap, pmadvise, and ::mappings, wasted horizontal whitespace has been removed, in order to prevent the addition of the segment name information from causing unwelcome line wrapping.
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:
- 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.
- 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:
- Program header names are shown when available, in the elfdump style above.
- The existing phdr: module commands are all given 2 new selection options, -with-name, and -with-name-offset, to allow program headers to be selected by name.
- Operations that move or delete program headers maintain the name information in parallel, to keep them in sync.
- A new elfedit command, phdr:name, is provided to allow inspecting and altering the name information. Although not necessarily recommended, phdr:name can be used to alter names, or to assign names to program headers that don’t have one.
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:
- Numeric columns are now dynamically sized to the width required to show the actual values encountered in a process. This provides a dramatic and visually pleasing compression in width, particularly in the -x output.
- When available, the segment names precede the displayed file names, in [] brackets, in the style used for other segments (e.g. [ heap ], or [ stack ]).
- pmap has historically indented the synthesized segment names shown in brackets with an extra 2 spaces. For instance:
% pmap $$ 19147: -bash ... 0000000000639000 40K rw----- /usr/bin/bash 0000000DADD07000 408K rw----- [ heap ] ...In the past, when named and unnamed segments were commonly intermingled, this provided a visually helpful contrast between the two cases. Going forward however, nearly all segments will have segment names, and this extra indentation serves no purpose, and adds unnecessary whitespace. As such, it was removed, allowing all of the final column content to line up.
- A new option, -b, allows the display of file basenames (final path segment), rather than the full path.
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 ]
[ This article is permanently archived at http://www.linker-aliens.org/blogs/ali/entry/elf_phdr_names/ ]