in Source/PLCrashAsyncCompactUnwindEncoding.c [503:583]
plcrash_error_t plcrash_async_cfe_register_decode (uint32_t permutation, uint32_t count, uint32_t registers[]) {
/* Validate that count falls within the supported range */
if (count > PLCRASH_ASYNC_CFE_PERMUTATION_REGISTER_MAX) {
PLCF_DEBUG("Register permutation decoding attempted with an unsupported count of %" PRIu32, count);
return PLCRASH_EINVAL;
}
/*
* Each register is encoded by mapping the values to a 10-bit range, and then further sub-ranges within that range,
* with a subrange allocated to each position. See the encoding function for full documentation.
*/
int permunreg[PLCRASH_ASYNC_CFE_PERMUTATION_REGISTER_MAX];
#define PERMUTE(pos, factor) do { \
permunreg[pos] = permutation/factor; \
permutation -= (permunreg[pos]*factor); \
} while (0)
/* Assert that the maximum register count matches our switch() statement. */
PLCR_ASSERT_STATIC(expected_max_register_count, PLCRASH_ASYNC_CFE_PERMUTATION_REGISTER_MAX == 6);
switch (count) {
case 6:
PERMUTE(0, 120);
PERMUTE(1, 24);
PERMUTE(2, 6);
PERMUTE(3, 2);
PERMUTE(4, 1);
/*
* There are 6 elements in the list, 6 possible values for each element, and values may not repeat. The
* value of the last element can be derived from the values previously seen (and due to the positional
* renumbering performed, the value of the last element will *always* be 0).
*/
permunreg[5] = 0;
break;
case 5:
PERMUTE(0, 120);
PERMUTE(1, 24);
PERMUTE(2, 6);
PERMUTE(3, 2);
PERMUTE(4, 1);
break;
case 4:
PERMUTE(0, 60);
PERMUTE(1, 12);
PERMUTE(2, 3);
PERMUTE(3, 1);
break;
case 3:
PERMUTE(0, 20);
PERMUTE(1, 4);
PERMUTE(2, 1);
break;
case 2:
PERMUTE(0, 5);
PERMUTE(1, 1);
break;
case 1:
PERMUTE(0, 1);
break;
}
#undef PERMUTE
/* Recompute the actual register values based on the position-relative values. */
bool position_used[PLCRASH_ASYNC_CFE_SAVED_REGISTER_MAX+1] = { 0 };
for (uint32_t i = 0; i < count; ++i) {
int renumbered = 0;
for (int u = 1; u < 7; u++) {
if (!position_used[u]) {
if (renumbered == permunreg[i]) {
registers[i] = u;
position_used[u] = true;
break;
}
renumbered++;
}
}
}
return PLCRASH_ESUCCESS;
}