[RFC][PATCH v2 0/4] readelf and libbfd: Add Extended Numbering Support for ELF corefiles

Daisuke HATAYAMA d.hatayama@jp.fujitsu.com
Mon Jan 18 07:43:00 GMT 2010


This is the second version to which given comments are reflected.

Change log from v1 to v2:
  * Add a patch for libbfd, part of writing corefiles
  * Correct some miss typo
  * Add complementary explanation for mmaps
  * Add test program

On the other hand, I have additional question to gcore function of
GDB:

What's the difference between kernel coredump and gcore?

In this patch set, I have modified writing part of libbfd, so I need
to test it using gcore function of GDB. I have prepared a test program
to produce many-program-header corefiles, already attached in the
previous message, but this time it couldn't behave as I intended.

The test program tries to increase map counts using mmap() system
call. By this, kernel coredump successfully contained many program
headers (at least on Linux), but the coredump generated by gcore
appeared to contain only initially generated mmaps.

Hence, keeping RFC.
=
Summary
=======

Extended Numbering is an ELF extension specified in order to cover a
lack of field size for some fields of ELF header. Concretely, they are
e_phnum, e_shnum and e_shstrndx, which have only 2 byte length in
either 32- or 64-bit environments.

Program headers consist mainly of mmaps, so there is possibility of
program headers exceeding 65535 for core files in the extreme
situation. If you google MAX_MAP_COUNT, then you'll find people facing
the same problem.

Sun's document and AMD64 ABI Draft describe the ELF extension. You can
reach them from Reference in the bottom of the message.

Currently, readelf and libbfd library have implemented the Extended
Numbering for e_shnum and e_shstrndx fields but not yet for e_phnum
field.

The purpose of the patch set is to implement the Extended Numbering
for e_phnum field, which is important particularly for ELF object as
corefile.

Compatibility Concern
=====================

* Accorinding to Sun's document, Solaris OS produces ELF corefile
  conforming to the ELF extension.

  The activity of applying the patch set to Linux is now in progress.
  Linux will soon change to produce the extended ELF core object
  file. Currently, the patch set is in mmotm tree.

* There are four combinations according to whether OS and ELF
  maniplating tools are respectively modified or not. The next table
  summarizes shortly for each combination.

                  ---------------------------------------------
                        Original OS     |     Modified OS
                  ---------------------------------------------
    		              < 65535  | >= 65535 | < 65535  | >= 65535 
  -------------------------------------------------------------
   Original Tools |    OK    |  broken  |    OK    | broken (#)
  -------------------------------------------------------------
   Modified Tools |    OK    |  broken  |    OK    |    OK
  -------------------------------------------------------------

  Note that there is no case that `OK' changes to `broken'.

  (#) Although this case remains broken, O-M behaves better than
  O-O. That is, while in O-O case e_phnum field would be extremely
  small due to integer overflow, in O-M case it is guaranteed to be at
  least 65535 by being set to PN_XNUM(0xFFFF), much closer to the
  actual value than the O-O case.

How to fix
==========

The required code change is part of reading/writing ELF header. We
need to determine where to read/write the actual number of program
headers.

I wrote this by following the similar part for e_shnum and e_shstrndx
fields.

* The reading process proceeds as follows.

  First, we introduce a new constant PN_XNUM which is defined to be
  0xFFFF. The place where the number of actual program headers is
  located varies according wheather e_phnum field is PN_XNUM or not.

  Let n be the value of e_phnum field of the ELF object file. Then,

  - if n < PN_XNUM, then the n is the number of program headers.

  - if n == PN_XNUM, then the number of program headers is located in
    sh_info field of the section header at index 0.

* The writing process proceeds just conversely, i.e. if the actual
  number of program headers is strictly smaller than PN_XNUM, then it
  is written into e_phnum in ELF header; if not, set PN_XNUM to
  e_phnum and the actual number is written into sh_info in the section
  header at index 0.

Patch
=====

* The patch set comprises of three patches.

  [PATCH 0/4] describes patch description in detail,
  [PATCH 1/4] introduces PN_XNUM,
  [PATCH 2/4] modifies readelf,
  [PATCH 3/4] modifies libbfd library, part of reading corefiles, and
  [PATCH 4/4] modifies libbfd library, part of writing corefiles

* Tested on x86-64. readelf and objdump work well.

* diff stat output for a whole patch set

 bfd/elfcode.h        |    7 +++++-
 bfd/elfcore.h        |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++
 binutils/readelf.c   |    7 +++++-
 include/elf/common.h |    3 ++
 4 files changed, 72 insertions(+), 2 deletions(-)

* ChangeLog

2010-01-18  Daisuke Hatayama  <d.hatayama@jp.fujitsu.com>

	* elfcode.h: Add extended numbering support for corefiles
	* elfcore.h: Add extended numbering support for corefiles 

2010-01-18  Daisuke Hatayama  <d.hatayama@jp.fujitsu.com>

	* readelf.c: Add extended numbering support

2010-01-18  Daisuke Hatayama  <d.hatayama@jp.fujitsu.com>

	* common.h: Add PN_XNUM


Test Program
============

Here is a small program that is useful to create the corefile with
many program headers. I use this on Linux.

Usage:

Type as follows:

$ ulimit -c unlimited
$ sysctl vm.max_map_count=70000 # default 65530 is too small
$ sysctl fs.file-max=70000
$ mkmmaps 65535

Then, the program will abort and a corefile will be generated.

If failed, there are two cases according to the error message
displayed.

* ``out of memory'' means vm.max_map_count is still smaller

* ``too many open files'' means fs.file-max is still smaller

So, please change it to a larger value, and then retry it.

mkmmaps.c
==
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
	int maps_num;
	if (argc < 2) {
		fprintf(stderr, "mkmmaps [number of maps to be created]\n");
		exit(1);
	}
	if (sscanf(argv[1], "%d", &maps_num) == EOF) {
		perror("sscanf");
		exit(2);
	}
	if (maps_num < 0) {
		fprintf(stderr, "%d is invalid\n", maps_num);
		exit(3);
	}
	for (; maps_num > 0; --maps_num) {
		if (MAP_FAILED == mmap((void *)NULL, (size_t) 1, PROT_READ,
					MAP_SHARED | MAP_ANONYMOUS, (int) -1,
					(off_t) NULL)) {
						perror("mmap");
						exit(4);
		}
	}
	abort();
	{
		char buffer[128];
		sprintf(buffer, "wc -l /proc/%u/maps", getpid());
		system(buffer);
	}
	return 0;
}
/* mkmmaps.c */

Reference
=========

- Sun microsystems: Linker and Libraries.
  Part No: 817-1984-17, September 2008.
  URL: http://docs.sun.com/app/docs/doc/817-1984

- System V ABI AMD64 Architecture Processor Supplement
  Draft Version 0.99., May 11, 2009.
  URL: http://www.x86-64.org/



More information about the Binutils mailing list