1
0

ArchInfo.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "util/Bits.h"
  16. #include "util/ArchInfo.h"
  17. #include "util/CString.h"
  18. #include <stdio.h>
  19. #ifndef linux
  20. uint32_t ArchInfo_toAuditArch(enum ArchInfo ai)
  21. {
  22. return 0xffffffff;
  23. }
  24. #else
  25. #include <linux/audit.h>
  26. // TODO(cjd): understand why some machines are not defining this.
  27. #ifndef EM_ARM
  28. #define EM_ARM 40
  29. #endif
  30. uint32_t ArchInfo_toAuditArch(enum ArchInfo ai)
  31. {
  32. switch (ArchInfo_getArch(ai)) {
  33. case ArchInfo_Arch_AMD64: return AUDIT_ARCH_X86_64;
  34. case ArchInfo_Arch_I386: return AUDIT_ARCH_I386;
  35. case ArchInfo_Arch_ARM: {
  36. if (ArchInfo_isBigEndian(ai)) {
  37. return AUDIT_ARCH_ARMEB;
  38. }
  39. return AUDIT_ARCH_ARM;
  40. }
  41. case ArchInfo_Arch_PPC: {
  42. switch (ArchInfo_getBits(ai)) {
  43. case 32: return AUDIT_ARCH_PPC;
  44. case 64: return AUDIT_ARCH_PPC64;
  45. default:;
  46. }
  47. return 0xffffffff;
  48. }
  49. case ArchInfo_Arch_SPARC: {
  50. switch (ArchInfo_getBits(ai)) {
  51. case 32: return AUDIT_ARCH_SPARC;
  52. case 64: return AUDIT_ARCH_SPARC64;
  53. default:;
  54. }
  55. return 0xffffffff;
  56. }
  57. case ArchInfo_Arch_MIPS: {
  58. if (ArchInfo_isBigEndian(ai)) {
  59. switch (ArchInfo_getBits(ai)) {
  60. case 32: return AUDIT_ARCH_MIPS;
  61. case 64: return AUDIT_ARCH_MIPS64;
  62. default:;
  63. }
  64. return 0xffffffff;
  65. } else {
  66. switch (ArchInfo_getBits(ai)) {
  67. case ArchInfo_Bits_32: return AUDIT_ARCH_MIPSEL;
  68. case ArchInfo_Bits_64: return AUDIT_ARCH_MIPSEL64;
  69. default:;
  70. }
  71. return 0xffffffff;
  72. }
  73. }
  74. default: return 0xffffffff;
  75. }
  76. }
  77. #endif
  78. static char* archStr(enum ArchInfo ai)
  79. {
  80. switch (ArchInfo_getArch(ai)) {
  81. case ArchInfo_Arch_AMD64: return "AMD64";
  82. case ArchInfo_Arch_ARM: return "ARM";
  83. case ArchInfo_Arch_PPC: return "PPC";
  84. case ArchInfo_Arch_SPARC: return "SPARC";
  85. case ArchInfo_Arch_MIPS: return "MIPS";
  86. case ArchInfo_Arch_I386: return "i386";
  87. default: return "UNKNOWN";
  88. };
  89. }
  90. #define archFlags_BUFF_SZ 512
  91. static void archFlags(enum ArchInfo arch, uint8_t buff[archFlags_BUFF_SZ])
  92. {
  93. switch (ArchInfo_getArch(arch)) {
  94. case ArchInfo_Arch_ARM: {
  95. snprintf(buff, archFlags_BUFF_SZ, "%s%s",
  96. ((arch & ArchInfo_Arm_SUBTYPE_BITS) == ArchInfo_Arm_EABI) ? " EABI": "",
  97. (arch & ArchInfo_Arm_NEON) ? " NEON": ""
  98. );
  99. break;
  100. }
  101. case ArchInfo_Arch_SPARC: {
  102. switch (arch & ArchInfo_Sparc_SUBTYPE_BITS) {
  103. case ArchInfo_Sparc_v8: snprintf(buff, archFlags_BUFF_SZ, " sparcv8"); break;
  104. case ArchInfo_Sparc_v9: snprintf(buff, archFlags_BUFF_SZ, " sparcv9"); break;
  105. }
  106. break;
  107. }
  108. case ArchInfo_Arch_MIPS: {
  109. switch (arch & ArchInfo_Mips_SUBTYPE_BITS) {
  110. case ArchInfo_Mips_OABI: snprintf(buff, archFlags_BUFF_SZ, " OABI"); break;
  111. case ArchInfo_Mips_NABI: snprintf(buff, archFlags_BUFF_SZ, " NABI"); break;
  112. }
  113. break;
  114. }
  115. case ArchInfo_Arch_AMD64:
  116. case ArchInfo_Arch_PPC:
  117. default: {
  118. buff[0] = '\0';
  119. break;
  120. }
  121. };
  122. }
  123. char* ArchInfo_describe(enum ArchInfo ai, struct Allocator* alloc)
  124. {
  125. uint8_t flagBuff[archFlags_BUFF_SZ];
  126. archFlags(ai, flagBuff);
  127. uint8_t buff[1024];
  128. snprintf(buff, 1024, "%s %d-bit %sEndian %s",
  129. archStr(ai),
  130. ArchInfo_getBits(ai),
  131. ArchInfo_isBigEndian(ai) ? "Big" : "Little",
  132. flagBuff);
  133. int len = CString_strlen(buff);
  134. Assert_true(len < 1024);
  135. if (buff[len-1] == ' ') { buff[--len] = '\0'; }
  136. char* out = Allocator_malloc(alloc, len+1);
  137. Bits_memcpy(out, buff, len+1);
  138. return out;
  139. }
  140. static enum ArchInfo_Bits detectBits()
  141. {
  142. switch (sizeof(long)) {
  143. case 4: return ArchInfo_Bits_32;
  144. case 8: return ArchInfo_Bits_64;
  145. default: return ArchInfo_Bits_UNKNOWN;
  146. }
  147. }
  148. static enum ArchInfo_Bits assertBits(enum ArchInfo_Bits bits)
  149. {
  150. enum ArchInfo_Bits detected = detectBits();
  151. if (bits != detected) { return ArchInfo_Bits_UNKNOWN; }
  152. return bits;
  153. }
  154. enum ArchInfo_Endian
  155. {
  156. ArchInfo_Endian_LITTLE = (0 << ArchInfo_Endian_SHIFT),
  157. ArchInfo_Endian_BIG = (1 << ArchInfo_Endian_SHIFT),
  158. ArchInfo_Endian_UNKNOWN = -1,
  159. };
  160. static enum ArchInfo_Endian detectEndian()
  161. {
  162. union {
  163. uint32_t i;
  164. uint8_t c[4];
  165. } bint = { .i = 0xff0000ee };
  166. if (bint.c[0] == 0xff) {
  167. return ArchInfo_Endian_BIG;
  168. } else if (bint.c[0] == 0xee) {
  169. return ArchInfo_Endian_LITTLE;
  170. }
  171. // 2+2=5
  172. Assert_true(0);
  173. return -1;
  174. }
  175. static enum ArchInfo_Endian assertEndian(enum ArchInfo_Endian end)
  176. {
  177. enum ArchInfo_Endian detected = detectEndian();
  178. if (end != detected) { return ArchInfo_Endian_UNKNOWN; }
  179. return end;
  180. }
  181. enum ArchInfo ArchInfo_detect()
  182. {
  183. enum ArchInfo arch = 0;
  184. #if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || \
  185. defined(_M_X64) || defined(__amd64)
  186. arch |= ArchInfo_Arch_AMD64;
  187. #elif defined(__i386__) || defined(__x86__) || defined(__X86__) || \
  188. defined(_M_IX86) || defined(__i386)
  189. arch |= ArchInfo_Arch_I386;
  190. #elif defined(__ARM_EABI__) || defined(__arm__)
  191. arch |= ArchInfo_Arch_ARM;
  192. #elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(_ARCH_PPC64)
  193. arch |= ArchInfo_Arch_PPC | ArchInfo_Bits_64;
  194. #elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
  195. arch |= ArchInfo_Arch_PPC | ArchInfo_Bits_32;
  196. #elif defined(__sparcv9__) || defined(__sparcv9)
  197. arch |= ArchInfo_Arch_SPARC | ArchInfo_Sparc_v9;
  198. #elif defined(__sparc_v8__)
  199. arch |= ArchInfo_Arch_SPARC | ArchInfo_Sparc_v8;
  200. #elif defined(__sparc__) || defined(__sparc)
  201. arch |= ArchInfo_Arch_SPARC;
  202. #elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
  203. arch |= ArchInfo_Arch_MIPS;
  204. #else
  205. arch |= ArchInfo_UNKNOWN;
  206. #endif
  207. switch ((int)arch) {
  208. case ArchInfo_Arch_AMD64:
  209. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_LITTLE);
  210. case ArchInfo_Arch_I386: {
  211. #define HAS_SSE2 0
  212. #ifdef __SSE2__
  213. #undef HAS_SSE2
  214. #define HAS_SSE2 1
  215. #endif
  216. if (HAS_SSE2) {
  217. arch |= ArchInfo_I386_SSE2;
  218. }
  219. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_LITTLE);
  220. }
  221. case ArchInfo_Arch_ARM: {
  222. #define HAS_EABI 0
  223. #ifdef __ARM_EABI__
  224. #undef HAS_EABI
  225. #define HAS_EABI 1
  226. #endif
  227. if (HAS_EABI) {
  228. arch |= ArchInfo_Arm_EABI;
  229. }
  230. #define HAS_NEON 0
  231. #ifdef __ARM_NEON__
  232. #undef HAS_NEON
  233. #define HAS_NEON 1
  234. #endif
  235. if (HAS_NEON) {
  236. arch |= ArchInfo_Arm_NEON;
  237. }
  238. return arch | detectBits() | detectEndian();
  239. }
  240. case (ArchInfo_Arch_PPC | ArchInfo_Bits_64): {
  241. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_BIG);
  242. }
  243. case (ArchInfo_Arch_PPC | ArchInfo_Bits_32): {
  244. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_BIG);
  245. }
  246. case (ArchInfo_Arch_SPARC | ArchInfo_Sparc_v9): {
  247. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_BIG);
  248. }
  249. case (ArchInfo_Arch_SPARC | ArchInfo_Sparc_v8): {
  250. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_BIG);
  251. }
  252. case ArchInfo_Arch_SPARC: {
  253. arch |= detectBits();
  254. switch (ArchInfo_getBits(arch)) {
  255. case ArchInfo_Bits_32: arch |= ArchInfo_Sparc_v8; break;
  256. case ArchInfo_Bits_64: arch |= ArchInfo_Sparc_v9; break;
  257. default: return ArchInfo_UNKNOWN;
  258. }
  259. return arch | assertEndian(ArchInfo_Endian_BIG);
  260. }
  261. case ArchInfo_Arch_MIPS: {
  262. #define IS_OABI 0
  263. #if defined(_ABIO32)
  264. #undef IS_OABI
  265. #define IS_OABI 1
  266. #endif
  267. if (IS_OABI) {
  268. return arch | ArchInfo_Mips_OABI | assertBits(ArchInfo_Bits_32);
  269. }
  270. #define IS_NABI 0
  271. #if defined(_ABIN32)
  272. #undef IS_NABI
  273. #define IS_NABI 1
  274. #endif
  275. if (IS_NABI) {
  276. if (IS_OABI) { return ArchInfo_UNKNOWN; }
  277. return arch | ArchInfo_Mips_NABI | assertBits(ArchInfo_Bits_32);
  278. }
  279. // If it's not oabi or nabi and it's not mips64 then it's UNKNOWN.
  280. return arch | assertBits(ArchInfo_Bits_64);
  281. }
  282. default: return ArchInfo_UNKNOWN;
  283. }
  284. }