1 /*
2  * Copyright 2011 Red Hat, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author(s): Peter Jones <pjones@redhat.com>
18  */
19 #ifndef LIBDPE_COMMON_H
20 #define LIBDPE_COMMON_H 1
21 
22 #include <stdlib.h>
23 #include <sys/mman.h>
24 
25 #define pwrite_retry(fd, buf,  len, off) \
26 	pwrite (fd, buf, len, off)
27 #define write_retry(fd, buf, n) \
28 	write (fd, buf, n)
29 #define pread_retry(fd, buf,  len, off) \
30 	pread (fd, buf, len, off)
31 
32 #define is_64_bit(pe) ((pe)->flags & IMAGE_FILE_32BIT_MACHINE)
33 
34 #define ALIGNMENT_PADDING(address, align) ((align - (address % align)) % align)
35 
36 #define xfree(x) ({if (x) { free(x); x = NULL; }})
37 #define xmunmap(addr, size) ({if (addr) { munmap(addr,size); addr = NULL; }})
38 
39 #include <stdio.h>
40 
41 static inline void *
42 __attribute__ ((unused))
compute_mem_addr(Pe * pe,off_t offset)43 compute_mem_addr(Pe *pe, off_t offset)
44 {
45 	/* XXX this might not work when we're not mmapped */
46 	return (char *)pe->map_address + le32_to_cpu(offset);
47 }
48 
49 static inline uint32_t
50 __attribute__ ((unused))
compute_file_addr(Pe * pe,void * addr)51 compute_file_addr(Pe *pe, void *addr)
52 {
53 	/* XXX this might not work when we're not mmapped */
54 	return cpu_to_le32((char *)addr - ((char *)pe->map_address));
55 }
56 
57 static inline size_t
58 __attribute__ ((unused))
get_shnum(void * map_address,size_t maxsize)59 get_shnum(void *map_address, size_t maxsize)
60 {
61 	size_t result = 0;
62 	void *buf = (void *)map_address;
63 	struct mz_hdr *mz = (struct mz_hdr *)buf;
64 
65 	off_t hdr = (off_t)le32_to_cpu(mz->peaddr);
66 	struct pe_hdr *pe = (struct pe_hdr *)(buf + hdr);
67 
68 	uint16_t sections = pe->sections;
69 
70 	result = le16_to_cpu(sections);
71 
72 	return result;
73 }
74 
75 static inline Pe_Kind
76 __attribute__ ((unused))
determine_kind(void * buf,size_t len)77 determine_kind(void *buf, size_t len)
78 {
79 	Pe_Kind retval = PE_K_NONE;
80 	uint16_t mz_magic = MZ_MAGIC;
81 	struct mz_hdr *mz = (struct mz_hdr *)buf;
82 
83 	if (cmp_le16(&mz->magic, &mz_magic))
84 		return retval;
85 
86 	retval = PE_K_MZ;
87 
88 	off_t hdr = (off_t)le32_to_cpu(mz->peaddr);
89 	struct pe_hdr *pe = (struct pe_hdr *)(buf + hdr);
90 	uint32_t pe_magic = PE_MAGIC;
91 
92 	if (cmp_le32(&pe->magic, &pe_magic))
93 		return retval;
94 
95 	if (pe->flags & IMAGE_FILE_EXECUTABLE_IMAGE) {
96 		if (le32_to_cpu(pe->opt_hdr_size) == 0) {
97 			/* this PE header is invalid, so return PE_K_MZ */
98 			return retval;
99 		}
100 
101 		struct pe32_opt_hdr *peo =
102 			(struct pe32_opt_hdr *)(buf + hdr + sizeof(*pe));
103 
104 		/* if we don't have an optional header, fall back to testing
105 		 * our machine type list... */
106 		switch (le16_to_cpu(peo->magic)) {
107 			case PE_OPT_MAGIC_PE32:
108 				retval = PE_K_PE_EXE;
109 				break;
110 			case PE_OPT_MAGIC_PE32_ROM:
111 				retval = PE_K_PE_ROM;
112 				break;
113 			case PE_OPT_MAGIC_PE32PLUS:
114 				retval = PE_K_PE64_EXE;
115 				break;
116 			default:
117 				/* some magic we don't know?  Guess based on
118 				 * machine type */
119 				retval = is_64_bit(pe)
120 					? PE_K_PE64_EXE : PE_K_PE_EXE;
121 				break;
122 		}
123 	} else {
124 		/* this is an object file */
125 		retval = is_64_bit(pe) ? PE_K_PE64_OBJ : PE_K_PE_OBJ;
126 	}
127 
128 	return retval;
129 }
130 
131 #undef choose_kind
132 #undef is_64_bit
133 
134 static inline Pe *
135 __attribute__ ((unused))
allocate_pe(int fildes,void * map_address,size_t maxsize,Pe_Cmd cmd,Pe * parent,Pe_Kind kind,size_t extra)136 allocate_pe(int fildes, void *map_address, size_t maxsize,
137 	Pe_Cmd cmd, Pe *parent, Pe_Kind kind, size_t extra)
138 {
139 	Pe *result = (Pe *) calloc(1, sizeof (Pe) + extra);
140 	if (result == NULL) {
141 		__libpe_seterrno(PE_E_NOMEM);
142 	} else {
143 		result->kind = kind;
144 		result->ref_count = 1;
145 		result->cmd = cmd;
146 		result->fildes = fildes;
147 		result->maximum_size = maxsize;
148 		result->map_address = map_address;
149 		result->parent = parent;
150 
151 		rwlock_init(result->lock);
152 	}
153 
154 	return result;
155 }
156 
157 static void
158 __attribute__ ((unused))
libpe_acquire_all(Pe * pe)159 libpe_acquire_all(Pe *pe)
160 {
161 	rwlock_wrlock(pe->lock);
162 }
163 
164 static void
165 __attribute__ ((unused))
libpe_release_all(Pe * pe)166 libpe_release_all(Pe *pe)
167 {
168 	rwlock_unlock(pe->lock);
169 }
170 
171 /* We often have to update a flag iff a value changed.  Make this
172  * convenient.  */
173 #define update_if_changed(var, exp, flag)				\
174 	({								\
175 		__typeof__ (var) *_var = &(var);			\
176 		__typeof__ (exp) _exp = (exp);				\
177 		if (*_var != _exp) {					\
178 			*_var = _exp;					\
179 			(flag) |= PE_F_DIRTY;				\
180 		}							\
181 	})
182 
183 #endif /* LIBDPE_COMMON_H */
184