From 7020fe7156c0251a44844b64dce2a1b7f62c3462 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 20 Nov 2023 08:42:28 -0800 Subject: [PATCH] Fix corruption on some ELF input files (#17) --- tools/uf2/build.zig | 3 +- tools/uf2/src/uf2.zig | 121 +++++++++++++----------------------------- 2 files changed, 38 insertions(+), 86 deletions(-) diff --git a/tools/uf2/build.zig b/tools/uf2/build.zig index 85045b2..39f00e5 100644 --- a/tools/uf2/build.zig +++ b/tools/uf2/build.zig @@ -49,9 +49,10 @@ pub fn build(b: *std.Build) void { const main_tests = b.addTest(.{ .root_source_file = .{ .path = "src/uf2.zig" }, }); + const run_main_tests = b.addRunArtifact(main_tests); const test_step = b.step("test", "Run library tests"); - test_step.dependOn(&main_tests.step); + test_step.dependOn(&run_main_tests.step); const gen = b.addExecutable(.{ .name = "gen", diff --git a/tools/uf2/src/uf2.zig b/tools/uf2/src/uf2.zig index c5d17ad..9dfbc3b 100644 --- a/tools/uf2/src/uf2.zig +++ b/tools/uf2/src/uf2.zig @@ -73,99 +73,50 @@ pub const Archive = struct { std.sort.insertion(Segment, segments.items, {}, Segment.lessThan); // TODO: check for overlaps, assert no zero sized segments - var blocks = std.ArrayList(Block).init(self.allocator); - defer blocks.deinit(); - - const last_segment_end = last_segment_end: { - const last_segment = &segments.items[segments.items.len - 1]; - break :last_segment_end last_segment.addr + last_segment.size; - }; - - var segment_idx: usize = 0; - var addr = std.mem.alignBackward(u32, segments.items[0].addr, prog_page_size); - while (addr < last_segment_end and segment_idx < segments.items.len) { - const segment = &segments.items[segment_idx]; - const segment_end = segment.addr + segment.size; - - // if the last segment is not full, then there was a partial write - // of the end of the last segment, and we've started processing a - // new segment - if (blocks.items.len > 0 and blocks.items[blocks.items.len - 1].payload_size != prog_page_size) { - const block = &blocks.items[blocks.items.len - 1]; - assert(segment.addr >= block.target_addr); - const block_end = block.target_addr + prog_page_size; - - if (segment.addr < block_end) { - const n_bytes = @min(segment.size, block_end - segment.addr); - try file.seekTo(segment.file_offset); - const block_offset = segment.addr - block.target_addr; - const n_read = try file.reader().readAll(block.data[block_offset .. block_offset + n_bytes]); - if (n_read != n_bytes) - return error.ExpectedMoreElf; - - addr += n_bytes; - block.payload_size += n_bytes; - - // in this case the segment can fit in the page and there - // is room for an additional segment - if (block.payload_size < prog_page_size) { - segment_idx += 1; - continue; - } - } else { - block.payload_size = prog_page_size; - addr = std.mem.alignBackward(u32, segment.addr, prog_page_size); + var first = true; + for (segments.items) |segment| { + var segment_offset: u32 = 0; + while (segment_offset < segment.size) { + const addr = segment.addr + segment_offset; + if (first or addr >= self.blocks.items[self.blocks.items.len - 1].target_addr + prog_page_size) { + try self.blocks.append(.{ + .flags = .{ + .not_main_flash = false, + .file_container = false, + .family_id_present = opts.family_id != null, + .md5_checksum_present = false, + .extension_tags_present = false, + }, + .target_addr = std.mem.alignBackward(u32, addr, prog_page_size), + .payload_size = 0, + .block_number = undefined, + .total_blocks = undefined, + .file_size_or_family_id = .{ + .family_id = if (opts.family_id) |family_id| + family_id + else + @as(FamilyId, @enumFromInt(0)), + }, + .data = .{0} ** 476, + }); + first = false; } - } - try blocks.append(.{ - .flags = .{ - .not_main_flash = false, - .file_container = false, - .family_id_present = opts.family_id != null, - .md5_checksum_present = false, - .extension_tags_present = false, - }, - .target_addr = addr, - .payload_size = @min(prog_page_size, segment_end - addr), - .block_number = undefined, - .total_blocks = undefined, - .file_size_or_family_id = .{ - .family_id = if (opts.family_id) |family_id| - family_id - else - @as(FamilyId, @enumFromInt(0)), - }, - .data = std.mem.zeroes([476]u8), - }); - - const block = &blocks.items[blocks.items.len - 1]; + const block = &self.blocks.items[self.blocks.items.len - 1]; + const block_offset = addr - block.target_addr; + const n_bytes = @min(prog_page_size - block_offset, segment.size - segment_offset); - // in the case where padding is prepended to the block - if (addr < segment.addr) - addr = segment.addr; + try file.seekTo(segment.file_offset + segment_offset); + try file.reader().readNoEof(block.data[block_offset..][0..n_bytes]); - const n_bytes = (block.target_addr + block.payload_size) - addr; - assert(n_bytes <= prog_page_size); - - try file.seekTo(segment.file_offset + addr - segment.addr); - const block_offset = addr - block.target_addr; - const n_read = try file.reader().readAll(block.data[block_offset .. block_offset + n_bytes]); - if (n_read != n_bytes) - return error.ExpectedMoreElf; - - addr += n_bytes; - - assert(addr <= segment_end); - if (addr == segment_end) - segment_idx += 1; + segment_offset += n_bytes; + block.payload_size = block_offset + n_bytes; + } } // pad last page with zeros - if (blocks.items.len > 0) - blocks.items[blocks.items.len - 1].payload_size = prog_page_size; + if (!first) self.blocks.items[self.blocks.items.len - 1].payload_size = prog_page_size; - try self.blocks.appendSlice(blocks.items); if (opts.bundle_source) @panic("TODO: bundle source in UF2 file"); }