summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sgs/libelf/common/decl.h
blob: 9ccca2e5a91501490462a5eb1f9ed635f40c0ee1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/


/*
 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef	_DECL_H
#define	_DECL_H

#include <thread.h>
#include <_libelf.h>
#include <sys/machelf.h>
#include <msg.h>


#ifdef	__cplusplus
extern "C" {
#endif

typedef struct Member	Member;
typedef struct Memlist	Memlist;
typedef struct Memident	Memident;
typedef struct Dnode	Dnode;
typedef struct Snode32	Snode32;
typedef struct Snode64	Snode64;


/*
 * Data alignment
 *	An elf file is defined to have its structures aligned on
 *	appropriate boundaries.  The following type lets the
 *	library test whether the file's alignment meets its own
 *	constraints in memory.  This assumes every machine uses
 *	an alignment that is no greater than an object's size.
 *	The pointer isn't relevant for the file, but the code uses
 *	it to get memory alignment.  ANSI C void * holds any pointer,
 *	making it appropriate here.
 */

typedef union
{
	Elf32_Word	w;
	Elf32_Addr	a;
	Elf32_Off	o;
} Elf32;

typedef union {
	Elf64_Xword	x;
	Elf64_Word	w;
	Elf64_Addr	a;
	Elf64_Off	o;
	Elf_Void	*p;
} Elf64;


/*
 * Memory allocation
 *	Structures are obtained several ways: file mapping,
 *	malloc(), from the user.  A status bit in the structures
 *	tells whether an object was obtained with malloc() and
 *	therefore should be released with free().  The bits
 *	named ...ALLOC indicate this.
 */


/*
 * Data descriptor
 *	db_data must be first in the Dnode structure, because
 *	&db_data must == &Dnode.
 *
 *	db_buf is a pointer to an allocated buffer.  The same value
 *	goes into db_data.d_buf originally, but the user can touch
 *	it.  If the data buffer is not to be freed, db_buf is null.
 *
 *	When "reading" an input file's buffer, the data are left
 *	alone until needed.  When they've been converted to internal
 *	form, the READY flag is set.
 *
 *	db_raw points to a parallel raw buffer.  Raw buffers
 *	have null db_raw.
 */

struct	Dnode
{
	Elf_Data	db_data;
	Elf_Scn		*db_scn;	/* section parent */
	Dnode		*db_next;
	Dnode		*db_raw;	/* raw data */
	off_t		db_off;		/* orig file offset, 0 o/w */
	size_t		db_fsz;		/* orig file size, 0 o/w */
	size_t		db_shsz;	/* orig shdr size, 0 o/w */
	size_t		db_osz;		/* output size for update */
	Elf_Void	*db_buf;	/* allocated data buffer */
	unsigned	db_uflags;	/* user flags: ELF_F_... */
	unsigned	db_myflags;	/* internal flags: DBF_... */
	Elf64_Off	db_xoff;	/* extended offset for 32-bit Elf64 */
};

#define	DBF_ALLOC	0x1	/* applies to Dnode itself */
#define	DBF_READY	0x2	/* buffer ready */


/*
 * Section descriptor
 *	These are sometimes allocated in a block.  If the SF_ALLOC
 *	bit is set in the flags, the Scn address may be passed to free.
 *	The caller must first follow the s_next list to the next freeable
 *	node, because free can clobber the s_next value in the block.
 */

struct	Elf_Scn
{
	mutex_t		s_mutex;
	Elf_Scn		*s_next;	/* next section */
	Elf		*s_elf; 	/* parent file */
	Dnode		*s_hdnode;	/* head Dnode */
	Dnode		*s_tlnode;	/* tail Dnode */
	Elf_Void	*s_shdr;	/* Elf32 or Elf64 scn header */
	size_t		s_index;	/* section index */
	int		s_err;		/* for delaying data error */
	unsigned	s_shflags;	/* user shdr flags */
	unsigned	s_uflags;	/* user flags */
	unsigned	s_myflags;	/* SF_... */
	Dnode		s_dnode;	/* every scn needs one */
};

/*
 * Designates whether or not we are in a threaded_app.
 */
extern int *_elf_libc_threaded;
#define	elf_threaded	(_elf_libc_threaded && *_elf_libc_threaded)

#define	SCNLOCK(x) \
	if (elf_threaded) \
		(void) mutex_lock(&((Elf_Scn *)x)->s_mutex);

#define	SCNUNLOCK(x) \
	if (elf_threaded) \
		(void) mutex_unlock(&((Elf_Scn *)x)->s_mutex);

#define	UPGRADELOCKS(e, s)\
	if (elf_threaded) { \
		(void) mutex_unlock(&((Elf_Scn *)s)->s_mutex); \
		(void) rw_unlock(&((Elf *)e)->ed_rwlock); \
		(void) rw_wrlock(&((Elf *)e)->ed_rwlock); \
	}

#define	DOWNGRADELOCKS(e, s)\
	if (elf_threaded) { \
		(void) rw_unlock(&((Elf *)e)->ed_rwlock); \
		(void) rw_rdlock(&((Elf *)e)->ed_rwlock); \
		(void) mutex_lock(&((Elf_Scn *)s)->s_mutex); \
	}

#define	READLOCKS(e, s) \
	if (elf_threaded) { \
		(void) rw_rdlock(&((Elf *)e)->ed_rwlock); \
		(void) mutex_lock(&((Elf_Scn *)s)->s_mutex); \
	}

#define	READUNLOCKS(e, s) \
	if (elf_threaded) { \
		(void) mutex_unlock(&((Elf_Scn *)s)->s_mutex); \
		(void) rw_unlock(&((Elf *)e)->ed_rwlock); \
	}

#define	SF_ALLOC	0x1	/* applies to Scn */
#define	SF_READY	0x2	/* has section been cooked */


struct	Snode32
{
	Elf_Scn		sb_scn;		/* must be first */
	Elf32_Shdr	sb_shdr;
};

struct	Snode64
{
	Elf_Scn		sb_scn;		/* must be first */
	Elf64_Shdr	sb_shdr;
};


/*
 *	A file's status controls how the library can use file data.
 *	This is important to keep "raw" operations and "cooked"
 *	operations from interfering with each other.
 *
 *	A file's status is "fresh" until something touches it.
 *	If the first thing is a raw operation, we freeze the data
 *	and force all cooking operations to make a copy.  If the
 *	first operation cooks, raw operations use the file system.
 */

typedef enum
{
	ES_FRESH = 0,	/* unchanged */
	ES_COOKED,	/* translated */
	ES_FROZEN	/* raw, can't be translated */
} Status;


/*
 * Elf descriptor
 *	The major handle between user code and the library.
 *
 *	Descriptors can have parents: archive members reference
 *	the archive itself.  Relevant "offsets:"
 *
 *	ed_baseoff	The file offset, relative to zero, to the first
 *			byte in the file.  For all files, this gives
 *			the lseek(fd, ed_baseoff, 0) value.
 *
 *	ed_memoff	The offset from the beginning of the nesting file
 *			to the bytes of a member.  For an archive member,
 *			this is the offset from the beginning of the
 *			archive to the member bytes (not the hdr).  If an
 *			archive member slides, memoff changes.
 *
 *	ed_siboff	Similar to ed_memoff, this gives the offset from
 *			the beginning of the nesting file to the following
 *			sibling's header (not the sibling's bytes).  This
 *			value is necessary, because of archive sliding.
 *
 *	ed_nextoff	For an archive, this gives the offset of the next
 *			member to process on elf_begin.  That is,
 *			(ed_ident + ed_nextoff) gives pointer to member hdr.
 *
 *	Keeping these absolute and relative offsets allows nesting of
 *	files, including archives within archives, etc.  The only current
 *	nesting file is archive, but others might be supported.
 *
 *	ed_image	This is a pointer to the base memory image holding
 *			the file.  Library code assumes the image is aligned
 *			to a boundary appropriate for any object.  This must
 *			be true, because we get an image only from malloc
 *			or mmap, both of which guarantee alignment.
 */

struct Elf
{
	rwlock_t	ed_rwlock;
	Elf		*ed_parent;	/* archive parent */
	int		ed_activ;	/* activation count */
	int		ed_fd;		/* file descriptor */
	Status		ed_status;	/* file's memory status */
	off_t		ed_baseoff;	/* base file offset, zero based */
	size_t		ed_memoff;	/* offset within archive */
	size_t		ed_siboff;	/* sibling offset with archive */
	size_t		ed_nextoff;	/* next archive member hdr offset */
	char		*ed_image;	/* pointer to file image */
	size_t		ed_imagesz;	/* # bytes in ed_image */
	char		*ed_wrimage;	/* pointer to output image */
	size_t		ed_wrimagesz;	/* # bytes in ed_wrimagesz */
	char		*ed_ident;	/* file start, getident() bytes */
	size_t		ed_identsz;	/* # bytes for getident() */
	char		*ed_raw;	/* raw file ptr */
	size_t		ed_fsz;		/* file size */
	unsigned	*ed_vm;		/* virtual memory map */
	size_t		ed_vmsz;	/* # regions in vm */
	unsigned	ed_encode;	/* data encoding */
	unsigned	ed_version;	/* file version */
	int		ed_class;	/* file class */
	Elf_Kind	ed_kind;	/* file type */
	Elf_Void	*ed_ehdr;	/* Elf{32,64}_Ehdr elf header */
	Elf_Void	*ed_phdr;	/* Elf{32,64}_Phdr phdr table */
	size_t		ed_phdrsz;	/* sizeof phdr table */
	Elf_Void	*ed_shdr;	/* Elf{32,64}_Shdr shdr table */
	Elf_Scn		*ed_hdscn;	/* head scn */
	Elf_Scn		*ed_tlscn;	/* tail scn */
	size_t		ed_scntabsz;	/* number sects. alloc. in table */
	Memlist		*ed_memlist;	/* list of archive member nodes */
	Member		*ed_armem;	/* archive member header */
	Elf_Void	*ed_arsym;	/* archive symbol table */
	size_t		ed_arsymsz;	/* archive symbol table size */
	size_t		ed_arsymoff;	/* archive symbol table hdr offset */
	char		*ed_arstr;	/* archive string table */
	size_t		ed_arstrsz;	/* archive string table size */
	size_t		ed_arstroff;	/* archive string table hdr offset */
	unsigned	ed_myflags;	/* EDF_... */
	unsigned	ed_ehflags;	/* ehdr flags */
	unsigned	ed_phflags;	/* phdr flags */
	unsigned	ed_uflags;	/* elf descriptor flags */
};

#define	ELFRLOCK(e) \
	if (elf_threaded) \
		(void) rw_rdlock(&((Elf *)e)->ed_rwlock);

#define	ELFWLOCK(e) \
	if (elf_threaded) \
		(void) rw_wrlock(&((Elf *)e)->ed_rwlock);

#define	ELFUNLOCK(e) \
	if (elf_threaded) \
		(void) rw_unlock(&((Elf *)e)->ed_rwlock);

#define	EDF_ASALLOC	0x1	/* applies to ed_arsym */
#define	EDF_EHALLOC	0x2	/* applies to ed_ehdr */
#define	EDF_PHALLOC	0x4	/* applies to ed_phdr */
#define	EDF_SHALLOC	0x8	/* applies to ed_shdr */
#define	EDF_COFFAOUT	0x10	/* original file was coff a.out */
#define	EDF_RAWALLOC	0x20	/* applies to ed_raw */
#define	EDF_READ	0x40	/* file can be read */
#define	EDF_WRITE	0x80	/* file can be written */
#define	EDF_MEMORY	0x100	/* file opened via elf_memory() */
#define	EDF_ASTRALLOC	0x200	/* applies to ed_arstr */
#define	EDF_MPROTECT	0x400	/* applies to slideable archives */
#define	EDF_IMALLOC	0x800	/* wrimage dynamically allocated */
#define	EDF_WRALLOC	0x1000	/* wrimage is to by dyn allocated */
#define	EDF_ARSYM64	0x2000	/* archive symbol table is 64-bit format */


typedef enum
{
	OK_YES = 0,
	OK_NO = ~0
} Okay;

#define	_(a)		a

/*
 * Max size for an Elf error message string
 */
#define	MAXELFERR	1024

/*
 * General thread management macros
 */
#define	ELFACCESSDATA(a, b) \
	if (elf_threaded) { \
		(void) mutex_lock(&_elf_globals_mutex); \
		a = b; \
		(void) mutex_unlock(&_elf_globals_mutex); \
	} else \
		a = b;

#define	ELFRWLOCKINIT(lock) \
	if (elf_threaded) { \
		(void) rwlock_init((lock), USYNC_THREAD, 0); \
	}

#define	ELFMUTEXINIT(lock) \
	if (elf_threaded) { \
		(void) mutex_init(lock, USYNC_THREAD, 0); \
	}

extern Member		*_elf_armem(Elf *, char *, size_t);
extern void		_elf_arinit(Elf *);
extern Okay		_elf_cook(Elf *);
extern Okay		_elf_cookscn(Elf_Scn * s);
extern Okay		_elf32_cookscn(Elf_Scn * s);
extern Okay		_elf64_cookscn(Elf_Scn * s);
extern Dnode		*_elf_dnode(void);
extern Elf_Data		*_elf_locked_getdata(Elf_Scn *, Elf_Data *);
extern size_t		_elf32_entsz(Elf *elf, Elf32_Word, unsigned);
extern size_t		_elf64_entsz(Elf *elf, Elf64_Word, unsigned);
extern Okay		_elf_inmap(Elf *);
extern char		*_elf_outmap(int, size_t, unsigned *);
extern size_t		_elf_outsync(int, char *, size_t, unsigned);
extern size_t		_elf32_msize(Elf_Type, unsigned);
extern size_t		_elf64_msize(Elf_Type, unsigned);
extern Elf_Type		_elf32_mtype(Elf *, Elf32_Word, unsigned);
extern Elf_Type		_elf64_mtype(Elf *, Elf64_Word, unsigned);
extern char		*_elf_read(int, off_t, size_t);
extern Snode32		*_elf32_snode(void);
extern Snode64		*_elf64_snode(void);
extern void		_elf_unmap(char *, size_t);
extern Okay		_elf_vm(Elf *, size_t, size_t);
extern int		_elf32_ehdr(Elf *, int);
extern int		_elf32_phdr(Elf *, int);
extern int		_elf32_shdr(Elf *, int);
extern int		_elf64_ehdr(Elf *, int);
extern int		_elf64_phdr(Elf *, int);
extern int		_elf64_shdr(Elf *, int);
extern int		_elf_byte;
extern const Elf32_Ehdr	_elf32_ehdr_init;
extern const Elf64_Ehdr	_elf64_ehdr_init;
extern unsigned		_elf_encode;
extern _elf_execfill_func_t *_elf_execfill_func;
extern void		_elf_seterr(Msg, int);
extern const Snode32	_elf32_snode_init;
extern const Snode64	_elf64_snode_init;
extern const Dnode	_elf_dnode_init;
extern unsigned		_elf_work;
extern mutex_t		_elf_globals_mutex;
extern off_t		_elf64_update(Elf * elf, Elf_Cmd cmd);
extern int		_elf64_swap_wrimage(Elf *elf);

#ifdef	__cplusplus
}
#endif

#endif	/* _DECL_H */