1*7304104dSAndroid Build Coastguard Worker /* Linux kernel image support for libdwfl.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2009-2011 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker Copyright (C) 2022, 2024 Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of either
8*7304104dSAndroid Build Coastguard Worker
9*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker your option) any later version
12*7304104dSAndroid Build Coastguard Worker
13*7304104dSAndroid Build Coastguard Worker or
14*7304104dSAndroid Build Coastguard Worker
15*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker your option) any later version
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker
21*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24*7304104dSAndroid Build Coastguard Worker General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker
26*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
28*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker
34*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
35*7304104dSAndroid Build Coastguard Worker
36*7304104dSAndroid Build Coastguard Worker #if BYTE_ORDER == LITTLE_ENDIAN
37*7304104dSAndroid Build Coastguard Worker # define LE16(x) (x)
38*7304104dSAndroid Build Coastguard Worker #else
39*7304104dSAndroid Build Coastguard Worker # define LE16(x) bswap_16 (x)
40*7304104dSAndroid Build Coastguard Worker #endif
41*7304104dSAndroid Build Coastguard Worker
42*7304104dSAndroid Build Coastguard Worker /* See Documentation/x86/boot.txt in Linux kernel sources
43*7304104dSAndroid Build Coastguard Worker for an explanation of these format details. */
44*7304104dSAndroid Build Coastguard Worker
45*7304104dSAndroid Build Coastguard Worker #define MAGIC1 0xaa55
46*7304104dSAndroid Build Coastguard Worker #define MAGIC2 0x53726448 /* "HdrS" little-endian */
47*7304104dSAndroid Build Coastguard Worker #define MIN_VERSION 0x0208
48*7304104dSAndroid Build Coastguard Worker
49*7304104dSAndroid Build Coastguard Worker #define H_START (H_SETUP_SECTS & -4)
50*7304104dSAndroid Build Coastguard Worker #define H_SETUP_SECTS 0x1f1
51*7304104dSAndroid Build Coastguard Worker #define H_MAGIC1 0x1fe
52*7304104dSAndroid Build Coastguard Worker #define H_MAGIC2 0x202
53*7304104dSAndroid Build Coastguard Worker #define H_VERSION 0x206
54*7304104dSAndroid Build Coastguard Worker #define H_PAYLOAD_OFFSET 0x248
55*7304104dSAndroid Build Coastguard Worker #define H_PAYLOAD_LENGTH 0x24c
56*7304104dSAndroid Build Coastguard Worker #define H_END 0x250
57*7304104dSAndroid Build Coastguard Worker #define H_READ_SIZE (H_END - H_START)
58*7304104dSAndroid Build Coastguard Worker
59*7304104dSAndroid Build Coastguard Worker Dwfl_Error
60*7304104dSAndroid Build Coastguard Worker internal_function
__libdw_image_header(int fd,off_t * start_offset,void * mapped,size_t mapped_size)61*7304104dSAndroid Build Coastguard Worker __libdw_image_header (int fd, off_t *start_offset,
62*7304104dSAndroid Build Coastguard Worker void *mapped, size_t mapped_size)
63*7304104dSAndroid Build Coastguard Worker {
64*7304104dSAndroid Build Coastguard Worker if (likely (mapped_size > H_END))
65*7304104dSAndroid Build Coastguard Worker {
66*7304104dSAndroid Build Coastguard Worker const void *header = mapped;
67*7304104dSAndroid Build Coastguard Worker char header_buffer[H_READ_SIZE + H_START];
68*7304104dSAndroid Build Coastguard Worker if (header == NULL)
69*7304104dSAndroid Build Coastguard Worker {
70*7304104dSAndroid Build Coastguard Worker ssize_t n = pread_retry (fd, header_buffer + H_START, H_READ_SIZE,
71*7304104dSAndroid Build Coastguard Worker *start_offset + H_START);
72*7304104dSAndroid Build Coastguard Worker if (n < 0)
73*7304104dSAndroid Build Coastguard Worker return DWFL_E_ERRNO;
74*7304104dSAndroid Build Coastguard Worker if (n < H_READ_SIZE)
75*7304104dSAndroid Build Coastguard Worker return DWFL_E_BADELF;
76*7304104dSAndroid Build Coastguard Worker
77*7304104dSAndroid Build Coastguard Worker header = header_buffer;
78*7304104dSAndroid Build Coastguard Worker }
79*7304104dSAndroid Build Coastguard Worker
80*7304104dSAndroid Build Coastguard Worker uint16_t magic1;
81*7304104dSAndroid Build Coastguard Worker uint32_t magic2;
82*7304104dSAndroid Build Coastguard Worker uint16_t version;
83*7304104dSAndroid Build Coastguard Worker memcpy (&magic1, header + H_MAGIC1, sizeof (uint16_t));
84*7304104dSAndroid Build Coastguard Worker memcpy (&magic2, header + H_MAGIC2, sizeof (uint32_t));
85*7304104dSAndroid Build Coastguard Worker memcpy (&version, header + H_VERSION, sizeof (uint16_t));
86*7304104dSAndroid Build Coastguard Worker if (magic1 == LE16 (MAGIC1) && magic2 == LE32 (MAGIC2)
87*7304104dSAndroid Build Coastguard Worker && LE16 (version) >= MIN_VERSION)
88*7304104dSAndroid Build Coastguard Worker {
89*7304104dSAndroid Build Coastguard Worker /* The magic numbers match and the version field is sufficient.
90*7304104dSAndroid Build Coastguard Worker Extract the payload bounds. */
91*7304104dSAndroid Build Coastguard Worker
92*7304104dSAndroid Build Coastguard Worker uint32_t offset;
93*7304104dSAndroid Build Coastguard Worker uint32_t length;
94*7304104dSAndroid Build Coastguard Worker uint8_t sects;
95*7304104dSAndroid Build Coastguard Worker memcpy (&offset, header + H_PAYLOAD_OFFSET, sizeof (uint32_t));
96*7304104dSAndroid Build Coastguard Worker memcpy (&length, header + H_PAYLOAD_LENGTH, sizeof (uint32_t));
97*7304104dSAndroid Build Coastguard Worker memcpy (§s, header + H_SETUP_SECTS, sizeof (uint8_t));
98*7304104dSAndroid Build Coastguard Worker offset = LE32 (offset);
99*7304104dSAndroid Build Coastguard Worker length = LE32 (length);
100*7304104dSAndroid Build Coastguard Worker
101*7304104dSAndroid Build Coastguard Worker offset += ((sects ?: 4) + 1) * 512;
102*7304104dSAndroid Build Coastguard Worker
103*7304104dSAndroid Build Coastguard Worker if (offset > H_END && offset < mapped_size
104*7304104dSAndroid Build Coastguard Worker && mapped_size - offset >= length)
105*7304104dSAndroid Build Coastguard Worker {
106*7304104dSAndroid Build Coastguard Worker /* It looks kosher. Use it! */
107*7304104dSAndroid Build Coastguard Worker *start_offset += offset;
108*7304104dSAndroid Build Coastguard Worker return DWFL_E_NOERROR;
109*7304104dSAndroid Build Coastguard Worker }
110*7304104dSAndroid Build Coastguard Worker }
111*7304104dSAndroid Build Coastguard Worker }
112*7304104dSAndroid Build Coastguard Worker return DWFL_E_BADELF;
113*7304104dSAndroid Build Coastguard Worker }
114