2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
6 #include "elf_haiku_version.h"
12 #include <image_defs.h>
15 #include "elf_symbol_lookup.h"
18 // interim Haiku API versions
19 #define HAIKU_VERSION_PRE_GLUE_CODE 0x00000010
23 analyze_object_gcc_version(int fd
, image_t
* image
, elf_ehdr
& eheader
,
24 int32 sheaderSize
, char* buffer
, size_t bufferSize
)
26 if (sheaderSize
> (int)bufferSize
) {
27 FATAL("%s: Cannot handle section headers bigger than %lu bytes\n",
28 image
->path
, bufferSize
);
32 // read section headers
33 ssize_t length
= _kern_read(fd
, eheader
.e_shoff
, buffer
, sheaderSize
);
34 if (length
!= sheaderSize
) {
35 FATAL("%s: Could not read section headers: %s\n", image
->path
,
40 // load the string section
41 elf_shdr
* sectionHeader
42 = (elf_shdr
*)(buffer
+ eheader
.e_shstrndx
* eheader
.e_shentsize
);
44 if (sheaderSize
+ sectionHeader
->sh_size
> bufferSize
) {
45 FATAL("%s: Buffer not big enough for section string section\n",
50 char* sectionStrings
= buffer
+ bufferSize
- sectionHeader
->sh_size
;
51 length
= _kern_read(fd
, sectionHeader
->sh_offset
, sectionStrings
,
52 sectionHeader
->sh_size
);
53 if (length
!= (int)sectionHeader
->sh_size
) {
54 FATAL("%s: Could not read section string section: %s\n", image
->path
,
59 // find the .comment section
60 off_t commentOffset
= 0;
61 size_t commentSize
= 0;
62 for (uint32 i
= 0; i
< eheader
.e_shnum
; i
++) {
63 sectionHeader
= (elf_shdr
*)(buffer
+ i
* eheader
.e_shentsize
);
64 const char* sectionName
= sectionStrings
+ sectionHeader
->sh_name
;
65 if (sectionHeader
->sh_name
!= 0
66 && strcmp(sectionName
, ".comment") == 0) {
67 commentOffset
= sectionHeader
->sh_offset
;
68 commentSize
= sectionHeader
->sh_size
;
73 if (commentSize
== 0) {
74 FATAL("%s: Could not find .comment section\n", image
->path
);
78 // read a part of the comment section
79 if (commentSize
> 512)
82 length
= _kern_read(fd
, commentOffset
, buffer
, commentSize
);
83 if (length
!= (int)commentSize
) {
84 FATAL("%s: Could not read .comment section: %s\n", image
->path
,
89 // the common prefix of the strings in the .comment section
90 static const char* kGCCVersionPrefix
= "GCC: (GNU) ";
91 size_t gccVersionPrefixLen
= strlen(kGCCVersionPrefix
);
99 // Read up to 10 comments. The first three or four are usually from the
101 for (int i
= 0; i
< 10; i
++) {
103 while (index
< commentSize
&& buffer
[index
] == '\0')
105 char* stringStart
= buffer
+ index
;
108 while (index
< commentSize
&& buffer
[index
] != '\0')
111 // ignore the entry at the end of the buffer
112 if (index
== commentSize
)
115 // We have to analyze string like these:
116 // GCC: (GNU) 2.9-beos-991026
117 // GCC: (GNU) 2.95.3-haiku-080322
120 // skip the common prefix
121 if (strncmp(stringStart
, kGCCVersionPrefix
, gccVersionPrefixLen
) != 0)
124 // the rest is the GCC version
125 char* gccVersion
= stringStart
+ gccVersionPrefixLen
;
126 char* gccPlatform
= strchr(gccVersion
, '-');
127 char* patchLevel
= NULL
;
128 if (gccPlatform
!= NULL
) {
131 patchLevel
= strchr(gccPlatform
, '-');
132 if (patchLevel
!= NULL
) {
138 // split the gcc version into major, middle, and minor
139 int version
[3] = { 0, 0, 0 };
141 for (int k
= 0; gccVersion
!= NULL
&& k
< 3; k
++) {
142 char* dot
= strchr(gccVersion
, '.');
147 version
[k
] = atoi(gccVersion
);
155 // Select the gcc version with the smallest major, but the greatest
156 // middle/minor. This should usually ignore the glue code version as
157 // well as cases where e.g. in a gcc 2 program a single C file has
158 // been compiled with gcc 4.
159 if (gccMajor
== 0 || gccMajor
> version
[0]
160 || (gccMajor
== version
[0]
161 && (gccMiddle
< version
[1]
162 || (gccMiddle
== version
[1] && gccMinor
< version
[2])))) {
163 gccMajor
= version
[0];
164 gccMiddle
= version
[1];
165 gccMinor
= version
[2];
168 if (gccMajor
== 2 && gccPlatform
!= NULL
169 && strcmp(gccPlatform
, "haiku")) {
179 image
->abi
= B_HAIKU_ABI_GCC_2_ANCIENT
;
181 image
->abi
= B_HAIKU_ABI_GCC_2_HAIKU
;
183 image
->abi
= B_HAIKU_ABI_GCC_2_BEOS
;
185 image
->abi
= gccMajor
<< 16;
192 analyze_image_haiku_version_and_abi(int fd
, image_t
* image
, elf_ehdr
& eheader
,
193 int32 sheaderSize
, char* buffer
, size_t bufferSize
)
196 elf_sym
* symbol
= find_symbol(image
,
197 SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME
,
198 B_SYMBOL_TYPE_DATA
));
199 if (symbol
!= NULL
&& symbol
->st_shndx
!= SHN_UNDEF
200 && symbol
->st_value
> 0
201 && symbol
->Type() == STT_OBJECT
202 && symbol
->st_size
>= sizeof(uint32
)) {
204 = *(uint32
*)(symbol
->st_value
+ image
->regions
[0].delta
);
206 image
->api_version
= 0;
209 symbol
= find_symbol(image
,
210 SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME
,
211 B_SYMBOL_TYPE_DATA
));
212 if (symbol
!= NULL
&& symbol
->st_shndx
!= SHN_UNDEF
213 && symbol
->st_value
> 0
214 && symbol
->Type() == STT_OBJECT
215 && symbol
->st_size
>= sizeof(uint32
)) {
216 image
->abi
= *(uint32
*)(symbol
->st_value
+ image
->regions
[0].delta
);
220 if (image
->abi
== 0) {
221 // No ABI version in the shared object, i.e. it has been built before
222 // that was introduced in Haiku. We have to try and analyze the gcc
224 if (!analyze_object_gcc_version(fd
, image
, eheader
, sheaderSize
,
225 buffer
, bufferSize
)) {
226 FATAL("%s: Failed to get gcc version.\n", image
->path
);
227 // not really fatal, actually
229 // assume ancient BeOS
230 image
->abi
= B_HAIKU_ABI_GCC_2_ANCIENT
;
234 // guess the API version, if we couldn't figure it out yet
235 if (image
->api_version
== 0) {
236 image
->api_version
= image
->abi
> B_HAIKU_ABI_GCC_2_BEOS
237 ? HAIKU_VERSION_PRE_GLUE_CODE
: B_HAIKU_VERSION_BEOS
;