ArchInfo.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. default: return "UNKNOWN";
  87. };
  88. }
  89. #define archFlags_BUFF_SZ 512
  90. static void archFlags(enum ArchInfo arch, uint8_t buff[archFlags_BUFF_SZ])
  91. {
  92. switch (ArchInfo_getArch(arch)) {
  93. case ArchInfo_Arch_ARM: {
  94. snprintf(buff, archFlags_BUFF_SZ, "%s%s",
  95. ((arch & ArchInfo_Arm_SUBTYPE_BITS) == ArchInfo_Arm_EABI) ? " EABI": "",
  96. (arch & ArchInfo_Arm_NEON) ? " NEON": ""
  97. );
  98. break;
  99. }
  100. case ArchInfo_Arch_SPARC: {
  101. switch (arch & ArchInfo_Sparc_SUBTYPE_BITS) {
  102. case ArchInfo_Sparc_v8: snprintf(buff, archFlags_BUFF_SZ, " sparcv8"); break;
  103. case ArchInfo_Sparc_v9: snprintf(buff, archFlags_BUFF_SZ, " sparcv9"); break;
  104. }
  105. break;
  106. }
  107. case ArchInfo_Arch_MIPS: {
  108. switch (arch & ArchInfo_Mips_SUBTYPE_BITS) {
  109. case ArchInfo_Mips_OABI: snprintf(buff, archFlags_BUFF_SZ, " OABI"); break;
  110. case ArchInfo_Mips_NABI: snprintf(buff, archFlags_BUFF_SZ, " NABI"); break;
  111. }
  112. break;
  113. }
  114. case ArchInfo_Arch_AMD64:
  115. case ArchInfo_Arch_PPC:
  116. default: {
  117. buff[0] = '\0';
  118. break;
  119. }
  120. };
  121. }
  122. char* ArchInfo_describe(enum ArchInfo ai, struct Allocator* alloc)
  123. {
  124. uint8_t flagBuff[archFlags_BUFF_SZ];
  125. archFlags(ai, flagBuff);
  126. uint8_t buff[1024];
  127. snprintf(buff, 1024, "%s %d-bit %sEndian %s",
  128. archStr(ai),
  129. ArchInfo_getBits(ai),
  130. ArchInfo_isBigEndian(ai) ? "Big" : "Little",
  131. flagBuff);
  132. int len = CString_strlen(buff);
  133. Assert_true(len < 1024);
  134. if (buff[len-1] == ' ') { buff[--len] = '\0'; }
  135. char* out = Allocator_malloc(alloc, len+1);
  136. Bits_memcpy(out, buff, len+1);
  137. return out;
  138. }
  139. static enum ArchInfo_Bits detectBits()
  140. {
  141. switch (sizeof(long)) {
  142. case 4: return ArchInfo_Bits_32;
  143. case 8: return ArchInfo_Bits_64;
  144. default: return ArchInfo_Bits_UNKNOWN;
  145. }
  146. }
  147. static enum ArchInfo_Bits assertBits(enum ArchInfo_Bits bits)
  148. {
  149. enum ArchInfo_Bits detected = detectBits();
  150. if (bits != detected) { return ArchInfo_Bits_UNKNOWN; }
  151. return bits;
  152. }
  153. enum ArchInfo_Endian
  154. {
  155. ArchInfo_Endian_LITTLE = (0 << ArchInfo_Endian_SHIFT),
  156. ArchInfo_Endian_BIG = (1 << ArchInfo_Endian_SHIFT),
  157. ArchInfo_Endian_UNKNOWN = -1,
  158. };
  159. static enum ArchInfo_Endian detectEndian()
  160. {
  161. union {
  162. uint32_t i;
  163. uint8_t c[4];
  164. } bint = { .i = 0xff0000ee };
  165. if (bint.c[0] == 0xff) {
  166. return ArchInfo_Endian_BIG;
  167. } else if (bint.c[0] == 0xee) {
  168. return ArchInfo_Endian_LITTLE;
  169. }
  170. // 2+2=5
  171. Assert_true(0);
  172. return -1;
  173. }
  174. static enum ArchInfo_Endian assertEndian(enum ArchInfo_Endian end)
  175. {
  176. enum ArchInfo_Endian detected = detectEndian();
  177. if (end != detected) { return ArchInfo_Endian_UNKNOWN; }
  178. return end;
  179. }
  180. enum ArchInfo ArchInfo_detect()
  181. {
  182. enum ArchInfo arch = 0;
  183. #if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || \
  184. defined(_M_X64) || defined(__amd64)
  185. arch |= ArchInfo_Arch_AMD64;
  186. #elif defined(__i386__) || defined(__x86__) || defined(__X86__) || \
  187. defined(_M_IX86) || defined(__i386)
  188. arch |= ArchInfo_Arch_I386;
  189. #elif defined(__ARM_EABI__) || defined(__arm__)
  190. arch |= ArchInfo_Arch_ARM;
  191. #elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(_ARCH_PPC64)
  192. arch |= ArchInfo_Arch_PPC | ArchInfo_Bits_64;
  193. #elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
  194. arch |= ArchInfo_Arch_PPC | ArchInfo_Bits_32;
  195. #elif defined(__sparcv9__) || defined(__sparcv9)
  196. arch |= ArchInfo_Arch_SPARC | ArchInfo_Sparc_v9;
  197. #elif defined(__sparc_v8__)
  198. arch |= ArchInfo_Arch_SPARC | ArchInfo_Sparc_v8;
  199. #elif defined(__sparc__) || defined(__sparc)
  200. arch |= ArchInfo_Arch_SPARC;
  201. #elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
  202. arch |= ArchInfo_Arch_MIPS;
  203. #else
  204. arch |= ArchInfo_UNKNOWN;
  205. #endif
  206. switch ((int)arch) {
  207. case ArchInfo_Arch_AMD64:
  208. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_LITTLE);
  209. case ArchInfo_Arch_I386: {
  210. #define HAS_SSE2 0
  211. #ifdef __SSE2__
  212. #undef HAS_SSE2
  213. #define HAS_SSE2 1
  214. #endif
  215. if (HAS_SSE2) {
  216. arch |= ArchInfo_I386_SSE2;
  217. }
  218. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_LITTLE);
  219. }
  220. case ArchInfo_Arch_ARM: {
  221. #define HAS_EABI 0
  222. #ifdef __ARM_EABI__
  223. #undef HAS_EABI
  224. #define HAS_EABI 1
  225. #endif
  226. if (HAS_EABI) {
  227. arch |= ArchInfo_Arm_EABI;
  228. }
  229. #define HAS_NEON 0
  230. #ifdef __ARM_NEON__
  231. #undef HAS_NEON
  232. #define HAS_NEON 1
  233. #endif
  234. if (HAS_NEON) {
  235. arch |= ArchInfo_Arm_NEON;
  236. }
  237. return arch | detectBits() | detectEndian();
  238. }
  239. case (ArchInfo_Arch_PPC | ArchInfo_Bits_64): {
  240. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_BIG);
  241. }
  242. case (ArchInfo_Arch_PPC | ArchInfo_Bits_32): {
  243. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_BIG);
  244. }
  245. case (ArchInfo_Arch_SPARC | ArchInfo_Sparc_v9): {
  246. return arch | assertBits(ArchInfo_Bits_64) | assertEndian(ArchInfo_Endian_BIG);
  247. }
  248. case (ArchInfo_Arch_SPARC | ArchInfo_Sparc_v8): {
  249. return arch | assertBits(ArchInfo_Bits_32) | assertEndian(ArchInfo_Endian_BIG);
  250. }
  251. case ArchInfo_Arch_SPARC: {
  252. arch |= detectBits();
  253. switch (ArchInfo_getBits(arch)) {
  254. case ArchInfo_Bits_32: arch |= ArchInfo_Sparc_v8; break;
  255. case ArchInfo_Bits_64: arch |= ArchInfo_Sparc_v9; break;
  256. default: return ArchInfo_UNKNOWN;
  257. }
  258. return arch | assertEndian(ArchInfo_Endian_BIG);
  259. }
  260. case ArchInfo_Arch_MIPS: {
  261. #define IS_OABI 0
  262. #if defined(_ABIO32)
  263. #undef IS_OABI
  264. #define IS_OABI 1
  265. #endif
  266. if (IS_OABI) {
  267. return arch | ArchInfo_Mips_OABI | assertBits(ArchInfo_Bits_32);
  268. }
  269. #define IS_NABI 0
  270. #if defined(_ABIN32)
  271. #undef IS_NABI
  272. #define IS_NABI 1
  273. #endif
  274. if (IS_NABI) {
  275. if (IS_OABI) { return ArchInfo_UNKNOWN; }
  276. return arch | ArchInfo_Mips_NABI | assertBits(ArchInfo_Bits_32);
  277. }
  278. // If it's not oabi or nabi and it's not mips64 then it's UNKNOWN.
  279. return arch | assertBits(ArchInfo_Bits_64);
  280. }
  281. default: return ArchInfo_UNKNOWN;
  282. }
  283. }