Improve ARM CPU info reporting.
This patch improves several things for Linux/ARM: - Better detection of the number of CPUs on the target device. The content of /proc/cpuinfo only matches the number of "online" CPUs, which varies over time with recent Android devices. - Reconstruct the CPUID and ELF hwcaps values from /proc/cpuinfo, this is useful to better identify target devices in minidumps. - Make minidump_dump display the new information in useful ways. - Write a small helper class to parse /proc/cpuinfo and also use it for x86/64. - Write a small helper class to parse sysfds cpu lists. - Add a my_memchr() implementation. - Add unit tests. Tested on a Nexus S (1 CPU), Galaxy Nexus (2 CPUs) and a Nexus 4 (4 CPUs). Review URL: https://breakpad.appspot.com/540003 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1160 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
@@ -305,6 +305,128 @@ static const MDRawSystemInfo* GetSystemInfo(Minidump *dump,
|
||||
return minidump_system_info->system_info();
|
||||
}
|
||||
|
||||
// Extract CPU info string from ARM-specific MDRawSystemInfo structure.
|
||||
// raw_info: pointer to source MDRawSystemInfo.
|
||||
// cpu_info: address of target string, cpu info text will be appended to it.
|
||||
static void GetARMCpuInfo(const MDRawSystemInfo* raw_info,
|
||||
std::string* cpu_info) {
|
||||
assert(raw_info != NULL && cpu_info != NULL);
|
||||
|
||||
// Write ARM architecture version.
|
||||
char cpu_string[32];
|
||||
snprintf(cpu_string, sizeof(cpu_string), "ARMv%d",
|
||||
raw_info->processor_level);
|
||||
cpu_info->append(cpu_string);
|
||||
|
||||
// There is no good list of implementer id values, but the following
|
||||
// pages provide some help:
|
||||
// http://comments.gmane.org/gmane.linux.linaro.devel/6903
|
||||
// http://forum.xda-developers.com/archive/index.php/t-480226.html
|
||||
const struct {
|
||||
uint32_t id;
|
||||
const char* name;
|
||||
} vendors[] = {
|
||||
{ 0x41, "ARM" },
|
||||
{ 0x51, "Qualcomm" },
|
||||
{ 0x56, "Marvell" },
|
||||
{ 0x69, "Intel/Marvell" },
|
||||
};
|
||||
const struct {
|
||||
uint32_t id;
|
||||
const char* name;
|
||||
} parts[] = {
|
||||
{ 0x4100c050, "Cortex-A5" },
|
||||
{ 0x4100c080, "Cortex-A8" },
|
||||
{ 0x4100c090, "Cortex-A9" },
|
||||
{ 0x4100c0f0, "Cortex-A15" },
|
||||
{ 0x4100c140, "Cortex-R4" },
|
||||
{ 0x4100c150, "Cortex-R5" },
|
||||
{ 0x4100b360, "ARM1136" },
|
||||
{ 0x4100b560, "ARM1156" },
|
||||
{ 0x4100b760, "ARM1176" },
|
||||
{ 0x4100b020, "ARM11-MPCore" },
|
||||
{ 0x41009260, "ARM926" },
|
||||
{ 0x41009460, "ARM946" },
|
||||
{ 0x41009660, "ARM966" },
|
||||
{ 0x510006f0, "Krait" },
|
||||
{ 0x510000f0, "Scorpion" },
|
||||
};
|
||||
|
||||
const struct {
|
||||
uint32_t hwcap;
|
||||
const char* name;
|
||||
} features[] = {
|
||||
{ MD_CPU_ARM_ELF_HWCAP_SWP, "swp" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_HALF, "half" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_THUMB, "thumb" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_26BIT, "26bit" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_FAST_MULT, "fastmult" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_FPA, "fpa" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_VFP, "vfpv2" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_EDSP, "edsp" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_JAVA, "java" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_IWMMXT, "iwmmxt" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_CRUNCH, "crunch" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_THUMBEE, "thumbee" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_NEON, "neon" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_VFPv3, "vfpv3" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_VFPv3D16, "vfpv3d16" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_TLS, "tls" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_VFPv4, "vfpv4" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_IDIVA, "idiva" },
|
||||
{ MD_CPU_ARM_ELF_HWCAP_IDIVT, "idivt" },
|
||||
};
|
||||
|
||||
uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid;
|
||||
if (cpuid != 0) {
|
||||
// Extract vendor name from CPUID
|
||||
const char* vendor = NULL;
|
||||
uint32_t vendor_id = (cpuid >> 24) & 0xff;
|
||||
for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) {
|
||||
if (vendors[i].id == vendor_id) {
|
||||
vendor = vendors[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cpu_info->append(" ");
|
||||
if (vendor) {
|
||||
cpu_info->append(vendor);
|
||||
} else {
|
||||
snprintf(cpu_string, sizeof(cpu_string), "vendor(0x%x)", vendor_id);
|
||||
cpu_info->append(cpu_string);
|
||||
}
|
||||
|
||||
// Extract part name from CPUID
|
||||
uint32_t part_id = (cpuid & 0xff00fff0);
|
||||
const char* part = NULL;
|
||||
for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) {
|
||||
if (parts[i].id == part_id) {
|
||||
part = parts[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cpu_info->append(" ");
|
||||
if (part != NULL) {
|
||||
cpu_info->append(part);
|
||||
} else {
|
||||
snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)", part_id);
|
||||
cpu_info->append(cpu_string);
|
||||
}
|
||||
}
|
||||
uint32_t elf_hwcaps = raw_info->cpu.arm_cpu_info.elf_hwcaps;
|
||||
if (elf_hwcaps != 0) {
|
||||
cpu_info->append(" features: ");
|
||||
const char* comma = "";
|
||||
for (size_t i = 0; i < sizeof(features)/sizeof(features[0]); ++i) {
|
||||
if (elf_hwcaps & features[i].hwcap) {
|
||||
cpu_info->append(comma);
|
||||
cpu_info->append(features[i].name);
|
||||
comma = ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
|
||||
assert(dump);
|
||||
@@ -359,6 +481,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
|
||||
|
||||
case MD_CPU_ARCHITECTURE_ARM: {
|
||||
info->cpu = "arm";
|
||||
GetARMCpuInfo(raw_system_info, &info->cpu_info);
|
||||
break;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user