OSDN Git Service

- tidy up utils_install
[uclinux-h8/uClibc.git] / utils / readsoname2.c
1 char *readsonameXX(char *name, FILE *infile, int expected_type, int *type)
2 {
3         ElfW(Ehdr) *epnt;
4         ElfW(Phdr) *ppnt;
5         unsigned int i, j;
6         char *header;
7         ElfW(Addr) dynamic_addr = 0;
8         ElfW(Addr) dynamic_size = 0;
9         unsigned long page_size = getpagesize();
10         ElfW(Addr) strtab_val = 0;
11         ElfW(Addr) needed_val;
12         ElfW(Addr) loadaddr = -1;
13         ElfW(Dyn) *dpnt;
14         struct stat st;
15         char *needed;
16         char *soname = NULL;
17         int multi_libcs = 0;
18
19         if (expected_type == LIB_DLL) {
20                 warn("%s does not match type specified for directory!", name);
21                 expected_type = LIB_ANY;
22         }
23
24         *type = LIB_ELF;
25
26         if (fstat(fileno(infile), &st))
27                 return NULL;
28         header =
29             mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
30                  fileno(infile), 0);
31         if (header == (caddr_t) - 1)
32                 return NULL;
33
34         epnt = (ElfW(Ehdr) *) header;
35         if ((char *)(epnt + 1) > (char *)(header + st.st_size))
36                 goto skip;
37
38 #if __BYTE_ORDER == __LITTLE_ENDIAN
39         byteswap = (epnt->e_ident[5] == ELFDATA2MSB) ? 1 : 0;
40 #elif __BYTE_ORDER == __BIG_ENDIAN
41         byteswap = (epnt->e_ident[5] == ELFDATA2LSB) ? 1 : 0;
42 #else
43 #error Unknown host byte order!
44 #endif
45         /* Be very lazy, and only byteswap the stuff we use */
46         if (byteswap == 1) {
47                 epnt->e_phoff = bswap_32(epnt->e_phoff);
48                 epnt->e_phnum = bswap_16(epnt->e_phnum);
49         }
50
51         ppnt = (ElfW(Phdr) *) & header[epnt->e_phoff];
52         if ((char *)ppnt < (char *)header ||
53             (char *)(ppnt + epnt->e_phnum) > (char *)(header + st.st_size))
54                 goto skip;
55
56         for (i = 0; i < epnt->e_phnum; i++) {
57                 /* Be very lazy, and only byteswap the stuff we use */
58                 if (byteswap == 1) {
59                         ppnt->p_type = bswap_32(ppnt->p_type);
60                         ppnt->p_vaddr = bswap_32(ppnt->p_vaddr);
61                         ppnt->p_offset = bswap_32(ppnt->p_offset);
62                         ppnt->p_filesz = bswap_32(ppnt->p_filesz);
63                 }
64
65                 if (loadaddr == (ElfW(Addr)) - 1 && ppnt->p_type == PT_LOAD)
66                         loadaddr = (ppnt->p_vaddr & ~(page_size - 1)) -
67                             (ppnt->p_offset & ~(page_size - 1));
68                 if (ppnt->p_type == 2) {
69                         dynamic_addr = ppnt->p_offset;
70                         dynamic_size = ppnt->p_filesz;
71                 };
72                 ppnt++;
73         };
74
75         dpnt = (ElfW(Dyn) *) & header[dynamic_addr];
76         dynamic_size = dynamic_size / sizeof(ElfW(Dyn));
77         if ((char *)dpnt < (char *)header ||
78             (char *)(dpnt + dynamic_size) > (char *)(header + st.st_size))
79                 goto skip;
80
81         if (byteswap == 1) {
82                 dpnt->d_tag = bswap_32(dpnt->d_tag);
83                 dpnt->d_un.d_val = bswap_32(dpnt->d_un.d_val);
84         }
85
86         while (dpnt->d_tag != DT_NULL) {
87                 if (dpnt->d_tag == DT_STRTAB)
88                         strtab_val = dpnt->d_un.d_val;
89                 dpnt++;
90                 if (byteswap == 1) {
91                         dpnt->d_tag = bswap_32(dpnt->d_tag);
92                         dpnt->d_un.d_val = bswap_32(dpnt->d_un.d_val);
93                 }
94         };
95
96         if (!strtab_val)
97                 goto skip;
98
99         dpnt = (ElfW(Dyn) *) & header[dynamic_addr];
100         while (dpnt->d_tag != DT_NULL) {
101                 if (dpnt->d_tag == DT_SONAME || dpnt->d_tag == DT_NEEDED) {
102                         needed_val = dpnt->d_un.d_val;
103                         if (needed_val + strtab_val >= loadaddr ||
104                             needed_val + strtab_val < st.st_size - loadaddr) {
105                                 needed =
106                                     (char *)(header - loadaddr + strtab_val +
107                                              needed_val);
108
109                                 if (dpnt->d_tag == DT_SONAME)
110                                         soname = xstrdup(needed);
111
112                                 for (j = 0; needed_tab[j].soname != NULL; j++) {
113                                         if (strcmp(needed, needed_tab[j].soname)
114                                             == 0) {
115                                                 if (*type != LIB_ELF
116                                                     && *type !=
117                                                     needed_tab[j].type)
118                                                         multi_libcs = 1;
119                                                 *type = needed_tab[j].type;
120                                         }
121                                 }
122                         }
123                 }
124                 dpnt++;
125         };
126
127         if (multi_libcs)
128                 warn("%s appears to be for multiple libc's", name);
129
130         /* If we could not deduce the libc type, and we know what to expect, set the type */
131         if (*type == LIB_ELF && expected_type != LIB_ANY)
132                 *type = expected_type;
133
134         if (expected_type != LIB_ANY && expected_type != LIB_ELF &&
135             expected_type != *type) {
136                 warn("%s does not match type specified for directory!", name);
137         }
138
139       skip:
140         munmap(header, st.st_size);
141
142         return soname;
143 }