xref: /aosp_15_r20/external/elfutils/libdwfl/image-header.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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 (&sects, 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