Only use COW hooks in diff mode.
[ksplice.git] / objcommon.h
blob7f405812bed2c658375b42d575e48242e896b557
1 #include <bfd.h>
2 #include <limits.h>
3 #include <stdarg.h>
4 #include <stdbool.h>
5 #include <stddef.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #define BITS_PER_LONG LONG_BIT
11 #define _PASTE(x, y) x##y
12 #define PASTE(x, y) _PASTE(x, y)
14 #define DIE do { fprintf(stderr, "ksplice: died at %s:%d\n", __FILE__, __LINE__); abort(); } while(0)
15 #define assert(x) do { if(!(x)) DIE; } while(0)
16 #define align(x, n) ((((x)+(n)-1)/(n))*(n))
18 #define container_of(ptr, type, member) ({ \
19 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
20 (type *)( (char *)__mptr - offsetof(type,member) );})
22 #define DECLARE_VEC_TYPE(elt_t, vectype) \
23 struct vectype { \
24 elt_t *data; \
25 size_t size; \
26 size_t mem_size; \
29 /* void vec_init(struct vectype *vec); */
30 #define vec_init(vec) *(vec) = (typeof(*(vec))) { NULL, 0, 0 }
32 /* void vec_move(struct vectype *dstvec, struct vectype *srcvec); */
33 #define vec_move(dstvec, srcvec) do { \
34 typeof(srcvec) _srcvec = (srcvec); \
35 *(dstvec) = *(_srcvec); \
36 vec_init(_srcvec); \
37 } while (0)
39 /* void vec_free(struct vectype *vec); */
40 #define vec_free(vec) do { \
41 typeof(vec) _vec1 = (vec); \
42 free(_vec1->data); \
43 vec_init(_vec1); \
44 } while (0)
46 void vec_do_reserve(void **data, size_t *mem_size, size_t newsize);
48 /* void vec_reserve(struct vectype *vec, size_t new_mem_size); */
49 #define vec_reserve(vec, new_mem_size) do { \
50 typeof(vec) _vec2 = (vec); \
51 vec_do_reserve((void **)&_vec2->data, &_vec2->mem_size, \
52 (new_mem_size)); \
53 } while (0)
55 /* void vec_resize(struct vectype *vec, size_t new_size); */
56 #define vec_resize(vec, new_size) do { \
57 typeof(vec) _vec3 = (vec); \
58 _vec3->size = (new_size); \
59 vec_reserve(_vec3, _vec3->size * sizeof(*_vec3->data)); \
60 } while (0)
62 /* elt_t *vec_grow(struct vectype *vec, size_t n); */
63 #define vec_grow(vec, n) ({ \
64 typeof(vec) _vec4 = (vec); \
65 size_t _n = (n); \
66 vec_resize(_vec4, _vec4->size + _n); \
67 _vec4->data + (_vec4->size - _n); \
70 DECLARE_VEC_TYPE(void, void_vec);
71 DECLARE_VEC_TYPE(arelent *, arelentp_vec);
72 DECLARE_VEC_TYPE(asymbol *, asymbolp_vec);
73 DECLARE_VEC_TYPE(asymbol **, asymbolpp_vec);
75 #define DECLARE_HASH_TYPE(elt_t, hashtype, \
76 hashtype_init, hashtype_free, \
77 hashtype_lookup) \
78 struct hashtype { \
79 struct bfd_hash_table root; \
80 }; \
82 void hashtype_init(struct hashtype *table); \
83 void hashtype_free(struct hashtype *table); \
84 typeof(elt_t) *hashtype_lookup(struct hashtype *table, \
85 const char *string, \
86 bfd_boolean create)
88 #ifndef BFD_HASH_TABLE_HAS_ENTSIZE
89 #define bfd_hash_table_init(table, newfunc, entry) \
90 bfd_hash_table_init(table, newfunc)
91 #endif
93 #define IMPLEMENT_HASH_TYPE(elt_t, hashtype, \
94 hashtype_init, hashtype_free, \
95 hashtype_lookup, \
96 elt_construct) \
98 struct hashtype##_entry { \
99 struct bfd_hash_entry root; \
100 typeof(elt_t) val; \
101 }; \
103 static struct bfd_hash_entry *hashtype##_newfunc( \
104 struct bfd_hash_entry *entry, \
105 struct bfd_hash_table *table, \
106 const char *string) \
108 if (entry == NULL) { \
109 entry = bfd_hash_allocate(table, \
110 sizeof(struct hashtype##_entry)); \
111 if (entry == NULL) \
112 return entry; \
114 entry = bfd_hash_newfunc(entry, table, string); \
115 typeof(elt_t) *v = \
116 &container_of(entry, struct hashtype##_entry, \
117 root)->val; \
118 elt_construct(v); \
119 return entry; \
120 }; \
122 void hashtype_init(struct hashtype *table) \
124 bfd_hash_table_init(&table->root, hashtype##_newfunc, \
125 sizeof(struct hashtype##_entry)); \
128 void hashtype_free(struct hashtype *table) \
130 bfd_hash_table_free(&table->root); \
133 typeof(elt_t) *hashtype_lookup(struct hashtype *table, \
134 const char *string, \
135 bfd_boolean create) \
137 struct bfd_hash_entry *e = \
138 bfd_hash_lookup(&table->root, string, create, \
139 TRUE); \
140 if (create) \
141 assert(e != NULL); \
142 else if (e == NULL) \
143 return NULL; \
144 return &container_of(e, struct hashtype##_entry, \
145 root)->val; \
148 struct eat_trailing_semicolon
150 #define DEFINE_HASH_TYPE(elt_t, hashtype, \
151 hashtype_init, hashtype_free, \
152 hashtype_lookup, \
153 elt_construct) \
154 DECLARE_HASH_TYPE(elt_t, hashtype, hashtype_init, \
155 hashtype_free, hashtype_lookup); \
156 IMPLEMENT_HASH_TYPE(elt_t, hashtype, hashtype_init, \
157 hashtype_free, hashtype_lookup, \
158 elt_construct);
161 #ifndef bfd_get_section_size
162 #define bfd_get_section_size(x) ((x)->_cooked_size)
163 #endif
165 DECLARE_HASH_TYPE(arelent *, arelentp_hash, arelentp_hash_init,
166 arelentp_hash_free, arelentp_hash_lookup);
167 DECLARE_HASH_TYPE(asymbol **, asymbolpp_hash, asymbolpp_hash_init,
168 asymbolpp_hash_free, asymbolpp_hash_lookup);
169 DECLARE_HASH_TYPE(const char *, string_hash, string_hash_init,
170 string_hash_free, string_hash_lookup);
172 struct label_map {
173 asymbol *csym;
174 const char *orig_label;
175 const char *label;
176 int count;
178 DECLARE_VEC_TYPE(struct label_map, label_map_vec);
179 DECLARE_HASH_TYPE(struct label_map *, label_mapp_hash, label_mapp_hash_init,
180 label_mapp_hash_free, label_mapp_hash_lookup);
182 struct span {
183 struct supersect *ss;
184 asymbol *symbol;
185 const char *orig_label;
186 const char *label;
187 bfd_vma start;
188 bfd_vma size;
189 bool keep;
190 bool new;
191 bool patch;
192 bool bugpatch;
193 bool datapatch;
194 bool precallable;
195 struct span *match;
196 bfd_size_type shift;
198 DECLARE_VEC_TYPE(struct span, span_vec);
200 struct superbfd {
201 bfd *abfd;
202 struct asymbolp_vec syms;
203 struct supersect *new_supersects;
204 struct label_map_vec maps;
205 struct label_mapp_hash maps_hash;
206 struct asymbolpp_vec new_syms;
207 struct asymbolpp_hash csyms;
208 struct string_hash callers;
211 enum supersect_type {
212 SS_TYPE_TEXT, SS_TYPE_DATA, SS_TYPE_RODATA, SS_TYPE_STRING,
213 SS_TYPE_SPECIAL, SS_TYPE_IGNORED, SS_TYPE_KSPLICE, SS_TYPE_EXPORT,
214 SS_TYPE_EXIT, SS_TYPE_KSPLICE_CALL, SS_TYPE_UNKNOWN
217 struct supersect {
218 struct superbfd *parent;
219 const char *name;
220 flagword flags;
221 struct void_vec contents;
222 int alignment;
223 unsigned int entsize;
224 struct arelentp_vec relocs;
225 struct arelentp_vec new_relocs;
226 struct supersect *next;
227 struct asymbolp_vec syms;
228 struct span_vec spans;
229 struct arelentp_hash reloc_hash;
230 asymbol *symbol;
231 bool keep;
232 enum supersect_type type;
233 enum supersect_type orig_type;
236 struct superbfd *fetch_superbfd(bfd *abfd);
237 struct supersect *fetch_supersect(struct superbfd *sbfd, asection *sect);
238 struct supersect *new_supersect(struct superbfd *sbfd, const char *name);
239 void supersect_move(struct supersect *dest_ss, struct supersect *src_ss);
241 #define sect_grow(ss, n, type) \
242 ((type *)sect_do_grow(ss, n, sizeof(type), __alignof__(type)))
243 void *sect_do_grow(struct supersect *ss, size_t n, size_t size, int alignment);
245 #define sect_copy(dest_ss, dest, src_ss, src, n) \
246 sect_do_copy(dest_ss, dest, src_ss, src, (n) * sizeof(*(src)))
247 void sect_do_copy(struct supersect *dest_ss, void *dest,
248 struct supersect *src_ss, const void *src, size_t n);
250 #define starts_with(str, prefix) \
251 (strncmp(str, prefix, strlen(prefix)) == 0)
252 #define ends_with(str, suffix) \
253 (strlen(str) >= strlen(suffix) && \
254 strcmp(&str[strlen(str) - strlen(suffix)], suffix) == 0)
256 bfd_vma addr_offset(struct supersect *ss, const void *addr);
257 bfd_vma get_reloc_offset(struct supersect *ss, arelent *reloc, bool adjust_pc);
258 arelent *find_reloc(struct supersect *ss, const void *addr);
259 bfd_vma read_reloc(struct supersect *ss, const void *addr, size_t size,
260 asymbol **symp);
261 const void *read_pointer(struct supersect *ss, void *const *addr,
262 struct supersect **ssp);
263 const char *read_string(struct supersect *ss, const char *const *addr);
265 #define read_num(ss, addr) ((typeof(*(addr))) \
266 read_reloc(ss, addr, sizeof(*(addr)), NULL))
268 static inline char *vstrprintf(const char *fmt, va_list ap)
270 char *str;
271 assert(vasprintf(&str, fmt, ap) >= 0);
272 return str;
275 static inline char * __attribute__((format (printf, 1, 2)))
276 strprintf(const char *fmt, ...)
278 va_list ap;
279 va_start(ap, fmt);
280 char *str = vstrprintf(fmt, ap);
281 va_end(ap);
282 return str;