Showing posts with label kcore. Show all posts
Showing posts with label kcore. Show all posts

Monday, September 22, 2008

/proc/kcore part II

It will take me a few posts to go through the kcore file... The last kcore post dealt only with ELF headers of the kcore file. After the ELF header ends, there are 3 program headers:

From elf.h we see that the structure of a program header is:

typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;



A look at the first program header below:

0000030: 0000 0000 0400 0000 9400 0000 0000 0000 ................
0000040: 0000 0000 d807 0000 0000 0000 0000 0000 ................
0000050: 0000 0000



The first program header is of type PT_NOTE (Auxiliary info) which has a value of 0x4
We can see that the offset is 0x94
The filesize has a value of 0x7d8

All other parts of the struct are set to 0x0

A look at the second program header below:

0000050: 0000 0000 0100 0000 0010 8038 0000 80f8 ...........8....
0000060: 0000 0000 00e0 ff06 00e0 ff06 0700 0000 ................
0000070: 0010 0000



The type is of type PT_LOAD 0x1 (loadable program segment)
The offset is 0x38801000
vaddr is 0xf8800000 (vmalloc)
filesz and memsz are both 0x6ffe000
flags are 0x7 (PF_R | PF_W | PF_X)
page alignment is 0x1000 (size of a page - 4096)

The other remaining part of the structure (p_paddr) is 0x0

The third program header looks like:

0000070: 0010 0000 0100 0000 0010 0000 0000 00c0 ................
0000080: 0000 0000 0000 0038 0000 0038 0700 0000 .......8...8....
0000090: 0010 0000



The type is of type PT_LOAD 0x1 (loadable program segment)
The offset is 0x1000 (size of a page - 4096)
vaddr is 0xc0000000 (start of lowmem)
filesz and memsz are both 0x38000000 (size of (kcore-4096))
flags are 0x7 (PF_R | PF_W | PF_X)
page alignment is 0x1000 (size of a page - 4096)

The other remaining part of the structure (p_paddr) is 0x0

From my messages file to compare:

Sep 15 12:28:57 kanga kernel:
Memory: 2060724k/2087616k available
(2252k kernel code, 25548k reserved, 1182k data, 284k init, 1170112k highmem)
Sep 15 12:28:57 kanga kernel: virtual kernel memory layout:
Sep 15 12:28:57 kanga kernel: fixmap : 0xffc53000 - 0xfffff000 (3760 kB)
Sep 15 12:28:57 kanga kernel: pkmap : 0xff400000 - 0xff800000 (4096 kB)
Sep 15 12:28:57 kanga kernel: vmalloc : 0xf8800000 - 0xff3fe000 ( 107 MB)
Sep 15 12:28:57 kanga kernel: lowmem : 0xc0000000 - 0xf8000000 ( 896 MB)
Sep 15 12:28:57 kanga kernel: .init : 0xc0761000 - 0xc07a8000 ( 284 kB)
Sep 15 12:28:57 kanga kernel: .data : 0xc063337f - 0xc075ab88 (1182 kB)
Sep 15 12:28:57 kanga kernel: .text : 0xc0400000 - 0xc063337f (2252 kB)



Notes

The next three sections will use this structure:

struct memelfnote
{
const char *name;
int type;
unsigned int datasz;
void *data;
};



Looking at the first note (only the interesting part, the rest is zeroed out):

0000090: 0010 0000 0500 0000 9000 0000 0100 0000 ................
00000a0: 434f 5245



In this case the items shown are not in the same order of the struct. This is because they have been placed in a slightly different order.

First we have the size of the name: 0x5 (strlen(CORE)+1)
Then the data size: 0x90 (size of elf_prstatus struct)
Then the type: 0x1 (NT_PRSTATUS)
Then the name itself: CORE
And finally the data, which has been zeroed out (not shown).

The next note looks like the following:


0500 0000 7c00 0000 ............|...
0000140: 0300 0000 434f 5245 0000 0000 0052 0000 ....CORE.....R..
0000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000160: 0000 0000 0000 0000 766d 6c69 6e75 7800 ........vmlinux.
0000170: 0000 0000 0000 0000 726f 2072 6f6f 743d ........ro root=
0000180: 2f64 6576 2f56 6f6c 4772 6f75 7030 302f /dev/VolGroup00/
0000190: 4c6f 6756 6f6c 3030 2072 6867 6220 7175 LogVol00 rhgb qu
00001a0: 6965 7400 0000 0000 0000 0000 0000 0000 iet.............
00001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001c0: 0000 0000 0000 0000



First we have the size of the name: 0x5 (strlen(CORE)+1)
Then the data size: 0x7c (sizeof(struct elf_prpsinfo))
Then the type: 0x3 (NT_PRPSINFO )
Then the name itself: CORE
And finally the data, which uses the elf_prpsinfo structure:

struct elf_prpsinfo
{
char pr_state; /* numeric process state */
char pr_sname; /* char for pr_state */
char pr_zomb; /* zombie */
char pr_nice; /* nice val */
unsigned long pr_flag; /* flags */
__kernel_uid_t pr_uid;
__kernel_gid_t pr_gid;
pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
/* Lots missing */
char pr_fname[16]; /* filename of executable */
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
};



The data consists of:
pr_state 0x0
pr_sname 0x52 (R)
pr_zomb 0x0
Executable file name (pr_fname) "vmlinux"
Saved command line (pr_psargs) up to 80 characters
ro root=/dev/VolGroup00/LogVol00 rhgb quiet

The rest is zeroed out from a memset command

The third note denotes information about the current task. Here is part of it:


0500 0000 9006 0000 ................
00001d0: 0400 0000 434f 5245 0000 0000 0000 0000 ....CORE........
00001e0: 0020 b2f0 0200 0000 0021 4000 ffff ffff . .......!@.....
00001f0: 7800 0000 7800 0000 7800 0000 b086 8af0 x...x...x.......
0000200: b086 8af0 4072 63c0 0004 0000 0000 4000 ....@rc.......@.
0000210: 0100 0000 0000 0000 0000 0000 0100 0000 ................
0000220: 494c 6a33 c10a 0000 2fd2 1d00 0000 0000 ILj3..../.......
0000230: 85b4 abc6 0c01 0000 6134 0c00 0000 0000 ........a4......
0000240: 0000 0000 0000 0000 5669 0d00 0000 0000



First we have the size of the name: 0x5 (strlen(CORE)+1)
Then the data size: 0x690 (sizeof(struct task_struct) found in linux/sched.h)
Then the type: 0x4 (NT_TASKSTRUCT )
Then the name itself: CORE
And finally the data, which consists of `current' which is the current thread (not shown above).

Now we must dissect task_struct info, which we'll do a bit later...

Thursday, August 14, 2008

ELF headers: executable vs /proc/kcore

This is for 32bit

According to elf.h:

#define EI_NIDENT (16)

typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;



Sizes for ELF32_* (in bytes):

Word: 4
Half: 2
Off: 4
Addr: 4

Looking at a regular binary like ls for example:


$ dd if=/bin/ls bs=52 count=1|xxd
1+0 records in
1+0 records out
52 bytes (52 B) copied, 3.6108e-05 s, 1.4 MB/s
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000 .ELF............
0000010: 0200 0300 0100 0000 0099 0408 3400 0000 ............4...
0000020: ec7f 0100 0000 0000 3400 2000 0800 2800 ........4. ...(.
0000030: 2000 1f00 ...



I'm using the ELF manual to analyze this.

The first line (16 bytes) is the (e_ident) value which consists of:

The ``magic'' value for the first four characters - 7f45 4c46
The file class (EI_CLASS) - 0x1 (ELF32CLASS)
Data encoding (EI_DATA) - 0x1 (ELFDATA2LSB) little endian
File version (EI_VERSION) - 0x1 current
Start of padded bytes (EI_PAD)

On the second line (e_type) 0x2 tells us it is an executable file
(e_machine) value 0x3 tells us that this was compiled on Intel Architecture
(e_version) value 0x1 tells us it is current
(e_entry) virtual address to which to control is given is 0x8049900
(e_phoff) Program headers start at offset 0x34

On the third line 0x17fec is the section header offset (e_shoff)
(e_flags) value 0x0 tells us that no flags are set
(e_ehsize) value of 0x34 tells that the header is of size 52 bytes decimal
(e_phentsize) value of 0x20 tells that one entry in the program header table size is 32 bytes
(e_phnum) value of 0x8 tells us the number of entries in the program header table is 8
(e_shentsize) value of 0x28 tells us the size of one entry in the section header table is 40 bytes

On the fourth line
(e_shnum) value of 0x20 tells us that number of entries in the section header table is 32
(e_shstrndx) value of 0x1f holds the section header table index of the entry associated with the section name string table


So what does /proc/kcore look like?


# dd if=/proc/kcore bs=52 count=1|xxd
1+0 records in
1+0 records out
52 bytes (52 B) copied, 3.9321e-05 s, 1.3 MB/s
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000 .ELF............
0000010: 0400 0300 0100 0000 0000 0000 3400 0000 ............4...
0000020: 0000 0000 0000 0000 3400 2000 0300 0000 ........4. .....
0000030: 0000 0000 ....



The first line is the same as above.

The second line:

(e_type) 0x4 tells us it is a core file (ET_CORE) *
(e_machine) value 0x3 tells us that this was compiled on Intel Architecture
(e_version) value 0x1 tells us it is current
(e_entry) virtual address to which to control is given is 0x0
(e_phoff) program headers start at offset 0x34

* this is useful to know if we are dealing with a core file...

In the third line:

(e_shoff) value is 0x0 letting us know there is no section header offset
(e_flags) value 0x0 tells us that no flags are set
(e_ehsize) value of 0x34 tells that the elf header is of size 52 bytes decimal
(e_phentsize) value of 0x20 tells that one entry in the program header table size is 32 bytes
(e_phnum) value of 0x3 tells us the number of entries in the program header table is 3
(e_shentsize) value of 0x0 tells us that there is no section header

The fourth line values are all 0x0

To make your life easier here is a C program that will extract all of that information for you :-) You must be root to run it.

Note: I know I could have done this a bit more elegantly, but decided against that...