1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#include <mach-o/ldsyms.h>
25#include <mach-o/swap.h>
26#include <string.h>
27#ifdef __DYNAMIC__
28#include <mach-o/dyld.h> /* defines _dyld_lookup_and_bind() */
29#endif /* defined(__DYNAMIC__) */
30#ifndef __OPENSTEP__
31#include <crt_externs.h>
32#else /* defined(__OPENSTEP__) */
33
34#if !defined(__DYNAMIC__)
35#define DECLARE_VAR(var, type) \
36extern type var
37#define SETUP_VAR(var)
38#define USE_VAR(var) var
39#else
40#define STRINGIFY(a) # a
41#define DECLARE_VAR(var, type)	\
42static type * var ## _pointer = NULL
43#define SETUP_VAR(var)						\
44if ( var ## _pointer == NULL) {				\
45    _dyld_lookup_and_bind( STRINGIFY(_ ## var),		\
46                           (uint32_t *) & var ## _pointer, NULL);	\
47}
48#define USE_VAR(var) (* var ## _pointer)
49#endif
50#endif /* __OPENSTEP__ */
51
52/*
53 * This routine returns the section structure for the named section in the
54 * named segment for the mach_header pointer passed to it if it exist.
55 * Otherwise it returns zero.
56 */
57const struct section *
58getsectbynamefromheader(
59struct mach_header *mhp,
60const char *segname,
61const char *sectname)
62{
63	struct segment_command *sgp;
64	struct section *sp;
65	uint32_t i, j;
66
67	sgp = (struct segment_command *)
68	      ((char *)mhp + sizeof(struct mach_header));
69	for(i = 0; i < mhp->ncmds; i++){
70	    if(sgp->cmd == LC_SEGMENT)
71		if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
72		   mhp->filetype == MH_OBJECT){
73		    sp = (struct section *)((char *)sgp +
74			 sizeof(struct segment_command));
75		    for(j = 0; j < sgp->nsects; j++){
76			if(strncmp(sp->sectname, sectname,
77			   sizeof(sp->sectname)) == 0 &&
78			   strncmp(sp->segname, segname,
79			   sizeof(sp->segname)) == 0)
80			    return(sp);
81			sp = (struct section *)((char *)sp +
82			     sizeof(struct section));
83		    }
84		}
85	    sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
86	}
87	return((struct section *)0);
88}
89
90/*
91 * This routine returns the section structure for the named section in the
92 * named segment for the mach_header_64 pointer passed to it if it exist.
93 * Otherwise it returns zero.
94 */
95const struct section_64 *
96getsectbynamefromheader_64(
97struct mach_header_64 *mhp,
98const char *segname,
99const char *sectname)
100{
101	struct segment_command_64 *sgp;
102	struct section_64 *sp;
103	uint32_t i, j;
104
105	sgp = (struct segment_command_64 *)
106	      ((char *)mhp + sizeof(struct mach_header_64));
107	for(i = 0; i < mhp->ncmds; i++){
108	    if(sgp->cmd == LC_SEGMENT_64)
109		if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
110		   mhp->filetype == MH_OBJECT){
111		    sp = (struct section_64 *)((char *)sgp +
112			 sizeof(struct segment_command_64));
113		    for(j = 0; j < sgp->nsects; j++){
114			if(strncmp(sp->sectname, sectname,
115			   sizeof(sp->sectname)) == 0 &&
116			   strncmp(sp->segname, segname,
117			   sizeof(sp->segname)) == 0)
118			    return(sp);
119			sp = (struct section_64 *)((char *)sp +
120			     sizeof(struct section_64));
121		    }
122		}
123	    sgp = (struct segment_command_64 *)((char *)sgp + sgp->cmdsize);
124	}
125	return((struct section_64 *)0);
126}
127
128/*
129 * This routine returns the section structure for the named section in the
130 * named segment for the mach_header pointer passed to it if it exist.
131 * Otherwise it returns zero.  If fSwap == YES (the mach header has been
132 * swapped to the endiannes of the current machine, but the segments and
133 * sections are different) then the segment and sections are swapped.
134 */
135const struct section *
136getsectbynamefromheaderwithswap(
137    struct mach_header *mhp,
138    const char *segname,
139    const char *sectname,
140    int fSwap)
141{
142	struct segment_command *sgp;
143	struct section *sp;
144	uint32_t i, j;
145
146	sgp = (struct segment_command *)
147	      ((char *)mhp + sizeof(struct mach_header));
148	for(i = 0; i < mhp->ncmds; i++){
149	    if(sgp->cmd == (fSwap ? OSSwapInt32(LC_SEGMENT) : LC_SEGMENT)) {
150
151		if (fSwap) {
152#ifdef __LITTLE_ENDIAN__
153		    swap_segment_command(sgp, NX_BigEndian);
154#else
155		    swap_segment_command(sgp, NX_LittleEndian);
156#endif /* __LITTLE_ENDIAN__ */
157		}
158
159		if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
160		   mhp->filetype == MH_OBJECT){
161		    sp = (struct section *)((char *)sgp +
162			 sizeof(struct segment_command));
163
164		    if (fSwap) {
165#ifdef __LITTLE_ENDIAN__
166			swap_section(sp, sgp->nsects, NX_BigEndian);
167#else
168			swap_section(sp, sgp->nsects, NX_LittleEndian);
169#endif /* __LITTLE_ENDIAN__ */
170		    }
171
172		    for(j = 0; j < sgp->nsects; j++){
173			if(strncmp(sp->sectname, sectname,
174			   sizeof(sp->sectname)) == 0 &&
175			   strncmp(sp->segname, segname,
176			   sizeof(sp->segname)) == 0)
177			    return(sp);
178			sp = (struct section *)((char *)sp +
179			     sizeof(struct section));
180		    }
181		}
182		sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
183	    } else {
184		sgp = (struct segment_command *)((char *)sgp +
185		    (fSwap ? OSSwapInt32(sgp->cmdsize) : sgp->cmdsize));
186	    }
187	}
188	return((struct section *)0);
189}
190
191/*
192 * This routine returns the a pointer the section structure of the named
193 * section in the named segment if it exist in the mach executable it is
194 * linked into.  Otherwise it returns zero.
195 */
196#ifndef __LP64__
197
198const struct section *
199getsectbyname(
200const char *segname,
201const char *sectname)
202{
203#ifndef __OPENSTEP__
204    struct mach_header *mhp = _NSGetMachExecuteHeader();
205#else /* defined(__OPENSTEP__) */
206    static struct mach_header *mhp = NULL;
207	DECLARE_VAR(_mh_execute_header, struct mach_header);
208        SETUP_VAR(_mh_execute_header);
209	mhp = (struct mach_header *)(& USE_VAR(_mh_execute_header));
210#endif /* __OPENSTEP__ */
211	return(getsectbynamefromheader(mhp, segname, sectname));
212}
213
214#else /* defined(__LP64__) */
215
216const struct section_64 *
217getsectbyname(
218const char *segname,
219const char *sectname)
220{
221    struct mach_header_64 *mhp = _NSGetMachExecuteHeader();
222
223	return(getsectbynamefromheader_64(mhp, segname, sectname));
224}
225
226#endif /* defined(__LP64__) */
227
228/*
229 * This routine returns the a pointer to the data for the named section in the
230 * named segment if it exist in the mach executable it is linked into.  Also
231 * it returns the size of the section data indirectly through the pointer size.
232 * Otherwise it returns zero for the pointer and the size.
233 */
234char *
235getsectdata(
236const char *segname,
237const char *sectname,
238unsigned long *size)
239{
240#ifndef __LP64__
241    const struct section *sp;
242#else /* defined(__LP64__) */
243    const struct section_64 *sp;
244#endif /* defined(__LP64__) */
245
246	sp = getsectbyname(segname, sectname);
247	if(sp == NULL){
248	    *size = 0;
249	    return(NULL);
250	}
251	*size = sp->size;
252	return((char *)(sp->addr));
253}
254
255/*
256 * This routine returns the a pointer to the section contents of the named
257 * section in the named segment if it exists in the image pointed to by the
258 * mach header.  Otherwise it returns zero.
259 */
260#ifndef __LP64__
261
262uint8_t *
263getsectiondata(
264const struct mach_header *mhp,
265const char *segname,
266const char *sectname,
267unsigned long *size)
268{
269    struct segment_command *sgp, *zero;
270    struct section *sp, *find;
271    uint32_t i, j;
272
273	zero = 0;
274	find = 0;
275	sp = 0;
276	sgp = (struct segment_command *)
277	      ((char *)mhp + sizeof(struct mach_header));
278	for(i = 0; i < mhp->ncmds; i++){
279	    if(sgp->cmd == LC_SEGMENT){
280		if(zero == 0 && sgp->fileoff == 0 && sgp->nsects != 0){
281		    zero = sgp;
282		    if(find != 0)
283			goto done;
284		}
285		if(find == 0 &&
286		   strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0){
287		    sp = (struct section *)((char *)sgp +
288			 sizeof(struct segment_command));
289		    for(j = 0; j < sgp->nsects; j++){
290			if(strncmp(sp->sectname, sectname,
291			   sizeof(sp->sectname)) == 0 &&
292			   strncmp(sp->segname, segname,
293			   sizeof(sp->segname)) == 0){
294			    find = sp;
295			    if(zero != 0)
296				goto done;
297			}
298			sp = (struct section *)((char *)sp +
299			     sizeof(struct section));
300		    }
301		}
302	    }
303	    sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
304	}
305	return(0);
306done:
307	*size = sp->size;
308	return((uint8_t *)((uintptr_t)mhp - zero->vmaddr + sp->addr));
309}
310
311uint8_t *
312getsegmentdata(
313const struct mach_header *mhp,
314const char *segname,
315unsigned long *size)
316{
317    struct segment_command *sgp, *zero, *find;
318    uint32_t i;
319
320	zero = 0;
321	find = 0;
322	sgp = (struct segment_command *)
323	      ((char *)mhp + sizeof(struct mach_header));
324	for(i = 0; i < mhp->ncmds; i++){
325	    if(sgp->cmd == LC_SEGMENT){
326		if(zero == 0 && sgp->fileoff == 0 && sgp->nsects != 0){
327		    zero = sgp;
328		    if(find != 0)
329			goto done;
330		}
331		if(find == 0 &&
332		   strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0){
333		    find = sgp;
334		    if(zero != 0)
335			goto done;
336		}
337	    }
338	    sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
339	}
340	return(0);
341done:
342	*size = sgp->vmsize;
343	return((uint8_t *)((uintptr_t)mhp - zero->vmaddr + sgp->vmaddr));
344}
345
346#else /* defined(__LP64__) */
347
348uint8_t *
349getsectiondata(
350const struct mach_header_64 *mhp,
351const char *segname,
352const char *sectname,
353unsigned long *size)
354{
355    struct segment_command_64 *sgp, *zero;
356    struct section_64 *sp, *find;
357    uint32_t i, j;
358
359	zero = 0;
360	find = 0;
361	sp = 0;
362	sgp = (struct segment_command_64 *)
363	      ((char *)mhp + sizeof(struct mach_header_64));
364	for(i = 0; i < mhp->ncmds; i++){
365	    if(sgp->cmd == LC_SEGMENT_64){
366		if(zero == 0 && sgp->fileoff == 0 && sgp->nsects != 0){
367		    zero = sgp;
368		    if(find != 0)
369			goto done;
370		}
371		if(find == 0 &&
372		   strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0){
373		    sp = (struct section_64 *)((char *)sgp +
374			 sizeof(struct segment_command_64));
375		    for(j = 0; j < sgp->nsects; j++){
376			if(strncmp(sp->sectname, sectname,
377			   sizeof(sp->sectname)) == 0 &&
378			   strncmp(sp->segname, segname,
379			   sizeof(sp->segname)) == 0){
380			    find = sp;
381			    if(zero != 0)
382				goto done;
383			}
384			sp = (struct section_64 *)((char *)sp +
385			     sizeof(struct section_64));
386		    }
387		}
388	    }
389	    sgp = (struct segment_command_64 *)((char *)sgp + sgp->cmdsize);
390	}
391	return(0);
392done:
393	*size = sp->size;
394	return((uint8_t *)((uintptr_t)mhp - zero->vmaddr + sp->addr));
395}
396
397uint8_t *
398getsegmentdata(
399const struct mach_header_64 *mhp,
400const char *segname,
401unsigned long *size)
402{
403    struct segment_command_64 *sgp, *zero, *find;
404    uint32_t i;
405
406	zero = 0;
407	find = 0;
408	sgp = (struct segment_command_64 *)
409	      ((char *)mhp + sizeof(struct mach_header_64));
410	for(i = 0; i < mhp->ncmds; i++){
411	    if(sgp->cmd == LC_SEGMENT_64){
412		if(zero == 0 && sgp->fileoff == 0 && sgp->nsects != 0){
413		    zero = sgp;
414		    if(find != 0)
415			goto done;
416		}
417		if(find == 0 &&
418		   strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0){
419		    find = sgp;
420		    if(zero != 0)
421			goto done;
422		}
423	    }
424	    sgp = (struct segment_command_64 *)((char *)sgp + sgp->cmdsize);
425	}
426	return(0);
427done:
428	*size = sgp->vmsize;
429	return((uint8_t *)((uintptr_t)mhp - zero->vmaddr + sgp->vmaddr));
430}
431
432#endif /* defined(__LP64__) */
433
434/*
435 * This routine returns the a pointer to the data for the named section in the
436 * named segment if it exist in the mach header passed to it.  Also it returns
437 * the size of the section data indirectly through the pointer size.  Otherwise
438 * it returns zero for the pointer and the size.
439 */
440char *
441getsectdatafromheader(
442struct mach_header *mhp,
443const char *segname,
444const char *sectname,
445unsigned long *size)
446{
447    const struct section *sp;
448
449	sp = getsectbynamefromheader(mhp, segname, sectname);
450	if(sp == NULL){
451	    *size = 0;
452	    return(NULL);
453	}
454	*size = sp->size;
455	return((char *)((uintptr_t)(sp->addr)));
456}
457
458/*
459 * This routine returns the a pointer to the data for the named section in the
460 * named segment if it exist in the 64-bit mach header passed to it.  Also it
461 * returns the size of the section data indirectly through the pointer size.
462 * Otherwise it returns zero for the pointer and the size.
463 */
464char *
465getsectdatafromheader_64(
466struct mach_header_64 *mhp,
467const char *segname,
468const char *sectname,
469unsigned long *size)
470{
471    const struct section_64 *sp;
472
473	sp = getsectbynamefromheader_64(mhp, segname, sectname);
474	if(sp == NULL){
475	    *size = 0;
476	    return(NULL);
477	}
478	*size = sp->size;
479	return((char *)((uintptr_t)(sp->addr)));
480}
481
482#ifdef __DYNAMIC__
483/*
484 * This routine returns the a pointer to the data for the named section in the
485 * named segment if it exist in the named Framework.  Also it returns the size
486 * of the section data indirectly through the pointer size.  Otherwise it
487 * returns zero for the pointer and the size.  The last component of the path
488 * of the Framework is passed as FrameworkName.
489 */
490void *
491getsectdatafromFramework(
492const char *FrameworkName,
493const char *segname,
494const char *sectname,
495unsigned long *size)
496{
497    uint32_t i, n;
498    uintptr_t vmaddr_slide;
499#ifndef __LP64__
500    struct mach_header *mh;
501    const struct section *s;
502#else /* defined(__LP64__) */
503    struct mach_header_64 *mh;
504    const struct section_64 *s;
505#endif /* defined(__LP64__) */
506    char *name, *p;
507
508        n = _dyld_image_count();
509        for(i = 0; i < n ; i++){
510            name = _dyld_get_image_name(i);
511            p = strrchr(name, '/');
512            if(p != NULL && p[1] != '\0')
513                name = p + 1;
514            if(strcmp(name, FrameworkName) != 0)
515                continue;
516            mh = _dyld_get_image_header(i);
517            vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
518#ifndef __LP64__
519            s = getsectbynamefromheader(mh, segname, sectname);
520#else /* defined(__LP64__) */
521            s = getsectbynamefromheader_64(mh, segname, sectname);
522#endif /* defined(__LP64__) */
523            if(s == NULL){
524                *size = 0;
525                return(NULL);
526            }
527            *size = s->size;
528            return((void *)(s->addr + vmaddr_slide));
529        }
530        *size = 0;
531        return(NULL);
532}
533#endif /* __DYNAMIC__ */
534#endif /* !defined(RLD) */
535