// Copyright 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include "cpu_features_macros.h" #include "cpuinfo_aarch64.h" #include "cpuinfo_arm.h" #include "cpuinfo_mips.h" #include "cpuinfo_ppc.h" #include "cpuinfo_x86.h" static void PrintEscapedAscii(const char* str) { putchar('"'); for (; str && *str; ++str) { switch (*str) { case '\"': case '\\': case '/': case '\b': case '\f': case '\n': case '\r': case '\t': putchar('\\'); } putchar(*str); } putchar('"'); } static void PrintVoid(void) {} static void PrintComma(void) { putchar(','); } static void PrintLineFeed(void) { putchar('\n'); } static void PrintOpenBrace(void) { putchar('{'); } static void PrintCloseBrace(void) { putchar('}'); } static void PrintOpenBracket(void) { putchar('['); } static void PrintCloseBracket(void) { putchar(']'); } static void PrintString(const char* field) { printf("%s", field); } static void PrintAlignedHeader(const char* field) { printf("%-15s : ", field); } static void PrintIntValue(int value) { printf("%d", value); } static void PrintDecHexValue(int value) { printf("%3d (0x%02X)", value, value); } static void PrintJsonHeader(const char* field) { PrintEscapedAscii(field); putchar(':'); } typedef struct { void (*Start)(void); void (*ArrayStart)(void); void (*ArraySeparator)(void); void (*ArrayEnd)(void); void (*PrintString)(const char* value); void (*PrintValue)(int value); void (*EndField)(void); void (*StartField)(const char* field); void (*End)(void); } Printer; static Printer getJsonPrinter(void) { return (Printer){ .Start = &PrintOpenBrace, .ArrayStart = &PrintOpenBracket, .ArraySeparator = &PrintComma, .ArrayEnd = &PrintCloseBracket, .PrintString = &PrintEscapedAscii, .PrintValue = &PrintIntValue, .EndField = &PrintComma, .StartField = &PrintJsonHeader, .End = &PrintCloseBrace, }; } static Printer getTextPrinter(void) { return (Printer){ .Start = &PrintVoid, .ArrayStart = &PrintVoid, .ArraySeparator = &PrintComma, .ArrayEnd = &PrintVoid, .PrintString = &PrintString, .PrintValue = &PrintDecHexValue, .EndField = &PrintLineFeed, .StartField = &PrintAlignedHeader, .End = &PrintVoid, }; } // Prints a named numeric value in both decimal and hexadecimal. static void PrintN(const Printer p, const char* field, int value) { p.StartField(field); p.PrintValue(value); p.EndField(); } // Prints a named string. static void PrintS(const Printer p, const char* field, const char* value) { p.StartField(field); p.PrintString(value); p.EndField(); } static int cmp(const void* p1, const void* p2) { return strcmp(*(const char* const*)p1, *(const char* const*)p2); } #define DEFINE_PRINT_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \ static void PrintFlags(const Printer p, const FeatureType* features) { \ size_t i; \ const char* ptrs[LastEnum] = {0}; \ size_t count = 0; \ for (i = 0; i < LastEnum; ++i) { \ if (HasFeature(features, i)) { \ ptrs[count] = FeatureName(i); \ ++count; \ } \ } \ qsort(ptrs, count, sizeof(char*), cmp); \ p.StartField("flags"); \ p.ArrayStart(); \ for (i = 0; i < count; ++i) { \ if (i > 0) p.ArraySeparator(); \ p.PrintString(ptrs[i]); \ } \ p.ArrayEnd(); \ } #if defined(CPU_FEATURES_ARCH_X86) DEFINE_PRINT_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features, X86_LAST_) #elif defined(CPU_FEATURES_ARCH_ARM) DEFINE_PRINT_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures, ARM_LAST_) #elif defined(CPU_FEATURES_ARCH_AARCH64) DEFINE_PRINT_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName, Aarch64Features, AARCH64_LAST_) #elif defined(CPU_FEATURES_ARCH_MIPS) DEFINE_PRINT_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName, MipsFeatures, MIPS_LAST_) #elif defined(CPU_FEATURES_ARCH_PPC) DEFINE_PRINT_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures, PPC_LAST_) #endif static void PrintFeatures(const Printer printer) { #if defined(CPU_FEATURES_ARCH_X86) char brand_string[49]; const X86Info info = GetX86Info(); FillX86BrandString(brand_string); PrintS(printer, "arch", "x86"); PrintS(printer, "brand", brand_string); PrintN(printer, "family", info.family); PrintN(printer, "model", info.model); PrintN(printer, "stepping", info.stepping); PrintS(printer, "uarch", GetX86MicroarchitectureName(GetX86Microarchitecture(&info))); PrintFlags(printer, &info.features); #elif defined(CPU_FEATURES_ARCH_ARM) const ArmInfo info = GetArmInfo(); PrintS(printer, "arch", "ARM"); PrintN(printer, "implementer", info.implementer); PrintN(printer, "architecture", info.architecture); PrintN(printer, "variant", info.variant); PrintN(printer, "part", info.part); PrintN(printer, "revision", info.revision); PrintFlags(printer, &info.features); #elif defined(CPU_FEATURES_ARCH_AARCH64) const Aarch64Info info = GetAarch64Info(); PrintS(printer, "arch", "aarch64"); PrintN(printer, "implementer", info.implementer); PrintN(printer, "variant", info.variant); PrintN(printer, "part", info.part); PrintN(printer, "revision", info.revision); PrintFlags(printer, &info.features); #elif defined(CPU_FEATURES_ARCH_MIPS) const MipsInfo info = GetMipsInfo(); PrintS(printer, "arch", "mips"); PrintFlags(printer, &info.features); #elif defined(CPU_FEATURES_ARCH_PPC) const PPCInfo info = GetPPCInfo(); const PPCPlatformStrings strings = GetPPCPlatformStrings(); PrintS(printer, "arch", "ppc"); PrintS(printer, "platform", strings.platform); PrintS(printer, "model", strings.model); PrintS(printer, "machine", strings.machine); PrintS(printer, "cpu", strings.cpu); PrintS(printer, "instruction set", strings.type.platform); PrintS(printer, "microarchitecture", strings.type.base_platform); PrintFlags(printer, &info.features); #endif } static void showUsage(const char* name) { printf( "\n" "Usage: %s [options]\n" " Options:\n" " -h | --help Show help message.\n" " -j | --json Format output as json instead of plain text.\n" "\n", name); } int main(int argc, char** argv) { Printer printer = getTextPrinter(); int i = 1; for (; i < argc; ++i) { const char* arg = argv[i]; if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) { printer = getJsonPrinter(); } else { showUsage(argv[0]); if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) return EXIT_SUCCESS; return EXIT_FAILURE; } } printer.Start(); PrintFeatures(printer); printer.End(); PrintLineFeed(); return EXIT_SUCCESS; }