Fix Intersection bucket retrievals

This commit is contained in:
Michael Scire 2018-03-31 17:46:28 -06:00
parent 3d12b43f7b
commit 67d09c125b
3 changed files with 42 additions and 10 deletions

25
bktr.c
View file

@ -1,6 +1,10 @@
#include "bktr.h" #include "bktr.h"
#include "utils.h" #include "utils.h"
bktr_relocation_bucket_t *bktr_get_relocation_bucket(bktr_relocation_block_t *block, uint32_t i) {
return (bktr_relocation_bucket_t *)((uint8_t *)block->buckets + (sizeof(bktr_relocation_bucket_t) + sizeof(bktr_relocation_entry_t)) * i);
}
/* Get a relocation entry from offset and relocation block. */ /* Get a relocation entry from offset and relocation block. */
bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) { bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) {
/* Weak check for invalid offset. */ /* Weak check for invalid offset. */
@ -9,16 +13,19 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
bktr_relocation_bucket_t *bucket = &block->buckets[0]; uint32_t bucket_num = 0;
for (unsigned int i = 1; i < block->num_buckets; i++) { for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_virtual_offsets[i] < offset) { if (block->bucket_virtual_offsets[i] <= offset) {
bucket++; bucket_num++;
} }
} }
bktr_relocation_bucket_t *bucket = bktr_get_relocation_bucket(block, bucket_num);
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0]; return &bucket->entries[0];
} }
/* Binary search. */ /* Binary search. */
uint32_t low = 0, high = bucket->num_entries - 1; uint32_t low = 0, high = bucket->num_entries - 1;
while (low <= high) { while (low <= high) {
@ -37,6 +44,10 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
bktr_subsection_bucket_t *bktr_get_subsection_bucket(bktr_subsection_block_t *block, uint32_t i) {
return (bktr_subsection_bucket_t *)((uint8_t *)block->buckets + (sizeof(bktr_subsection_bucket_t) + sizeof(bktr_subsection_entry_t)) * i);
}
/* Get a subsection entry from offset and subsection block .*/ /* Get a subsection entry from offset and subsection block .*/
bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) { bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) {
/* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */ /* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */
@ -44,13 +55,15 @@ bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uin
return &block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries]; return &block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries];
} }
bktr_subsection_bucket_t *bucket = &block->buckets[0]; uint32_t bucket_num = 0;
for (unsigned int i = 1; i < block->num_buckets; i++) { for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_physical_offsets[i] < offset) { if (block->bucket_physical_offsets[i] <= offset) {
bucket++; bucket_num++;
} }
} }
bktr_subsection_bucket_t *bucket = bktr_get_subsection_bucket(block, bucket_num);
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0]; return &bucket->entries[0];
} }

3
bktr.h
View file

@ -69,7 +69,10 @@ typedef struct {
} bktr_subsection_block_t; } bktr_subsection_block_t;
#pragma pack(pop) #pragma pack(pop)
bktr_relocation_bucket_t *bktr_get_relocation_bucket(bktr_relocation_block_t *block, uint32_t i);
bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset); bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset);
bktr_subsection_bucket_t *bktr_get_subsection_bucket(bktr_subsection_block_t *block, uint32_t i);
bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset); bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset);
#endif #endif

24
nca.c
View file

@ -921,13 +921,13 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Allocate space for an extra (fake) relocation entry, to simplify our logic. */ /* Allocate space for an extra (fake) relocation entry, to simplify our logic. */
void *relocs = calloc(1, sb->relocation_header.size + sizeof(bktr_relocation_entry_t)); void *relocs = calloc(1, sb->relocation_header.size + (0x3FF0 / sizeof(uint64_t)) * sizeof(bktr_relocation_entry_t));
if (relocs == NULL) { if (relocs == NULL) {
fprintf(stderr, "Failed to allocate relocation header!\n"); fprintf(stderr, "Failed to allocate relocation header!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Allocate space for an extra (fake) subsection entry, to simplify our logic. */ /* Allocate space for an extra (fake) subsection entry, to simplify our logic. */
void *subs = calloc(1, sb->subsection_header.size + 2 * sizeof(bktr_subsection_entry_t)); void *subs = calloc(1, sb->subsection_header.size + (0x3FF0 / sizeof(uint64_t)) * sizeof(bktr_subsection_entry_t) + sizeof(bktr_subsection_entry_t));
if (subs == NULL) { if (subs == NULL) {
fprintf(stderr, "Failed to allocate subsection header!\n"); fprintf(stderr, "Failed to allocate subsection header!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -957,8 +957,24 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
} }
/* This simplifies logic greatly... */ /* This simplifies logic greatly... */
bktr_relocation_bucket_t *last_reloc_bucket = &ctx->bktr_ctx.relocation_block->buckets[ctx->bktr_ctx.relocation_block->num_buckets - 1]; for (unsigned int i = ctx->bktr_ctx.relocation_block->num_buckets - 1; i > 0; i--) {
bktr_subsection_bucket_t *last_subsec_bucket = &ctx->bktr_ctx.subsection_block->buckets[ctx->bktr_ctx.subsection_block->num_buckets - 1]; memcpy(bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, i), &ctx->bktr_ctx.relocation_block->buckets[i], sizeof(bktr_relocation_bucket_t));
}
for (unsigned int i = 0; i + 1 < ctx->bktr_ctx.relocation_block->num_buckets; i++) {
bktr_relocation_bucket_t *cur_bucket = bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, i);
cur_bucket->entries[cur_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->bucket_virtual_offsets[i + 1];
}
for (unsigned int i = ctx->bktr_ctx.subsection_block->num_buckets - 1; i > 0; i--) {
memcpy(bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i), &ctx->bktr_ctx.subsection_block->buckets[i], sizeof(bktr_subsection_bucket_t));
}
for (unsigned int i = 0; i + 1 < ctx->bktr_ctx.subsection_block->num_buckets; i++) {
bktr_subsection_bucket_t *cur_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i);
bktr_subsection_bucket_t *next_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i+1);
cur_bucket->entries[cur_bucket->num_entries].offset = next_bucket->entries[0].offset;
cur_bucket->entries[cur_bucket->num_entries].ctr_val = next_bucket->entries[0].ctr_val;
}
bktr_relocation_bucket_t *last_reloc_bucket = bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, ctx->bktr_ctx.relocation_block->num_buckets - 1);
bktr_subsection_bucket_t *last_subsec_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, ctx->bktr_ctx.subsection_block->num_buckets - 1);
last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->total_size; last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->total_size;
last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = sb->relocation_header.offset; last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = sb->relocation_header.offset;
last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = ctx->header->section_ctr_low; last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = ctx->header->section_ctr_low;