summaryrefslogtreecommitdiff
path: root/elf_info.c
diff options
context:
space:
mode:
authorPetr Tesarik <ptesarik@suse.cz>2016-02-10 16:50:41 +0900
committerAtsushi Kumagai <ats-kumagai@wm.jp.nec.com>2016-02-18 13:39:14 +0900
commit7a7cebcba334792f3f38f9171830ad7e4eef023c (patch)
tree934ff3bdffc760849af5de468d107d48d218ea18 /elf_info.c
parent1cdabcdb1c0bb74f8e65bf85834d6c80f9f5507c (diff)
[PATCH 3/3] Rewrite readpage_elf
The current code in readpage_elf (and readpage_elf_parallel) is extremely hard to follow. Additionally, it still does not cover all possible cases. For example, attempts to read outside of any ELF segment will end up with phys_start being 0, frac_head a negative number, interpreted as a large positive number by memset() and write past buffer end. Instead of trying to handle even more "corner cases", I rewrote the algorithm from scratch. The basic idea is simple: set a goal to fill the page buffer with data, then work towards that goal by: - filling holes with zeroes (see Note below), - p_filesz portions with file data and - remaining p_memsz portions again with zeroes. Repeat this method for each LOAD until the goal is achieved, or an error occurs. In most cases, the loop runs only once. Note: A "hole" is data at a physical address that is not covered by any ELF LOAD program header. In other words, the ELF file does not specify any data for such a hole (not even zeroes). So, why does makedumpfile fill them with zeroes? It's because makedumpfile works with page granularity (the compressed format does not even have a way to store a partial page), so if only part of a page is stored, a complete page must be provided to make this partial data accessible. Credits to Ivan Delalande <colona@arista.com> who first found the problem and wrote the original fix. Tested-by: Ivan Delalande <colona@arista.com> Signed-off-by: Petr Tesarik <ptesarik@suse.com>
Diffstat (limited to 'elf_info.c')
-rw-r--r--elf_info.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/elf_info.c b/elf_info.c
index 80a4da6..65ff333 100644
--- a/elf_info.c
+++ b/elf_info.c
@@ -691,6 +691,34 @@ get_max_paddr(void)
return max_paddr;
}
+/*
+ * Find the LOAD segment which is closest to the requested
+ * physical address within a given distance.
+ * If there is no such segment, return a negative number.
+ */
+int
+closest_pt_load(unsigned long long paddr, unsigned long distance)
+{
+ int i, bestidx;
+ struct pt_load_segment *pls;
+ unsigned long bestdist;
+
+ bestdist = distance;
+ bestidx = -1;
+ for (i = 0; i < num_pt_loads; ++i) {
+ pls = &pt_loads[i];
+ if (paddr >= pls->phys_end)
+ continue;
+ if (paddr >= pls->phys_start)
+ return i; /* Exact match */
+ if (bestdist > pls->phys_start - paddr) {
+ bestdist = pls->phys_start - paddr;
+ bestidx = i;
+ }
+ }
+ return bestidx;
+}
+
int
get_elf64_ehdr(int fd, char *filename, Elf64_Ehdr *ehdr)
{