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