blob: acda5e77c078bcf83a93952aa222c0223154ffbc [file] [log] [blame]
// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#if defined(CPU_FEATURES_ARCH_X86)
#include "cpuinfo_x86.h"
#elif defined(CPU_FEATURES_ARCH_ARM)
#include "cpuinfo_arm.h"
#elif defined(CPU_FEATURES_ARCH_AARCH64)
#include "cpuinfo_aarch64.h"
#elif defined(CPU_FEATURES_ARCH_MIPS)
#include "cpuinfo_mips.h"
#elif defined(CPU_FEATURES_ARCH_PPC)
#include "cpuinfo_ppc.h"
#endif
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((void*)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)
(void)&PrintN; // Remove unused function warning.
const MipsInfo info = GetMipsInfo();
PrintS(printer, "arch", "mips");
PrintFlags(printer, &info.features);
#elif defined(CPU_FEATURES_ARCH_PPC)
(void)&PrintN; // Remove unused function warning.
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;
}