blob: 25fbfd999c8139b978061979512a827410535034 [file] [log] [blame]
Roland McGrath6bb90712009-08-27 12:36:47 -07001/* Linux kernel image support for libdwfl.
Roland McGrath32899ac2011-07-09 03:17:24 -07002 Copyright (C) 2009-2011 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Roland McGrath6bb90712009-08-27 12:36:47 -07004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Roland McGrath6bb90712009-08-27 12:36:47 -07007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
11
12 or
13
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
Roland McGrath6bb90712009-08-27 12:36:47 -070021 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
Roland McGrath6bb90712009-08-27 12:36:47 -070028
Ulf Hermann575198c2017-04-20 16:31:02 +020029#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
Roland McGrath6bb90712009-08-27 12:36:47 -070033#include "libdwflP.h"
34#include "system.h"
35
36#include <unistd.h>
37#include <endian.h>
38
39#if BYTE_ORDER == LITTLE_ENDIAN
40# define LE16(x) (x)
Roland McGrath6bb90712009-08-27 12:36:47 -070041#else
42# define LE16(x) bswap_16 (x)
Roland McGrath6bb90712009-08-27 12:36:47 -070043#endif
44
45/* See Documentation/x86/boot.txt in Linux kernel sources
46 for an explanation of these format details. */
47
48#define MAGIC1 0xaa55
49#define MAGIC2 0x53726448 /* "HdrS" little-endian */
50#define MIN_VERSION 0x0208
51
52#define H_START (H_SETUP_SECTS & -4)
53#define H_SETUP_SECTS 0x1f1
54#define H_MAGIC1 0x1fe
55#define H_MAGIC2 0x202
56#define H_VERSION 0x206
57#define H_PAYLOAD_OFFSET 0x248
58#define H_PAYLOAD_LENGTH 0x24c
59#define H_END 0x250
60#define H_READ_SIZE (H_END - H_START)
61
62Dwfl_Error
63internal_function
Josh Stone34254542015-10-09 10:10:37 -070064__libdw_image_header (int fd, off_t *start_offset,
Roland McGrath6bb90712009-08-27 12:36:47 -070065 void *mapped, size_t mapped_size)
66{
67 if (likely (mapped_size > H_END))
68 {
69 const void *header = mapped;
70 char header_buffer[H_READ_SIZE];
71 if (header == NULL)
72 {
73 ssize_t n = pread_retry (fd, header_buffer, H_READ_SIZE,
74 *start_offset + H_START);
75 if (n < 0)
76 return DWFL_E_ERRNO;
77 if (n < H_READ_SIZE)
78 return DWFL_E_BADELF;
79
80 header = header_buffer - H_START;
81 }
82
83 if (*(uint16_t *) (header + H_MAGIC1) == LE16 (MAGIC1)
84 && *(uint32_t *) (header + H_MAGIC2) == LE32 (MAGIC2)
85 && LE16 (*(uint16_t *) (header + H_VERSION)) >= MIN_VERSION)
86 {
87 /* The magic numbers match and the version field is sufficient.
88 Extract the payload bounds. */
89
90 uint32_t offset = LE32 (*(uint32_t *) (header + H_PAYLOAD_OFFSET));
91 uint32_t length = LE32 (*(uint32_t *) (header + H_PAYLOAD_LENGTH));
92
93 offset += ((*(uint8_t *) (header + H_SETUP_SECTS) ?: 4) + 1) * 512;
94
95 if (offset > H_END && offset < mapped_size
Roland McGrathde6730c2009-09-04 03:05:31 -070096 && mapped_size - offset >= length)
Roland McGrath6bb90712009-08-27 12:36:47 -070097 {
98 /* It looks kosher. Use it! */
99 *start_offset += offset;
100 return DWFL_E_NOERROR;
101 }
102 }
103 }
104 return DWFL_E_BADELF;
105}