Skip to content

Commit

Permalink
discover: Add helper functions to read ELF notes
Browse files Browse the repository at this point in the history
The libelf has low level functions to access the ELF structures.
This commit adds two external higher level functions:

elf_open_image():
 - Get the ELF structure from a binary;

elf_getnote_desc()
 - Get the ELF note 'descriptor' using both namespace and ELF type.

The definitions used in the 'elf.h' was taken from linux source code:
- arch/powerpc/include/asm/elfnote.h
- arch/powerpc/kernel/note.S

Signed-off-by: Maxiwell S. Garcia <maxiwell@linux.ibm.com>
  • Loading branch information
maxiwell authored and jk-ozlabs committed Jan 23, 2020
1 parent 827a7af commit 0c07402
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
4 changes: 3 additions & 1 deletion discover/Makefile.am
Expand Up @@ -80,7 +80,9 @@ discover_platform_ro_SOURCES = \
discover/ipmi.h \
discover/dt.c \
discover/dt.h \
discover/hostboot.h
discover/hostboot.h \
discover/elf.c \
discover/elf.h

if PLATFORM_ARM64
discover_platform_ro_SOURCES += discover/platform-arm64.c
Expand Down
86 changes: 86 additions & 0 deletions discover/elf.c
@@ -0,0 +1,86 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include <log/log.h>
#include "elf.h"

Elf *elf_open_image(const char *image)
{
int fd;
Elf *elf = NULL;
int err;

if (!image) {
pb_log_fn("kernel image path is null\n");
return NULL;
}

if ((elf_version(EV_CURRENT) == EV_NONE) ||
((fd = open(image, O_RDONLY, 0)) == -1) ||
(!(elf = elf_begin(fd, ELF_C_READ, NULL)))) {
err = elf_errno();
if (err)
pb_log_fn("failed to read %s elf: %s\n",
image, elf_errmsg(err));
}

return elf;
}

static bool elf_getnote_offset(Elf_Data * const edata,
const char *namespace,
const uint32_t type, GElf_Nhdr *nhdr,
size_t *n_off, size_t *d_off)
{
size_t off = 0;
size_t next;

/* Iterate through notes */
while ((next = gelf_getnote(edata, off, nhdr, n_off, d_off)) > 0) {
char *note_ns = (char *) edata->d_buf + (*n_off);
if ((strcmp(note_ns, namespace) == 0) && (nhdr->n_type == type))
return true;

off = next;
}
return false;
}

void *elf_getnote_desc(Elf *elf,
const char *namespace,
uint32_t type)
{
Elf_Scn *scn = NULL;
Elf_Data *edata = NULL;
GElf_Shdr shdr;
GElf_Nhdr nhdr;

size_t n_off;
size_t d_off;
void *desc = NULL;

if (!elf || !namespace)
return NULL;

/* Iterate through sections */
while ((scn = elf_nextscn(elf, scn))) {
gelf_getshdr(scn, &shdr);

/* ELF might have more than one SHT_NOTE section but
only one has the 'namespace' note */
if (shdr.sh_type == SHT_NOTE) {
edata = elf_getdata(scn, NULL);
if (elf_getnote_offset(edata, namespace, type,
&nhdr, &n_off, &d_off)) {
desc = calloc(nhdr.n_descsz, sizeof(char));
memcpy(desc, edata->d_buf + d_off,
nhdr.n_descsz);
break;
}
}
}

return desc;
}

29 changes: 29 additions & 0 deletions discover/elf.h
@@ -0,0 +1,29 @@
#ifndef _PB_ELF_H
#define _PB_ELF_H

#include <elfutils/libdw.h>
#include <libelf.h>

/*
* The PowerPC namespace in an ELF Note of the kernel binary is used to store
* capabilities and information which can be used by a bootloader or userland
*
* docs: Documentation/powerpc/elfnote.rst
*/
#define POWERPC_ELFNOTE_NAMESPACE "PowerPC"

/*
* The capabilities supported/required by the kernel
* This type uses a bitmap as "desc" field.
*/
#define PPC_ELFNOTE_CAPABILITIES 0x1

/* bitmap fields: */
#define PPCCAP_ULTRAVISOR_BIT 0x1

Elf *elf_open_image(const char *image);
void *elf_getnote_desc(Elf *elf,
const char *namespace,
uint32_t type);

#endif /* _PB_ELF_H */

0 comments on commit 0c07402

Please sign in to comment.