cbfstool: Add option to ignore section in add-stage
Allow add-stage to have an optional parameter for ignoring any section. This is
required to ensure proper operation of elf_to_stage in case of loadable segments
with zero filesize.
Change-Id: I49ad62c2a4260ab9cec173c80c0f16923fc66c79
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: http://review.coreboot.org/7304
Tested-by: build bot (Jenkins)
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
diff --git a/util/cbfstool/cbfs-mkstage.c b/util/cbfstool/cbfs-mkstage.c
index 3da0836..8459334 100644
--- a/util/cbfstool/cbfs-mkstage.c
+++ b/util/cbfstool/cbfs-mkstage.c
@@ -28,16 +28,79 @@
#include "common.h"
#include "cbfs.h"
+/* Checks if program segment contains the ignored section */
+static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr *shdr)
+{
+ /* If no ignored section, return false. */
+ if (shdr == NULL)
+ return 0;
+
+ Elf64_Addr sh_start = shdr->sh_addr;
+ Elf64_Addr sh_end = shdr->sh_addr + shdr->sh_size;
+ Elf64_Addr ph_start = phdr->p_vaddr;
+ Elf64_Addr ph_end = phdr->p_vaddr + phdr->p_memsz;
+
+ /* Return true only if section occupies whole of segment. */
+ if ((sh_start == ph_start) && (sh_end == ph_end)) {
+ DEBUG("Ignoring program segment at %p\n", (void *)ph_start);
+ return 1;
+ }
+
+ /* If shdr intersects phdr at all, its a conflict */
+ if (((sh_start >= ph_start) && (sh_start <= ph_end)) ||
+ ((sh_end >= ph_start) && (sh_end <= ph_end))) {
+ ERROR("Conflicting sections in segment\n");
+ exit(1);
+ }
+
+ /* Program header doesn't need to be ignored. */
+ return 0;
+}
+
+/* Find section header based on ignored section name */
+static Elf64_Shdr *find_ignored_section_header(struct parsed_elf *pelf,
+ const char *ignore_section)
+{
+ int i;
+ const char *shstrtab;
+
+ /* No section needs to be ignored */
+ if (ignore_section == NULL)
+ return NULL;
+
+ DEBUG("Section to be ignored: %s\n", ignore_section);
+
+ /* Get pointer to string table */
+ shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
+
+ for (i = 0; i < pelf->ehdr.e_shnum; i++) {
+ Elf64_Shdr *shdr;
+ const char *section_name;
+
+ shdr = &pelf->shdr[i];
+ section_name = &shstrtab[shdr->sh_name];
+
+ /* If section name matches ignored string, return shdr */
+ if (strcmp(section_name, ignore_section) == 0)
+ return shdr;
+ }
+
+ /* No section matches ignore string */
+ return NULL;
+}
+
/* returns size of result, or -1 if error.
* Note that, with the new code, this function
* works for all elf files, not just the restricted set.
*/
int parse_elf_to_stage(const struct buffer *input, struct buffer *output,
- uint32_t arch, comp_algo algo, uint32_t *location)
+ uint32_t arch, comp_algo algo, uint32_t *location,
+ const char *ignore_section)
{
struct parsed_elf pelf;
Elf64_Phdr *phdr;
Elf64_Ehdr *ehdr;
+ Elf64_Shdr *shdr_ignored;
char *buffer;
struct buffer outheader;
int ret = -1;
@@ -62,8 +125,20 @@
ehdr = &pelf.ehdr;
phdr = &pelf.phdr[0];
+ /* Find the section header corresponding to ignored-section */
+ shdr_ignored = find_ignored_section_header(&pelf, ignore_section);
+
+ if (ignore_section && (shdr_ignored == NULL))
+ WARN("Ignore section not found\n");
+
headers = ehdr->e_phnum;
+ /* Ignore the program header containing ignored section */
+ for (i = 0; i < headers; i++) {
+ if (is_phdr_ignored(&phdr[i], shdr_ignored))
+ phdr[i].p_type = PT_NULL;
+ }
+
data_start = ~0;
data_end = 0;
mem_end = 0;
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index ca02ca6..66c425b 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -41,6 +41,7 @@
char *name;
char *filename;
char *bootblock;
+ char *ignore_section;
uint64_t u64val;
uint32_t type;
uint32_t baseaddress;
@@ -184,7 +185,7 @@
struct buffer output;
int ret;
ret = parse_elf_to_stage(buffer, &output, param.arch, param.algo,
- offset);
+ offset, param.ignore_section);
if (ret != 0)
return -1;
buffer_delete(buffer);
@@ -516,7 +517,7 @@
static const struct command commands[] = {
{"add", "f:n:t:b:vh?", cbfs_add},
{"add-payload", "f:n:t:c:b:vh?C:I:", cbfs_add_payload},
- {"add-stage", "f:n:t:c:b:vh?", cbfs_add_stage},
+ {"add-stage", "f:n:t:c:b:S:vh?", cbfs_add_stage},
{"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
{"add-int", "i:n:b:vh?", cbfs_add_integer},
{"remove", "n:vh?", cbfs_remove},
@@ -546,6 +547,7 @@
{"empty-fits", required_argument, 0, 'x' },
{"initrd", required_argument, 0, 'I' },
{"cmdline", required_argument, 0, 'C' },
+ {"ignore-sec", required_argument, 0, 'S' },
{"verbose", no_argument, 0, 'v' },
{"help", no_argument, 0, 'h' },
{NULL, 0, 0, 0 }
@@ -566,7 +568,8 @@
" add-payload -f FILE -n NAME [-c compression] [-b base] "
"Add a payload to the ROM\n"
" (linux specific: [-C cmdline] [-I initrd])\n"
- " add-stage -f FILE -n NAME [-c compression] [-b base] "
+ " add-stage -f FILE -n NAME [-c compression] [-b base] \\\n"
+ " [-S section-to-ignore] "
"Add a stage to the ROM\n"
" add-flat-binary -f FILE -n NAME -l load-address \\\n"
" -e entry-point [-c compression] [-b base] "
@@ -714,6 +717,9 @@
case 'C':
param.cmdline = optarg;
break;
+ case 'S':
+ param.ignore_section = optarg;
+ break;
case 'h':
case '?':
usage(argv[0]);
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index 02a088b..41659a2 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -139,7 +139,8 @@
comp_algo algo);
/* cbfs-mkstage.c */
int parse_elf_to_stage(const struct buffer *input, struct buffer *output,
- uint32_t arch, comp_algo algo, uint32_t *location);
+ uint32_t arch, comp_algo algo, uint32_t *location,
+ const char *ignore_section);
void print_supported_filetypes(void);