1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
30 /*	  All Rights Reserved	*/
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 #include "syn.h"
35 #include <errno.h>
36 #include <libelf.h>
37 #include "decl.h"
38 #include "msg.h"
39 
40 /*
41  * Routines for generating a checksum for an elf image. Typically used to create
42  * a DT_CHECKSUM entry.  This checksum is intended to remain constant after
43  * operations such as strip(1)/mcs(1), thus only allocatable sections are
44  * processed, and of those, any that might be modified by these external
45  * commands are skipped.
46  */
47 #define	MSW(l)	(((l) >> 16) & 0x0000ffffL)
48 #define	LSW(l)	((l) & 0x0000ffffL)
49 
50 
51 /*
52  * update and epilogue sum functions (stolen from libcmd)
53  */
54 static long
55 sumupd(long sum, char *cp, unsigned long cnt)
56 {
57 	if ((cp == 0) || (cnt == 0))
58 		return (sum);
59 
60 	while (cnt--)
61 		sum += *cp++ & 0x00ff;
62 
63 	return (sum);
64 }
65 
66 static long
67 sumepi(long sum)
68 {
69 	long	_sum;
70 
71 	_sum = LSW(sum) + MSW(sum);
72 	return ((ushort_t)(LSW(_sum) + MSW(_sum)));
73 }
74 
75 long
76 elf32_checksum(Elf * elf)
77 {
78 	long		sum = 0;
79 	Elf32_Ehdr *	ehdr;
80 	Elf32_Shdr *	shdr;
81 	Elf_Scn *	scn;
82 	Elf_Data *	data, * (* getdata)(Elf_Scn *, Elf_Data *);
83 	size_t		shnum;
84 
85 	if ((ehdr = elf32_getehdr(elf)) == 0)
86 		return (0);
87 
88 	/*
89 	 * Determine the data information to retrieve.  When called from ld()
90 	 * we're processing an ELF_C_IMAGE (memory) image and thus need to use
91 	 * elf_getdata(), as there is not yet a file image (or raw data) backing
92 	 * this.  When called from utilities like elfdump(1) we're processing a
93 	 * file image and thus using the elf_rawdata() allows the same byte
94 	 * stream to be processed from different architectures - presently this
95 	 * is irrelevant, as the checksum simply sums the data bytes, their
96 	 * order doesn't matter.  But being uncooked is slightly less overhead.
97 	 */
98 	if (elf->ed_myflags & EDF_MEMORY)
99 		getdata = elf_getdata;
100 	else
101 		getdata = elf_rawdata;
102 
103 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
104 		if ((scn = elf_getscn(elf, shnum)) == 0)
105 			return (0);
106 		if ((shdr = elf32_getshdr(scn)) == 0)
107 			return (0);
108 
109 		if (!(shdr->sh_flags & SHF_ALLOC))
110 			continue;
111 
112 		if ((shdr->sh_type == SHT_DYNSYM) ||
113 		    (shdr->sh_type == SHT_DYNAMIC))
114 			continue;
115 
116 		data = 0;
117 		while ((data = (*getdata)(scn, data)) != 0)
118 			sum = sumupd(sum, data->d_buf, data->d_size);
119 
120 	}
121 	return (sumepi(sum));
122 }
123 
124 long
125 elf64_checksum(Elf * elf)
126 {
127 	long		sum = 0;
128 	Elf64_Ehdr *	ehdr;
129 	Elf64_Shdr *	shdr;
130 	Elf_Scn *	scn;
131 	Elf_Data *	data;
132 	size_t		shnum;
133 
134 	if ((ehdr = elf64_getehdr(elf)) == 0)
135 		return (0);
136 
137 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
138 		if ((scn = elf_getscn(elf, shnum)) == 0)
139 			return (0);
140 		if ((shdr = elf64_getshdr(scn)) == 0)
141 			return (0);
142 
143 		/* Exclude strippable sections */
144 		if (!(shdr->sh_flags & SHF_ALLOC))
145 			continue;
146 
147 		/*
148 		 * Exclude allocable sections that can change:
149 		 *	- The .dynsym section can contain section symbols
150 		 *		that strip might remove.
151 		 *	- The .dynamic section is modified by the setting of
152 		 *		this checksum value.
153 		 */
154 		if ((shdr->sh_type == SHT_DYNSYM) ||
155 		    (shdr->sh_type == SHT_DYNAMIC))
156 			continue;
157 
158 		data = 0;
159 		while ((data = elf_getdata(scn, data)) != 0)
160 			sum = sumupd(sum, data->d_buf, data->d_size);
161 
162 	}
163 	return (sumepi(sum));
164 }
165