Repository navigation
Commit a530693
authored
Add Mach-O support (#50)
* Add test fixtures for Mach-O support
LibObjectFile has no Mach-O test inputs. Adds committed fixtures covering the variants an implementation has to handle: 32- and 64-bit, LC_UNIXTHREAD and LC_MAIN entry points, dyld info opcode streams and chained fixups, a dylib, an object file with relocations, and a universal binary.
Both 32-bit fixtures are synthesized with yaml2obj because LLVM and current cctools have dropped 32-bit Mach-O linking, so neither the LC_UNIXTHREAD nor the LC_MAIN-with-dyld-info shape can come from a linker any more. The sources call into libc so the linked fixtures carry lazy-binding stubs and an indirect symbol table, and the fixtures keep the padding after the load commands that in-place injection consumes.
- src/LibObjectFile.Tests/MachO/generate_files.sh: regenerates the fixtures via OSXCross cctools and LLVM, and links to where OSXCross comes from
- src/LibObjectFile.Tests/MachO/unixthread_i386_rpath: the same input after install_name_tool adds a runpath, used as an encoding reference
- src/LibObjectFile.Tests/LibObjectFile.Tests.csproj: copies the fixtures to the test output
* Add Mach-O format constants and raw structures
Nothing in the library described the Mach-O format, so there was no vocabulary to write a reader against. Adds the load command, CPU, file type, header flag, segment, section, platform and relocation type enumerations, the packed version helpers, and the blittable structures matching the on-disk layout.
The structures are hand-written rather than generated from Apple's headers, whose licence this project cannot bundle, which follows what the PE support already does. A test pins every structure size, because the fields are copied by value and a wrong size would shift every later field rather than fail outright.
- src/LibObjectFile/MachO/MachOLoadCommandType.cs: keeps the LC_REQ_DYLD high bit as part of the stored value
- src/LibObjectFile/MachO/MachORelocation.cs: the two forms of entry, told apart by the top bit of the first word
- src/LibObjectFile/MachO/Internal: the on-disk structures, including the always big-endian universal binary header
* Add Mach-O object model and reader
The format constants had nothing to build on, so a Mach-O image could not be turned into anything inspectable. Adds the file, segment, section and load command model, and a reader that walks the command table and decodes every command an image of these architectures carries. Anything unrecognised is kept as raw bytes, so images from a newer linker still load.
Everything in the file becomes an ordered content list: the header, the load command table, the padding after it, the bytes of each section, each table in __LINKEDIT, and the gaps between them. Every byte belongs to an element, which is what makes writing the list back reproduce the image and a layout a single walk over it.
Content carrying an address is pinned, because a section's address is its segment's address plus its distance from the segment's file offset, so moving it in the file would move it in memory. Padding is kept as the bytes that were read rather than regenerated, since a linker pads executable sections with nop and zero-filling would leave a different instruction somewhere reachable.
- src/LibObjectFile/MachO/MachOFile.Read.cs: turns the file into content, leaving nothing implicit
- src/LibObjectFile/MachO/Content: the element types, and which of them a layout may move
- src/LibObjectFile/MachO/MachOPathLoadCommand.cs: keeps the linker's own padding on the commands carrying a string
* Add Mach-O writer
Reading an image was of no use without being able to write one back. Adds the write path, which lays the content out and then writes each element at its position.
Only the header, the load command table and the padding after it are placed by that layout; everything else keeps the position recorded for it, because moving content in a Mach-O moves the addresses that refer to it. The padding is what absorbs a command table that has grown, so writing fails when the commands no longer fit rather than moving content and invalidating the image.
- src/LibObjectFile/MachO/MachOFile.Write.cs: writes the content list
- src/LibObjectFile.Tests/MachO/MachOSimpleTests.cs: byte-exact round-trip per fixture, and every recorded file offset being reachable
* Add Mach-O verification
Every other backend implements Verify, twenty-four types between ELF and PE, and Mach-O implemented none of it, so nothing checked the invariant the format rests on: a section's address is its segment's address plus its distance from the segment's file offset. Break that and the loader maps a section somewhere other than where the code expects, which no round-trip test would notice because the bytes still match.
Checks that relationship, that sections stay inside their segment, that a section header agrees with the content holding its bytes, that the content list covers the file with no gap or overlap, and that load command sizes are walkable by dyld. Seventy-five real images pass it.
- src/LibObjectFile/MachO/MachOFile.Verify.cs: the checks
* Add address-preserving load command injection to Mach-O
There was no way to add a dependency or a runpath to an existing Mach-O image, which is what makes a shipped binary load a library it was not linked against. Adds the operations install_name_tool offers, appending commands into the padding the linker left ahead of the first section so no content moves and every address in the image stays valid.
A dependency is appended rather than inserted, because dyld identifies a library by its position among the load commands and the symbol table binds against that number. When the padding runs out the edit throws and names the shortfall, since the alternative is moving content and invalidating the image. Removing a dependency is deliberately not offered for the same numbering reason, matching what install_name_tool exposes.
- src/LibObjectFile/MachO/MachOFile.Edit.cs: the add, change and remove operations and the space check
- src/LibObjectFile.Tests/MachO/MachOEditingTests.cs: compares against the install_name_tool reference fixture, and asserts no section moves
* Add ad-hoc code signing for Mach-O images
Apple Silicon refuses to execute an unsigned image, and any edit invalidates an existing signature, so an arm64 binary could be modified by this library only to become unrunnable. Adds ad-hoc signing: a code directory of SHA-256 page digests plus an empty requirement set, appended to __LINKEDIT with the load command added when the image was previously unsigned.
The signature covers exactly the bytes preceding it, so its size is derived from the identifier and the signed length before any digest is taken, and the image is laid out once and then hashed as it will finally be written.
Signing has to be the last thing done, since editing afterwards leaves the digests covering bytes that are no longer there. The editing operations record that, and writing fails while it is set, so the library cannot hand back a file that looks signed and would be refused at execution.
- src/LibObjectFile/MachO/CodeSign/MachOAdHocSignatureBuilder.cs: builds the superblob, which is big-endian throughout unlike the rest of the format
- src/LibObjectFile/MachO/MachOFile.Sign.cs: appends the signature as content and grows __LINKEDIT to cover it
- src/LibObjectFile.Tests/MachO/MachOSigningTests.cs: recomputes every page digest from the written image, which is the property the kernel checks
* Add Mach-O symbol table and relocation reading
The symbol table, the indirect symbol table and the relocations of a section were bytes that nothing decoded, so there was no way to see what an image defines, imports or fixes up. Adds reading for all three, resolving symbol names against the string table and separating the four things a symbol's type byte packs together.
An object file keeps its tables past the end of its only segment, so the lookup covers that as well as a linked image's __LINKEDIT. The result is a decoded snapshot rather than a live view, and the documentation says so, because resizing a table would move everything after it.
Relocations come in two forms sharing eight bytes, told apart by the top bit of the first word. Encoding is implemented alongside decoding and tested to round-trip, because a field read from the wrong bit still reads back consistently on its own and would otherwise look correct.
- src/LibObjectFile/MachO/MachOSymbol.cs: separates the debug, external and kind bits of the type byte
- src/LibObjectFile/MachO/MachOFile.Symbols.cs: reads both symbol tables, from a segment or from the bytes past one
- src/LibObjectFile/MachO/MachOFile.Relocations.cs: reads the entries a section points at
* Add Mach-O universal binary support
A universal binary could not be read at all, so an image shipping for both Intel and Apple Silicon was out of reach even though each slice inside it was already readable. Adds reading and writing of the container, exposing one image per architecture.
The header and its slice table are big-endian whatever the architectures inside are, which is the one place the format departs from the image's own byte order, so they are read through explicit big-endian primitives rather than by copying a structure. Each slice is read through a view bounded to it, so a malformed slice cannot reach into its neighbours.
The slices are laid out before writing, so one that changed size since it was read is placed and recorded correctly rather than overrunning the one after it. The space between them is left zeroed: every universal binary examined pads with zeros, and slices are page aligned rather than packed.
- src/LibObjectFile/MachO/MachOFatFile.cs: the container, its slice table and the bounded reads
- src/LibObjectFile/MachO/MachOFatSlice.cs: one architecture's placement and image
* Add otool-style printing for Mach-O images
A decoded image could only be inspected through a debugger. Adds printing of the header and every load command, and snapshots the result for each fixture, so decoding a new command extends the snapshot rather than needing another test and a change to how anything is read shows up as a diff.
Commands are named by their LC_ spelling rather than the enumeration's, so output can be read next to otool's. That mapping is written out rather than derived from the enumeration names, because several do not follow from them: LC_UNIXTHREAD is one word and LC_VERSION_MIN_MACOSX breaks in places the casing does not. The command sequence each fixture prints was checked against otool before the snapshots were taken.
- src/LibObjectFile/MachO/MachOPrinter.cs: the printer
- src/LibObjectFile.Tests/Verified: one snapshot per fixture
* Add doc for the Mach-O API
The readme listed Mach-O among the formats left for contributors, and the manual did not mention it. Adds it to both, following how the other formats are covered: a feature list in the readme and a section in the manual with an overview, reading, writing, editing and signing.
The overview states the relationship a caller has to know about, that a section's address is its segment's address plus the section's distance from the segment's file offset, since that is what decides which parts of an image a layout may move and why adding a load command is bounded by the padding the linker left.
- readme.md: Mach-O added to the supported formats and dropped from the longer term plan
- doc/readme.md: the manual section
* Add doc for Gatekeeper and bundle sealing
The signing section said an ad-hoc signature is what lets an edited arm64 image run, which is true of the kernel and not of Gatekeeper. A reader could reasonably take it to mean a signed bundle will launch, and then find that a downloaded one is refused whatever this library did to it.
Says what an ad-hoc signature does not buy: no Developer ID, no notarization, and no way back to notarized once it is replaced. Also that signing one image is not sealing a bundle, and which of the two is at stake depends on what was edited. A bundle's main executable is not listed in the seal, so re-signing it leaves the seal correct, while nested code is listed by hash and editing it does not.
- doc/readme.md: Gatekeeper, and sealing a bundle, under code signing
* Bound Mach-O load command reads to their declared size
The header's sizeofcmds was ignored and each command was bounded only by the whole stream, so a command declaring a cmdsize too small for its own fields still read them, taking bytes that belong to whatever follows. A count-bearing command could do the same: a segment claiming more sections than fit, or a build version claiming more tools, read section headers and tool entries out of the commands after it.
The table is now bounded by sizeofcmds and has to end exactly there, each command is checked against the size its fixed part needs before it is read, and a command that reads past its own cmdsize is reported rather than trusted. The counts inside segments and build versions are checked against the space the command declares.
Also states what file offset remapping covers, since the contract claimed every recorded offset and did not include a section's relocations. Those are now mapped. Placement is deliberately excluded and says why: a segment's or a section's file offset is where something is mapped, not merely stored, so moving it moves the thing in memory.
The remapping test read offsets back through the same walk it was testing, which made an omitted field invisible to it. It now reads them off the commands directly, and fails if the walk misses one.
- src/LibObjectFile/MachO/MachOFile.Read.cs: the bounded walk
- src/LibObjectFile/MachO/MachOLoadCommand.cs: the smallest cmdsize each kind can legally have
- src/LibObjectFile/MachO/MachOSegment.cs: section counts bounded, section relocations remapped
* Follow the established write pipeline for Mach-O
Writing did not verify and did not flush, so a model that Verify rejects could still be emitted, and a buffered stream could be left holding the tail of the file. ELF and PE both run Verify, then the layout, then the write, then flush.
TryWrite now does the same, and the universal binary container flushes once its slices are written.
Wiring Verify in exposed a hole signing was leaving. Aligning the signature to sixteen bytes can leave a gap before it, and nothing occupied that gap, so the content list no longer covered every byte of the file. The gap is now content like any other rather than a hole the writer happened to skip over.
- src/LibObjectFile/MachO/MachOFile.Write.cs: verify, lay out, write, flush
- src/LibObjectFile/MachO/MachOFile.Sign.cs: the alignment gap before a signature is content
- src/LibObjectFile/MachO/MachOFatFile.cs: flush after the slices
* Make Mach-O load command edits atomic on failure
The edits assigned before they checked. ChangeDylibName and SetInstallName wrote the new name and only then asked whether it fits, so an edit that did not fit left the command renamed but not resized, describing a string longer than it has room for. AppendCommand marked the signature stale before finding out the command would not fit, so a failed edit left the image unable to be written until it was signed again.
Each now works out what the change costs, checks there is room, and only then makes it, so a failure leaves the image exactly as it was.
- src/LibObjectFile/MachO/MachOFile.Edit.cs: validate, then mutate
- src/LibObjectFile.Tests/MachO/MachOEditingTests.cs: a failed rename leaves names, sizes and the written bytes untouched
* Document why an ad-hoc signature keeps an empty CMS slot
The empty CMS wrapper looked like it might not belong, since the linker-produced fixture here carries only a code directory. A linker writes a lone code directory flagged LINKER_SIGNED, which is a different thing from what signing a finished image produces: codesign writes a code directory, a twelve byte empty requirement set and an eight byte empty CMS wrapper, which is what a shipping ad-hoc signed dylib contains and what this writes.
Says so where the wrapper is written, and checks the sizes of all three blobs rather than only their count.
- src/LibObjectFile/MachO/CodeSign/MachOAdHocSignatureBuilder.cs: why the slot is present and empty
* Bound the remaining reads sized by untrusted counts
Reviewing the load command bounds turned up three more of the same kind elsewhere.
A symbol, indirect symbol or relocation count was multiplied by an entry size in 32-bit arithmetic. A count large enough to wrap that product gave a small, plausible length that passed the coverage check, and the loop then read past what had been read. Those products are now computed in 64 bits, so the wrap cannot happen and an impossible length is reported instead. The symbol table count reached the caller as an ArgumentOutOfRangeException rather than a diagnostic.
A universal binary header's slice count was used to size an allocation before anything checked the file was big enough to hold that many. It is now checked against the bytes actually there.
Signing changed a good deal before it could fail: it removed the previous signature's content, moved the command, resized __LINKEDIT and cleared the stale flag, then wrote the image to take the digests, and that write can fail. What it changes is now put back if it does, so a failed signing leaves the image exactly as it was rather than half signed.
- src/LibObjectFile/MachO/MachOFile.Symbols.cs: lengths computed in 64 bits
- src/LibObjectFile/MachO/MachOFatFile.cs: the slice count checked before it sizes anything
- src/LibObjectFile/MachO/MachOFile.Sign.cs: signing restores what it changed if it fails
* Derive load command count bounds without multiplying
The count checks added with the previous bounds could be walked around by the arithmetic in the checks themselves. A segment declaring 0x40000001 sections multiplies out to 124 in 32 bits, the size of the command being checked, so the check passed and the section headers were read out of the commands after it. A build version declaring 0x20000000 tools multiplies out to nothing at all.
The largest count that fits is now derived by division, so there is no product to wrap. ComputeCommandSize computes wide and rejects a count that would not fit rather than returning a wrapped size, since it is public and a caller can reach it directly.
The same widening was missing where the reader gathers the regions the commands point at: those sizes were counts times an entry size in 32-bit arithmetic, so a wrapped product would have named a small region and left the rest of the table looking like padding.
- src/LibObjectFile/MachO/MachOSegment.cs: section count derived by division, command size computed wide
- src/LibObjectFile/MachO/MachOBuildVersionCommand.cs: tool count derived by division
- src/LibObjectFile/MachO/MachOFile.Read.cs: region sizes computed wide
- src/LibObjectFile.Tests/MachO/MachOSimpleTests.cs: the two overflow counts, which fail against the multiplying checks
* Refactor Mach-O diagnostic ids to match their use sites
MACHO_ERR_InvalidSegmentFileRange was minted with the rest of the block before
the readers existed and was never raised. Give 5004 the condition that had been
borrowing MACHO_ERR_ValueTooLargeFor32Bit: a segment whose width does not match
the image it sits in is not a value that failed to fit a field.
MACHO_ERR_InvalidSectionFileRange is raised from CollectKnownRegions for every
content region, so name it after what it checks.
* Add verify and try-write to the Mach-O universal binary
MachOFatFile was the one writable type in the library with no Verify and no
TryWrite, so a malformed universal binary was written out rather than reported
and a slice failure surfaced as an exception from the middle of a write.
Verify covers what only the containing file can see: slices overlapping each
other or the table they are listed in, an offset off the slice's own alignment,
a duplicate architecture, and a slice a 32-bit table cannot record. That last
one guarded the casts in the writer, which silently truncated.
Slices are now laid out before the containing file is placed, since the size
recorded for a slice has to be the size that slice goes on to write, and they
write through a writer sharing one diagnostic bag.
The reader also rejects an alignment exponent past 63. A shift count is masked
to the width of what it shifts, so a larger one aliased to a different alignment
instead of being caught.
* Fix Mach-O TryRead throwing instead of reporting on short input
The magic was the one read in the walk taken without a bound, so a stream of
fewer than four bytes left TryRead as an EndOfStreamException rather than false
plus diagnostics. MachOFatFile reached the same escape through a slice sized
zero, which passed the range check and was then descended into. ELF and PE both
report on the same input, so this was Mach-O being the outlier.
The magic is now read through the bounded primitive the rest of the header
already used, a slice too short to hold a header is rejected before it is read,
and TryRead converts an EndOfStreamException into a diagnostic so that a bound
missed at any of the sites that check one by hand cannot break the contract.
Fuzzing truncations and bit flips over the fixtures escaped six times before
this and none after.
* Add Mach-O API parity with the other file types
ElfFile and ArArchiveFile both offer a parameterless Verify returning the bag,
which is the shape a caller wants when it has nothing to merge into. Mach-O
only had the overload taking one.
AddLoadDylib took the command type as an optional parameter. AGENTS.md prefers
overloads for binary compatibility, so it is now two methods.
* Fix unchecked size arithmetic on the Mach-O write path
The earlier overflow work bounded the counts the reader trusts. The same class
was still live on the layout side, where the values come from the model rather
than the file.
SizeOfCommands accumulated into a uint, so a command table past 4GB wrapped to a
small number. AvailableLoadCommandSpace is derived from it and gates every edit,
so the wrap offered room that did not exist. It now totals wide and saturates,
which leaves the space negative rather than plausible, and Verify reports it.
LoadCommandsEndOffset becomes a file offset like ContentStartOffset beside it,
since adding the header size to a saturated total wrapped again.
AdHocSign cast the image size down to the 32-bit offset LC_CODE_SIGNATURE
records, which for an image past 4GB pointed the signature back into the image.
It now refuses, which is already what its documented failures do.
The header test asserted HeaderSize + SizeOfCommands == LoadCommandsEndOffset,
which restates the definition of the property. It now checks the decoded table
against the ncmds and sizeofcmds the file actually carries.
* Fix test coverage that could pass without checking anything
The i386 fixture declared two symbols but carried no bytes for them, so every
field decoded as zero and any bug in the 32-bit nlist path would have produced
the same result as a correct read. The fixture now carries a real text and data
symbol, which llvm-nm agrees with, and the symbol test asserts against them.
yaml2obj emits a two byte export trie ahead of the tables it generates, so
LC_DYLD_INFO_ONLY now records that trie rather than leaving the bytes
unexplained, and LC_SYMTAB points past it.
The space exhaustion test filled until fewer than 120 bytes were left, then
expected a command costing about 116 to fail. Whether it did depended on the
padding the fill happened to stop on. It now asks for a path longer than the
space that is actually left.
arm64 reads symbols through the same 64-bit path as x86_64, so it is covered
against the fixture rather than as a separate decode.
* Update doc for the Mach-O editing and write surface
SetInstallName and RemoveRPath were implemented but absent from the editing
section, and the feature list claimed all load commands are decoded in the same
breath as saying the unmodelled ones round-trip verbatim.
The write section now covers TryWrite and the universal binary, and records why
the reader insists the commands end exactly at sizeofcmds where dyld tolerates
slack after them.
generate_files.sh discovers the SDK instead of naming a version, and records the
toolchain the committed fixtures came out of, since a different one will move
offsets and show up as a diff worth reading rather than accepting.
* Fix test fixtures being copied to output by a wildcard
The glob excluded MachO\*.c, which does not match MachO\*.cs, so the four test
sources were copied to the output directory alongside the fixtures. Listing the
fixtures the way the ELF and PE ones are listed states which files are inputs
instead of inferring it from an exclusion that has to stay in step.
* Fix the SuperBlob length covering its alignment padding
The signature is rounded up to a 16 byte boundary, and the SuperBlob header was
given that rounded size as its own length. The length field describes the blob,
not the room reserved for it: Apple's codesign writes the offset one past the
last blob and leaves the slack to the load command's datasize, which is how it
reports the value back.
Verified against macOS 13.7.6. codesign -s - on the same input produces a
SuperBlob of 322 bytes over three slots, and after this change so does
AdHocSign, with matching slot offsets and lengths.
* Fix Verify rejecting relocatable object files
The section address invariant holds for a linked image, where a section's
address is its segment's address plus its distance from the segment's file
offset. An object file keeps its sections in one unnamed segment with addresses
the linker has still to assign, so they do not track file offsets at all.
Apple's own crt1.o and lazydylib1.o from the MacOSX14 SDK were rejected by it
despite reading and round-tripping byte for byte.
The committed object fixture satisfies the invariant by chance, its sections
being packed in the same order as their offsets, so the test makes the case
rather than relying on finding it.
* Improve the diagnostic for an ar archive read as a Mach-O image
A universal static library is a fat file whose slices are ar archives rather
than images, so reading one arrived at "Invalid Mach-O magic 0x72613C21". That
is the ar magic, and the library can read it through ArArchiveFile, so say so.
Found running the SDK's static libraries through the reader.
* Fix the fat slice alignment bound being looser than the format allows
The bound was 63, which is where a shift count stops being well defined rather
than where a universal binary stops being valid. lipo refuses anything past
2^15, reporting that -segalign "must be equal to or less than 8000 (hex)",
which matches MAXSECTALIGN in cctools. At 63 we would have accepted and written
fat files Apple's own tools reject. Checked against lipo on macOS 13.7.6.
* Update doc for why object files skip the section address check
The exemption cited the fixture that exposed it rather than the rule. loader.h
states it directly: non-MH_OBJECT files have their sections padded to the
segment alignment, while MH_OBJECT keeps all sections in one segment for
compactness with no padding to a segment boundary.
* Fix __LINKEDIT ending mid-page after signing
Signing grew __LINKEDIT to cover the signature but only to exactly that size.
A segment is sized in whole units of the segment alignment, and codesign rounds
it up: signing the 8MB i386 KOTOR binary with Apple's tool takes __LINKEDIT
from 0x30D000 to 0x32C000, where we produced 0x31CB00.
It was not visible in the fixtures because their signature fits in the slack
the linker already left. A real image does not: that binary has 0x7CC spare and
the signature is about 65KB.
loader.h calls the value "the specified segment alignment" and leaves it to the
link editor, so it comes from what the toolchain does. Signing an arm64 image
rounds 0x4A50 to 0x8000, which only 16KB explains, while the linker's own x86
and x86_64 images carry sizes such as 0x30D000 that are not 16KB multiples.
Checked on macOS 13.7.6: both arm64 images pass codesign --verify --strict.1 parent e864861 commit a530693
115 files changed
Lines changed: 9916 additions & 1 deletion
File tree
- doc
- src
- LibObjectFile.Tests
- MachO
- Verified
- LibObjectFile
- Diagnostics
- MachO
- CodeSign
- Content
- Internal
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
545 | 546 | | |
546 | 547 | | |
547 | 548 | | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
57 | 68 | | |
58 | 69 | | |
59 | 70 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
28 | 37 | | |
29 | 38 | | |
30 | 39 | | |
| |||
84 | 93 | | |
85 | 94 | | |
86 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
87 | 125 | | |
88 | 126 | | |
89 | 127 | | |
| |||
0 commit comments