Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
     31 /*	  All Rights Reserved	*/
     32 
     33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     34 
     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 the file is writable, the raw data will not reflect any
     99 	 * changes made in the process, so the uncooked version is only
    100 	 * for readonly files.
    101 	 */
    102 	if ((elf->ed_myflags & (EDF_MEMORY | EDF_WRITE)) != 0)
    103 		getdata = elf_getdata;
    104 	else
    105 		getdata = elf_rawdata;
    106 
    107 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
    108 		if ((scn = elf_getscn(elf, shnum)) == 0)
    109 			return (0);
    110 		if ((shdr = elf32_getshdr(scn)) == 0)
    111 			return (0);
    112 
    113 		if (!(shdr->sh_flags & SHF_ALLOC))
    114 			continue;
    115 
    116 		if ((shdr->sh_type == SHT_DYNSYM) ||
    117 		    (shdr->sh_type == SHT_DYNAMIC))
    118 			continue;
    119 
    120 		data = 0;
    121 		while ((data = (*getdata)(scn, data)) != 0)
    122 			sum = sumupd(sum, data->d_buf, data->d_size);
    123 
    124 	}
    125 	return (sumepi(sum));
    126 }
    127 
    128 long
    129 elf64_checksum(Elf * elf)
    130 {
    131 	long		sum = 0;
    132 	Elf64_Ehdr *	ehdr;
    133 	Elf64_Shdr *	shdr;
    134 	Elf_Scn *	scn;
    135 	Elf_Data *	data;
    136 	size_t		shnum;
    137 
    138 	if ((ehdr = elf64_getehdr(elf)) == 0)
    139 		return (0);
    140 
    141 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
    142 		if ((scn = elf_getscn(elf, shnum)) == 0)
    143 			return (0);
    144 		if ((shdr = elf64_getshdr(scn)) == 0)
    145 			return (0);
    146 
    147 		/* Exclude strippable sections */
    148 		if (!(shdr->sh_flags & SHF_ALLOC))
    149 			continue;
    150 
    151 		/*
    152 		 * Exclude allocable sections that can change:
    153 		 *	- The .dynsym section can contain section symbols
    154 		 *		that strip might remove.
    155 		 *	- The .dynamic section is modified by the setting of
    156 		 *		this checksum value.
    157 		 */
    158 		if ((shdr->sh_type == SHT_DYNSYM) ||
    159 		    (shdr->sh_type == SHT_DYNAMIC))
    160 			continue;
    161 
    162 		data = 0;
    163 		while ((data = elf_getdata(scn, data)) != 0)
    164 			sum = sumupd(sum, data->d_buf, data->d_size);
    165 
    166 	}
    167 	return (sumepi(sum));
    168 }
    169