Skip to content

[llvm-cov][MC/DC] "Branch not found in Decisions" when handling complicated macros #87000

Closed
@whentojump

Description

@whentojump

Example file perfmon.c (It currently looks tedious and should be able to be further minimized, I'll work on that)

// A example simplified from https://elixir.bootlin.com/linux/v6.8.1/source/drivers/iommu/intel/perfmon.c
// Reproducible with clang version 18.1.3 ([email protected]:llvm/llvm-project.git
// 2498e3a07f3df2272fec885f53f09ae13214ca38) and Ubuntu clang version 18.1.3
// (++20240322073153+ef6d1ec07c69-1~exp1~20240322193300.86).
//
// Note that assertions *might* have to be enabled, therefore prebuilt packages
// from apt.llvm.org etc *might* not behave the same. E.g. as of Mar 28,
// llvm-cov-18 from apt.llvm.org ends up with "Segmentation fault", llvm-cov-19
// doesn't fail at least explicitly. On the other hand, if we build LLVM from
// source and enable assertion, we can observe explicit "UNREACHABLE executed"
// messages.
//
// Steps:
//
//   $ rm -rf a.out *.profraw *.profdata
//   $ clang -Wno-c23-extensions -fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc perfmon.c
//   $ ./a.out
//   $ llvm-profdata merge default.profraw -o default.profdata
//   $ llvm-cov show --show-mcdc -instr-profile default.profdata a.out
//

// Dummy definitions to make this file compile.
// (Some of them are also kernel code but incomplete or modified)

struct attr {
	long config1;
	long config2;
};

struct hw_perf_event {
	long idx;
	long config;
};

struct perf_event {
	struct hw_perf_event hw;
	struct attr attr;
};

struct iommu_pmu {
	long filter;
	long cfg_reg;
	struct perf_event *event_list[100];
	long num_cntr;
	long used_mask;
};

long test_and_set_bit(long, long) { return 0; }
long iommu_pmu_validate_per_cntr_event(struct iommu_pmu *, long, struct perf_event *) { return 1; }
void clear_bit(long, long) {}
void writeq(long, long) {}
void writel(long, long) {}
long iommu_config_base(struct iommu_pmu *, long) { return 0; }
long variable_ffs(long) { return 1; }

#define UL(X) X##UL

// Actually copied from kernel source

#define BIT(nr)			(UL(1) << (nr))

#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))

#define dmar_readq(a) readq(a)
#define dmar_writeq(a,v) writeq(v,a)
#define dmar_readl(a) readl(a)
#define dmar_writel(a, v) writel(v, a)

#define iommu_pmu_en_requester_id(e)		((e) & 0x1)
#define iommu_pmu_en_domain(e)			(((e) >> 1) & 0x1)
#define iommu_pmu_en_pasid(e)			(((e) >> 2) & 0x1)
#define iommu_pmu_en_ats(e)			(((e) >> 3) & 0x1)
#define iommu_pmu_en_page_table(e)		(((e) >> 4) & 0x1)
#define iommu_pmu_get_requester_id(filter)	(((filter) >> 16) & 0xffff)
#define iommu_pmu_get_domain(filter)		(((filter) >> 32) & 0xffff)
#define iommu_pmu_get_pasid(filter)		((filter) & 0x3fffff)
#define iommu_pmu_get_ats(filter)		(((filter) >> 24) & 0x1f)
#define iommu_pmu_get_page_table(filter)	(((filter) >> 32) & 0x1f)

#define IOMMU_PMU_NUM_OFF_REGS			4
#define IOMMU_PMU_OFF_REGS_STEP			4

#define IOMMU_PMU_FILTER_REQUESTER_ID		0x01
#define IOMMU_PMU_FILTER_DOMAIN			0x02
#define IOMMU_PMU_FILTER_PASID			0x04
#define IOMMU_PMU_FILTER_ATS			0x08
#define IOMMU_PMU_FILTER_PAGE_TABLE		0x10

#define IOMMU_PMU_FILTER_EN			BIT(31)

#define IOMMU_PMU_CFG_OFFSET			0x100
#define IOMMU_PMU_CFG_CNTRCAP_OFFSET		0x80
#define IOMMU_PMU_CFG_CNTREVCAP_OFFSET		0x84
#define IOMMU_PMU_CFG_SIZE			0x8
#define IOMMU_PMU_CFG_FILTERS_OFFSET		0x4

#define IOMMU_PMU_CAP_REGS_STEP			8

#define iommu_pmu_set_filter(_name, _config, _filter, _idx, _econfig)		\
{										\
	if ((iommu_pmu->filter & _filter) && iommu_pmu_en_##_name(_econfig)) {	\
		dmar_writel(iommu_pmu->cfg_reg + _idx * IOMMU_PMU_CFG_OFFSET +	\
			    IOMMU_PMU_CFG_SIZE +				\
			    (ffs(_filter) - 1) * IOMMU_PMU_CFG_FILTERS_OFFSET,	\
			    iommu_pmu_get_##_name(_config) | IOMMU_PMU_FILTER_EN);\
	}									\
}

// Part of https://elixir.bootlin.com/linux/v6.8.1/source/drivers/iommu/intel/perfmon.c#L408

static int iommu_pmu_assign_event(struct iommu_pmu *iommu_pmu,
				  struct perf_event *event)
{
	int idx;

	iommu_pmu_set_filter(requester_id, event->attr.config1,
			     IOMMU_PMU_FILTER_REQUESTER_ID, idx,
			     event->attr.config1);
	// iommu_pmu_set_filter(domain, event->attr.config1,
	// 		     IOMMU_PMU_FILTER_DOMAIN, idx,
	// 		     event->attr.config1);

	return 0;
}

// Dummy main

int main(void) {
	struct iommu_pmu iommu_pmu;
	struct perf_event event;
	iommu_pmu_assign_event(&iommu_pmu, &event);
	return 0;
}

Steps to reproduce:

rm -rf a.out *.profraw *.profdata
clang -Wno-c23-extensions -fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc perfmon.c
./a.out
llvm-profdata merge default.profraw -o default.profdata
# Crash
llvm-cov show --show-mcdc -instr-profile default.profdata a.out

Message:

Branch not found in Decisions
UNREACHABLE executed at /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:784!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: llvm-cov "llvm-cov show" --show-mcdc -instr-profile default.profdata a.out
 #0 0x000055cfdb4bf61f llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/Support/Unix/Signals.inc:727:3
 #1 0x000055cfdb4bd30f llvm::sys::RunSignalHandlers() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/Support/Signals.cpp:105:20
 #2 0x000055cfdb4bd666 SignalHandler(int) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/Support/Unix/Signals.inc:413:1
 #3 0x00007f0aefc5e520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007f0aefcb29fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007f0aefcb29fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007f0aefcb29fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x00007f0aefc5e476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007f0aefc447f3 abort ./stdlib/abort.c:81:7
 #9 0x000055cfdb46736e (/users/wtj/have-been/llvm-project/build/bin/llvm-cov+0x45436e)
#10 0x000055cfdb55527f (anonymous namespace)::MCDCDecisionRecorder::processBranch(llvm::coverage::CounterMappingRegion const&) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:784:5
#11 0x000055cfdb55b030 llvm::coverage::CoverageMapping::loadFunctionRecord(llvm::coverage::CoverageMappingRecord const&, llvm::IndexedInstrProfReader&) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:879:5
#12 0x000055cfdb55c260 llvm::Error::setChecked(bool) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:307:22
#13 0x000055cfdb55c260 llvm::Error::operator bool() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:239:15
#14 0x000055cfdb55c260 llvm::coverage::CoverageMapping::loadFromReaders(llvm::ArrayRef<std::unique_ptr<llvm::coverage::CoverageMappingReader, std::default_delete<llvm::coverage::CoverageMappingReader>>>, llvm::IndexedInstrProfReader&, llvm::coverage::CoverageMapping&) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:933:71
#15 0x000055cfdb55c8b9 llvm::Error::setChecked(bool) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:307:22
#16 0x000055cfdb55c8b9 llvm::Error::operator bool() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:239:15
#17 0x000055cfdb55c8b9 llvm::coverage::CoverageMapping::loadFromFile(llvm::StringRef, llvm::StringRef, llvm::StringRef, llvm::IndexedInstrProfReader&, llvm::coverage::CoverageMapping&, bool&, llvm::SmallVectorImpl<llvm::SmallVector<unsigned char, 10u>>*) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:992:66
#18 0x000055cfdb55d35a llvm::Error::setChecked(bool) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:307:22
#19 0x000055cfdb55d35a llvm::Error::operator bool() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:239:15
#20 0x000055cfdb55d35a llvm::coverage::CoverageMapping::load(llvm::ArrayRef<llvm::StringRef>, llvm::StringRef, llvm::vfs::FileSystem&, llvm::ArrayRef<llvm::StringRef>, llvm::StringRef, llvm::object::BuildIDFetcher const*, bool) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp:1020:80
#21 0x000055cfdb2ad4c2 llvm::Expected<std::unique_ptr<llvm::coverage::CoverageMapping, std::default_delete<llvm::coverage::CoverageMapping>>>::takeError() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/include/llvm/Support/Error.h:603:15
#22 0x000055cfdb2ad4c2 (anonymous namespace)::CodeCoverageTool::load() /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/tools/llvm-cov/CodeCoverage.cpp:486:41
#23 0x000055cfdb2b118f (anonymous namespace)::CodeCoverageTool::doShow(int, char const**, llvm::function_ref<int (int, char const**)>) (.constprop.0) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/tools/llvm-cov/CodeCoverage.cpp:1143:3
#24 0x000055cfdb2b6d58 (anonymous namespace)::CodeCoverageTool::run((anonymous namespace)::CodeCoverageTool::Command, int, char const**) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/tools/llvm-cov/CodeCoverage.cpp:980:18
#25 0x000055cfdb2b764f showMain(int, char const**) /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/tools/llvm-cov/CodeCoverage.cpp:1348:1
#26 0x000055cfdb29908d std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string() /usr/include/c++/11/bits/basic_string.h:672:19
#27 0x000055cfdb29908d main /users/wtj/have-been/enhanced-gcov/llvm-mcdc/llvm/llvm/tools/llvm-cov/llvm-cov.cpp:82:5
#28 0x00007f0aefc45d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#29 0x00007f0aefc45e40 call_init ./csu/../csu/libc-start.c:128:20
#30 0x00007f0aefc45e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#31 0x000055cfdb298625 _start (/users/wtj/have-been/llvm-project/build/bin/llvm-cov+0x285625)
Aborted

It somewhat looks like #77871 and perhaps has something to do with region ordering.

cc @chapuni @evodius96

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions