gimli-0.19.0/.gitignore010066400017500001750000000000271343337721300131220ustar0000000000000000target Cargo.lock *.bk gimli-0.19.0/CHANGELOG.md010066400017500001750000000455121351057326000127470ustar0000000000000000# `gimli` Change Log -------------------------------------------------------------------------------- ## 0.19.0 Released 2019/07/08. ### Breaking changes * Small API changes related to `.debug_loc` and `.debug_loclists`: added `read::RawLocListEntry::AddressOrOffsetPair` enum variant, added `write::Sections::debug_loc/debug_loclists` public members, and replaced `write::AttributeValue::LocationListsRef` with `LocationListRef`. [#425](https://github.com/gimli-rs/gimli/pull/425) ### Added * Added `read::Attribute::exprloc_value` and `read::AttributeValue::exprloc_value`. [#422](https://github.com/gimli-rs/gimli/pull/422) * Added support for writing `.debug_loc` and `.debug_loclists` sections. [#425](https://github.com/gimli-rs/gimli/pull/425) * Added `-G` flag to `dwarfdump` example to display global offsets. [#427](https://github.com/gimli-rs/gimli/pull/427) * Added `examples/simple.rs`. [#429](https://github.com/gimli-rs/gimli/pull/429) ### Fixed * `write::LineProgram::from` no longer requires `DW_AT_name` or `DW_AT_comp_dir` attributes to be present in the unit DIE. [#430](https://github.com/gimli-rs/gimli/pull/430) -------------------------------------------------------------------------------- ## 0.18.0 Released 2019/04/25. The focus of this release has been on improving support for reading CFI, and adding support for writing CFI. ### Breaking changes * For types which have an `Offset` type parameter, the default `Offset` has changed from `usize` to `R::Offset`. [#392](https://github.com/gimli-rs/gimli/pull/392) * Added an `Offset` type parameter to the `read::Unit` type to allow variance. [#393](https://github.com/gimli-rs/gimli/pull/393) * Changed the `UninitializedUnwindContext::initialize` method to borrow `self`, and return `&mut UnwindContext`. Deleted the `InitializedUnwindContext` type. [#395](https://github.com/gimli-rs/gimli/pull/395) * Deleted the `UnwindSection` type parameters from the `CommonInformationEntry`, `FrameDescriptionEntry`, `UninitializedUnwindContext`, `UnwindContext`, and `UnwindTable` types. [#399](https://github.com/gimli-rs/gimli/pull/399) * Changed the signature of the `get_cie` callback parameter for various functions. The signature now matches the `UnwindSection::cie_from_offset` method, so that method can be used as the parameter. [#400](https://github.com/gimli-rs/gimli/pull/400) * Reduced the number of lifetime parameters for the `UnwindTable` type. [#400](https://github.com/gimli-rs/gimli/pull/400) * Updated `fallible-iterator` to version 0.2.0. [#407](https://github.com/gimli-rs/gimli/pull/407) * Added a parameter to the `Error::UnexpectedEof` enum variant. [#408](https://github.com/gimli-rs/gimli/pull/408) ### Added * Update to 2018 edition. [#391](https://github.com/gimli-rs/gimli/pull/391) * Added the `FrameDescriptionEntry::unwind_info_for_address` method. [#396](https://github.com/gimli-rs/gimli/pull/396) * Added the `FrameDescriptionEntry::rows` method. [#396](https://github.com/gimli-rs/gimli/pull/396) * Added the `EhHdrTable::unwind_info_for_address` method. [#400](https://github.com/gimli-rs/gimli/pull/400) * Added the `EhHdrTable::fde_for_address` method and deprecated the `EhHdrTable::lookup_and_parse` method. [#400](https://github.com/gimli-rs/gimli/pull/400) * Added the `EhHdrTable::pointer_to_offset` method. [#400](https://github.com/gimli-rs/gimli/pull/400) * Added the `UnwindSection::fde_for_address` method. [#396](https://github.com/gimli-rs/gimli/pull/396) * Added the `UnwindSection::fde_from_offset` method. [#400](https://github.com/gimli-rs/gimli/pull/400) * Added the `UnwindSection::partial_fde_from_offset` method. [#400](https://github.com/gimli-rs/gimli/pull/400) * Added the `Section::id` method. [#406](https://github.com/gimli-rs/gimli/pull/406) * Added the `Dwarf::load` method, and corresponding methods for individual sections. [#406](https://github.com/gimli-rs/gimli/pull/406) * Added the `Dwarf::borrow` method, and corresponding methods for individual sections. [#406](https://github.com/gimli-rs/gimli/pull/406) * Added the `Dwarf::format_error` method. [#408](https://github.com/gimli-rs/gimli/pull/408) * Added the `Dwarf::die_ranges` method. [#417](https://github.com/gimli-rs/gimli/pull/417) * Added the `Dwarf::unit_ranges` method. [#417](https://github.com/gimli-rs/gimli/pull/417) * Added support for writing `.debug_frame` and `.eh_frame` sections. [#412](https://github.com/gimli-rs/gimli/pull/412) [#419](https://github.com/gimli-rs/gimli/pull/419) ### Fixed * The `code_alignment_factor` is now used when evaluting CFI instructions that advance the location. [#401](https://github.com/gimli-rs/gimli/pull/401) * Fixed parsing of pointers encoded with `DW_EH_PE_funcrel`. [#402](https://github.com/gimli-rs/gimli/pull/402) * Use the FDE address encoding from the augmentation when parsing `DW_CFA_set_loc`. [#403](https://github.com/gimli-rs/gimli/pull/403) * Fixed setting of `.eh_frame` base addresses in dwarfdump. [#410](https://github.com/gimli-rs/gimli/pull/410) ## 0.17.0 Released 2019/02/21. The focus of this release has been on improving DWARF 5 support, and adding support for writing DWARF. ### Breaking changes * Changed register values to a `Register` type instead of `u8`/`u64`. [#328](https://github.com/gimli-rs/gimli/pull/328) * Replaced `BaseAddresses::set_cfi` with `set_eh_frame_hdr` and `set_eh_frame`. Replaced `BaseAddresses::set_data` with `set_got`. You should now use the same `BaseAddresses` value for parsing both `.eh_frame` and `.eh_frame_hdr`. [#351](https://github.com/gimli-rs/gimli/pull/351) * Renamed many types and functions related to `.debug_line`. Renamed `LineNumberProgram` to `LineProgram`. Renamed `IncompleteLineNumberProgram` to `IncompleteLineProgram`. Renamed `CompleteLineNumberProgram` to `CompleteLineProgram`. Renamed `LineNumberProgramHeader` to `LineProgramHeader`. Renamed `LineNumberRow` to `LineRow`. Renamed `StateMachine` to `LineRows`. Renamed `Opcode` to `LineInstruction`. Renamed `OpcodesIter` to `LineInstructions`. Renamed `LineNumberSequence` to `LineSequence`. [#359](https://github.com/gimli-rs/gimli/pull/359) * Added `Offset` type parameter to `AttributeValue`, `LineProgram`, `IncompleteLineProgram`, `CompleteLineProgram`, `LineRows`, `LineInstruction`, and `FileEntry`. [#324](https://github.com/gimli-rs/gimli/pull/324) * Changed `FileEntry::path_name`, `FileEntry::directory`, and `LineProgramHeader::directory` to return an `AttributeValue` instead of a `Reader`. [#366](https://github.com/gimli-rs/gimli/pull/366) * Renamed `FileEntry::last_modification` to `FileEntry::timestamp` and renamed `FileEntry::length` to `FileEntry::size`. [#366](https://github.com/gimli-rs/gimli/pull/366) * Added an `Encoding` type. Changed many functions that previously accepted `Format`, version or address size parameters to accept an `Encoding` parameter instead. Notable changes are `LocationLists::locations`, `RangeLists::ranges`, and `Expression::evaluation`. [#364](https://github.com/gimli-rs/gimli/pull/364) * Changed return type of `LocationLists::new` and `RangeLists::new`. [#370](https://github.com/gimli-rs/gimli/pull/370) * Added parameters to `LocationsLists::locations` and `RangeLists::ranges` to support `.debug_addr`. [#358](https://github.com/gimli-rs/gimli/pull/358) * Added more `AttributeValue` variants: `DebugAddrBase`, `DebugAddrIndex`, `DebugLocListsBase`, `DebugLocListsIndex`, `DebugRngListsBase`, `DebugRngListsIndex`, `DebugStrOffsetsBase`, `DebugStrOffsetsIndex`, `DebugLineStrRef`. [#358](https://github.com/gimli-rs/gimli/pull/358) * Changed `AttributeValue::Data*` attributes to native endian integers instead of byte arrays. [#365](https://github.com/gimli-rs/gimli/pull/365) * Replaced `EvaluationResult::TextBase` with `EvaluationResult::RequiresRelocatedAddress`. The handling of `TextBase` was incorrect. [#335](https://github.com/gimli-rs/gimli/pull/335) * Added `EvaluationResult::IndexedAddress` for operations that require an address from `.debug_addr`. [#358](https://github.com/gimli-rs/gimli/pull/358) * Added `Reader::read_slice`. Added a default implementation of `Reader::read_u8_array` which uses this. [#358](https://github.com/gimli-rs/gimli/pull/358) ### Added * Added initial support for writing DWARF. This is targeted at supporting line number information only. [#340](https://github.com/gimli-rs/gimli/pull/340) [#344](https://github.com/gimli-rs/gimli/pull/344) [#346](https://github.com/gimli-rs/gimli/pull/346) [#361](https://github.com/gimli-rs/gimli/pull/361) [#362](https://github.com/gimli-rs/gimli/pull/362) [#365](https://github.com/gimli-rs/gimli/pull/365) [#368](https://github.com/gimli-rs/gimli/pull/368) [#382](https://github.com/gimli-rs/gimli/pull/382) * Added `read` and `write` Cargo features. Both are enabled by default. [#343](https://github.com/gimli-rs/gimli/pull/343) * Added support for reading DWARF 5 `.debug_line` and `.debug_line_str` sections. [#366](https://github.com/gimli-rs/gimli/pull/366) * Added support for reading DWARF 5 `.debug_str_offsets` sections, including parsing `DW_FORM_strx*` attributes. [#358](https://github.com/gimli-rs/gimli/pull/358) * Added support for reading DWARF 5 `.debug_addr` sections, including parsing `DW_FORM_addrx*` attributes and evaluating `DW_OP_addrx` and `DW_OP_constx` operations. [#358](https://github.com/gimli-rs/gimli/pull/358) * Added support for reading DWARF 5 indexed addresses and offsets in `.debug_loclists` and `.debug_rnglists`, including parsing `DW_FORM_rnglistx` and `DW_FORM_loclistx` attributes. [#358](https://github.com/gimli-rs/gimli/pull/358) * Added high level `Dwarf` and `Unit` types. Existing code does not need to switch to using these types, but doing so will make DWARF 5 support simpler. [#352](https://github.com/gimli-rs/gimli/pull/352) [#380](https://github.com/gimli-rs/gimli/pull/380) [#381](https://github.com/gimli-rs/gimli/pull/381) * Added `EhFrame::set_address_size` and `DebugFrame::set_address_size` methods to allow parsing non-native CFI sections. The default address size is still the native size. [#325](https://github.com/gimli-rs/gimli/pull/325) * Added architecture specific definitions for `Register` values and names. Changed dwarfdump to print them. [#328](https://github.com/gimli-rs/gimli/pull/328) * Added support for reading relocatable DWARF sections. [#337](https://github.com/gimli-rs/gimli/pull/337) * Added parsing of `DW_FORM_data16`. [#366](https://github.com/gimli-rs/gimli/pull/366) ### Fixed * Fixed parsing DWARF 5 ranges with `start == end == 0`. [#323](https://github.com/gimli-rs/gimli/pull/323) * Changed `LineRows` to be covariant in its `Reader` type parameter. [#324](https://github.com/gimli-rs/gimli/pull/324) * Fixed handling of empty units in dwarfdump. [#330](https://github.com/gimli-rs/gimli/pull/330) * Fixed `UnitHeader::length_including_self` for `Dwarf64`. [#342](https://github.com/gimli-rs/gimli/pull/342) * Fixed parsing of `DW_CFA_set_loc`. [#355](https://github.com/gimli-rs/gimli/pull/355) * Fixed handling of multiple headers in `.debug_loclists` and `.debug_rnglists`. [#370](https://github.com/gimli-rs/gimli/pull/370) -------------------------------------------------------------------------------- ## 0.16.1 Released 2018/08/28. ### Added * Added `EhFrameHdr::lookup_and_parse`. [#316][] * Added support for `DW_CFA_GNU_args_size`. [#319][] ### Fixed * Implement `Send`/`Sync` for `SubRange`. [#305][] * Fixed `alloc` support on nightly. [#306][] [#310][] [#305]: https://github.com/gimli-rs/gimli/pull/305 [#306]: https://github.com/gimli-rs/gimli/pull/306 [#310]: https://github.com/gimli-rs/gimli/pull/310 [#316]: https://github.com/gimli-rs/gimli/pull/316 [#319]: https://github.com/gimli-rs/gimli/pull/319 -------------------------------------------------------------------------------- ## 0.16.0 Released 2018/06/01. ### Added * Added support for building in `#![no_std]` environments, when the `alloc` crate is available. Disable the "std" feature and enable the "alloc" feature. [#138][] [#271][] * Added support for DWARF 5 `.debug_rnglists` and `.debug_loclists` sections. [#272][] * Added support for DWARF 5 `DW_FORM_ref_sup` and `DW_FORM_strp_sup` attribute forms. [#288][] * Added support for DWARF 5 operations on typed values. [#293][] * A `dwarf-validate` example program that checks the integrity of the given DWARF and its references between sections. [#290][] * Added the `EndianReader` type, an easy way to define a custom `Reader` implementation with a reference to a generic buffer of bytes and an associated endianity. [#298][] [#302][] ### Changed * Various speed improvements for evaluating `.debug_line` line number programs. [#276][] * The example `dwarfdump` clone is a [whole lot faster now][dwarfdump-faster]. [#282][] [#284][] [#285][] ### Deprecated * `EndianBuf` has been renamed to `EndianSlice`, use that name instead. [#295][] ### Fixed * Evaluating the `DW_CFA_restore_state` opcode properly maintains the current location. Previously it would incorrectly restore the old location when popping from evaluation stack. [#274][] [#271]: https://github.com/gimli-rs/gimli/issues/271 [#138]: https://github.com/gimli-rs/gimli/issues/138 [#274]: https://github.com/gimli-rs/gimli/issues/274 [#272]: https://github.com/gimli-rs/gimli/issues/272 [#276]: https://github.com/gimli-rs/gimli/issues/276 [#282]: https://github.com/gimli-rs/gimli/issues/282 [#285]: https://github.com/gimli-rs/gimli/issues/285 [#284]: https://github.com/gimli-rs/gimli/issues/284 [#288]: https://github.com/gimli-rs/gimli/issues/288 [#290]: https://github.com/gimli-rs/gimli/issues/290 [#293]: https://github.com/gimli-rs/gimli/issues/293 [#295]: https://github.com/gimli-rs/gimli/issues/295 [#298]: https://github.com/gimli-rs/gimli/issues/298 [#302]: https://github.com/gimli-rs/gimli/issues/302 [dwarfdump-faster]: https://robert.ocallahan.org/2018/03/speeding-up-dwarfdump-with-rust.html -------------------------------------------------------------------------------- ## 0.15.0 Released 2017/12/01. ### Added * Added the `EndianBuf::to_string()` method. [#233][] * Added more robust error handling in our example `dwarfdump` clone. [#234][] * Added `FrameDescriptionEntry::initial_address` method. [#237][] * Added `FrameDescriptionEntry::len` method. [#237][] * Added the `FrameDescriptionEntry::entry_len` method. [#241][] * Added the `CommonInformationEntry::offset` method. [#241][] * Added the `CommonInformationEntry::entry_len` method. [#241][] * Added the `CommonInformationEntry::version` method. [#241][] * Added the `CommonInformationEntry::augmentation` method. [#241][] * Added the `CommonInformationEntry::code_alignment_factor` method. [#241][] * Added the `CommonInformationEntry::data_alignment_factor` method. [#241][] * Added the `CommonInformationEntry::return_address_register` method. [#241][] * Added support for printing `.eh_frame` sections to our example `dwarfdump` clone. [#241][] * Added support for parsing the `.eh_frame_hdr` section. On Linux, the `.eh_frame_hdr` section provides a pointer to the already-mapped-in-memory `.eh_frame` data, so that it doesn't need to be duplicated, and a binary search table of its entries for faster unwinding information lookups. [#250][] * Added support for parsing DWARF 5 compilation unit headers. [#257][] * Added support for DWARF 5's `DW_FORM_implicit_const`. [#257][] ### Changed * Unwinding methods now give ownership of the unwinding context back to the caller if errors are encountered, not just on the success path. This allows recovering from errors in signal-safe code, where constructing a new unwinding context is not an option because it requires allocation. This is a **breaking change** affecting `UnwindSection::unwind_info_for_address` and `UninitializedUnwindContext::initialize`. [#241][] * `CfaRule` and `RegisterRule` now expose their `DW_OP` expressions as `Expression`. This is a minor **breaking change**. [#241][] * The `Error::UnknownVersion` variant now contains the unknown version number. This is a minor **breaking change**. [#245][] * `EvaluationResult::RequiresEntryValue` requires an `Expression` instead of a `Reader` now. This is a minor **breaking change**. [#256][] [#233]: https://github.com/gimli-rs/gimli/pull/233 [#234]: https://github.com/gimli-rs/gimli/pull/234 [#237]: https://github.com/gimli-rs/gimli/pull/237 [#241]: https://github.com/gimli-rs/gimli/pull/241 [#245]: https://github.com/gimli-rs/gimli/pull/245 [#250]: https://github.com/gimli-rs/gimli/pull/250 [#256]: https://github.com/gimli-rs/gimli/pull/256 [#257]: https://github.com/gimli-rs/gimli/pull/257 -------------------------------------------------------------------------------- ## 0.14.0 Released 2017/08/08. ### Added * All `pub` types now `derive(Hash)`. [#192][] * All the constants from DWARF 5 are now defined. [#193][] * Added support for the `DW_OP_GNU_parameter_ref` GNU extension to parsing and evaluation DWARF opcodes. [#208][] * Improved LEB128 parsing performance. [#216][] * Improved `.debug_{aranges,pubnames,pubtypes}` parsing performance. [#218][] * Added the ability to choose endianity dynamically at run time, rather than only statically at compile time. [#219][] ### Changed * The biggest change of this release is that `gimli` no longer requires the object file's section be fully loaded into memory. This enables using `gimli` on 32 bit platforms where there often isn't enough contiguous virtual memory address space to load debugging information into. The default behavior is still geared for 64 bit platforms, where address space overfloweth, and you can still load the whole sections of the object file (or the entire object file) into memory. This is abstracted over with the `gimli::Reader` trait. This manifests as small (but many) breaking changes to much of the public API. [#182][] ### Fixed * The `DW_END_*` constants for defining endianity of a compilation unit were previously incorrect. [#193][] * The `DW_OP_addr` opcode is relative to the base address of the `.text` section of the binary, but we were incorrectly treating it as an absolute value. [#210][] [GitHub]: https://github.com/gimli-rs/gimli [crates.io]: https://crates.io/crates/gimli [contributing]: https://github.com/gimli-rs/gimli/blob/master/CONTRIBUTING.md [easy]: https://github.com/gimli-rs/gimli/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy [#192]: https://github.com/gimli-rs/gimli/pull/192 [#193]: https://github.com/gimli-rs/gimli/pull/193 [#182]: https://github.com/gimli-rs/gimli/issues/182 [#208]: https://github.com/gimli-rs/gimli/pull/208 [#210]: https://github.com/gimli-rs/gimli/pull/210 [#216]: https://github.com/gimli-rs/gimli/pull/216 [#218]: https://github.com/gimli-rs/gimli/pull/218 [#219]: https://github.com/gimli-rs/gimli/pull/219 gimli-0.19.0/CONTRIBUTING.md010066400017500001750000000064701343337721300133730ustar0000000000000000# Contributing to `gimli` Hi! We'd love to have your contributions! If you want help or mentorship, reach out to us in a GitHub issue, or ping `fitzgen` in `#rust` on `irc.mozilla.org`. * [Code of Conduct](#coc) * [Filing an Issue](#issues) * [Building `gimli`](#building) * [Testing `gimli`](#testing) * [Test Coverage](#coverage) * [Using `test-assembler`](#test-assembler) * [Benchmarking](#benchmarking) * [Style](#style) ## Code of Conduct We abide by the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html) and ask that you do as well. ## Filing an Issue Think you've found a bug? File an issue! To help us understand and reproduce the issue, provide us with: * The (preferably minimal) test case * Steps to reproduce the issue using the test case * The expected result of following those steps * The actual result of following those steps Definitely file an issue if you see an unexpected panic originating from within `gimli`! `gimli` should never panic unless it is explicitly documented to panic in the specific circumstances provided. ## Building `gimli` `gimli` should always build on stable `rustc`, but we recommend using [`rustup`](https://www.rustup.rs/) so you can switch to nightly `rustc` and run benchmarks. To build `gimli`: ``` $ cargo build ``` ## Testing `gimli` Run the tests with `cargo`: ``` $ cargo test ``` ### Test Coverage If you have `kcov` installed under linux, then you can generate code coverage results using the `coverage` script in the root of the repository, and view them at `target/kcov/index.html`. Otherwise you can create a pull request and view the coverage results on coveralls.io. ``` $ ./coverage ``` The ideal we aim to reach is having our unit tests exercise every branch in `gimli`. We allow an exception for branches which propagate errors inside a `try!(..)` invocation, but we *do* want to exercise the original error paths. Pull requests adding new code should ensure that this ideal is met. At the time of writing we have 94% test coverage according to our coveralls.io continuous integration. That number should generally stay the same or go up ;) This is a bit subjective, because -.001% is just noise and doesn't matter. ### Using `test-assembler` We use the awesome [`test-assembler`](https://github.com/luser/rust-test-assembler) crate to construct binary test data. It makes building complex test cases readable. [Here is an example usage in `gimli`](https://github.com/gimli-rs/gimli/blob/156451f3fe6eeb2fa62b84b362c33fcb176e1171/src/loc.rs#L263) ## Benchmarking The benchmarks require nightly `rustc`, so use `rustup`: ``` $ rustup run nightly cargo bench ``` We aim to be the fastest DWARF library. Period. Please provide before and after benchmark results with your pull requests. You may also find [`cargo benchcmp`](https://github.com/BurntSushi/cargo-benchcmp) handy for comparing results. Pull requests adding `#[bench]` micro-benchmarks that exercise a new edge case are very welcome! ## Style We use `rustfmt` to automatically format and style all of our code. To install `rustfmt`: ``` $ rustup component add rustfmt-preview ``` To run `rustfmt` on `gimli`: ``` $ cargo fmt ``` gimli-0.19.0/Cargo.toml.orig010066400017500001750000000025351351057326000140230ustar0000000000000000[package] authors = ["Nick Fitzgerald ", "Philip Craig "] categories = ["development-tools::debugging", "development-tools::profiling", "parser-implementations"] description = "A library for reading and writing the DWARF debugging format." documentation = "https://docs.rs/gimli" keywords = ["DWARF", "debug", "ELF", "eh_frame"] license = "Apache-2.0/MIT" name = "gimli" readme = "./README.md" repository = "https://github.com/gimli-rs/gimli" version = "0.19.0" exclude = ["/ci/*", "/releases/*", "/.travis.yml"] edition = "2018" [badges] travis-ci = { repository = "gimli-rs/gimli" } coveralls = { repository = "gimli-rs/gimli" } [dependencies] arrayvec = { version = "0.4.6", default-features = false } byteorder = { version = "1.0", default-features = false } fallible-iterator = { version = "0.2.0", default-features = false } indexmap = { version = "1.0.2", optional = true } stable_deref_trait = { version = "1.1.0", default-features = false } [dev-dependencies] crossbeam = "0.7.1" getopts = "0.2" memmap = "0.7" num_cpus = "1" object = "0.12" rayon = "1.0" regex = "1" test-assembler = "0.1.3" typed-arena = "1" [features] read = [] write = ["std", "indexmap"] std = ["fallible-iterator/std", "stable_deref_trait/std"] alloc = ["fallible-iterator/alloc", "stable_deref_trait/alloc"] default = ["read", "write", "std"] gimli-0.19.0/Cargo.toml0000644000000041520000000000000102630ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "gimli" version = "0.19.0" authors = ["Nick Fitzgerald ", "Philip Craig "] exclude = ["/ci/*", "/releases/*", "/.travis.yml"] description = "A library for reading and writing the DWARF debugging format." documentation = "https://docs.rs/gimli" readme = "./README.md" keywords = ["DWARF", "debug", "ELF", "eh_frame"] categories = ["development-tools::debugging", "development-tools::profiling", "parser-implementations"] license = "Apache-2.0/MIT" repository = "https://github.com/gimli-rs/gimli" [dependencies.arrayvec] version = "0.4.6" default-features = false [dependencies.byteorder] version = "1.0" default-features = false [dependencies.fallible-iterator] version = "0.2.0" default-features = false [dependencies.indexmap] version = "1.0.2" optional = true [dependencies.stable_deref_trait] version = "1.1.0" default-features = false [dev-dependencies.crossbeam] version = "0.7.1" [dev-dependencies.getopts] version = "0.2" [dev-dependencies.memmap] version = "0.7" [dev-dependencies.num_cpus] version = "1" [dev-dependencies.object] version = "0.12" [dev-dependencies.rayon] version = "1.0" [dev-dependencies.regex] version = "1" [dev-dependencies.test-assembler] version = "0.1.3" [dev-dependencies.typed-arena] version = "1" [features] alloc = ["fallible-iterator/alloc", "stable_deref_trait/alloc"] default = ["read", "write", "std"] read = [] std = ["fallible-iterator/std", "stable_deref_trait/std"] write = ["std", "indexmap"] [badges.coveralls] repository = "gimli-rs/gimli" [badges.travis-ci] repository = "gimli-rs/gimli" gimli-0.19.0/LICENSE-APACHE010066400017500001750000000251371343337721300130670ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. gimli-0.19.0/LICENSE-MIT010066400017500001750000000020571343337721300125730ustar0000000000000000Copyright (c) 2015 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gimli-0.19.0/README.md010066400017500001750000000054241351057326000124130ustar0000000000000000# `gimli` [![](http://meritbadge.herokuapp.com/gimli) ![](https://img.shields.io/crates/d/gimli.svg)](https://crates.io/crates/gimli) [![](https://docs.rs/gimli/badge.svg)](https://docs.rs/gimli/) [![Build Status](https://travis-ci.org/gimli-rs/gimli.svg?branch=master)](https://travis-ci.org/gimli-rs/gimli) [![Coverage Status](https://coveralls.io/repos/github/gimli-rs/gimli/badge.svg?branch=master)](https://coveralls.io/github/gimli-rs/gimli?branch=master) `gimli` is a blazing fast library for consuming the [DWARF debugging format](http://dwarfstd.org/). * **Zero copy:** everything is just a reference to the original input buffer. No copies of the input data get made. * **Lazy:** you can iterate compilation units without parsing their contents. Parse only as many debugging information entry (DIE) trees as you iterate over. `gimli` also uses `DW_AT_sibling` references to avoid parsing a DIE's children to find its next sibling, when possible. * **Cross-platform:** `gimli` makes no assumptions about what kind of object file you're working with. The flipside to that is that it's up to you to provide an ELF loader on Linux or Mach-O loader on OSX. * Unsure which object file parser to use? Try the cross-platform [`object`](https://github.com/gimli-rs/object) crate. See the [`examples/`](./examples) directory for usage with `gimli`. ## Install Add this to your `Cargo.toml`: ```toml [dependencies] gimli = "0.19.0" ``` The minimum supported rust version is 1.32.0. ## Documentation * [Documentation on docs.rs](https://docs.rs/gimli/) * Example programs: * [A simple parser](./examples/simple.rs) * [A `dwarfdump` clone](./examples/dwarfdump.rs) * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into code generation by making debugging information readable * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the compilers used to create each compilation unit within a shared library or executable (via `DW_AT_producer`) * [`dwarf-validate`](./examples/dwarf-validate.rs), a program to validate the integrity of some DWARF and its references between sections and ocmpilation units. ## License Licensed under either of * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution See [CONTRIBUTING.md](./CONTRIBUTING.md) for hacking. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. gimli-0.19.0/benches/bench.rs010066400017500001750000000635531346020377600142050ustar0000000000000000#![feature(test)] extern crate test; use gimli::{ AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, DebugLineOffset, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, Encoding, EndianSlice, EntriesTreeNode, Expression, LittleEndian, LocationLists, Operation, RangeLists, Reader, ReaderOffset, }; use std::env; use std::fs::File; use std::io::Read; use std::path::PathBuf; use std::rc::Rc; pub fn read_section(section: &str) -> Vec { let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into())); path.push("./fixtures/self/"); path.push(section); assert!(path.is_file()); let mut file = File::open(path).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); buf } #[bench] fn bench_parsing_debug_abbrev(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let unit = debug_info .units() .next() .expect("Should have at least one compilation unit") .expect("And it should parse OK"); let debug_abbrev = read_section("debug_abbrev"); b.iter(|| { let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); test::black_box( unit.abbreviations(&debug_abbrev) .expect("Should parse abbreviations"), ); }); } #[inline] fn impl_bench_parsing_debug_info( debug_info: DebugInfo, debug_abbrev: DebugAbbrev, ) { let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") { let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { test::black_box(&attr); } } } } #[bench] fn bench_parsing_debug_info(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); b.iter(|| impl_bench_parsing_debug_info(debug_info, debug_abbrev)); } #[bench] fn bench_parsing_debug_info_with_endian_rc_slice(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = Rc::from(&debug_info[..]); let debug_info = gimli::EndianRcSlice::new(debug_info, LittleEndian); let debug_info = DebugInfo::from(debug_info); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = Rc::from(&debug_abbrev[..]); let debug_abbrev = gimli::EndianRcSlice::new(debug_abbrev, LittleEndian); let debug_abbrev = DebugAbbrev::from(debug_abbrev); b.iter(|| impl_bench_parsing_debug_info(debug_info.clone(), debug_abbrev.clone())); } #[bench] fn bench_parsing_debug_info_tree(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_info = read_section("debug_info"); b.iter(|| { let debug_info = DebugInfo::new(&debug_info, LittleEndian); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut tree = unit .entries_tree(&abbrevs, None) .expect("Should have entries tree"); let root = tree.root().expect("Should parse root entry"); parse_debug_info_tree(root); } }); } fn parse_debug_info_tree(node: EntriesTreeNode) { { let mut attrs = node.entry().attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { test::black_box(&attr); } } let mut children = node.children(); while let Some(child) = children.next().expect("Should parse child entry") { parse_debug_info_tree(child); } } #[bench] fn bench_parsing_debug_aranges(b: &mut test::Bencher) { let debug_aranges = read_section("debug_aranges"); let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian); b.iter(|| { let mut aranges = debug_aranges.items(); while let Some(arange) = aranges.next().expect("Should parse arange OK") { test::black_box(arange); } }); } #[bench] fn bench_parsing_debug_pubnames(b: &mut test::Bencher) { let debug_pubnames = read_section("debug_pubnames"); let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian); b.iter(|| { let mut pubnames = debug_pubnames.items(); while let Some(pubname) = pubnames.next().expect("Should parse pubname OK") { test::black_box(pubname); } }); } #[bench] fn bench_parsing_debug_pubtypes(b: &mut test::Bencher) { let debug_pubtypes = read_section("debug_pubtypes"); let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian); b.iter(|| { let mut pubtypes = debug_pubtypes.items(); while let Some(pubtype) = pubtypes.next().expect("Should parse pubtype OK") { test::black_box(pubtype); } }); } // We happen to know that there is a line number program and header at // offset 0 and that address size is 8 bytes. No need to parse DIEs to grab // this info off of the compilation units. const OFFSET: DebugLineOffset = DebugLineOffset(0); const ADDRESS_SIZE: u8 = 8; #[bench] fn bench_parsing_line_number_program_opcodes(b: &mut test::Bencher) { let debug_line = read_section("debug_line"); let debug_line = DebugLine::new(&debug_line, LittleEndian); b.iter(|| { let program = debug_line .program(OFFSET, ADDRESS_SIZE, None, None) .expect("Should parse line number program header"); let header = program.header(); let mut instructions = header.instructions(); while let Some(instruction) = instructions .next_instruction(header) .expect("Should parse instruction") { test::black_box(instruction); } }); } #[bench] fn bench_executing_line_number_programs(b: &mut test::Bencher) { let debug_line = read_section("debug_line"); let debug_line = DebugLine::new(&debug_line, LittleEndian); b.iter(|| { let program = debug_line .program(OFFSET, ADDRESS_SIZE, None, None) .expect("Should parse line number program header"); let mut rows = program.rows(); while let Some(row) = rows .next_row() .expect("Should parse and execute all rows in the line number program") { test::black_box(row); } }); } #[bench] fn bench_parsing_debug_loc(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let mut offsets = Vec::new(); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let mut low_pc = 0; { let unit_entry = cursor.current().expect("Should have a root entry"); let low_pc_attr = unit_entry .attr_value(gimli::DW_AT_low_pc) .expect("Should parse low_pc"); if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr { low_pc = address; } } while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() { offsets.push((offset, unit.encoding(), low_pc)); } } } } b.iter(|| { for &(offset, encoding, base_address) in &*offsets { let mut locs = loclists .locations(offset, encoding, base_address, &debug_addr, debug_addr_base) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { test::black_box(loc); } } }); } #[bench] fn bench_parsing_debug_ranges(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let mut offsets = Vec::new(); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let mut low_pc = 0; { let unit_entry = cursor.current().expect("Should have a root entry"); let low_pc_attr = unit_entry .attr_value(gimli::DW_AT_low_pc) .expect("Should parse low_pc"); if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr { low_pc = address; } } while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let gimli::AttributeValue::RangeListsRef(offset) = attr.value() { offsets.push((offset, unit.encoding(), low_pc)); } } } } b.iter(|| { for &(offset, encoding, base_address) in &*offsets { let mut ranges = rnglists .ranges(offset, encoding, base_address, &debug_addr, debug_addr_base) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { test::black_box(range); } } }); } fn debug_info_expressions( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, ) -> Vec<(Expression, Encoding)> { let mut expressions = Vec::new(); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") { let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::Exprloc(expression) = attr.value() { expressions.push((expression, unit.encoding())); } } } } expressions } #[bench] fn bench_parsing_debug_info_expressions(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let expressions = debug_info_expressions(&debug_info, &debug_abbrev); b.iter(|| { for &(expression, encoding) in &*expressions { let mut pc = expression.0; while !pc.is_empty() { Operation::parse(&mut pc, &expression.0, encoding).expect("Should parse operation"); } } }); } #[bench] fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let expressions = debug_info_expressions(&debug_info, &debug_abbrev); b.iter(|| { for &(expression, encoding) in &*expressions { let mut eval = expression.evaluation(encoding); eval.set_initial_value(0); let result = eval.evaluate().expect("Should evaluate expression"); test::black_box(result); } }); } fn debug_loc_expressions( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, debug_addr: &DebugAddr, loclists: &LocationLists, ) -> Vec<(Expression, Encoding)> { let debug_addr_base = DebugAddrBase(R::Offset::from_u8(0)); let mut expressions = Vec::new(); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let mut low_pc = 0; { let unit_entry = cursor.current().expect("Should have a root entry"); let low_pc_attr = unit_entry .attr_value(gimli::DW_AT_low_pc) .expect("Should parse low_pc"); if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr { low_pc = address; } } while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() { let mut locs = loclists .locations(offset, unit.encoding(), low_pc, debug_addr, debug_addr_base) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { expressions.push((loc.data, unit.encoding())); } } } } } expressions } #[bench] fn bench_parsing_debug_loc_expressions(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists); b.iter(|| { for &(expression, encoding) in &*expressions { let mut pc = expression.0; while !pc.is_empty() { Operation::parse(&mut pc, &expression.0, encoding).expect("Should parse operation"); } } }); } #[bench] fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists); b.iter(|| { for &(expression, encoding) in &*expressions { let mut eval = expression.evaluation(encoding); eval.set_initial_value(0); let result = eval.evaluate().expect("Should evaluate expression"); test::black_box(result); } }); } // See comment above `test_parse_self_eh_frame`. #[cfg(target_pointer_width = "64")] mod cfi { use super::*; use fallible_iterator::FallibleIterator; use gimli::{ BaseAddresses, CieOrFde, EhFrame, FrameDescriptionEntry, LittleEndian, UninitializedUnwindContext, UnwindSection, }; #[bench] fn iterate_entries_and_do_not_parse_any_fde(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); b.iter(|| { let mut entries = eh_frame.entries(&bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { test::black_box(entry); } }); } #[bench] fn iterate_entries_and_parse_every_fde(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); b.iter(|| { let mut entries = eh_frame.entries(&bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { match entry { CieOrFde::Cie(cie) => { test::black_box(cie); } CieOrFde::Fde(partial) => { let fde = partial .parse(EhFrame::cie_from_offset) .expect("Should be able to get CIE for FED"); test::black_box(fde); } }; } }); } #[bench] fn iterate_entries_and_parse_every_fde_and_instructions(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); b.iter(|| { let mut entries = eh_frame.entries(&bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { match entry { CieOrFde::Cie(cie) => { let mut instrs = cie.instructions(&eh_frame, &bases); while let Some(i) = instrs.next().expect("Can parse next CFI instruction OK") { test::black_box(i); } } CieOrFde::Fde(partial) => { let fde = partial .parse(EhFrame::cie_from_offset) .expect("Should be able to get CIE for FED"); let mut instrs = fde.instructions(&eh_frame, &bases); while let Some(i) = instrs.next().expect("Can parse next CFI instruction OK") { test::black_box(i); } } }; } }); } #[bench] fn iterate_entries_evaluate_every_fde(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); let mut ctx = UninitializedUnwindContext::new(); b.iter(|| { let mut entries = eh_frame.entries(&bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { match entry { CieOrFde::Cie(_) => {} CieOrFde::Fde(partial) => { let fde = partial .parse(EhFrame::cie_from_offset) .expect("Should be able to get CIE for FED"); let mut table = fde .rows(&eh_frame, &bases, &mut ctx) .expect("Should be able to initialize ctx"); while let Some(row) = table.next_row().expect("Should get next unwind table row") { test::black_box(row); } } }; } }); } fn instrs_len( eh_frame: &EhFrame, bases: &BaseAddresses, fde: &FrameDescriptionEntry, ) -> usize { fde.instructions(eh_frame, bases) .fold(0, |count, _| Ok(count + 1)) .expect("fold over instructions OK") } fn get_fde_with_longest_cfi_instructions( eh_frame: &EhFrame, bases: &BaseAddresses, ) -> FrameDescriptionEntry { let mut longest: Option<(usize, FrameDescriptionEntry<_>)> = None; let mut entries = eh_frame.entries(bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { match entry { CieOrFde::Cie(_) => {} CieOrFde::Fde(partial) => { let fde = partial .parse(EhFrame::cie_from_offset) .expect("Should be able to get CIE for FED"); let this_len = instrs_len(eh_frame, bases, &fde); let found_new_longest = match longest { None => true, Some((longest_len, ref _fde)) => this_len > longest_len, }; if found_new_longest { longest = Some((this_len, fde)); } } }; } longest.expect("At least one FDE in .eh_frame").1 } #[bench] fn parse_longest_fde_instructions(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases); b.iter(|| { let mut instrs = fde.instructions(&eh_frame, &bases); while let Some(i) = instrs.next().expect("Should parse instruction OK") { test::black_box(i); } }); } #[bench] fn eval_longest_fde_instructions_new_ctx_everytime(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases); b.iter(|| { let mut ctx = UninitializedUnwindContext::new(); let mut table = fde .rows(&eh_frame, &bases, &mut ctx) .expect("Should initialize the ctx OK"); while let Some(row) = table.next_row().expect("Should get next unwind table row") { test::black_box(row); } }); } #[bench] fn eval_longest_fde_instructions_same_ctx(b: &mut test::Bencher) { let eh_frame = read_section("eh_frame"); let eh_frame = EhFrame::new(&eh_frame, LittleEndian); let bases = BaseAddresses::default() .set_eh_frame(0) .set_got(0) .set_text(0); let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases); let mut ctx = UninitializedUnwindContext::new(); b.iter(|| { let mut table = fde .rows(&eh_frame, &bases, &mut ctx) .expect("Should initialize the ctx OK"); while let Some(row) = table.next_row().expect("Should get next unwind table row") { test::black_box(row); } }); } } gimli-0.19.0/examples/dwarf-validate.rs010066400017500001750000000214701346020377600162170ustar0000000000000000// Allow clippy lints when building without clippy. #![allow(unknown_lints)] use gimli::{AttributeValue, CompilationUnitHeader}; use object::Object; use rayon::prelude::*; use std::borrow::{Borrow, Cow}; use std::env; use std::error; use std::fs; use std::io::{self, BufWriter, Write}; use std::iter::Iterator; use std::path::{Path, PathBuf}; use std::process; use std::sync::Mutex; use typed_arena::Arena; trait Reader: gimli::Reader + Send + Sync { type SyncSendEndian: gimli::Endianity + Send + Sync; } impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where Endian: gimli::Endianity + Send + Sync, { type SyncSendEndian = Endian; } struct ErrorWriter { inner: Mutex<(W, usize)>, path: PathBuf, } impl ErrorWriter { #[allow(clippy::needless_pass_by_value)] fn error(&self, s: String) { let mut lock = self.inner.lock().unwrap(); writeln!(&mut lock.0, "DWARF error in {}: {}", self.path.display(), s).unwrap(); lock.1 += 1; } } fn main() { let mut w = BufWriter::new(io::stdout()); let mut errors = 0; for arg in env::args_os().skip(1) { let path = Path::new(&arg); let file = match fs::File::open(&path) { Ok(file) => file, Err(err) => { eprintln!( "Failed to open file '{}': {}", path.display(), error::Error::description(&err) ); errors += 1; continue; } }; let file = match unsafe { memmap::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { eprintln!("Failed to map file '{}': {}", path.display(), &err); errors += 1; continue; } }; let file = match object::File::parse(&*file) { Ok(file) => file, Err(err) => { eprintln!("Failed to parse file '{}': {}", path.display(), err); errors += 1; continue; } }; let endian = if file.is_little_endian() { gimli::RunTimeEndian::Little } else { gimli::RunTimeEndian::Big }; let mut error_writer = ErrorWriter { inner: Mutex::new((&mut w, 0)), path: path.to_owned(), }; validate_file(&mut error_writer, &file, endian); errors += error_writer.inner.into_inner().unwrap().1; } // Flush any errors. drop(w); if errors > 0 { process::exit(1); } } fn validate_file(w: &mut ErrorWriter, file: &object::File, endian: Endian) where W: Write + Send, Endian: gimli::Endianity + Send + Sync, { let arena = Arena::new(); fn load_section<'a, 'file, 'input, S, Endian>( arena: &'a Arena>, file: &'file object::File<'input>, endian: Endian, ) -> S where S: gimli::Section>, Endian: gimli::Endianity + Send + Sync, 'file: 'input, 'a: 'file, { let data = file .section_data_by_name(S::section_name()) .unwrap_or(Cow::Borrowed(&[])); let data_ref = (*arena.alloc(data)).borrow(); S::from(gimli::EndianSlice::new(data_ref, endian)) } // Variables representing sections of the file. The type of each is inferred from its use in the // validate_info function below. let debug_abbrev = &load_section(&arena, file, endian); let debug_info = &load_section(&arena, file, endian); validate_info(w, debug_info, debug_abbrev); } struct UnitSummary { // True if we successfully parsed all the DIEs and attributes in the compilation unit internally_valid: bool, offset: gimli::DebugInfoOffset, die_offsets: Vec, global_die_references: Vec<(gimli::UnitOffset, gimli::DebugInfoOffset)>, } fn validate_info( w: &mut ErrorWriter, debug_info: &gimli::DebugInfo, debug_abbrev: &gimli::DebugAbbrev, ) where W: Write + Send, R: Reader, { let mut units = Vec::new(); let mut units_iter = debug_info.units(); let mut last_offset = 0; loop { let u = match units_iter.next() { Err(err) => { w.error(format!( "Can't read unit header at offset {:#x}, stopping reading units: {}", last_offset, error::Error::description(&err) )); break; } Ok(None) => break, Ok(Some(u)) => u, }; last_offset = u.offset().0 + u.length_including_self(); units.push(u); } let process_unit = |unit: CompilationUnitHeader| -> UnitSummary { let mut ret = UnitSummary { internally_valid: false, offset: unit.offset(), die_offsets: Vec::new(), global_die_references: Vec::new(), }; let abbrevs = match unit.abbreviations(debug_abbrev) { Ok(abbrevs) => abbrevs, Err(err) => { w.error(format!( "Invalid abbrevs for unit {:#x}: {}", unit.offset().0, error::Error::description(&err) )); return ret; } }; let mut entries = unit.entries(&abbrevs); let mut unit_refs = Vec::new(); loop { let (_, entry) = match entries.next_dfs() { Err(err) => { w.error(format!( "Invalid DIE for unit {:#x}: {}", unit.offset().0, error::Error::description(&err) )); return ret; } Ok(None) => break, Ok(Some(entry)) => entry, }; ret.die_offsets.push(entry.offset()); let mut attrs = entry.attrs(); loop { let attr = match attrs.next() { Err(err) => { w.error(format!( "Invalid attribute for unit {:#x} at DIE {:#x}: {}", unit.offset().0, entry.offset().0, error::Error::description(&err) )); return ret; } Ok(None) => break, Ok(Some(attr)) => attr, }; match attr.value() { AttributeValue::UnitRef(offset) => { unit_refs.push((entry.offset(), offset)); } AttributeValue::DebugInfoRef(offset) => { ret.global_die_references.push((entry.offset(), offset)); } _ => (), } } } ret.internally_valid = true; ret.die_offsets.shrink_to_fit(); ret.global_die_references.shrink_to_fit(); // Check intra-unit references for (from, to) in unit_refs { if ret.die_offsets.binary_search(&to).is_err() { w.error(format!( "Invalid intra-unit reference in unit {:#x} from DIE {:#x} to {:#x}", unit.offset().0, from.0, to.0 )); } } ret }; let processed_units = units.into_par_iter().map(process_unit).collect::>(); let check_unit = |summary: &UnitSummary| { if !summary.internally_valid { return; } for &(from, to) in summary.global_die_references.iter() { let u = match processed_units.binary_search_by_key(&to, |v| v.offset) { Ok(i) => &processed_units[i], Err(i) => { if i > 0 { &processed_units[i - 1] } else { w.error(format!("Invalid cross-unit reference in unit {:#x} from DIE {:#x} to global DIE {:#x}: no unit found", summary.offset.0, from.0, to.0)); continue; } } }; if !u.internally_valid { continue; } let to_offset = gimli::UnitOffset(to.0 - u.offset.0); if u.die_offsets.binary_search(&to_offset).is_err() { w.error(format!("Invalid cross-unit reference in unit {:#x} from DIE {:#x} to global DIE {:#x}: unit at {:#x} contains no DIE {:#x}", summary.offset.0, from.0, to.0, u.offset.0, to_offset.0)); } } }; processed_units.par_iter().for_each(check_unit); } gimli-0.19.0/examples/dwarfdump.rs010066400017500001750000002077361351057326000153230ustar0000000000000000// Allow clippy lints when building without clippy. #![allow(unknown_lints)] use fallible_iterator::FallibleIterator; use gimli::{CompilationUnitHeader, Section, UnitOffset, UnitSectionOffset, UnwindSection}; use object::{Object, ObjectSection}; use regex::bytes::Regex; use std::borrow::{Borrow, Cow}; use std::cmp::min; use std::collections::HashMap; use std::env; use std::fmt::{self, Debug}; use std::fs; use std::io; use std::io::{BufWriter, Write}; use std::iter::Iterator; use std::mem; use std::process; use std::result; use std::sync::{Condvar, Mutex}; use typed_arena::Arena; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { GimliError(gimli::Error), IoError, } impl fmt::Display for Error { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { Debug::fmt(self, f) } } fn writeln_error( w: &mut W, dwarf: &gimli::Dwarf, err: Error, msg: &str, ) -> io::Result<()> { writeln!( w, "{}: {}", msg, match err { Error::GimliError(err) => dwarf.format_error(err), Error::IoError => "An I/O error occurred while writing.".to_string(), } ) } impl From for Error { fn from(err: gimli::Error) -> Self { Error::GimliError(err) } } impl From for Error { fn from(_: io::Error) -> Self { Error::IoError } } pub type Result = result::Result; fn parallel_output(max_workers: usize, iter: II, f: F) -> Result<()> where F: Sync + Fn(II::Item, &mut Vec) -> Result<()>, II: IntoIterator, II::IntoIter: Send, { struct ParallelOutputState { iterator: I, current_worker: usize, result: Result<()>, } let state = Mutex::new(ParallelOutputState { iterator: iter.into_iter().fuse(), current_worker: 0, result: Ok(()), }); let workers = min(max_workers, num_cpus::get()); let mut condvars = Vec::new(); for _ in 0..workers { condvars.push(Condvar::new()); } { let state_ref = &state; let f_ref = &f; let condvars_ref = &condvars; crossbeam::scope(|scope| { for i in 0..workers { scope.spawn(move |_| { let mut v = Vec::new(); let mut lock = state_ref.lock().unwrap(); while lock.current_worker != i { lock = condvars_ref[i].wait(lock).unwrap(); } loop { let item = if lock.result.is_ok() { lock.iterator.next() } else { None }; lock.current_worker = (i + 1) % workers; condvars_ref[lock.current_worker].notify_one(); mem::drop(lock); let ret = if let Some(item) = item { v.clear(); f_ref(item, &mut v) } else { return; }; lock = state_ref.lock().unwrap(); while lock.current_worker != i { lock = condvars_ref[i].wait(lock).unwrap(); } if lock.result.is_ok() { let out = io::stdout(); let ret2 = out.lock().write_all(&v); if ret.is_err() { lock.result = ret; } else { lock.result = ret2.map_err(Error::from); } } } }); } }) .unwrap(); } state.into_inner().unwrap().result } trait Reader: gimli::Reader + Send + Sync {} impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where Endian: gimli::Endianity + Send + Sync { } type RelocationMap = HashMap; fn add_relocations( relocations: &mut RelocationMap, file: &object::File, section: &object::Section, ) { for (offset64, mut relocation) in section.relocations() { let offset = offset64 as usize; if offset as u64 != offset64 { continue; } let offset = offset as usize; match relocation.kind() { object::RelocationKind::Absolute => { if let Some(symbol) = file.symbol_by_index(relocation.symbol()) { let addend = symbol.address().wrapping_add(relocation.addend() as u64); relocation.set_addend(addend as i64); if relocations.insert(offset, relocation).is_some() { println!( "Multiple relocations for section {} at offset 0x{:08x}", section.name().unwrap(), offset ); } } else { println!( "Relocation with invalid symbol for section {} at offset 0x{:08x}", section.name().unwrap(), offset ); } } _ => { println!( "Unsupported relocation for section {} at offset 0x{:08x}", section.name().unwrap(), offset ); } } } } /// Apply relocations to addresses and offsets during parsing, /// instead of requiring the data to be fully relocated prior /// to parsing. /// /// Pros /// - allows readonly buffers, we don't need to implement writing of values back to buffers /// - potentially allows us to handle addresses and offsets differently /// - potentially allows us to add metadata from the relocation (eg symbol names) /// Cons /// - maybe incomplete #[derive(Debug, Clone)] struct Relocate<'a, R: gimli::Reader> { relocations: &'a RelocationMap, section: R, reader: R, } impl<'a, R: gimli::Reader> Relocate<'a, R> { fn relocate(&self, offset: usize, value: u64) -> u64 { if let Some(relocation) = self.relocations.get(&offset) { match relocation.kind() { object::RelocationKind::Absolute => { if relocation.has_implicit_addend() { // Use the explicit addend too, because it may have the symbol value. return value.wrapping_add(relocation.addend() as u64); } else { return relocation.addend() as u64; } } _ => {} } }; value } } impl<'a, R: gimli::Reader> gimli::Reader for Relocate<'a, R> { type Endian = R::Endian; type Offset = R::Offset; fn read_address(&mut self, address_size: u8) -> gimli::Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_address(address_size)?; Ok(self.relocate(offset, value)) } fn read_length(&mut self, format: gimli::Format) -> gimli::Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_length(format)?; ::from_u64(self.relocate(offset, value as u64)) } fn read_offset(&mut self, format: gimli::Format) -> gimli::Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_offset(format)?; ::from_u64(self.relocate(offset, value as u64)) } fn read_sized_offset(&mut self, size: u8) -> gimli::Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_sized_offset(size)?; ::from_u64(self.relocate(offset, value as u64)) } #[inline] fn split(&mut self, len: Self::Offset) -> gimli::Result { let mut other = self.clone(); other.reader.truncate(len)?; self.reader.skip(len)?; Ok(other) } // All remaining methods simply delegate to `self.reader`. #[inline] fn endian(&self) -> Self::Endian { self.reader.endian() } #[inline] fn len(&self) -> Self::Offset { self.reader.len() } #[inline] fn empty(&mut self) { self.reader.empty() } #[inline] fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> { self.reader.truncate(len) } #[inline] fn offset_from(&self, base: &Self) -> Self::Offset { self.reader.offset_from(&base.reader) } #[inline] fn offset_id(&self) -> gimli::ReaderOffsetId { self.reader.offset_id() } #[inline] fn lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option { self.reader.lookup_offset_id(id) } #[inline] fn find(&self, byte: u8) -> gimli::Result { self.reader.find(byte) } #[inline] fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> { self.reader.skip(len) } #[inline] fn to_slice(&self) -> gimli::Result> { self.reader.to_slice() } #[inline] fn to_string(&self) -> gimli::Result> { self.reader.to_string() } #[inline] fn to_string_lossy(&self) -> gimli::Result> { self.reader.to_string_lossy() } #[inline] fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> { self.reader.read_slice(buf) } } impl<'a, R: Reader> Reader for Relocate<'a, R> {} #[derive(Default)] struct Flags { eh_frame: bool, goff: bool, info: bool, line: bool, pubnames: bool, pubtypes: bool, aranges: bool, raw: bool, match_units: Option, } fn print_usage(opts: &getopts::Options) -> ! { let brief = format!("Usage: {} ", env::args().next().unwrap()); write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok(); process::exit(1); } fn main() { let mut opts = getopts::Options::new(); opts.optflag( "", "eh-frame", "print .eh-frame exception handling frame information", ); opts.optflag("G", "", "show global die offsets"); opts.optflag("i", "", "print .debug_info and .debug_types sections"); opts.optflag("l", "", "print .debug_line section"); opts.optflag("p", "", "print .debug_pubnames section"); opts.optflag("r", "", "print .debug_aranges section"); opts.optflag("y", "", "print .debug_pubtypes section"); opts.optflag("", "raw", "print raw data values"); opts.optopt( "u", "match-units", "print compilation units whose output matches a regex", "REGEX", ); let matches = match opts.parse(env::args().skip(1)) { Ok(m) => m, Err(e) => { writeln!(&mut io::stderr(), "{:?}\n", e).ok(); print_usage(&opts); } }; if matches.free.is_empty() { print_usage(&opts); } let mut all = true; let mut flags = Flags::default(); if matches.opt_present("eh-frame") { flags.eh_frame = true; all = false; } if matches.opt_present("G") { flags.goff = true; } if matches.opt_present("i") { flags.info = true; all = false; } if matches.opt_present("l") { flags.line = true; all = false; } if matches.opt_present("p") { flags.pubnames = true; all = false; } if matches.opt_present("y") { flags.pubtypes = true; all = false; } if matches.opt_present("r") { flags.aranges = true; all = false; } if matches.opt_present("raw") { flags.raw = true; } if all { // .eh_frame is excluded even when printing all information. // cosmetic flags like -G must be set explicitly too. flags.info = true; flags.line = true; flags.pubnames = true; flags.pubtypes = true; flags.aranges = true; } flags.match_units = if let Some(r) = matches.opt_str("u") { match Regex::new(&r) { Ok(r) => Some(r), Err(e) => { println!("Invalid regular expression {}: {}", r, e); process::exit(1); } } } else { None }; for file_path in &matches.free { if matches.free.len() != 1 { println!("{}", file_path); println!(); } let file = match fs::File::open(&file_path) { Ok(file) => file, Err(err) => { println!("Failed to open file '{}': {}", file_path, err); continue; } }; let file = match unsafe { memmap::Mmap::map(&file) } { Ok(mmap) => mmap, Err(err) => { println!("Failed to map file '{}': {}", file_path, err); continue; } }; let file = match object::File::parse(&*file) { Ok(file) => file, Err(err) => { println!("Failed to parse file '{}': {}", file_path, err); continue; } }; let endian = if file.is_little_endian() { gimli::RunTimeEndian::Little } else { gimli::RunTimeEndian::Big }; let ret = dump_file(&file, endian, &flags); match ret { Ok(_) => (), Err(err) => println!("Failed to dump '{}': {}", file_path, err,), } } } fn dump_file(file: &object::File, endian: Endian, flags: &Flags) -> Result<()> where Endian: gimli::Endianity + Send + Sync, { let arena = (Arena::new(), Arena::new()); let mut load_section = |id: gimli::SectionId| -> Result<_> { let mut relocations = RelocationMap::default(); let data = match file.section_by_name(id.name()) { Some(ref section) => { add_relocations(&mut relocations, file, section); section.uncompressed_data() } // Use a non-zero capacity so that `ReaderOffsetId`s are unique. None => Cow::Owned(Vec::with_capacity(1)), }; let data_ref = (*arena.0.alloc(data)).borrow(); let reader = gimli::EndianSlice::new(data_ref, endian); let section = reader; let relocations = (*arena.1.alloc(relocations)).borrow(); Ok(Relocate { relocations, section, reader, }) }; let no_relocations = (*arena.1.alloc(RelocationMap::default())).borrow(); let no_reader = Relocate { relocations: no_relocations, section: Default::default(), reader: Default::default(), }; let dwarf = gimli::Dwarf::load(&mut load_section, |_| Ok(no_reader.clone())).unwrap(); let out = io::stdout(); if flags.eh_frame { // TODO: this might be better based on the file format. let address_size = match file.machine() { object::Machine::Arm | object::Machine::Mips | object::Machine::X86 => 4, object::Machine::Arm64 | object::Machine::X86_64 => 8, object::Machine::Other => mem::size_of::() as u8, }; fn register_name_none(_: gimli::Register) -> Option<&'static str> { None } let arch_register_name = match file.machine() { object::Machine::Arm | object::Machine::Arm64 => gimli::Arm::register_name, object::Machine::X86 => gimli::X86::register_name, object::Machine::X86_64 => gimli::X86_64::register_name, _ => register_name_none, }; let register_name = |register| match arch_register_name(register) { Some(name) => Cow::Borrowed(name), None => Cow::Owned(format!("{}", register.0)), }; let mut eh_frame = gimli::EhFrame::load(&mut load_section).unwrap(); eh_frame.set_address_size(address_size); let mut bases = gimli::BaseAddresses::default(); if let Some(section) = file.section_by_name(".eh_frame_hdr") { bases = bases.set_eh_frame_hdr(section.address()); } if let Some(section) = file.section_by_name(".eh_frame") { bases = bases.set_eh_frame(section.address()); } if let Some(section) = file.section_by_name(".text") { bases = bases.set_text(section.address()); } if let Some(section) = file.section_by_name(".got") { bases = bases.set_got(section.address()); } dump_eh_frame( &mut BufWriter::new(out.lock()), &eh_frame, &bases, ®ister_name, )?; } if flags.info { dump_info(&dwarf, flags)?; dump_types(&mut BufWriter::new(out.lock()), &dwarf, flags)?; writeln!(&mut out.lock())?; } let w = &mut BufWriter::new(out.lock()); if flags.line { dump_line(w, &dwarf)?; } if flags.pubnames { let debug_pubnames = &gimli::Section::load(&mut load_section).unwrap(); dump_pubnames(w, debug_pubnames, &dwarf.debug_info)?; } if flags.aranges { let debug_aranges = &gimli::Section::load(&mut load_section).unwrap(); dump_aranges(w, debug_aranges, &dwarf.debug_info)?; } if flags.pubtypes { let debug_pubtypes = &gimli::Section::load(&mut load_section).unwrap(); dump_pubtypes(w, debug_pubtypes, &dwarf.debug_info)?; } Ok(()) } fn dump_eh_frame( w: &mut W, eh_frame: &gimli::EhFrame, bases: &gimli::BaseAddresses, register_name: &Fn(gimli::Register) -> Cow<'static, str>, ) -> Result<()> { // TODO: Print "__eh_frame" here on macOS, and more generally use the // section that we're actually looking at, which is what the canonical // dwarfdump does. writeln!( w, "Exception handling frame information for section .eh_frame" )?; let mut cies = HashMap::new(); let mut entries = eh_frame.entries(bases); loop { match entries.next()? { None => return Ok(()), Some(gimli::CieOrFde::Cie(cie)) => { writeln!(w)?; writeln!(w, "{:#010x}: CIE", cie.offset())?; writeln!(w, " length: {:#010x}", cie.entry_len())?; // TODO: CIE_id writeln!(w, " version: {:#04x}", cie.version())?; // TODO: augmentation writeln!(w, " code_align: {}", cie.code_alignment_factor())?; writeln!(w, " data_align: {}", cie.data_alignment_factor())?; writeln!(w, " ra_register: {:#x}", cie.return_address_register().0)?; if let Some(encoding) = cie.lsda_encoding() { writeln!(w, " lsda_encoding: {:#02x}", encoding.0)?; } if let Some((encoding, personality)) = cie.personality_with_encoding() { write!(w, " personality: {:#02x} ", encoding.0)?; dump_pointer(w, personality)?; writeln!(w)?; } if let Some(encoding) = cie.fde_address_encoding() { writeln!(w, " fde_encoding: {:#02x}", encoding.0)?; } dump_cfi_instructions(w, cie.instructions(eh_frame, bases), true, register_name)?; writeln!(w)?; } Some(gimli::CieOrFde::Fde(partial)) => { let mut offset = None; let fde = partial.parse(|_, bases, o| { offset = Some(o); cies.entry(o) .or_insert_with(|| eh_frame.cie_from_offset(bases, o)) .clone() })?; writeln!(w)?; writeln!(w, "{:#010x}: FDE", fde.offset())?; writeln!(w, " length: {:#010x}", fde.entry_len())?; writeln!(w, " CIE_pointer: {:#010x}", offset.unwrap().0)?; // TODO: symbolicate the start address like the canonical dwarfdump does. writeln!(w, " start_addr: {:#018x}", fde.initial_address())?; writeln!( w, " range_size: {:#018x} (end_addr = {:#018x})", fde.len(), fde.initial_address() + fde.len() )?; if let Some(lsda) = fde.lsda() { write!(w, " lsda: ")?; dump_pointer(w, lsda)?; writeln!(w)?; } dump_cfi_instructions(w, fde.instructions(eh_frame, bases), false, register_name)?; writeln!(w)?; } } } } fn dump_pointer(w: &mut W, p: gimli::Pointer) -> Result<()> { match p { gimli::Pointer::Direct(p) => { write!(w, "{:#018x}", p)?; } gimli::Pointer::Indirect(p) => { write!(w, "({:#018x})", p)?; } } Ok(()) } #[allow(clippy::unneeded_field_pattern)] fn dump_cfi_instructions( w: &mut W, mut insns: gimli::CallFrameInstructionIter, is_initial: bool, register_name: &Fn(gimli::Register) -> Cow<'static, str>, ) -> Result<()> { use gimli::CallFrameInstruction::*; // TODO: we need to actually evaluate these instructions as we iterate them // so we can print the initialized state for CIEs, and each unwind row's // registers for FDEs. // // TODO: We should print DWARF expressions for the CFI instructions that // embed DWARF expressions within themselves. if !is_initial { writeln!(w, " Instructions:")?; } loop { match insns.next() { Err(e) => { writeln!(w, "Failed to decode CFI instruction: {}", e)?; return Ok(()); } Ok(None) => { if is_initial { writeln!(w, " Instructions: Init State:")?; } return Ok(()); } Ok(Some(op)) => match op { SetLoc { address } => { writeln!(w, " DW_CFA_set_loc ({:#x})", address)?; } AdvanceLoc { delta } => { writeln!(w, " DW_CFA_advance_loc ({})", delta)?; } DefCfa { register, offset } => { writeln!( w, " DW_CFA_def_cfa ({}, {})", register_name(register), offset )?; } DefCfaSf { register, factored_offset, } => { writeln!( w, " DW_CFA_def_cfa_sf ({}, {})", register_name(register), factored_offset )?; } DefCfaRegister { register } => { writeln!( w, " DW_CFA_def_cfa_register ({})", register_name(register) )?; } DefCfaOffset { offset } => { writeln!(w, " DW_CFA_def_cfa_offset ({})", offset)?; } DefCfaOffsetSf { factored_offset } => { writeln!( w, " DW_CFA_def_cfa_offset_sf ({})", factored_offset )?; } DefCfaExpression { expression: _ } => { writeln!(w, " DW_CFA_def_cfa_expression (...)")?; } Undefined { register } => { writeln!( w, " DW_CFA_undefined ({})", register_name(register) )?; } SameValue { register } => { writeln!( w, " DW_CFA_same_value ({})", register_name(register) )?; } Offset { register, factored_offset, } => { writeln!( w, " DW_CFA_offset ({}, {})", register_name(register), factored_offset )?; } OffsetExtendedSf { register, factored_offset, } => { writeln!( w, " DW_CFA_offset_extended_sf ({}, {})", register_name(register), factored_offset )?; } ValOffset { register, factored_offset, } => { writeln!( w, " DW_CFA_val_offset ({}, {})", register_name(register), factored_offset )?; } ValOffsetSf { register, factored_offset, } => { writeln!( w, " DW_CFA_val_offset_sf ({}, {})", register_name(register), factored_offset )?; } Register { dest_register, src_register, } => { writeln!( w, " DW_CFA_register ({}, {})", register_name(dest_register), register_name(src_register) )?; } Expression { register, expression: _, } => { writeln!( w, " DW_CFA_expression ({}, ...)", register_name(register) )?; } ValExpression { register, expression: _, } => { writeln!( w, " DW_CFA_val_expression ({}, ...)", register_name(register) )?; } Restore { register } => { writeln!( w, " DW_CFA_restore ({})", register_name(register) )?; } RememberState => { writeln!(w, " DW_CFA_remember_state")?; } RestoreState => { writeln!(w, " DW_CFA_restore_state")?; } ArgsSize { size } => { writeln!(w, " DW_CFA_GNU_args_size ({})", size)?; } Nop => { writeln!(w, " DW_CFA_nop")?; } }, } } } fn dump_info(dwarf: &gimli::Dwarf, flags: &Flags) -> Result<()> where R::Endian: Send + Sync, { let out = io::stdout(); writeln!(&mut BufWriter::new(out.lock()), "\n.debug_info")?; let units = match dwarf.units().collect::>() { Ok(units) => units, Err(err) => { writeln_error( &mut BufWriter::new(out.lock()), dwarf, Error::GimliError(err), "Failed to read unit headers", )?; return Ok(()); } }; let process_unit = |header: CompilationUnitHeader, buf: &mut Vec| -> Result<()> { writeln!( buf, "\nUNIT
:", header.offset().0, )?; let unit = match dwarf.unit(header) { Ok(unit) => unit, Err(err) => { writeln_error(buf, dwarf, err.into(), "Failed to parse unit root entry")?; return Ok(()); } }; let entries_result = dump_entries(buf, unit, dwarf, flags); if let Err(err) = entries_result { writeln_error(buf, dwarf, err, "Failed to dump entries")?; } if !flags .match_units .as_ref() .map(|r| r.is_match(&buf)) .unwrap_or(true) { buf.clear(); } Ok(()) }; // Don't use more than 16 cores even if available. No point in soaking hundreds // of cores if you happen to have them. parallel_output(16, units, process_unit) } fn dump_types( w: &mut W, dwarf: &gimli::Dwarf, flags: &Flags, ) -> Result<()> { writeln!(w, "\n.debug_types")?; let mut iter = dwarf.type_units(); while let Some(header) = iter.next()? { writeln!( w, "\nUNIT
:", header.offset().0, )?; write!(w, " signature = ")?; dump_type_signature(w, header.type_signature())?; writeln!(w)?; writeln!(w, " typeoffset = 0x{:08x}", header.type_offset().0,)?; let unit = match dwarf.type_unit(header) { Ok(unit) => unit, Err(err) => { writeln_error(w, dwarf, err.into(), "Failed to parse unit root entry")?; continue; } }; let entries_result = dump_entries(w, unit, dwarf, flags); if let Err(err) = entries_result { writeln_error(w, dwarf, err, "Failed to dump entries")?; } } Ok(()) } fn spaces(buf: &mut String, len: usize) -> &str { while buf.len() < len { buf.push(' '); } &buf[..len] } // " GOFF=0x{:08x}" adds exactly 16 spaces. const GOFF_SPACES: usize = 16; fn write_offset( w: &mut W, unit: &gimli::Unit, offset: gimli::UnitOffset, flags: &Flags, ) -> Result<()> { write!(w, "<0x{:08x}", offset.0)?; if flags.goff { let goff = match offset.to_unit_section_offset(unit) { UnitSectionOffset::DebugInfoOffset(o) => o.0, UnitSectionOffset::DebugTypesOffset(o) => o.0, }; write!(w, " GOFF=0x{:08x}", goff)?; } write!(w, ">")?; Ok(()) } fn dump_entries( w: &mut W, unit: gimli::Unit, dwarf: &gimli::Dwarf, flags: &Flags, ) -> Result<()> { let mut spaces_buf = String::new(); let mut depth = 0; let mut entries = unit.entries(); while let Some((delta_depth, entry)) = entries.next_dfs()? { depth += delta_depth; assert!(depth >= 0); let mut indent = depth as usize * 2 + 2; write!(w, "<{}{}>", if depth < 10 { " " } else { "" }, depth)?; write_offset(w, &unit, entry.offset(), flags)?; writeln!(w, "{}{}", spaces(&mut spaces_buf, indent), entry.tag())?; indent += 18; if flags.goff { indent += GOFF_SPACES; } let mut attrs = entry.attrs(); while let Some(attr) = attrs.next()? { w.write_all(spaces(&mut spaces_buf, indent).as_bytes())?; if let Some(n) = attr.name().static_string() { let right_padding = 27 - std::cmp::min(27, n.len()); write!(w, "{}{} ", n, spaces(&mut spaces_buf, right_padding))?; } else { write!(w, "{:27} ", attr.name())?; } if flags.raw { writeln!(w, "{:?}", attr.raw_value())?; } else { match dump_attr_value(w, &attr, &unit, dwarf) { Ok(_) => (), Err(err) => writeln_error(w, dwarf, err, "Failed to dump attribute value")?, }; } } } Ok(()) } fn dump_attr_value( w: &mut W, attr: &gimli::Attribute, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { let value = attr.value(); match value { gimli::AttributeValue::Addr(address) => { writeln!(w, "0x{:08x}", address)?; } gimli::AttributeValue::Block(data) => { for byte in data.to_slice()?.iter() { write!(w, "{:02x}", byte)?; } writeln!(w)?; } gimli::AttributeValue::Data1(_) | gimli::AttributeValue::Data2(_) | gimli::AttributeValue::Data4(_) | gimli::AttributeValue::Data8(_) => { if let (Some(udata), Some(sdata)) = (attr.udata_value(), attr.sdata_value()) { if sdata >= 0 { writeln!(w, "{}", udata)?; } else { writeln!(w, "{} ({})", udata, sdata)?; } } else { writeln!(w, "{:?}", value)?; } } gimli::AttributeValue::Sdata(data) => { match attr.name() { gimli::DW_AT_data_member_location => { writeln!(w, "{}", data)?; } _ => { if data >= 0 { writeln!(w, "0x{:08x}", data)?; } else { writeln!(w, "0x{:08x} ({})", data, data)?; } } }; } gimli::AttributeValue::Udata(data) => { match attr.name() { gimli::DW_AT_high_pc => { writeln!(w, "{}", data)?; } gimli::DW_AT_data_member_location => { if let Some(sdata) = attr.sdata_value() { // This is a DW_FORM_data* value. // libdwarf-dwarfdump displays this as signed too. if sdata >= 0 { writeln!(w, "{}", data)?; } else { writeln!(w, "{} ({})", data, sdata)?; } } else { writeln!(w, "{}", data)?; } } gimli::DW_AT_lower_bound | gimli::DW_AT_upper_bound => { writeln!(w, "{}", data)?; } _ => { writeln!(w, "0x{:08x}", data)?; } }; } gimli::AttributeValue::Exprloc(ref data) => { if let gimli::AttributeValue::Exprloc(_) = attr.raw_value() { write!(w, "len 0x{:04x}: ", data.0.len())?; for byte in data.0.to_slice()?.iter() { write!(w, "{:02x}", byte)?; } write!(w, ": ")?; } dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::AttributeValue::Flag(true) => { // We don't record what the value was, so assume 1. writeln!(w, "yes(1)")?; } gimli::AttributeValue::Flag(false) => { writeln!(w, "no")?; } gimli::AttributeValue::SecOffset(offset) => { writeln!(w, "0x{:08x}", offset)?; } gimli::AttributeValue::DebugAddrBase(base) => { writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugAddrIndex(index) => { let address = dwarf.address(unit, index)?; writeln!(w, "0x{:08x}", address)?; } gimli::AttributeValue::UnitRef(offset) => { write!(w, "0x{:08x}", offset.0)?; let goff = match offset.to_unit_section_offset(unit) { UnitSectionOffset::DebugInfoOffset(o) => { write!(w, "<.debug_info+")?; o.0 } UnitSectionOffset::DebugTypesOffset(o) => { write!(w, "<.debug_types+")?; o.0 } }; writeln!(w, "0x{:08x}>", goff)?; } gimli::AttributeValue::DebugInfoRef(gimli::DebugInfoOffset(offset)) => { writeln!(w, "<.debug_info+0x{:08x}>", offset)?; } gimli::AttributeValue::DebugInfoRefSup(gimli::DebugInfoOffset(offset)) => { writeln!(w, "<.debug_info(sup)+0x{:08x}>", offset)?; } gimli::AttributeValue::DebugLineRef(gimli::DebugLineOffset(offset)) => { writeln!(w, "0x{:08x}", offset)?; } gimli::AttributeValue::LocationListsRef(offset) => { dump_loc_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugLocListsBase(base) => { writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugLocListsIndex(index) => { let offset = dwarf.locations_offset(unit, index)?; dump_loc_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugMacinfoRef(gimli::DebugMacinfoOffset(offset)) => { writeln!(w, "{}", offset)?; } gimli::AttributeValue::RangeListsRef(offset) => { dump_range_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugRngListsBase(base) => { writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugRngListsIndex(index) => { let offset = dwarf.ranges_offset(unit, index)?; dump_range_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugTypesRef(signature) => { dump_type_signature(w, signature)?; writeln!(w, " ")?; } gimli::AttributeValue::DebugStrRef(offset) => { if let Ok(s) = dwarf.debug_str.get_str(offset) { writeln!(w, "{}", s.to_string_lossy()?)?; } else { writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; } } gimli::AttributeValue::DebugStrRefSup(offset) => { writeln!(w, "<.debug_str(sup)+0x{:08x}>", offset.0)?; } gimli::AttributeValue::DebugStrOffsetsBase(base) => { writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?; } gimli::AttributeValue::DebugStrOffsetsIndex(index) => { let offset = dwarf.debug_str_offsets.get_str_offset( unit.encoding().format, unit.str_offsets_base, index, )?; if let Ok(s) = dwarf.debug_str.get_str(offset) { writeln!(w, "{}", s.to_string_lossy()?)?; } else { writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; } } gimli::AttributeValue::DebugLineStrRef(offset) => { if let Ok(s) = dwarf.debug_line_str.get_str(offset) { writeln!(w, "{}", s.to_string_lossy()?)?; } else { writeln!(w, "<.debug_line_str=0x{:08x}>", offset.0)?; } } gimli::AttributeValue::String(s) => { writeln!(w, "{}", s.to_string_lossy()?)?; } gimli::AttributeValue::Encoding(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::DecimalSign(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Endianity(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Accessibility(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Visibility(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Virtuality(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Language(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::AddressClass(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::IdentifierCase(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::CallingConvention(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Inline(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::Ordering(value) => { writeln!(w, "{}", value)?; } gimli::AttributeValue::FileIndex(value) => { write!(w, "0x{:08x}", value)?; dump_file_index(w, value, unit, dwarf)?; writeln!(w)?; } } Ok(()) } fn dump_type_signature(w: &mut W, signature: gimli::DebugTypeSignature) -> Result<()> { write!(w, "0x{:016x}", signature.0)?; Ok(()) } fn dump_file_index( w: &mut W, file: u64, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { if file == 0 { return Ok(()); } let header = match unit.line_program { Some(ref program) => program.header(), None => return Ok(()), }; let file = match header.file(file) { Some(header) => header, None => { writeln!(w, "Unable to get header for file {}", file)?; return Ok(()); } }; write!(w, " ")?; if let Some(directory) = file.directory(header) { let directory = dwarf.attr_string(unit, directory)?; let directory = directory.to_string_lossy()?; if !directory.starts_with('/') { if let Some(ref comp_dir) = unit.comp_dir { write!(w, "{}/", comp_dir.to_string_lossy()?,)?; } } write!(w, "{}/", directory)?; } write!( w, "{}", dwarf .attr_string(unit, file.path_name())? .to_string_lossy()? )?; Ok(()) } fn dump_exprloc( w: &mut W, data: &gimli::Expression, unit: &gimli::Unit, ) -> Result<()> { let mut pc = data.0.clone(); let mut space = false; while pc.len() != 0 { let mut op_pc = pc.clone(); let dwop = gimli::DwOp(op_pc.read_u8()?); match gimli::Operation::parse(&mut pc, &data.0, unit.encoding()) { Ok(op) => { if space { write!(w, " ")?; } else { space = true; } dump_op(w, dwop, op, &pc)?; } Err(gimli::Error::InvalidExpression(op)) => { writeln!(w, "WARNING: unsupported operation 0x{:02x}", op.0)?; return Ok(()); } Err(gimli::Error::UnsupportedRegister(register)) => { writeln!(w, "WARNING: unsupported register {}", register)?; return Ok(()); } otherwise => panic!("Unexpected Operation::parse result: {:?}", otherwise), } } Ok(()) } fn dump_op( w: &mut W, dwop: gimli::DwOp, op: gimli::Operation, newpc: &R, ) -> Result<()> { write!(w, "{}", dwop)?; match op { gimli::Operation::Deref { base_type, size, .. } => { if dwop == gimli::DW_OP_deref_size || dwop == gimli::DW_OP_xderef_size { write!(w, " {}", size)?; } if base_type != UnitOffset(0) { write!(w, " type 0x{:08x}", base_type.0)?; } } gimli::Operation::Pick { index } => { if dwop == gimli::DW_OP_pick { write!(w, " {}", index)?; } } gimli::Operation::PlusConstant { value } => { write!(w, " {}", value as i64)?; } gimli::Operation::Bra { target } => { let offset = newpc.len() as isize - target.len() as isize; write!(w, " {}", offset)?; } gimli::Operation::Skip { target } => { let offset = newpc.len() as isize - target.len() as isize; write!(w, " {}", offset)?; } gimli::Operation::Literal { value } => match dwop { gimli::DW_OP_const1s | gimli::DW_OP_const2s | gimli::DW_OP_const4s | gimli::DW_OP_const8s | gimli::DW_OP_consts => { write!(w, " {}", value as i64)?; } gimli::DW_OP_const1u | gimli::DW_OP_const2u | gimli::DW_OP_const4u | gimli::DW_OP_const8u | gimli::DW_OP_constu => { write!(w, " {}", value)?; } _ => { // These have the value encoded in the operation, eg DW_OP_lit0. } }, gimli::Operation::Register { register } => { if dwop == gimli::DW_OP_regx { write!(w, " {}", register.0)?; } } gimli::Operation::RegisterOffset { register, offset, base_type, } => { if dwop >= gimli::DW_OP_breg0 && dwop <= gimli::DW_OP_breg31 { write!(w, "{:+}", offset)?; } else { write!(w, " {}", register.0)?; if offset != 0 { write!(w, "{:+}", offset)?; } if base_type != UnitOffset(0) { write!(w, " type 0x{:08x}", base_type.0)?; } } } gimli::Operation::FrameOffset { offset } => { write!(w, " {}", offset)?; } gimli::Operation::Call { offset } => match offset { gimli::DieReference::UnitRef(gimli::UnitOffset(offset)) => { write!(w, " 0x{:08x}", offset)?; } gimli::DieReference::DebugInfoRef(gimli::DebugInfoOffset(offset)) => { write!(w, " 0x{:08x}", offset)?; } }, gimli::Operation::Piece { size_in_bits, bit_offset: None, } => { write!(w, " {}", size_in_bits / 8)?; } gimli::Operation::Piece { size_in_bits, bit_offset: Some(bit_offset), } => { write!(w, " 0x{:08x} offset 0x{:08x}", size_in_bits, bit_offset)?; } gimli::Operation::ImplicitValue { data } => { let data = data.to_slice()?; write!(w, " 0x{:08x} contents 0x", data.len())?; for byte in data.iter() { write!(w, "{:02x}", byte)?; } } gimli::Operation::ImplicitPointer { value, byte_offset } => { write!(w, " 0x{:08x} {}", value.0, byte_offset)?; } gimli::Operation::EntryValue { expression } => { write!(w, " 0x{:08x} contents 0x", expression.len())?; for byte in expression.to_slice()?.iter() { write!(w, "{:02x}", byte)?; } } gimli::Operation::ParameterRef { offset } => { write!(w, " 0x{:08x}", offset.0)?; } gimli::Operation::Address { address } => { write!(w, " 0x{:08x}", address)?; } gimli::Operation::AddressIndex { index } => { write!(w, " 0x{:08x}", index.0)?; } gimli::Operation::ConstantIndex { index } => { write!(w, " 0x{:08x}", index.0)?; } gimli::Operation::TypedLiteral { base_type, value } => { write!(w, " type 0x{:08x} contents 0x", base_type.0)?; for byte in value.to_slice()?.iter() { write!(w, "{:02x}", byte)?; } } gimli::Operation::Convert { base_type } => { write!(w, " type 0x{:08x}", base_type.0)?; } gimli::Operation::Reinterpret { base_type } => { write!(w, " type 0x{:08x}", base_type.0)?; } gimli::Operation::Drop | gimli::Operation::Swap | gimli::Operation::Rot | gimli::Operation::Abs | gimli::Operation::And | gimli::Operation::Div | gimli::Operation::Minus | gimli::Operation::Mod | gimli::Operation::Mul | gimli::Operation::Neg | gimli::Operation::Not | gimli::Operation::Or | gimli::Operation::Plus | gimli::Operation::Shl | gimli::Operation::Shr | gimli::Operation::Shra | gimli::Operation::Xor | gimli::Operation::Eq | gimli::Operation::Ge | gimli::Operation::Gt | gimli::Operation::Le | gimli::Operation::Lt | gimli::Operation::Ne | gimli::Operation::Nop | gimli::Operation::PushObjectAddress | gimli::Operation::TLS | gimli::Operation::CallFrameCFA | gimli::Operation::StackValue => {} }; Ok(()) } fn dump_loc_list( w: &mut W, offset: gimli::LocationListsOffset, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { let raw_locations = dwarf.locations.raw_locations(offset, unit.encoding())?; let raw_locations: Vec<_> = raw_locations.collect()?; let mut locations = dwarf.locations(unit, offset)?; writeln!( w, "", if unit.encoding().version < 5 { ".debug_loc" } else { ".debug_loclists" }, offset.0, raw_locations.len() )?; for (i, raw) in raw_locations.iter().enumerate() { write!(w, "\t\t\t[{:2}]", i)?; match *raw { gimli::RawLocListEntry::BaseAddress { addr } => { writeln!(w, "", addr)?; } gimli::RawLocListEntry::BaseAddressx { addr } => { let addr_val = dwarf.address(unit, addr)?; writeln!(w, "", addr.0, addr_val)?; } gimli::RawLocListEntry::StartxEndx { begin, end, ref data, } => { let begin_val = dwarf.address(unit, begin)?; let end_val = dwarf.address(unit, end)?; let location = locations.next()?.unwrap(); write!( w, "", begin.0, begin_val, location.range.begin, end.0, end_val, location.range.end )?; dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::RawLocListEntry::StartxLength { begin, length, ref data, } => { let begin_val = dwarf.address(unit, begin)?; let location = locations.next()?.unwrap(); write!( w, "", begin.0, begin_val, location.range.begin, length, location.range.end )?; dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::RawLocListEntry::AddressOrOffsetPair { begin, end, ref data, } | gimli::RawLocListEntry::OffsetPair { begin, end, ref data, } => { let location = locations.next()?.unwrap(); write!( w, "", begin, location.range.begin, end, location.range.end )?; dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::RawLocListEntry::DefaultLocation { ref data } => { write!(w, "")?; dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::RawLocListEntry::StartEnd { begin, end, ref data, } => { let location = locations.next()?.unwrap(); write!( w, "", begin, location.range.begin, end, location.range.end )?; dump_exprloc(w, data, unit)?; writeln!(w)?; } gimli::RawLocListEntry::StartLength { begin, length, ref data, } => { let location = locations.next()?.unwrap(); write!( w, "", begin, location.range.begin, length, location.range.end )?; dump_exprloc(w, data, unit)?; writeln!(w)?; } }; } Ok(()) } fn dump_range_list( w: &mut W, offset: gimli::RangeListsOffset, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { let raw_ranges = dwarf.ranges.raw_ranges(offset, unit.encoding())?; let raw_ranges: Vec<_> = raw_ranges.collect()?; let mut ranges = dwarf.ranges(unit, offset)?; writeln!( w, "", if unit.encoding().version < 5 { ".debug_ranges" } else { ".debug_rnglists" }, offset.0, raw_ranges.len() )?; for (i, raw) in raw_ranges.iter().enumerate() { write!(w, "\t\t\t[{:2}] ", i)?; match *raw { gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } => { let range = ranges.next()?.unwrap(); writeln!( w, "
", begin, range.begin, end, range.end )?; } gimli::RawRngListEntry::BaseAddress { addr } => { writeln!(w, "", addr)?; } gimli::RawRngListEntry::BaseAddressx { addr } => { let addr_val = dwarf.address(unit, addr)?; writeln!(w, "", addr.0, addr_val)?; } gimli::RawRngListEntry::StartxEndx { begin, end } => { let begin_val = dwarf.address(unit, begin)?; let end_val = dwarf.address(unit, end)?; let range = if begin_val == end_val { gimli::Range { begin: begin_val, end: end_val, } } else { ranges.next()?.unwrap() }; writeln!( w, "", begin.0, begin_val, range.begin, end.0, end_val, range.end )?; } gimli::RawRngListEntry::StartxLength { begin, length } => { let begin_val = dwarf.address(unit, begin)?; let range = ranges.next()?.unwrap(); writeln!( w, "", begin.0, begin_val, range.begin, length, range.end )?; } gimli::RawRngListEntry::OffsetPair { begin, end } => { let range = ranges.next()?.unwrap(); writeln!( w, "", begin, range.begin, end, range.end )?; } gimli::RawRngListEntry::StartEnd { begin, end } => { let range = if begin == end { gimli::Range { begin, end } } else { ranges.next()?.unwrap() }; writeln!( w, "", begin, range.begin, end, range.end )?; } gimli::RawRngListEntry::StartLength { begin, length } => { let range = ranges.next()?.unwrap(); writeln!( w, "", begin, range.begin, length, range.end )?; } }; } Ok(()) } fn dump_line(w: &mut W, dwarf: &gimli::Dwarf) -> Result<()> { let mut iter = dwarf.units(); while let Some(header) = iter.next()? { writeln!( w, "\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}", header.offset().0 )?; let unit = match dwarf.unit(header) { Ok(unit) => unit, Err(err) => { writeln_error(w, dwarf, err.into(), "Failed to parse unit root entry")?; continue; } }; match dump_line_program(w, &unit, dwarf) { Ok(_) => (), Err(Error::IoError) => return Err(Error::IoError), Err(err) => writeln_error(w, dwarf, err, "Failed to dump line program")?, } } Ok(()) } fn dump_line_program( w: &mut W, unit: &gimli::Unit, dwarf: &gimli::Dwarf, ) -> Result<()> { if let Some(program) = unit.line_program.clone() { { let header = program.header(); writeln!(w)?; writeln!( w, "Offset: 0x{:x}", header.offset().0 )?; writeln!( w, "Length: {}", header.unit_length() )?; writeln!( w, "DWARF version: {}", header.version() )?; writeln!( w, "Address size: {}", header.address_size() )?; writeln!( w, "Prologue length: {}", header.header_length() )?; writeln!( w, "Minimum instruction length: {}", header.minimum_instruction_length() )?; writeln!( w, "Maximum operations per instruction: {}", header.maximum_operations_per_instruction() )?; writeln!( w, "Default is_stmt: {}", header.default_is_stmt() )?; writeln!( w, "Line base: {}", header.line_base() )?; writeln!( w, "Line range: {}", header.line_range() )?; writeln!( w, "Opcode base: {}", header.opcode_base() )?; writeln!(w)?; writeln!(w, "Opcodes:")?; for (i, length) in header .standard_opcode_lengths() .to_slice()? .iter() .enumerate() { writeln!(w, " Opcode {} has {} args", i + 1, length)?; } let base = if header.version() >= 5 { 0 } else { 1 }; writeln!(w)?; writeln!(w, "The Directory Table:")?; for (i, dir) in header.include_directories().iter().enumerate() { writeln!( w, " {} {}", base + i, dwarf.attr_string(unit, dir.clone())?.to_string_lossy()? )?; } writeln!(w)?; writeln!(w, "The File Name Table")?; write!(w, " Entry\tDir\tTime\tSize")?; if header.file_has_md5() { write!(w, "\tMD5\t\t\t\t")?; } writeln!(w, "\tName")?; for (i, file) in header.file_names().iter().enumerate() { write!( w, " {}\t{}\t{}\t{}", base + i, file.directory_index(), file.timestamp(), file.size(), )?; if header.file_has_md5() { let md5 = file.md5(); write!(w, "\t")?; for i in 0..16 { write!(w, "{:02X}", md5[i])?; } } writeln!( w, "\t{}", dwarf .attr_string(unit, file.path_name())? .to_string_lossy()? )?; } writeln!(w)?; writeln!(w, "Line Number Instructions:")?; let mut instructions = header.instructions(); while let Some(instruction) = instructions.next_instruction(header)? { writeln!(w, " {}", instruction)?; } writeln!(w)?; writeln!(w, "Line Number Rows:")?; writeln!(w, " [lno,col]")?; } let mut rows = program.rows(); let mut file_index = 0; while let Some((header, row)) = rows.next_row()? { let line = row.line().unwrap_or(0); let column = match row.column() { gimli::ColumnType::Column(column) => column, gimli::ColumnType::LeftEdge => 0, }; write!(w, "0x{:08x} [{:4},{:2}]", row.address(), line, column)?; if row.is_stmt() { write!(w, " NS")?; } if row.basic_block() { write!(w, " BB")?; } if row.end_sequence() { write!(w, " ET")?; } if row.prologue_end() { write!(w, " PE")?; } if row.epilogue_begin() { write!(w, " EB")?; } if row.isa() != 0 { write!(w, " IS={}", row.isa())?; } if row.discriminator() != 0 { write!(w, " DI={}", row.discriminator())?; } if file_index != row.file_index() { file_index = row.file_index(); if let Some(file) = row.file(header) { if let Some(directory) = file.directory(header) { write!( w, " uri: \"{}/{}\"", dwarf.attr_string(unit, directory)?.to_string_lossy()?, dwarf .attr_string(unit, file.path_name())? .to_string_lossy()? )?; } else { write!( w, " uri: \"{}\"", dwarf .attr_string(unit, file.path_name())? .to_string_lossy()? )?; } } } writeln!(w)?; } } Ok(()) } fn dump_pubnames( w: &mut W, debug_pubnames: &gimli::DebugPubNames, debug_info: &gimli::DebugInfo, ) -> Result<()> { writeln!(w, "\n.debug_pubnames")?; let mut cu_offset; let mut cu_die_offset = gimli::DebugInfoOffset(0); let mut prev_cu_offset = None; let mut pubnames = debug_pubnames.items(); while let Some(pubname) = pubnames.next()? { cu_offset = pubname.unit_header_offset(); if Some(cu_offset) != prev_cu_offset { let cu = debug_info.header_from_offset(cu_offset)?; cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); prev_cu_offset = Some(cu_offset); } let die_in_cu = pubname.die_offset(); let die_in_sect = cu_offset.0 + die_in_cu.0; writeln!(w, "global die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'", die_in_sect, cu_die_offset.0, die_in_cu.0, cu_offset.0, pubname.name().to_string_lossy()? )?; } Ok(()) } fn dump_pubtypes( w: &mut W, debug_pubtypes: &gimli::DebugPubTypes, debug_info: &gimli::DebugInfo, ) -> Result<()> { writeln!(w, "\n.debug_pubtypes")?; let mut cu_offset; let mut cu_die_offset = gimli::DebugInfoOffset(0); let mut prev_cu_offset = None; let mut pubtypes = debug_pubtypes.items(); while let Some(pubtype) = pubtypes.next()? { cu_offset = pubtype.unit_header_offset(); if Some(cu_offset) != prev_cu_offset { let cu = debug_info.header_from_offset(cu_offset)?; cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); prev_cu_offset = Some(cu_offset); } let die_in_cu = pubtype.die_offset(); let die_in_sect = cu_offset.0 + die_in_cu.0; writeln!(w, "pubtype die-in-sect 0x{:08x}, cu-in-sect 0x{:08x}, die-in-cu 0x{:08x}, cu-header-in-sect 0x{:08x} '{}'", die_in_sect, cu_die_offset.0, die_in_cu.0, cu_offset.0, pubtype.name().to_string_lossy()? )?; } Ok(()) } fn dump_aranges( w: &mut W, debug_aranges: &gimli::DebugAranges, debug_info: &gimli::DebugInfo, ) -> Result<()> { writeln!(w, "\n.debug_aranges")?; let mut cu_die_offset = gimli::DebugInfoOffset(0); let mut prev_cu_offset = None; let mut aranges = debug_aranges.items(); while let Some(arange) = aranges.next()? { let cu_offset = arange.debug_info_offset(); if Some(cu_offset) != prev_cu_offset { let cu = debug_info.header_from_offset(cu_offset)?; cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size()); prev_cu_offset = Some(cu_offset); } if let Some(segment) = arange.segment() { write!( w, "arange starts at seg,off 0x{:08x},0x{:08x}, ", segment, arange.address() )?; } else { write!(w, "arange starts at 0x{:08x}, ", arange.address())?; } writeln!( w, "length of 0x{:08x}, cu_die_offset = 0x{:08x}", arange.length(), cu_die_offset.0 )?; } Ok(()) } gimli-0.19.0/examples/simple.rs010066400017500001750000000044071351057326000146110ustar0000000000000000use object::Object; use std::{borrow, env, fs}; fn main() { for path in env::args() { let file = fs::File::open(&path).unwrap(); let mmap = unsafe { memmap::Mmap::map(&file).unwrap() }; let object = object::File::parse(&*mmap).unwrap(); let endian = if object.is_little_endian() { gimli::RunTimeEndian::Little } else { gimli::RunTimeEndian::Big }; dump_file(&object, endian).unwrap(); } } fn dump_file(object: &object::File, endian: gimli::RunTimeEndian) -> Result<(), gimli::Error> { // Load a section and return as `Cow<[u8]>`. let load_section = |id: gimli::SectionId| -> Result, gimli::Error> { Ok(object .section_data_by_name(id.name()) .unwrap_or(borrow::Cow::Borrowed(&[][..]))) }; // Load a supplementary section. We don't have a supplementary object file, // so always return an empty slice. let load_section_sup = |_| Ok(borrow::Cow::Borrowed(&[][..])); // Load all of the sections. let dwarf_cow = gimli::Dwarf::load(&load_section, &load_section_sup)?; // Borrow a `Cow<[u8]>` to create an `EndianSlice`. let borrow_section: &dyn for<'a> Fn( &'a borrow::Cow<[u8]>, ) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = &|section| gimli::EndianSlice::new(&*section, endian); // Create `EndianSlice`s for all of the sections. let dwarf = dwarf_cow.borrow(&borrow_section); // Iterate over the compilation units. let mut iter = dwarf.units(); while let Some(header) = iter.next()? { println!("Unit at <.debug_info+0x{:x}>", header.offset().0); let unit = dwarf.unit(header)?; // Iterate over the Debugging Information Entries (DIEs) in the unit. let mut depth = 0; let mut entries = unit.entries(); while let Some((delta_depth, entry)) = entries.next_dfs()? { depth += delta_depth; println!("<{}><{:x}> {}", depth, entry.offset().0, entry.tag()); // Iterate over the attributes in the DIE. let mut attrs = entry.attrs(); while let Some(attr) = attrs.next()? { println!(" {}: {:?}", attr.name(), attr.value()); } } } Ok(()) } gimli-0.19.0/fixtures/self/README.md010066400017500001750000000105451343337721300152210ustar0000000000000000# What are these files? These files are the DWARF data generated for (an early version of) this library. Each file corresponds is a section from the built library's object file. By splitting the sections out to their own files, we don't need to worry about cross platform and cross object file format issues when running examples. # Updating and adding new sections ## OSX Use `otool` to list the sections of a binary: ``` $ otool -l path/to/binary ``` You should see output similar to this: ``` Load command 0 cmd LC_SEGMENT_64 cmdsize 72 segname __PAGEZERO vmaddr 0x0000000000000000 vmsize 0x0000000100000000 fileoff 0 filesize 0 maxprot 0x00000000 initprot 0x00000000 nsects 0 flags 0x0 Load command 1 cmd LC_SEGMENT_64 cmdsize 712 segname __TEXT vmaddr 0x0000000100000000 vmsize 0x00000000001b7000 fileoff 0 filesize 1798144 maxprot 0x00000007 initprot 0x00000005 nsects 8 flags 0x0 Section sectname __text segname __TEXT addr 0x0000000100000a50 size 0x0000000000170716 offset 2640 align 2^4 (16) reloff 0 nreloc 0 flags 0x80000400 reserved1 0 reserved2 0 ``` Etc. Find the `Section` entry of the section you'd like to isolate. For example, if you're looking for `eh_frame`, find an entry like this: ``` Section sectname __eh_frame segname __TEXT addr 0x0000000100192f38 size 0x00000000000240c8 offset 1650488 align 2^3 (8) reloff 0 nreloc 0 flags 0x00000000 reserved1 0 reserved2 0 ``` Then use `dd` to copy `size` bytes starting from `offset`: ``` $ dd bs=1 skip=1650488 count=$(printf "%d" 0x00000000000240c8) if=path/to/binary of=fixtures/self/eh_frame ``` Finally, use `otool` and `hexdump` to verify that the isolated section has the same data as the section within the binary: ``` $ otool -s __TEXT __eh_frame path/to/binary | head path/to/binary: Contents of (__TEXT,__eh_frame) section 0000000100192f38 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 0000000100192f48 10 0c 07 08 90 01 00 00 24 00 00 00 1c 00 00 00 0000000100192f58 f8 da e6 ff ff ff ff ff 66 00 00 00 00 00 00 00 0000000100192f68 00 41 0e 10 86 02 43 0d 06 00 00 00 00 00 00 00 0000000100192f78 1c 00 00 00 00 00 00 00 01 7a 50 4c 52 00 01 78 0000000100192f88 10 07 9b 9d 40 02 00 10 10 0c 07 08 90 01 00 00 0000000100192f98 2c 00 00 00 24 00 00 00 20 db e6 ff ff ff ff ff 0000000100192fa8 8d 00 00 00 00 00 00 00 08 37 e7 fd ff ff ff ff $ otool -s __TEXT __eh_frame path/to/binary | tail 00000001001b6f68 9a 0a 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d 00000001001b6f78 06 50 83 07 8c 06 8d 05 8e 04 8f 03 00 00 00 00 00000001001b6f88 24 00 00 00 7c 0e 00 00 30 a0 fb ff ff ff ff ff 00000001001b6f98 15 00 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d 00000001001b6fa8 06 00 00 00 00 00 00 00 24 00 00 00 a4 0e 00 00 00000001001b6fb8 28 a0 fb ff ff ff ff ff 1c 00 00 00 00 00 00 00 00000001001b6fc8 00 41 0e 10 86 02 43 0d 06 00 00 00 00 00 00 00 00000001001b6fd8 24 00 00 00 cc 0e 00 00 20 a0 fb ff ff ff ff ff 00000001001b6fe8 66 01 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d 00000001001b6ff8 06 00 00 00 00 00 00 00 ``` This should be the same, ignoring the leading offsets: ``` $ hexdump fixtures/self/eh_frame | head 0000000 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 0000010 10 0c 07 08 90 01 00 00 24 00 00 00 1c 00 00 00 0000020 f8 da e6 ff ff ff ff ff 66 00 00 00 00 00 00 00 0000030 00 41 0e 10 86 02 43 0d 06 00 00 00 00 00 00 00 0000040 1c 00 00 00 00 00 00 00 01 7a 50 4c 52 00 01 78 0000050 10 07 9b 9d 40 02 00 10 10 0c 07 08 90 01 00 00 0000060 2c 00 00 00 24 00 00 00 20 db e6 ff ff ff ff ff 0000070 8d 00 00 00 00 00 00 00 08 37 e7 fd ff ff ff ff 0000080 ff 41 0e 10 86 02 43 0d 06 00 00 00 00 00 00 00 0000090 24 00 00 00 94 00 00 00 80 db e6 ff ff ff ff ff $ hexdump fixtures/self/eh_frame | tail 0024040 06 50 83 07 8c 06 8d 05 8e 04 8f 03 00 00 00 00 0024050 24 00 00 00 7c 0e 00 00 30 a0 fb ff ff ff ff ff 0024060 15 00 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d 0024070 06 00 00 00 00 00 00 00 24 00 00 00 a4 0e 00 00 0024080 28 a0 fb ff ff ff ff ff 1c 00 00 00 00 00 00 00 0024090 00 41 0e 10 86 02 43 0d 06 00 00 00 00 00 00 00 00240a0 24 00 00 00 cc 0e 00 00 20 a0 fb ff ff ff ff ff 00240b0 66 01 00 00 00 00 00 00 00 41 0e 10 86 02 43 0d 00240c0 06 00 00 00 00 00 00 00 ``` ## Linux Something like this: ``` objcopy --dump-section .eh_frame=fixtures/self/eh_frame path/to/binary ``` gimli-0.19.0/fixtures/self/debug_abbrev010066400017500001750000000035111343337721300162670ustar0000000000000000%U99: ; 9: ;4I: ;  ‡@4I: ; ‡@4I? : ;  ‡@.@ ‡@: ;I  : ;I  4 : ;I U /IIm  (    I8 .@ ‡@: ; I?  : ; I.@ ‡@: ; I.@ ‡@: ;I? .@ ‡@: ;I.@ ‡@: ;I  I8 4 : ; I.@ ‡@: ;1X Y 1.@ ‡@: ; I!I"$> #$> $.@ ‡@: ;I? % & '.@ ‡@: ;? (1X Y ).‡@: ;I? *.@ ‡@: ; ? +.‡@: ; I? ,: ; I-4: ; I.1UX Y/4 10.@ ‡@: ;I? 1I2I3.@ ‡@: ;? 4.@ 15.@ 16.@ ‡@: ; I? 7I8I9!I" :$ > ;: ;I4I? : ;  ?I@&IAI: ; B!I/ C!I/D4I: ; E4I: ;  F : ; G I: ; 8 HI: ;I : ;J I: ;8 K : ;L : ; MN : ; O I: ; 8 P : ; Q : ; R' S&TI' U : ;V4I: ;W4I: ; X.: ;' I Y.: ;' I Z4: ;I[.: ; ' I \.: ;' ].: ; ' ^.@ : ;' I_: ;I`1a41b1c1d.: ;' I? e.: ;' f.@ : ;' ? g4: ;Ih.: ;' I? i.: ;' ? j.@ : ;' I? k4: ;Il 1m1X Yn41o1UX Y p1UX Yq1X Y r.@ : ;' s41t%á Uu.@ : ; ' v: ; Iw: ; Ix4: ; Iy.@ : ; ' I? z.@ : ; ' ? {.@ : ; ' I? |.: ; ' I? }.@ : ; ' I~.@ : ;' I? 4 : ;I€!I1UX Y ‚.: ; ' ? ƒ4: ; I„4 1…gimli-0.19.0/fixtures/self/debug_aranges010066400017500001750000000376601343337721300164620ustar0000000000000000œ(#@ï0 @xÀ“`'Àà#"@#p°#àíÐ à ð# ñ  0@#p°Ð+@ù€6Àz@ß %P Q° Ð êÀ!2"Q`"êP#Q°#ê $Q%êð%QP&ê@'_  2?à2Ͱ5*à58 6!P6¿>n€Aø€B[àBC¬°Eÿ°HŒ@I5€I.°I>ðI- JCpJÖPK?K¡@L¤ðL[PMàN|`O™P8@P:€PQ°QÐQN RR€RW6ÐW2X2PX2X2ÐX¶Y2ÐYŸp[2°[6ð[a`\*]'À]Ð^ à^_&0_ @`2€`9À`m0b2pb® d2`d,dGàd¾ f¬PjxÐkqPlpl6°l—Pm3mÍp+0p+`p q| q¾`sâ wky2P‰ðŠ|p‹±"0®QÆßðÍ$ ÕµàÖ2 ×2`×$×vÚ®ÀÜ7à.0àUà  àÄpáU âGpâ( â7àâ7 ã&Pã#€ã ãÀã%PäÇ å @åå0æ]æï€çYàçðè ëKPë `ëC°ë.àë%ì#@ì`ì€ì7Àì7í%0í"`í'í‹ î&Pî4îLàî ðî ïz€ïðRpð# ðÀðPñG ñJðñ& ò2`ò2 òÀó>ô¯ ûR€üMÐ à ð q€.° #PR°u0å #Pp– Úð VP yÐ % =@ Ö  0    R @`Î0$`°l .P.€ 6àT@Ù @%p¯ fÐàÖÀ—` p5°YZp°Š@‘àúàKP`+— 0)¯à)ÚÀ* Ð*b@+Î,¤À,à,[@-[ -ˆ@/¼3IP3¯4 4¨Ð6ð67Rp7- 9g:3P:V°:1ð:. ;¡Ð;ˆ`<&< =+P=+€=²@Ee°EÐIðIJK`J€J Jå Wh\ \QÐ\$]æð]^ìð`¢ gÀgu@h¤ðhiO`iâPk:kXðk l l*PlL l °lÖm(ÀnR p„°p.àqðrøðuvC`vaÐvðv& wFpwœ°x‚@yg°yh ~Ip~¯ @¤@€`C°x0ˆĉg‰ª‹]@Œú@ŽCð‡€—™2Й¯€š¯0››ТÉ ¤Ìp¦FÀ­Я2°¯À°›`´¾ ¶À¹î°»2𻯠¼Ÿ@¾Ù ÀÀÃÒ ÅNðÈîàÊ2 ˯ÐË)ÐÎÐÑ2Ò¯ÀÒ#ðÖ£ÐßÁ Ðé2ê2Pê2ê2Ðê2ë2Pë!€ë™ ìµàí2 î@î(pîÛPïpðñ²Pùß°Fq€ "ÐF ñ Fp& ê©@)p…7@ƒÐF ê¨À ï°!)à"…p#FÀ$&ð&& )&P+&€-ÿ€/¼@0`1¼ 2Fp3ÿp5Ä@6`6€7ÉP8p9Æ@:`;ß@=Ì>0?É@ AÆðAC¼ÐCðD×ÐEðFÔÐGðHÔÐIðJ' K@KIK“ÐLðLM.@M!pM_ÐMðN×ÐOðPÔÐQR0RTRÎ`T2 T¯PUlÀW2XÄÐ_Ä g±`o®w*@|"p|® „±à‹¸ “Îp›" ›Àœj0žVž Ÿ ¡µà£~`¥J°¥&à¥6 ¦å§%@§?€§l𧨨f€¨ÎP°]°²¾pºBÀÊ=Ù¶ ÀäàëîÐú= 0¯à= &¤Ð.J D| Dq FBpFH GNpGK KAðKZPLß0Mm N2àN®P,ÀPBQ,@QGQ… R¼ àrœ€t"°u vJpxðy# { 0|ŒÀ|Û }¤P~lÀƒA…Áà…&† †.P†‡R€‡°‡Dˆ§°ˆ©`‰> ‰Dð‰' Š@Š`ŠA°‹†ðŒ2@,pGÀðl`ŽË0 @zÀà¬Øp”øp•æ`–Œð—˜)0˜Ü™g€™DЙêÀš.ðš. ›.P›à œ6`œÎ0 @.p¿0Ÿ+`Ÿƒð èà¡&¢#@¢`¢€¢ ¢+ТwP£;£¤GP¤(€¤7 ¥Ħ"0¦é § 0©7p©šª®Rð®RP¯,€¯GЯ% »Z`»bÐÀŒ`ÂpÂ) Â ÃI@Å&pÅÂ@ÆZ Æ·`Çû`È,ÈDàÈ[ @Ó}ÀÖD×ÎàØ2 Ù¯ÐÙË Û–@ã6€ä/°äÐåŒ`æîPè2è¯@éœàðÝÀòôÀøàý‘€þÎP2¯@“àÑÀR LÙpz@+p+ŒÚÝh°hÖj j/Ðk£€lWàl¯n:ÐpàpðpE@q)pq€qq§@†ã 0“I€›ƒ  ¤—@©µ­?0½ÉL'p¾fp¾Tоœp¿dà¿_@ïðÄýðÅ€ÇÉwÍ-ÀÍ] Ï.PЭÓÛàÙpÝã;Ðä‘péÎ@íÙ û0ûÇþR`ÿ$ÿ ÿDð   0 ä  +P  ` € $° Ð - œ   ° X" ö1 02 •Ð8 ð9 ; ÍàA ðC ÇÀE ˆPG Ì J ÈðK ûL©iðL 40O QO 3<á‚ÐO #P HLB„PP (€P  P NàP ðP Q ¼ÀQ ÐR  àS ñàT 5 U R€U ;À\ M] ‹ a ¿`c QÀd c0f k f <$°f Àf  <ÃÐf àg  , Åðg ãàh ™€j }m hpn # n _o š o •@p •àp •€q • r •Àr •`s VÀs «pt ® u ®Ðu ®€v ®0w ®àw ®x ®@y ®ðy ® z Àz ¼€{ ½@| ¼} ½À} à} ¼ ~ ½` ½ € ½à€  ¸À ¸€‚ ¸@ƒ ¸„ ¸À„ ¸€… ¸@† ¸‡ ¸À‡ ±€ˆ ±@‰ ±Š ±ÀŠ ®p‹ ® Œ ®ÐŒ ®€ ±@Ž ± ±À ±€ ®0‘ ®à‘  ð‘  ’  ’  ’  0’  @’  P’ vÐ’ !” ‰” ‰ • "P– ^°– _— _p— _З +š  š s š Àš i0› P› kÀ› i0œ l œ Hðœ . 4` vàž ¾ Ÿ ¾`  Ã0¢ R£ Æ`¦ 𨠀« eð« b`¬ bЬ _0­ l ­ b® b€® eð® b`¯ eЯ b@° e°°  À°  а e@± b°±  À±  б  à±  ð±  ²  ²  ²  0²  @²  P² [°² [³ [p³ [г _0´ [´ [ð´ [Pµ [°µ [¶ [p¶ [ж [0· [· [ð· d`» ò`½ ò`¿ ò`Á ò`à  pà  €Ã QàÇ œ€É ã¬؃pÑ  €Ñ ª0Ó %`Ö L°Ü  ÀÜ PÝ ³Þ ½Ðß (œ§å  å Õ ð ÿ ú æðû ¶°ü ©` rà Õ<2À Ð Ìà  ð     0 P  `  p  €   ° V|½ Äà q` ù` p € ,ƒ  \e)°  À u@ qÀ ’Lïb` p fà f< zP að3 ³ ó‘°T Ç€U TàX [ _`[ bÐ[ zP^ 7_ ^ðb ]Pf )€f IÐh àh ¾ i /Ði C j ¡ŒéËÐk ðk ÂÀo àt z ­°z b { gœ[î{ Jà{ .|  | ô ~ nP— ›ð— ™ gimli-0.19.0/fixtures/self/debug_info010066400017500001750000013772001343337721300157730ustar0000000000000000Ù5BP#[a h«ZÝ Ðe Êá ˆh ÕZÝà Pg Êá °h ÕZÝ (h Êá Èh ÕZÝî 8h Êá àh ÕÊá øh Õ Êá t C¼ZÝ h{ `Êá X| ¡ZÝ x{ `Êá p| ¡ZÝ ˆ{ `Êá ˆ| ¡ZÝÅ ˜{ `Êá  | ¡ÝËZÝ ¸| úÊá ø| ;ZÝ È| úÊá } ;ZÝ Ø| úÊá (} ;ZÝÙ è| úÊá @} ;wÞZÝã X} ¥Êá h} ÷DèZÝí €} fÊá } ¬íóZÝý ¨} Êá ¸} [ŸZÝ Ð} ÀÊá P~ ZÝ ð} ÀÊá h~ ZÝ ~ ÀÊá €~ E ZÝ% ˜~ sÊá ¸~ ÅZÝ, ¨~ sÊá Ð~ Å1ZÝ6 è~ ;Êá ø~ ˆÐHZÝ  òÊá   8ZÝN   òÊá ¸ 8ySZÝY Ð ¦Êá à ÷C^ZÝ ø eÊá € «ZÝd € eÊá 0€ «ìiZÝo H€  Êá X€ j ¶ yZÝ p€ Ñ Êá ð€  ZÝ~ €€ Ñ Êá    ¾J þÊá  U ˆ ;ZÝ H ± Êá ¨ þ ZÝQ X ± Êá À þ F WZÝ Ø o Êá ø ¼ ZÝo è o Êá ‚ ¼  ˜ ZÝ ðƒ  Êá Є \ ZÝ „  Êá è„ \ ZÝ „  • ¨á °„ ¦ Êá  … \ å º ZÝ 8…  Êá x… A ZÝ H…  Êá … A ZÝ X…  • ¨á h… | Êá ¨… A ½ Ý ZÝ À… Ù Êá † ZÝ Ð… Ù Êá † ZÝ à… Ù • ¨á ð… TÊá 0† • ZÝ H† ±Êá ˆ† ñZÝ X† ±Êá  † ñZÝ h† ±• ¨á x† ,Êá ¸† ñm# ZÝ І ˆÊá ‡ ÇZÝ à† ˆÊá (‡ ÇZÝ ð† ˆ• ¨á ‡ Êá @‡ ÇAF ZÝ X‡ \Êá ˆ‡ ›ZÝ h‡ \• ¨á x‡ ÕÊá  ‡ ›g ZÝ ¸‡ 0Êá ø‡ oZÝ ȇ 0Êá ˆ oZÝ ؇ 0• ¨á è‡ ©Êá (ˆ oé‰ ZÝ @ˆ Êá €ˆ CZÝ Pˆ Êá ˜ˆ CZÝ `ˆ • ¨á pˆ }Êá °ˆ C½« ZÝ Ȉ ØÊá ‰ ZÝ ؈ ØÊá  ‰ ZÝ èˆ Ø• ¨á øˆ QÊá 8‰ ‘Í ZÝ À‰ ¬Êá Š ëZÝ Љ ¬Êá Š ëZÝ à‰ ¬• ¨á ð‰ %Êá 0Š ëeô ZÝ pŠ €Êá °Š ¿ZÝ €Š €Êá ÈŠ ¿ZÝ Š €• ¨á  Š ùÊá àŠ ¿9 ZÝ øŠ VÊá 8‹ —ZÝ ‹ VÊá P‹ —ZÝ ‹ V• ¨á (‹ ÓÊá h‹ —> ZÝ €‹ 4Êá °‹ wZÝ ‹ 4• ¨á  ‹ µÊá È‹ wù_ ZÝ à‹ Êá Œ ]ZÝ ð‹ • ¨á Œ œÊá (Œ ]ဠZÝ @Œ Êá €Œ IZÝ PŒ Êá ˜Œ IZÝ `Œ • ¨á pŒ ŠÊá °Œ IѤ ZÝ ÈŒ ôÊá  ;ZÝ ØŒ ôÊá  ;ZÝ èŒ ô• ¨á øŒ }Êá 8 ;ÅÆ ZÝ P èÊá  /ZÝ ` èÊá ¨ /ZÝ p è• ¨á € qÊá À /¹è ZÝ Ø ÓÊá Ž ZÝ è Ó• ¨á ø JÊá  Ž ‰ ZÝ 8Ž £Êá xŽ áZÝ HŽ £Êá Ž áZÝ XŽ £• ¨á hŽ Êá ¨Ž áY+ ZÝ ÀŽ sÊá  ±ZÝ ÐŽ sÊá  ±ZÝ àŽ s• ¨á ðŽ êÊá 0 ±)M ZÝ H CÊá ˆ ZÝ X CÊá   ZÝ h C• ¨á x ºÊá ¸ ùo ZÝ Ð Êá  YZÝ à Êá ( YZÝ ð • ¨á  –Êá @ YÙ– ZÝ X ùÊá ˜ =ZÝ h ùÊá ° =ZÝ x ù• ¨á ˆ |Êá È =Á¸ ZÝ à áÊá  ‘ % ZÝ ð áÊá 8‘ % ZÝ ‘ á• ¨á ‘ d Êá P‘ % © Ú ZÝ h‘ Æ Êá ¨‘ !ZÝ x‘ Æ Êá À‘ !ZÝ ˆ‘ Æ • ¨á ˜‘ C!Êá Ø‘ !…!ý ZÝ ð‘ ¡!Êá 0’ á!ZÝ ’ ¡!Êá H’ á!ZÝ ’ ¡!• ¨á  ’ "Êá `’ á!]" ZÝ x’ z"Êá ¸’ »"ZÝ ˆ’ z"Êá Ð’ »"ZÝ ˜’ z"• ¨á ¨’ ÷"Êá è’ »"9#A ZÝ “ V#Êá @“ —#ZÝ “ V#Êá X“ —#ZÝ  “ V#• ¨á 0“ Ó#Êá p“ —#$c ZÝ Г 3$Êá ” u$ZÝ à“ 3$Êá (” u$ZÝ ð“ 3$• ¨á ” ²$Êá @” u$ œ õ$¥ Êá X” ú$pG@KV&%d%¥ ¢< ‘x†%¥ Ð ‚GõJ ‘‹%´ o1 ‘H%« U­ îI¯J ‘è}”%· ¤6 CJ¯J ‘À}‹%· 6 ¾JõJ ‘·}™%» 9& À+›%¢%Ä ZÝ È” ²%Êá P– æ%ZÝ Ø” ²%• ¨á (• &Êá h– æ%Êá €– æ%ZÝ h• ²%Êá ˜– æ%ZÝ x• ²%• ¨á ˆ• &Êá °– æ%Êá È– æ%ZÝ ¸• ²%Êá à– æ%ZÝ È• ²%• ¨á Ø• &Êá ø– æ%Êá — æ%Êá (— æ%Êá @— æ%ZÝ @– ²%Êá X— æ% :J&>Êá p— R&Êá ˆ— R&&l@ÅfÅVŽ&á&p“­ ‘p'p›Ö À+›%pÅ2ÆVŽ&á&q“­ ‘p'q›Ö À+›%'¥ZÝ  — 1'Êá °— l'0˜ ™V¢'á&­“­ ‘p‹%­›Ö À+›%ö'IZÝ ™  (Êá Xš D(ZÝ 8™  (Êá pš D(ZÝ X™  (Êá ˆš D(ZÝ x™  (Êá  š D(ZÝ ˜™  (Êá ¸š D(ZÝ ¸™  (Êá К D(ZÝ Ø™  (Êá èš D(ZÝ ø™  (Êá › D(ZÝ š  (Êá › D(Êá 0› D(Êá H› D(x(šZÝ `›  (Êá 8œ ì(Êá Pœ ì(Êá hœ ì(3)ÓZÝ €œ ])Êá °œ «)Êá Èœ «)Êá àœ «)ô)ŽZÝ øœ *Êá 8 R*ZÝ“  *Êá P R*Ž*˜ZÝ h ³*Êá x ü*@+°ZÝ  ]+Êá ž ž+ZÝ   ]+Êá (ž ž+ZÝ ° ]+Êá @ž ž+Zݹ À ]+Êá Xž ž+Ú+¾ZÝ pž ÷+Êá °ž 8,ZÝ €ž ÷+Êá Èž 8,ZÝ ž ÷+Êá àž 8,ZÝÇ  ž ÷+Êá øž 8,t,ÌZÝÒ Ÿ –,Êá  Ÿ Ü,-ZÝ 8Ÿ ?-• ¨á ¸Ÿ …-ZÝ ÈŸ ?-Êá   Ì-ZÝ? ØŸ ?-Êá    Ì-2Þ ..%.5.J.U.d.p.|.‰.£. ¹. È. á. õ. 2Þ/ //z¬/*/4/>/I/Y/i/}/ ƒ/ / —/£/±/½/È/Ö/å/í/÷/ 00!010=0O0V0f0 n0!{0"„0#–0$Ÿ0%ª0&´0'½0(È0)Ñ0*Ø0+á0,î0-ù0.1/10111<12E13Q14Z15g16v17ƒ18‘19›1:ª1;º1<Æ1=Ó1?Ý1Àè1Áñ1Â2Ã2€2ÿÿ2Þ!292<2z¬@2N2V2_2d2 m2 v2 €2 ˆ2‘2—2ž2§2­2¸2Ã2Ê2×2ç2ï2ú2 33 3!(3"33%<3'G3*R3,]3.g3/r313233œ34§35±36Ã37É38Ü39ç3:ð3;ù3<4=4>4?!4ÀÑ0Á+4Â:4Ãá0ÄD4ÅM4ÆU4Çc4Èn4És4Ê4Ë‘4Ìœ4ͯ4ι4ÏÄ4ÐÑ4ÑÜ4Òä4Óì4Ôö4Õý4Ö5×5Ø5Ù%5Ú15Û=5ÜJ5ÝP5Þ\5ßg5àu5á}5â‹5ã”5ä¢5å¬5æ¶5ç»5èÅ5éÏ5êÞ5ëì5ìö5í6î2€À2ÿÿ2Þ 666&6-63696?6F6 L6 S6 Y6 ^6 d6i6o6w6|66†6‹6”66§6¯6»6 2ÞÃ66F6Ò6^6i6§6Y66×6ß6 ì6 ú6 ?6 77$7(v#(7$7(v#77$7(v#I7$7(v#Y7$7(v#d7‹7®,# 2À2Vž7Û7k%, ‘p‹7kU­ À+›%À2ß2Vü7G8}–- ‘x†%}ÐÐ À+›%ˆ8$7U­#¯8]O#€BÛBV³8÷8·®,‘x†%·ÖÏ‘p9·lP À+›%K°KVž7Û7­®,‘p#9­U­ À+›%ðLKMV'9i9»®,‘x†%»ÖÏ‘p9»žP À+›%˜9Ê9®,#Ð90ý9(v# :z¬#:ì+#%:2Þ#2:™&#9:®,#  JcJVE:’:§9Þ ‘w2:§™& À+›%pJFKV×:;°9Þ ‘2:°™& 0 ‘pZ;±9Þ ‘hk;²9Þ ‘`x;³9Þ ‘X‘;·9Þ À+›%°K1LVž7Û7”©- ‘`ý9”(v ‘^ :•z¬ ‘P:–ì+ ‘G%:—2Þ ‘F2:˜™& ‘°9:™U­ À+›%@LäLV£;ò;É(v ‘p†%É‰Ç À+›%V;<<ß2Þ ‘x†%ß‰Ç À+›%@6W6V«<ë<ä™& ‘p†%ä‰Ç À+›%0|¼|V=P= 79 ‘x†% ‰Ç ‘p}= ŸÈ À+›% ÆWÇV‹=Ô=è“­ ‘p†%è‰Ç ‘h>è, ` ‘XK;é9Þ ‘P>î9Þ À+›%`Ç[ÈV³8÷8þU­ ‘h†%þ‰Ç ‘`9þ·P ‘¨0>9Þ À+›%6>$7®,#¯8™&#@IuIV_>ž>‰1 ‘x†%‰†® ‘h”%‰®, À+›%Ç>Þ>Q(#ã>Ä*#`ׄ×Vè>‡o1 ‘vÞ>‡Q( ‘uã>‡Ä*V?Þ>Q( ‘p†%§ÄV'?ã>”Ä* ‘p†%”§ÄG?(T?(v#Y?±&#]?9(# j?2°# ò²óVè>2 ‘pT?(v ‘nY?±& ‘m]?9( ‘Pj? 2°Vu?T?(v ‘x†%RÆV•?Y?±& ‘p†%RÆÀóþóV´?]?“­ ‘p†%RÆVÝ?j?'JÄ ‘h†%'RÆ@(@@š#pŽV@;@IB3°:VA@c@R¬ ‘h†%R›Ò ‘@j@R2 è% ‘Ø~q@U ¢ðvwVw@–@]„: ‘x†%]ŸÈ ‘pT?](vÃ6Œ4#«4#Ê4#é4#5#'5#F5#e5#„5#£5#Â5#á5#6#6š@f+#$7U­#F6š@f+#$7U­#Ò6š@f+#$7U­#^6š@f+#$7H¯#i6š@f+#$7(v#§6š@f+#$7U­#Y6š@f+#$7“­#6š@f+#$7(v#×6š@f+#$7,#ß6š@f+#$7ÿ+#ì6š@f+#$7Æ+#ú6š@f+#$7Ù+#?6š@f+#$7U­#©@ Þ>Q(#³@4# î9îV?Þ>Q( ‘p†%èÏ@îhîV¹@³@"4 ‘x†%"èÏÚ@ $7®,#¯8‰Ç#Ao1#qV AOA2¤6 ‘p†%2ÄÇ ‘`”%2U­ g ‘P#95U­ À+›% U­xA@ÃVzAïA2¤6 ‘p†%2ÄÇ ‘`”%2®, v¹ ‘P#95U­ À+›% ®,xApMÏMV³8÷89¤6 ‘x†%9ÄÇ ‘pHB9lP À+›%NB8…BU­#‘BäW#T?(v# j@RÆ#(B‰Ç#0™w™V¢BáBÕƒ8 ‘x†%Õ–È À+›% C(Ê9U­#j?JÄ#q@–È# 1CZC®,#àrsVž7Û7H®8 ‘pZCHU­ À+›% vpvVoC¶CM’& ‘x†%M× À+›%áCpÊ9U­#B‰Ç#}=ŸÈ# D:Y# P~¼ƒVD\D>K> ‘p†%?× ƒ~à ‘XDD,[ ª ‘¸DE"× _€€ ‘ß~™%P9& À€™ƒ ‘À~”%UU­ ‘°~T?U(v À ‘~j@VRÆ ð ‘È}ˆDWK> ‘°}D_²[ À+›%ª®VDÑDßÄ? ‘p†%ß×  ‘ J&á8 P ‘˜}EìÃÈ ‘Ø| Dù²[ 骫 ‘è~‘BâU­ «¬« ‘à~ Eåû¬ f«¬« ‘à}Eåƒ8 À+›%`»ÂÀVE_Elí@ ‘p†%l× € ‘˜J&n8 ° ‘è~‰Eo¢< ‘ˆ|•E‡ÃÈ ÿ¼¿ ‘à}‰Es×$ d½¿ ‘ð|>t, à ‘è{EˆÃÈ À+›%›E@ÁE©-#ÈE(v#0×EÆ+#8àýqþVž7Û7ä.< ‘PÁEä©- ‘HÈEå(v ‘@×EæÆ+ À+›% 3VãEFz¬‘p#9U­°ÓVF4F'á‘p#9U­ðV=FaF"(v‘p#9"U­ ZÐûVjF‹FZ9&‘p†%ZÐ@9V‘F°FZÝ‘p†%ZБh´FZ-­ ¨Ö‘¸¼FÓì Ú‘¼FÓì F‘è~¼FÓì M„‘À~¼FÓì ‹Â‘˜~¼FÓì É‘ð}¼FÓì >‘È}¼FÓì E|‘ }¼FÓì ƒº‘ø|¼FÓì Áø‘Ð|¼FÓì ÿ6‘¨|¼FÓì =t‘€|¼FÓì {¯‘Ø{¼FÓì ¶ê‘°{¼FÓìÀàVÄFßFÚ2‘pÊ9ÚU­ P ¡ VèFG“­ ‘x†%BÐ ‘p´FBÐ d •  ‘h GIÆ  •  ‘`GIÆÐ º!V‘F°FÝ ‘p†%BÐ ‘h´F-­ M!®! ‘`GIÆ M!®!‘@¼FÓì "Q"VèFG“­ ‘x†%–Ð ‘p´F–Ð "E" ‘h GIÆ /"E" ‘`GIÆ`"J#V‘F°FÝ ‘p†%–Ð ‘h´F-­ Ý"># ‘`GIÆ Ý">#‘@¼FÓì P#¡#VèFG“­ ‘x†%ßÏ ‘p´FßÏ d#•# ‘h GIÆ #•# ‘`GIư#š$V‘F°FÝ ‘p†%ßÏ ‘h´F-­ -$Ž$ ‘`GIÆ -$Ž$‘@¼FÓì  $ñ$VèFG“­ ‘x†%ŸÐ ‘p´FŸÐ ´$å$ ‘h GIÆ Ï$å$ ‘`GIÆ%ê%V‘F°FÝ ‘p†%ŸÐ ‘h´F-­ }%Þ% ‘`GIÆ }%Þ%‘@¼FÓì +ð%A&VèFG+“­ ‘x†%+¨Ð ‘p´F+¨Ð &5& ‘h G,IÆ &5& ‘`G,IÆP&:'V‘F°F+Ý ‘p†%+¨Ð ‘h´F+-­ Í&.' ‘`G,IÆ Í&.'‘@¼FÓì@'Ÿ2VGh« d'•2 ‘–#9¬±Ð ‘€IGÒ%, ‘à~TGÓ–-  ‘è}ÁEÖ©- @ ‘ð|ZGש- Ð*F,‘ˆ|cG‰Ç‘˜|mG‰Ç œ+ä+‘ðzvG¾Ð‘€{}G¾Ð p ‘ }„Gàf5 l,x,‘èy}GÇÐ   ‘ØxÁEä©- Ð ‘àwZGå©- 0ˆ1‘àvcG‰Ç‘ðvmG‰Ç Þ0&1‘ÈuvG¾Ð‘Øu}G¾Ð  ‘x„Gîf5 ®1º1‘Àt}GÇÐ à2­5V&%d%’f5 ‘x†%’ÙÐ 0 ‘Ð~ÁE—©- ` ‘¸~ŽG˜9Þ \4³4 ‘Ç~™% 9& À+›% É 6A6V—GÖGÍU­‘h†%ÍÖÏ À+›%P6>VÿGMHÉ ‘pÊ9®, …6ÿ= ‘Ð~”%®, ‘È~ý9(v ‘Ç~2:™& ñ67‘ð~¦HØ­ (7C7‘ç~ªH9& À7ÿ= ‘¸}”%®, ‘¶} :z¬ 8H8‘Ø}¦H5® W8r8‘Ï}ªH9& Ð8ÿ= ‘€|”% 1 ‘ø{> ì+ u9¯9‘¨|¦HT® ¾9Ù9‘Ÿ|ªH9& v:ÿ= ‘Øz”%!U­ ‘×z%:!2Þ ‘ÈzÃ:#9Þ ‘ÀzK;$9Þ ‘¸z%*9Þ ‘ z9:/U­ ý:);‘øz¦Hš­ 8;S;‘ïzªH9& À+›%>~AV®HðH¬ ‘hÊ9¬®, O>QA ‘~”%°®, ‘ˆ~¦H°(v ¹>Ü>‘Ø~¦H® ë>?‘Ï~ªH9& ß?-A ‘Ø|”%´®, ß?-A ‘Ð|¦H´(v >@j@‘ }¦H® y@Ÿ@‘—}ªH9& À+›%€AxBV1IrIs ‘pÊ9®, À+›%CðCV±IëIøs‘pÊ9ø®, À+›%ðC¬EVJZJn  ‘pÊ9®, %DšE ‘è~”%®, ‘æ~¦Hz¬ {D•D‘ˆ¦H5® ¡D¼D‘ÿ~ªH9& À+›%°E FV“JÍJân ‘pÊ9â®, À+›% FGVþJHK;m  ‘hÊ9<1 ÅF€G ‘H>@s À+›%K;°HD(v ‘h#Ê9D1 À+›%€I®IVðKLt2 ‘pÊ9tU­ –°IîIV)LgL™U­ ‘h†%™1 À+›% ÒðIJV)LgLÕU­‘`†%Õ®, À+›% ƒPMÑNVŽLÊLƒ“­ ‘x†%ƒ‰Ç ‘p´Fƒ‰Ç ¢M¾N ‘h G‡IÆ ‘PêLŠ® ‘`õLˆÍÏ ‘HM‹ÄÏ ‘X M‰ßÏ ‘@MŒÖÏ öM¾N ‘˜!M‹ÄÏ ‘¨,M‰ßÏ ‘ 7MŠ® ‘°BMˆÍÏ ‘¸G‡IÆ ‘MMŒÖÏ À+›%€RWVXM•MƒÝ ‘H†%ƒ‰Ç ‘@´Fƒ-­ óTzW ‘˜!M‹ÄÏ ‘¨,M‰ßÏ ‘ 7MŠ® ‘°BMˆÍÏ ‘¸G‡IÆ ‘MMŒÖÏ óTzW‘€¼F í À+›% zàN\OVèFGz“­ ‘p†%zÄÏ ‘h´FzÄÏ îNUO ‘`¶MzÃÈ ‘PÀMzÃÈÐX†YV‘F°FzÝ ‘p†%zÄÏ ‘h´Fz-­ YGY‘¸¼FÓì KYvY‘¼FÓì §`OùOVŽLÊL§“­‘x†%§ÖÏ‘p´F§ÖÏ ƒOéO‘h G¨AÄ‘`õL¨âÐ «OéO‘PBM¨âБXG¨AÄ À+›%ÐYo[VXM•M§Ý‘p†%§ÖÏ‘h´F§-­ µZc[‘XBM¨âБ`G¨AÄ µZc[‘¸¼FÓì À+›%àdžfVËMñMõ  ‘pÊ9õU­ Jene ‘@¦H÷(v  ‘¸™%øwÑ ‘¸™%øwÑ q^sVN(N ‘pÊ9U­ r.r ‘@¦HH¯ Ð ‘¸™%wÑ ‘¸™%wÑ w yV9NdN   ‘pÊ9 U­ ¶wùx ‘ø~”% U­ ‘ð~T? (v x1x‘˜¦H˜® :xRx‘ªH9&yB‰V|N¦N[i ‘pÊ9[U­ &y¸ˆ ‘ø~”%\U­ ‘ð~¦H\(v ‡y¡y‘˜¦H˜® ªyÂy‘ªH9&P‰íŠV½NðNë¾ ‘pÊ9ëU­ f‰ÙŠ ‘ø~”%ìU­ ‘÷~¦Hì2Þ Ç‰á‰‘˜¦Hš­ ꉊ‘ªH9& úðŠl‹VèFGú“­ ‘p†%úŸÑ ‘h´FúŸÑ þŠe‹ ‘`¶MúÃÈ ‘PÀMúÃÈp‹!®V‘F°FúÝ ‘p†%úŸÑ ‘h´Fú-­ —•Å•‘¸¼FÓì É•÷•‘¼FÓì þ•5–‘è~¼FÓì <–s–‘À~¼FÓì z–±–‘˜~¼FÓì ¸–ï–‘ð}¼FÓì ö–-—‘È}¼FÓì 4—k—‘ }¼FÓì r—©—‘ø|¼FÓì °—ç—‘Ð|¼FÓì î—%˜‘¨|¼FÓì ,˜c˜‘€|¼FÓì j˜¡˜‘Ø{¼FÓì ¨˜ߘ‘°{¼FÓì æ˜™‘ˆ{¼FÓì $™[™‘àz¼FÓì b™™™‘¸z¼FÓì  ™×™‘z¼FÓì Þ™š‘èy¼FÓì šSš‘Ày¼FÓì Zš‘š‘˜y¼FÓì ˜šÏš‘ðx¼FÓì Öš ›‘Èx¼FÓì ›K›‘ x¼FÓì R›‰›‘øw¼FÓì ›Ç›‘Ðw¼FÓì Λœ‘¨w¼FÓì œCœ‘€w¼FÓì Jœœ‘Øv¼FÓì ˆœ¿œ‘°v¼FÓì Æœýœ‘ˆv¼FÓì ;‘àu¼FÓì By‘¸u¼FÓì €·‘u¼FÓì ¾õ‘èt¼FÓì ü3ž‘Àt¼FÓì :žqž‘˜t¼FÓì xž¯ž‘ðs¼FÓì ¶žíž‘Ès¼FÓì ôž+Ÿ‘ s¼FÓì 2ŸiŸ‘ør¼FÓì pŸ§Ÿ‘Ðr¼FÓì ®ŸåŸ‘¨r¼FÓì ìŸ# ‘€r¼FÓì * a ‘Øq¼FÓì h Ÿ ‘°q¼FÓì ¦ Ý ‘ˆq¼FÓì ä ¡‘àp¼FÓì "¡Y¡‘¸p¼FÓì `¡—¡‘p¼FÓì ž¡Õ¡‘èo¼FÓì Ü¡¢‘Ào¼FÓì ¢Q¢‘˜o¼FÓì X¢¢‘ðn¼FÓì –¢Í¢‘Èn¼FÓì Ô¢ £‘ n¼FÓì £I£‘øm¼FÓì P£‡£‘Ðm¼FÓì Ž£Å£‘¨m¼FÓì Ì£¤‘€m¼FÓì ¤A¤‘Øl¼FÓì H¤¤‘°l¼FÓì †¤½¤‘ˆl¼FÓì Ĥû¤‘àk¼FÓì ¥9¥‘¸k¼FÓì @¥w¥‘k¼FÓì ~¥µ¥‘èj¼FÓì ¼¥ó¥‘Àj¼FÓì ú¥1¦‘˜j¼FÓì 8¦o¦‘ði¼FÓì v¦­¦‘Èi¼FÓì ´¦ë¦‘ i¼FÓì ò¦)§‘øh¼FÓì 0§g§‘Ðh¼FÓì n§¥§‘¨h¼FÓì ¬§ã§‘€h¼FÓì ê§!¨‘Øg¼FÓì (¨_¨‘°g¼FÓì f¨¨‘ˆg¼FÓì ¤¨Û¨‘àf¼FÓì ⨩‘¸f¼FÓì ©W©‘f¼FÓì ^©•©‘èe¼FÓì œ©Ó©‘Àe¼FÓì Ú©ª‘˜e¼FÓì ªOª‘ðd¼FÓì Vªª‘Èd¼FÓì ”ª˪‘ d¼FÓì Òª «‘øc¼FÓì «G«‘Ðc¼FÓì N«…«‘¨c¼FÓì Œ«ë‘€c¼FÓì Ê«¬‘Øb¼FÓì ¬?¬‘°b¼FÓì0®ÆVO8O^ ‘pÊ9^U­ F®µÅ ‘ø~”%_U­ ‘ð~¦H_(v §®Á®‘˜¦H˜® ʮ⮑ªH9& %ÆoÍV‘F°F%Ý ‘p†%%¨Ñ ‘h´F%-­ ÷Æ%Ç‘¸¼FÓì )ÇWÇ‘¼FÓì ^ǕǑè~¼FÓì œÇÓÇ‘À~¼FÓì ÚÇÈ‘˜~¼FÓì ÈOÈ‘ð}¼FÓì VÈÈ‘È}¼FÓì ”ÈËÈ‘ }¼FÓì ÒÈ É‘ø|¼FÓì ÉGÉ‘Ð|¼FÓì NÉ…É‘¨|¼FÓì ŒÉÃÉ‘€|¼FÓì ÊÉÊ‘Ø{¼FÓì Ê?Ê‘°{¼FÓì FÊ}Ê‘ˆ{¼FÓì „Ê»Ê‘àz¼FÓì ÂÊùÊ‘¸z¼FÓì Ë7Ë‘z¼FÓì >ËuË‘èy¼FÓì |˳ˑÀy¼FÓì ºËñË‘˜y¼FÓì øË/Ì‘ðx¼FÓì 6ÌmÌ‘Èx¼FÓì t̫̑ x¼FÓì ²ÌæÌ‘øw¼FÓìðÍÕVMOuODh ‘pÊ9DU­ ÎÒÔ ‘ø~”%EU­ ‘ð~¦HE(v gÎΑ˜¦H˜® ŠÎ¢Î‘ªH9&  ÕÕÖV‘F°FÝ ‘p†%§Ä ‘h´F-­ ÖÉÖ ‘XBM‚¨Ñ ‘`GŸÑ ÖÉÖ‘H¼F í×ÚVŠO»O˽ ‘pÊ9ËU­ ¦×öÙ ‘ø~”%ÌU­ ‘ö~Þ>ÌQ( Ø!Ø‘˜¦H¯ *ØBØ‘ªH9& ƒØöÙ ‘ø}”%ÍU­ ‘÷}ã>ÍÄ* ‘ð}ÙOÎo1 ôØ Ù‘˜~¦H¬¯ /ÙJÙ‘~ªH9&Ú¾ÜVÞOPÓ¼ ‘pÊ9ÓU­ &Ú®Ü ‘ø~”%ÔU­ ‘ð~Þ>Ô(v ‡Ú¡Ú‘˜¦H˜® ªÚÂÚ‘ªH9& 9Û®Ü ‘ø}”%ÙU­ ‘ð}ã>Ù(v §ÛÓÛ‘˜~¦H˜® âÛýÛ‘~ªH9&ÀÜ÷ßV7PiPãc ‘hÊ9ãU­  ‘PCå2° @ ‘°ˆDè¸ € ‘è~ˆDé¸ ‘à}”%êU­ ‘Ø}‹%ê[7 dÞ“Þ‘€~¦Hêà ¬Þ ß‘÷}ªH9& ¨ßÕß ‘È}‹%ïo1iPãpáÅáVˆP 'èêà ‘P”%èU­0ææVˆP 'é¸ ‘h#Ê9éU­ 'é€çÙçVÇP 'éêà ‘H”%éU­ ‘@Qéo1ô¯úVQ;Q-· ‘hÊ9-U­ ° ‘ð~”%.U­ ‘è~T?.(v ƒôô‘¦H˜® ¦ô¾ô‘‡ªH9& õgú ‘ð}”%/U­ ‘î}Y?/±& võ¢õ‘~¦HO¯ ±õÌõ‘‡~ªH9& *ögú ‘ð|”%0U­ ‘ï|]?09( žöÊö‘}¦Hn¯ Ùöôö‘‡}ªH9& à ‘Ø{”%1U­ ‘À{j?12° ‘˜{j@22 º÷û÷‘ˆ|¦H ° @ø²ø‘ÿ{ªH9& ûrüVNQyQ7¼ ‘pÊ97U­ 6û`ü ‘ø~”%8U­ ‘ð~Þ>8(v —û±û‘˜¦H˜® ºûÒû‘ªH9&°(ˆV‘Q¸Qc ‘hÊ9cU­  ‘@@dB3 @ ‘€ˆDgö € ‘˜~ˆDhö ‘è|”%iU­ ‘À|j@iO; M„Ž„‘ˆ}¦HjÇ Ó„C…‘ÿ|ªH9& à ‘¸|j@n2¸Qc‰g‰VÌQ 'gjÇ ‘P”%gU­‹í‹VÌQ 'hö ‘h#Ê9hU­ 'h@ŽƒVR 'hjÇ ‘ ”%hU­ ‘ø~Qh2ðw—VARC¼ n— ‘|#9½€Ð  ‘˜”%À®, ‘ˆqRÀ(v ‘ÿ~2:À™& õ‘c“‘ø}cG»Ï‘ˆ~mG»Ï ¹’“‘è|vG­Ò‘ø|}G­Ò ®“$•‘ |cGÄÏ‘°|mGÄÏ z””‘ˆ{vGÑ‘˜{}GÑ l•Ú–‘ÀzcGIÆ‘ÐzmGIÆ 0–x–‘°yvGæÆ‘Ày}GæÆ @ ‘È~„GÅ — —‘¨x}GhÓ0›Ë¢VxRÝË S›¢ ‘p#9Ì×Ó p ‘”%Ô®, ‘€qRÔ(v ‘÷~2:Ô™& I·ž‘ð}cG»Ï‘€~mG»Ï žUž‘à|vG­Ò‘ð|}G­Ò Ÿx ‘˜|cGÄÏ‘¨|mGÄÏ Ο ‘€{vGÑ‘{}GÑ À .¢‘¸zcGIÆ‘ÈzmGIÆ „¡Ì¡‘¨yvGæÆ‘¸y}GæÆ   ‘À~„GÙ T¢`¢‘ x}GhÓТ™¤V¨RwÞ ì¢¤ ‘|#9߀Р€£¤ ‘€„Gã "¤.¤‘~}GhÓ ¤l¦VéRDè ¼¤c¦ ‘|#9éäÓ S¥c¦ ‘€„Gí õ¥¦‘~}GhÓp¦@¨VSíó Œ¦7¨ ‘x#9ôfÐ '§7¨ ‘€„Gý ɧÕ§‘~}GhÓ@¨¶­VVSŸ \¨­­ ‘|#9€Ð Ð ‘ ”%®, ‘–¦Hz¬ Ó©A«‘¸~cGÍÏ‘È~mGÍÏ —ªߪ‘¨}vGÑ‘¸}}GÑ £«­‘Ð|cGÖÏ‘à|mGÖÏ o¬·¬‘¸{vG(Ñ‘È{}G(Ñ  ‘è~„Gn  ?­K­‘°z}GñÓÀ°[´VŠSE  ã°R´ ‘~#9!sÐ n±~² ‘„G%n  ²²‘ ~}GñÓ ~²R´ ‘†~#9(sÐ 0³R´ ‘˜}„G,n  ä³ð³‘¨|}GñÓ`´¶VËS1 |´¶ ‘#92‰Ñ µ¶ ‘„G6n  §µ³µ‘ ~}GñÓ ¶½¹VTÐH <¶´¹ ‘|#9I€Ð 0 ‘˜¦HMì+ ª· ¹‘¸~cGßÏ‘È~mGßÏ v¸¾¸‘ }vG Ñ‘°}}G Ñ ` ‘è~„GNm  F¹R¹‘˜|}GWÔ ƒ ¼?¾VXM•MƒÝ ‘p†%ƒ†® ‘h´Fƒ-­ …½3¾ ‘XBM„ÄÏ ‘`G„ÖÏ …½3¾‘¸¼FÓì À+›%@¾ÀVÄ* Ð ‘¨~”%…U­ ‘§~âV…Ä* , O ‘È~¦H¬¯ ^ y ‘¿~ªH9& ‘èkïVn T4 0 ‘¸k9p 9Þ ` ‘¨k#9q U­ À+›% G°öV)LgLJU­ ‘`†%J¤6 À+›%ÒV| VøVá&‹’Ç ‘¸”%‹U­ ‘¨EW‹U­ ‘h#Ê9¤6 …𠑈‹%Œ6 À+›%pPVøVá&”’Ç ‘¸”%”U­ ‘¨JW”U­ ‘h#Ê9–¤6 Õ@ ‘ˆ‹%•6 À+›% ŠVøVá&’Ç ‘¸”%®, ‘¨JWU­ ‘h#Ê9Ÿ¤6 z ‘ˆ‹%ž6 À+›%  VøVá&¦’Ç ‘¸”%¦®, ‘¨JW¦U­ ‘h#Ê9¨¤6 Œú ‘ˆ‹%§6 À+›%À$ %VøVá&¯’Ç ‘¸”%¯U­ ‘¨JW¯U­ ‘h#Ê9±¤6 %%% ‘ˆ‹%°6 À+›%ð&Ð'VøVá&¸’Ç ‘¸”%¸U­ ‘¨PW¸U­ ‘h#Ê9º¤6 U'À' ‘ˆ‹%¹6 À+›% )*VøVá&Á’Ç ‘¸”%ÁU­ ‘¨PWÁU­ ‘h#Ê9ä6 …)ð) ‘ˆ‹%Â6 À+›%P+0,VøVá&Ê’Ç ‘¸”%ÊU­ ‘¨PWÊU­ ‘h#Ê9̤6 µ+ , ‘ˆ‹%Ë6 À+›%€-`.VøVá&Ó’Ç ‘¸”%ÓU­ ‘¨PWÓU­ ‘h#Ê9Õ¤6 å-P. ‘ˆ‹%Ô6 À+›%€/<0VøVá&Ü’Ç ‘@”%ÜU­ ‘¸PWÜ(v ‘h#Ê9Þ¤6 Õ//0 ‘˜‹%Ý6 À+›%`12VøVá&å’Ç ‘@”%åU­ ‘¸PWåH¯ ‘h#Ê9ç¤6 µ12 ‘˜‹%æ6 À+›%p3P4VøVá&î’Ç ‘¸”%îU­ ‘¨JWîU­ ‘h#Ê9ð¤6 Õ3@4 ‘ˆ‹%ï6 À+›%p546VøVá&÷’Ç ‘@”%÷U­ ‘¿UW÷2Þ ‘h#Ê9ù¤6 Å5'6 ‘˜‹%ø6 À+›%€7I8VøVá& ’Ç ‘@”% ®, ‘¼> 'á ‘h#Ê9 ¤6 Ù798 ‘˜‹% 6 À+›%p96:VøVá& ’Ç ‘@”% ®, ‘¸> (v ‘h#Ê9 ¤6 É9&: ‘˜‹% 6 À+›%`; <VøVá& ’Ç ‘@”% U­ ‘¿]W 2Þ ‘h#Ê9! ¤6 µ;< ‘˜‹% 6 À+›%@= >VøVá&( ’Ç ‘@”%( ®, ‘¾]W( z¬ ‘h#Ê9* ¤6 ›=ü= ‘˜‹%) 6 À+›%0?ù?VøVá&1 ’Ç ‘@”%1 ®, ‘¼]W1 'á ‘h#Ê93 ¤6 ‰?é? ‘˜‹%2 6 À+›% AæAVøVá&: ’Ç ‘@”%: ®, ‘¸]W: (v ‘h#Ê9< ¤6 yAÖA ‘˜‹%; 6 À+›%CÌCVøVá&C ’Ç ‘@”%C U­ ‘¸]WC (v ‘h#Ê9E ¤6 eC¿C ‘˜‹%D 6 À+›%ðDÇEVøVá&N ’Ç ‘@”%N ®, ‘¼>N 'á ‘h#Ê9Q ¤6 IE·E ‘°>O ÿ+ ‘‹%P 6 À+›%ðFÄGVøVá&X ’Ç ‘@”%X ®, ‘¸>X (v ‘h#Ê9[ ¤6 IG´G ‘°>Y ÿ+ ‘‹%Z 6 À+›%ðHÄIVøVá&d ’Ç ‘@”%d ®, ‘¸>d (v ‘h#Ê9g ¤6 II´I ‘°>e Æ+ ‘‹%f 6 À+›%ðLMVøVá&n “­ ‘pgWn ® À+›%ðNÇOVøVá&~ ’Ç ‘@”%~ ®, ‘¼>~ 'á ‘h#Ê9 ¤6 IO·O ‘°> Ù+ ‘‹%€ 6 À+›%ðPÄQVøVá&ˆ ’Ç ‘@”%ˆ ®, ‘¸>ˆ (v ‘h#Ê9‹ ¤6 IQ´Q ‘°>‰ Ù+ ‘‹%Š 6 À+›%9VjW«WgE ‘pÊ9g®, Å) ‘è~”%k®, ‘æ~ÿUkz¬ 5‘ˆ¦H5® A\‘ÿ~ªH9& À+›%ÙWgpõVêWá&lÍÇ ‘@”%lU­ ‘°ˆDlU­ À+›% O7V)LgLT®, ‘`†%T¤6 À+›%¸ V8XyXoE ‘pÊ9o®, E¨  ‘è~”%s®, ‘ä~ÿUs'á ›µ‘ˆ¦HìÇ ÁÜ‘ÿ~ªH9& À+›%À ¯!V¸XòXíî ‘pÊ9í®, À+›%§Xoà"e#V#Yá&tÍÇ ‘@”%tU­ ‘°ˆDtU­ À+›% >@MaMV—GÖGBU­ ‘h†%BÄÇ À+›% (PU¼WVXM•M(Ý ‘`†%(ÄÇ ‘X´F(-­ V­W ‘@,M+§Ä ‘HBM*¾Ð ‘PG)ÖÏ V­W‘ ¼FÓì À+›%XÄ_VqYå º X»_ ‘x#9¼ øÕ ‘HB¾ ©- ‘¸ÙOÅ o1 ‘˜Ê9Ê ¤6 ‘ø}”%Í ¤6 ‘Ð}‹%Í 6 [–\‘€|cGèÏ‘|mGèÏ ì[4\‘èzvGÕ‘øz}GÕ T]Ê^‘èycGÖÏ‘øymGÖÏ ^h^‘ÐxvG(Ñ‘àx}G(Ñ À ‘€}„GÕ ð ð^ü^‘Èw}G™ÕÐ_”gV Y½ Ý ì_‹g ‘x#9ß øÕ ‘HBá ©- ‘¸ÙOè o1 ‘˜Ê9í ¤6 ð ‘ø}”%ð ¤6 ‘Ð}‹%ð 6 ðbfd‘€|cGèÏ‘|mGèÏ ¼cd‘èzvGÕ‘øz}GÕ $ešf‘èycGÖÏ‘øymGÖÏ ðe8f‘ÐxvG(Ñ‘àx}G(Ñ ‘€}„Gø ð ÀfÌf‘Èw}G™Õ gQoVÏY• ¼gHo ‘x#9 øÕ ‘HB ©- ‘¸ÙO o1 ‘˜Ê9 ¤6 P ‘ø}”% ¤6 ‘Ð}‹% 6 ­j#l‘ˆ|cGèÏ‘˜|mGèÏ ykÁk‘ðzvGÕ‘€{}GÕ álWn‘ðycGÖÏ‘€zmGÖÏ ­mõm‘ØxvG(Ñ‘èx}G(Ñ € ‘€}„G ð }n‰n‘Ðw}G™Õ`owVþYm# |ow ‘|#9% äÓ ‘HB' ©- ‘¸ÙO. o1 ‘˜Ê93 ¤6 ° ‘ø}”%6 ¤6 ‘Ð}‹%6 6 jràs‘ˆ|cGèÏ‘˜|mGèÏ 6s~s‘ðzvGÕ‘€{}GÕ žtv‘ðycGÖÏ‘€zmGÖÏ ju²u‘ØxvG(Ñ‘èx}G(Ñ à ‘€}„G> ð :vFv‘Ðw}G™Õw:|V,ZAF ,w1| ‘#9G ‰Ñ ‘HBI ©- ‘¸ÙOP o1 ‘˜Ê9U ¤6  ‘ø}‹%X 6 Êy@{‘¸|cGèÏ‘È|mGèÏ –zÞz‘ {vGÕ‘°{}GÕ @ ‘¨}„G_ ð f{r{‘˜z}G™Õp|„VZZg Œ|„ ‘|#9h äÓ ‘HBj ©- ‘¸ÙOq o1 ‘˜Ê9v ¤6 p ‘ø}”%y ¤6 ‘Ð}‹%y 6 zð€‘ˆ|cGèÏ‘˜|mGèÏ F€Ž€‘ðzvGÕ‘€{}GÕ ®$ƒ‘ðycGÖÏ‘€zmGÖÏ z‚‚‘ØxvG(Ñ‘èx}G(Ñ   ‘€}„G ð JƒVƒ‘Ðw}G™Õ „Ñ‹VˆZé‰ <„È‹ ‘x#9Š øÕ ‘HBŒ ©- ‘¸ÙO“ o1 ‘˜Ê9˜ ¤6 Ð ‘ø}”%› ¤6 ‘Ð}‹%› 6 -‡£ˆ‘ˆ|cGèÏ‘˜|mGèÏ ù‡Aˆ‘ðzvGÕ‘€{}GÕ a‰׊‘ðycGÖÏ‘€zmGÖÏ -ŠuŠ‘ØxvG(Ñ‘èx}G(Ñ ‘€}„G£ ð ýŠ ‹‘Ðw}G™Õà‹˜“V¶Z½« ü‹“ ‘p#9¬ Ö ‘@B® ©- ‘°ÙOµ o1 ‘Ê9º ¤6 0 ‘ð}”%½ ¤6 ‘È}‹%½ 6 ôŽj‘€|cGèÏ‘|mGèÏ À‘èzvGÕ‘øz}GÕ (‘ž’‘èycGÖÏ‘øymGÖÏ ô‘<’‘ÐxvG(Ñ‘àx}G(Ñ ` ‘ø|„GÅ ð Ä’Ð’‘Èw}G™Õ “n›VäZ‘Í ¼“e› ‘p#9Î Ö ‘h[Ð 9Þ ‘ð~BÕ ©- ‘à~ÙOÜ o1 ‘À~Ê9á ¤6 å“O” ‘X [Ñ t­ ‘ }”%ä ¤6 ‘ø|‹%ä 6 Æ–<˜‘ø{cGèÏ‘ˆ|mGèÏ ’—Ú—‘àzvGÕ‘ðz}GÕ þ˜tš‘ØycGÖÏ‘èymGÖÏ Ê™š‘ÀxvG(Ñ‘Ðx}G(Ñ À ‘¨|„Gì ð šš¦š‘¸w}G™Õ€¨N°V)[eô œ¨E° ‘p#9õ Ö ‘h[÷ 9Þ ‘ð~Bü ©- ‘à~ÙO o1 ‘À~Ê9 ¤6 Ũ/© ‘X [ø t­ ð ‘ }”% ¤6 ‘ø|‹% 6 ¦«­‘ø{cGèÏ‘ˆ|mGèÏ r¬º¬‘àzvGÕ‘ðz}GÕ Þ­T¯‘ØycGÖÏ‘èymGÖÏ ª®ò®‘ÀxvG(Ñ‘Ðx}G(Ñ  ‘¨|„G ð z¯†¯‘¸w}G™Õ°²nºVW[9 ̲eº ‘|#9 €Ð ‘HB ©- ‘¸ÙO& o1 ‘˜Ê9+ ¤6 P ‘ø}”%. ¤6 ‘Ð}‹%. 6 ʵ@·‘€|cGèÏ‘|mGèÏ –¶Þ¶‘èzvGÕ‘øz}GÕ þ·t¹‘èycGÖÏ‘øymGÖÏ ʸ¹‘ÐxvG(Ñ‘àx}G(Ñ € ‘€}„G6 ð š¹¦¹‘Èw}G™Õpº¿V‡[> Œº¿ ‘#9? ‰Ñ ‘HBA ©- ‘¸ÙOH o1 ‘˜Ê9M ¤6 ° ‘ø}‹%P 6  ¼¾‘ø|cGèÏ‘ˆ}mGèÏ l½´½‘à{vGÕ‘ð{}GÕ à ‘¨}„GW ð <¾H¾‘Øz}G™Õ¿°ÃV¹[ù_ ,¿§Ã ‘#9` ‰Ñ ‘HBb ©- ‘¸ÙOi o1 ‘˜Ê9n ¤6  ‘ø}‹%q 6 @Á¶Â‘ø|cGèÏ‘ˆ}mGèÏ ÂT‘à{vGÕ‘ð{}GÕ @ ‘¨}„Gx ð ÜÂè‘Øz}G™Õ°Ã²ÊVì[ဠÌÃ©Ê ‘|#9 €Ð ‘HBƒ ©- ‘¸ÙOŠ o1 ‘˜Ê9 ¤6 p ‘ø}”%’ ¤6 ‘Ð}‹%’ 6 ƕǑÐ|cGèÏ‘à|mGèÏ ëÆ3Ç‘¸{vGÕ‘È{}GÕ BȸɑÀzcGÖÏ‘ÐzmGÖÏ ÉVÉ‘¨yvG(Ñ‘¸y}G(Ñ   ‘€}„Gœ ð ÞÉêÉ‘ x}G™ÕÀÊàÑV!\Ѥ ÜÊ×Ñ ‘p#9¥ Ö ‘@B§ ©- ‘°ÙO® o1 ‘Ê9³ ¤6 Ð ‘ð}”%¶ ¤6 ‘È}‹%¶ 6 <ͲΑÈ|cGèÏ‘Ø|mGèÏ ÎPΑ°{vGÕ‘À{}GÕ pÏæÐ‘°zcGÖÏ‘ÀzmGÖÏ <ЄБ˜yvG(Ñ‘¨y}G(Ñ  ‘ø|„G¾ ð ÑÑ‘x}G™ÕàÑýØVW\ÅÆ üÑôØ ‘p#9Ç Ö ‘@BÉ ©- ‘°ÙOÐ o1 ‘Ê9Õ ¤6 0 ‘ð}”%Ø ¤6 ‘È}‹%Ø 6 YÔÏÕ‘È|cGèÏ‘Ø|mGèÏ %ÕmÕ‘°{vGÕ‘À{}GÕ ÖØ‘°zcGÖÏ‘ÀzmGÖÏ Yסב˜yvG(Ñ‘¨y}G(Ñ ` ‘ø|„Gà ð )Ø5Ø‘x}G™ÕÙ ÝV\¹è Ù—Ý ‘#9é ‰Ñ ‘HBë ©- ‘¸ÙOò o1 ‘˜Ê9÷ ¤6  ‘ø}‹%ú 6 0ۦܑø|cGèÏ‘ˆ}mGèÏ üÛDÜ‘à{vGÕ‘ð{}GÕ À ‘¨}„G ð ÌÜØÜ‘Øz}G™Õ Ý¶äVº\‰ ¼Ý­ä ‘|#9 äÓ ‘HB ©- ‘¸ÙO o1 ‘˜Ê9 ¤6 ð ‘ø}”% ¤6 ‘Ð}‹% 6 àˆá‘Ð|cGèÏ‘à|mGèÏ Þà&ᑸ{vGÕ‘È{}GÕ Fâ¼ã‘¸zcGÖÏ‘ÈzmGÖÏ ãZã‘ yvG(Ñ‘°y}G(Ñ  ‘€}„G# ð âãî㑘x}G™ÕÀäÙëVç\Y+ ÜäÐë ‘x#9, øÕ ‘HB. ©- ‘¸ÙO5 o1 ‘˜Ê9: ¤6 P ‘ø}”%= ¤6 ‘Ð}‹%= 6 5ç«è‘Ð|cGèÏ‘à|mGèÏ èI葸{vGÕ‘È{}GÕ iéßꑸzcGÖÏ‘ÈzmGÖÏ 5ê}ê‘ yvG(Ñ‘°y}G(Ñ € ‘€}„GE ð ë둘x}G™ÕàëóV])M üë÷ò ‘p#9N Ö ‘@BP ©- ‘°ÙOW o1 ‘Ê9\ ¤6 ° ‘ð}”%_ ¤6 ‘È}‹%_ 6 \îÒï‘È|cGèÏ‘Ø|mGèÏ (ïpï‘°{vGÕ‘À{}GÕ ðò‘°zcGÖÏ‘ÀzmGÖÏ \ñ¤ñ‘˜yvG(Ñ‘¨y}G(Ñ à ‘ø|„Gg ð ,ò8ò‘x}G™ÕóÎúVA]ùo óÅú ‘p#9p Ö ‘h[r 9Þ ‘ð~Bw ©- ‘à~ÙO~ o1 ‘À~Ê9ƒ ¤6 Eó¯ó ‘X [s t­  ‘ }”%† ¤6 ‘ø|‹%† 6 &öœ÷‘ø{cGèÏ‘ˆ|mGèÏ òö:÷‘àzvGÕ‘ðz}GÕ ^øÔù‘ØycGÖÏ‘èymGÖÏ *ùrù‘ÀxvG(Ñ‘Ðx}G(Ñ @ ‘¨|„GŽ ð úùú‘¸w}G™ÕÐúðVr]Ù– ìúç ‘p#9— Ö ‘@B™ ©- ‘°ÙO  o1 ‘Ê9¥ ¤6 p ‘ð}”%¨ ¤6 ‘È}‹%¨ 6 LýÂþ‘È|cGèÏ‘Ø|mGèÏ þ`þ‘°{vGÕ‘À{}GÕ €ÿö‘°zcGÖÏ‘ÀzmGÖÏ L”‘˜yvG(Ñ‘¨y}G(Ñ   ‘ø|„G° ð (‘x}G™Õð V¥]Á¸   ‘p#9¹ Ö ‘@B» ©- ‘°ÙO o1 ‘Ê9Ç ¤6 Ð ‘ð}”%Ê ¤6 ‘È}‹%Ê 6 iß‘È|cGèÏ‘Ø|mGèÏ 5}‘°{vGÕ‘À{}GÕ ‘°zcGÖÏ‘ÀzmGÖÏ i±‘˜yvG(Ñ‘¨y}G(Ñ  ‘ø|„GÒ ð 9E‘x}G™Õ -VØ]© Ú , $ ‘p#9Û Ö ‘@BÝ ©- ‘°ÙOä o1 ‘Ê9é ¤6 0 ‘ð}”%ì ¤6 ‘È}‹%ì 6 ‰ ÿ ‘È|cGèÏ‘Ø|mGèÏ U  ‘°{vGÕ‘À{}GÕ ½ 3‘°zcGÖÏ‘ÀzmGÖÏ ‰Ñ‘˜yvG(Ñ‘¨y}G(Ñ ` ‘ø|„Gõ ð Ye‘x}G™Õ0ßV^…!ý LÖ ‘x#9þ fÐ ‘HB ©- ‘¸ÙO o1 ‘˜Ê9 ¤6  ‘ø}”% ¤6 ‘Ð}‹% 6 ;±‘ˆ|cGèÏ‘˜|mGèÏ O‘ðzvGÕ‘€{}GÕ oå‘ðycGÖÏ‘€zmGÖÏ ;ƒ‘ØxvG(Ñ‘èx}G(Ñ À ‘€}„G ð ‘Ðw}G™ÕàV7^]" ü÷ ‘p#9 Ö ‘@B" ©- ‘°ÙO) o1 ‘Ê9. ¤6 ð ‘ð}”%1 ¤6 ‘È}‹%1 6 \Ò‘È|cGèÏ‘Ø|mGèÏ (p‘°{vGÕ‘À{}GÕ ‘°zcGÖÏ‘ÀzmGÖÏ \¤‘˜yvG(Ñ‘¨y}G(Ñ  ‘ø|„G9 ð ,8‘x}G™Õ&Vg^9#A & ‘p#9B Ö ‘@BD ©- ‘°ÙOK o1 ‘Ê9P ¤6 P ‘ð}”%S ¤6 ‘È}‹%S 6 y!ï"‘È|cGèÏ‘Ø|mGèÏ E""‘°{vGÕ‘À{}GÕ ­##%‘°zcGÖÏ‘ÀzmGÖÏ y$Á$‘˜yvG(Ñ‘¨y}G(Ñ € ‘ø|„G[ ð I%U%‘x}G™Õ &Ä.V—^$c Â&». ‘œ#9d MÖ ‘[f 9Þ ‘ð}Bm ©- ‘à}ÙOt o1 ‘À}Ê9y ¤6 ° ‘€ [g t­ à ‘ |”%| ¤6 ‘ø{‹%| 6 *’+‘øzcGèÏ‘ˆ{mGèÏ è*0+‘àyvGÕ‘ðy}GÕ T,Ê-‘ØxcGÖÏ‘èxmGÖÏ -h-‘ÀwvG(Ñ‘Ðw}G(Ñ  ‘¨{„G„ ð ð-ü-‘¸v}G™ÕÐ.DVÈ^¢%Ä þ.D ‘HBÅ ©- ‘˜j@Ì 2 ‘ø~#9á ZÖ ‘À~q@ä 8 ‘ˆ~Cì ƒ8 @ ‘ð|‹%ó 6 ?3Â4‘ˆ|cGèÏ‘˜|mGèÏ 4]4‘ðzvGÕ‘€{}GÕ p ‘¸|„Gú ¢< Ú4ò4‘èy}GgÖ   ‘¨x‹%6 ð7s9‘ÀwcGèÏ‘ÐwmGèÏ ¸89‘¨vvGÕ‘¸v}GÕ Ð ‘ðw„G ¢< ‹9£9‘ u}GgÖ  ‘às‹%6 ¡<$>‘ørcGèÏ‘ˆsmGèÏ i=¿=‘àqvGÕ‘ðq}GÕ 0 ‘¨s„G¢< <>T>‘Øp}GgÖ oBD‘ØmcGAÄ‘èmmGAÄ KC¡C‘ÀlvG1Ñ‘Ðl}G1Ñ@RÜrVë^ö'I ˜RÓr ‘p_JÏÖ ‘`_K®8 ‘¨@MB3 ‘ð~,_PØÖ ‘à~IGQ%, ‘~BS©- ‘˜|5_W79 ‘à{q@Y8 ðUaW‘ÀycG9БÐymG9Ð ¦VüV‘°xvGîÖ‘Àx}GîÖ cWÊr ‘àwq@_8 Y‹Z‘ÀucG9БÐumG9Ð ÐY&Z‘°tvGîÖ‘Àt}GîÖ ZÊr ‘àsq@e8 D\µ]‘ÀqcG9БÐqmG9Ð ú\P]‘°pvGîÖ‘Àp}GîÖ ·]Êr ‘àoq@k8 n_ß`‘ÀmcG9БÐmmG9Ð $`z`‘°lvGîÖ‘Àl}GîÖ á`Êr ‘àkq@q8 ˜b d‘ÀicG9БÐimG9Ð Nc¤c‘°hvGîÖ‘Àh}GîÖ dÊr ‘àgq@w8 Âe3g‘ÀecG9БÐemG9Ð xfÎf‘°dvGîÖ‘Àd}GîÖ 5gÊr ‘àcq@}8 ìh]j‘ÀacG9БÐamG9Ð ¢iøi‘°`vGîÖ‘À`}GîÖ _jÊr ‘à_q@ƒ8 l‡m‘À]cG9БÐ]mG9Ð Ìl"m‘°\vGîÖ‘À\}GîÖ ‰mÊr ‘à[q@‰8 @o±p‘ÀYcG9БÐYmG9Ð öoLp‘°XvGîÖ‘ÀX}GîÖ ³pÊr ‘àWq@8 7}=Mpx‡yV<_á&NB3 ‘ˆ@NB3 À+›% v°ˆY‰V_Ï_v8 ‘x†%v–È ûˆO‰ ‘P!M¾Ð ‘`,M}IÆ ‘X7M~’Ò ‘hBM|pÖ ‘pG{AÄ À+›%h”Vò_9`¥ ‘°q@¥8 ‘ Þ>©‚Ý ú_” ‘€‹%¬6 ‘è}m`±޲CÏ‘™‘±‘pUÏ Î’Q”‘è|cG0Бø|mG0Ð –“ì“‘Ð{vG‡Õ‘à{}G‡Õ À+›%ЯõºV¨`x(š ÷¯ìº ‘p_›ÏÖ ‘`_œ®8 ‘¨@žB3 ‘ð~,_¡ØÖ ‘à~IG¢%, ‘~B¤©- ‘˜|5_¨79 ‘à{q@ª8 O³À´‘ÀycG9БÐymG9Ð ´[´‘°xvGîÖ‘Àx}GîÖ ´ãº ‘àwq@²8 ¶ãº ‘Èuq@º8 d·ãº ‘°sq@À8 µ¸ãº ‘˜qq@Æ8àÈ;ÓVã`3)Ó É2Ó ‘p aÔÖ ‘`_ò®8 ‘¨@ôB3 ‘¸~,_÷í× ‘¨~IG[%, ‘Ø}B]©- ‘à{5_a79 ‘¨{+ac8 ‘¨wq@k8 æÌWΑˆycG9Б˜ymG9Ð œÍòÍ‘øwvGîÖ‘ˆx}GîÖ ªÏ)Ó ‘uq@s8 ûÐ)Ó ‘ørq@y8@Ó½ÖV0aô)Ž \Ó´Ö ‘x#9fÐ ` ‘¨¦H’(v ²Ô Ö‘Ð~cGIÆ‘à~mGIÆ vÕ¾Õ‘À}vGæÆ‘Ð}}GæÆ  ‘€„G“s FÖRÖ‘¸|}Gú×ÀÖ×V`a¥a†s ‘pÊ9†®, À+›%ÐÙ›ÛVìaŽ*˜ ìÙ’Û ‘x#9™.Ø ‚Ú’Û ‘„Gs $Û0Û‘ ~}Gú× Û6ãV$b@+° ÃÛ-ã ‘x#9±;Ø À ‘ø~>´Æ+ ‘ˆ”%´1 ¨Ýß‘ø}cG»Ï‘ˆ~mG»Ï lÞ´Þ‘è|vG­Ò‘ø|}G­Ò bßØà‘ |cGÄÏ‘°|mGÄÏ .àvà‘ˆ{vGÑ‘˜{}GÑ #á™â‘ÀzcGBБÐzmGBÐ ïá7⑨yvGuÕ‘¸y}GuÕ ð ‘È~„G¹´( ¿âËâ‘ x}GHØ@ãväVTb–b¢´( ‘hÊ9£1 eãfä ‘HˆD§s À+›% Ž€ä¯äV)LgL‘®, ‘h†%‘1 À+›%Åb¢Ðå\æV×bá&¬ïÈ ‘@”%¬®, ‘¸>¬(v ‘h#Ê9¬1 À+›%@éÜðV&cÚ+¾ céÓð ‘p#9¿•Ø  ‘ð~>ÂÆ+ ‘€”%Â1 Në¼ì‘ð}cG»Ï‘€~mG»Ï ìZì‘à|vG­Ò‘ð|}G­Ò í~|cGÄÏ‘¨|mGÄÏ Ôíî‘€{vGÑ‘{}GÑ Éî?ð‘¸zcGBБÈzmGBÐ •ïÝï‘ yvGuÕ‘°y}GuÕ P ‘À~„GÇ´( eðqð‘˜x}GHØàð½òVVct,Ì üð´ò ‘|#9ÎäÓ ¡ñ´ò ‘ø~„GÒ´( FòRò‘ˆ~}GHØÀò´øV‹c- êò«ø ‘X#9¢Ø ‘€ˆD0 ) ôô‘ð}}G¯Ø € ‘ˆ}ÁE4.< ¡öø‘øzcGKБˆ{mGKÐ m÷µ÷‘àyvG¸Ø‘ðy}G¸Ø ° ‘¨|„G? ) =øIø‘Øx}G¯ØÀøÚýVÀcd ) ‘pÊ9®, ùÊý ‘ð}”%®, ‘À}ÁE©- —ù¹ù‘~¦H¹­ Èùãù‘‡~ªH9& —úÊý ‘¸|”%®, ‘°|Rd(v óúû‘Ø|¦H® .ûIû‘Ï|ªH9& §ûÊý ‘€{”%1 ‘øz>Æ+ Mü‡ü‘¨{¦HïÈ –ü±ü‘Ÿ{ªH9& À+›% ×@ÓVXM•M×Ý ‘`†%×KÐ ‘X´F×-­ ŠÄ ‘@,MÝBÐ ‘HBMÜIÆ ‘PGÛ‰Ç ŠÄ‘°¼F í À+›%à±VŽLÊLד­ ‘x†%×KÐ ‘p´F×KÐ ¡ ‘h GÛ‰Ç ‘`õLÜIÆ ‘X MÝBÐ A¡ ‘@,MÝBÐ ‘HBMÜIÆ ‘PGÛ‰Ç À+›%\d 9Vcdzdd‡dyÝ#qR9Þ# ‚Ýdœd‡d¡Ý#qR9Þ#!2Þ¡d°ÉV«dÎd f¡Ý ‘x†% f¡Ý ‘pÙd fÃÈ 2ÞxAà^ù^Vßde %“­ ‘x†% %¡Ý 2ÞxA"e#e€ïðV eDe T4 ‘x†% 9Þ ‘pPe 9Þ —ï÷ï ‘XQ 9Þ ‘WVe “­ðbðVXe€e °iÄ ‘x†% °9Þ ‘pe °9Þ ð\ð ‘XQ ²(v ‘WVe ²“­ ð¹ðV”e¹e à9Þ ‘x†% à9Þ ‘pe à9ÞÀðAñVÆeêe ûT4 ‘x†% û9Þ ‘pPe û9Þ ×ð7ñ ‘XQ ü9Þ ‘WVe ü“­Pñ—ñVöef ~iÄ ‘x†% ~9Þ ‘pe ~9Þ _ñ•ñ ‘XQ €(v ‘WVe €“­ð F V.fVf [“­ ‘x†% [9ÞPQVfff l9Þ ‘x†% l9Þ à ‘p¢f m9Þ ‘`§f n9Þ`‹V«fÑf .'á ‘x†% .9Þßf$7‚Ý#¯8'á##ëfàìVïf g ê'á ‘|†% ê'á$Vg/g Ò'á ‘|†% Ò'á$V5gXg Š'á ‘|†% Š'ácg‡dÇá#qR9Þ# äá‚g¥g°Fªg­g°g@¹gâ#2:dâ#Âgâ#Eâ#Ëgš@-â#(vÂgËgÐgÐgš@-â#$79Þ#Óg0Þgëv#ãg§â#ég'á#ïgËâ#ùgËâ# 2Þÿg hhhhÃ3òâ#5ã#Tã#gã##hš@ã#$79Þ#(vÃ3#h&h,h6h&hš@ã#$79Þ#,hš@ã#6hš@ã#% .>h`ég'á#Þgëv#ãg§â#ùgT4#ïgT4# #9Ãä#0Hh¯E#@Oh6­#P€¶VThxhÜÓì ‘x†%Ü-­ ‘hÞ>Ü‚ÝWÆWV„h©hÀ í ‘x†%À-­ ‘hÞ>À‚Ý_&_V¶hÙhõ5í ‘x†%õ-­$Vähi'§î ‘x†%'-­%ii³@ ­#%i­# R@RV/i‰iÎÉä‘xËiξБpÍiÏëÐ ‰ÇxAÀ`à`VÏikjÎÉä‘xËiÎÇБpÍiÏCÑ f5xA707VîjkÎÉä‘xËiέÒ‘pÍiÏÚÒ »ÏxA€— —VkRkÎÉä‘xËiÎÑ‘pÍiÏqÓ ÄÏxA —À—VnkkÎÉä‘xËiÎæÆ‘pÍiÏŠÓ IÆxAÀ—à—V™k9lÎÉä‘xËiÎhÓ‘pÍiÏ£Ó xAÀ­à­VÀlálÎÉä‘xËiÎÑ‘pÍiÏúÓ ÍÏxAà­®Vël?mÎÉä‘xËiÎ(Ñ‘pÍiÏÔ ÖÏxA® ®V{mnÎÉä‘xËiÎñÓ‘pÍiÏ,Ô n xAÀ¹à¹Vpn¯nÎÉä‘xËiÎ Ñ‘pÍiÏ`Ô ßÏxA๺VÖn|oÎÉä‘xËiÎWÔ‘pÍiÏyÔ m xAðÈÉV p)pÎÉä‘xËiÎÑ‘pÍiÏ­Ô ®xAÉ0ÉV2p‡pÎÉä‘xËiΤÔ‘pÍiÏÆÔ 2xAÐ ÐVÄpƒqÎÉä‘xËiÎþÔ‘pÍiÏÕ ÉxAÐQðQV)r`rÎÉä‘xËiÎÕ‘pÍiÏ«Õ èÏxAR°RVr sÎÉä‘xËiΙÕ‘pÍiÏÄÕ ðxA0žPžV¨sÉsÎÉä‘xËiÎ]БpÍiÏÖ ‚ÝxAž°žVÓstÎÉä‘xËiÎwÑ‘pÍiÏ+Ö {{xA0MPMV!t™tÎÉä‘xËiÎgÖ‘pÍiÏ‚Ö ¢<xA R@RVùtuÎÉä‘xËiÎ1Ñ‘pÍi϶Ö AÄxA°uÐuV)u[uÎÉä‘xËiÎБpÍiÏ÷Ö 9&xAp©©Vuu±uÎÉä‘xËi·Õ‘pÍiÏ©× 0ÐxAð®¯VÕuùuÎÉä‘xËiÎîÖ‘pÍiÏÂ× 9ÐxA×0×VvŒvÎÉä‘xËiÎúבpÍiÏØ sxA`æ€æVúv8wÎÉä‘xËiÎuÕ‘pÍiÏQØ BÐxA€æ æV^wxÎÉä‘xËiÎHØ‘pÍiÏjØ ´(xA€þ þVxGyÎÉä‘xËiίØ‘pÍiÏÁØ )xAÀàVæy9zÎÉä‘xËiθØ‘pÍiÏìØ KÐxAtzyz‚z °F-­#ˆDÝ#z9Þ#”z“­#Ÿz°F-­#ˆDÝ#«z“­# ¶zÀz|î#`\Š]VÆz {8sÏ ‘x†%8sÏ ‘hu=8ÚE Ù\m] ‘` E<û¬ ø\m] ‘¸E<ÚE I]k] ‘˜q@<® ®-{ ÚE/{$V1{¼{8sÏ ‘x†%8sÏ ‘hu=8F& ‘` E<û¬& ‘¸E<F& ‘˜q@<§Ä §Ä-{ F/{%|°F-­#ˆDÝ#«z“­# 0|°F-­#ˆDÝ#«z“­# $V9|Ê|}©Ï ‘x†%}©Ï ‘Pu=}‚¡& ‘H E‚û¬& ‘ð~E‚‚¡& ‘À~9}‚RÆ ‘Ð~;}‚IÆ IÆ=} RÆ?} ‚¡/{A}0K}ZÝ#°F‘6#Oh6­# ÐQRVR}p}ófï‘pK}óZÝ‘`Ohô6­0R„RVw} }fï ‘pK}ZÝ ‘`Oh6­ ‘P°F¨á À!ò!V±}Ñ}IÝ ‘p†%IæÆ ‘hÍiI-­ (vxA@RrRVÚ}3~IÝ ‘p†%I¾Ð ‘hÍiI-­ ©-xAÐWXVt~”~IÝ ‘p†%IÑ ‘hÍiI-­ z¬xAXBXV~Û~IÝ ‘p†%I Ñ ‘hÍiI-­ ì+xAPX‚XV IÝ ‘p†%IÑ ‘hÍiI-­ 2ÞxAXÂXV([IÝ ‘p†%IÑ ‘hÍiI-­ ™&xAYÂYVvÉIÝ ‘p†%I(Ñ ‘hÍiI-­ ®,xAp[¢[V€'€IÝ ‘p†%I1Ñ ‘hÍiI-­ U­xA°[æ[V2€S€IÝ ‘p†%IAÄ ‘hÍiI-­ ùÊxAð[Q\V ?Ý ‘h†%?U­ ‘`Íi?-­ 2ÞxA@`r`V]€±€IÝ ‘p†%I:Ñ ‘hÍiI-­ ]OxA€`¹`V퀕MLÝ ‘p†%LâÐ ‘hÍiL-­ À+xA0bbbV&¬IÝ ‘p†%IeÑ ‘hÍiI-­ ÛxA dRdV‚K‚IÝ ‘p†%InÑ ‘hÍiI-­ 9&xAàÖ×Ve‚Ÿ‚IÝ ‘p†%I±Ñ ‘hÍiI-­ Q(xA ×R×VÁ‚û‚IÝ ‘p†%IºÑ ‘hÍiI-­ Ä*xA`ò’òVƒ`ƒIÝ ‘p†%IÒ ‘hÍiI-­ o1xA07b7V‹ƒ®ƒIÝ ‘p†%I­Ò ‘hÍiI-­ 9ÞxA™™V¹ƒ,„IÝ ‘p†%IÅÓ ‘hÍiI-­ Ø­xAЙšV‡„÷„-Ý ‘p†%-¼Ó ‘hÍi--­ ç™vš ‘H¼F.Óì ‘@O…/ÖÏ ‘¸S…/ÎÓ ®,O… ÷­S…€š/›VW…Ž…-Ý ‘p†%-ÎÓ ‘hÍi--­ —š&› ‘H¼F.Óì ‘@O…/IÆ ‘¸S…/ÄÏ (vO… ™&S…Я°V­…†IÝ ‘p†%INÔ ‘hÍiI-­ 5®xA°¿°VI† †-Ý ‘p†%-EÔ ‘hÍi--­ '°¶° ‘H¼F.Óì ‘@O…/ÖÏ ‘¸S…/ÍÏ ®,O… z¬S…°»â»V߆X‡IÝ ‘p†%I›Ô ‘hÍiI-­ T®xA𻟼V¹‡/ˆ-Ý ‘p†%-’Ô ‘hÍi--­ ¼–¼ ‘H¼F.Óì ‘@O…/†® ‘¸S…/ßÏ 1O… ì+S…àÊËVˆ¶ˆIÝ ‘p†%IèÔ ‘hÍiI-­ š­xA ËÏËVLjíˆ-Ý ‘p†%-ßÔ ‘hÍi--­ 7ËÆË ‘H¼F.Óì ‘@O…/AÄ ‘¸S…/® U­O… 2ÞS…ÐÑÒVûˆŽ‰IÝ ‘p†%I)Õ ‘hÍiI-­ ¹­xAÒ¿ÒVŠ˜Š-Ý ‘p†%- Õ ‘hÍi--­ 'Ò¶Ò ‘H¼F.Óì ‘@O…/ÖÏ ‘¸S…/‰Ç ®,O… ©-S…ÐéêV‹/‹IÝ ‘p†%IQÕ ‘hÍiI-­ H¯xAêBêV8‹Y‹IÝ ‘p†%IZÕ ‘hÍiI-­ “­xAPê‚êVc‹š‹IÝ ‘p†%IcÕ ‘hÍiI-­ ,xAêÂêV¹‹õ‹IÝ ‘p†%IlÕ ‘hÍiI-­ ÿ+xAÐêëVŒVŒIÝ ‘p†%IuÕ ‘hÍiI-­ Æ+xAëBëV{Œ¶ŒIÝ ‘p†%I~Õ ‘hÍiI-­ Ù+xAàíîVÙŒIÝ ‘p†%I‡Õ ‘hÍiI-­ 4xAðQ"RV7mIÝ ‘p†%IÕ ‘hÍiI-­ 6xA`T’TV‹ÿIÝ ‘p†%IæÕ ‘hÍiI-­ ’ÇxA TOUV[ŽÌŽ-Ý ‘p†%-ÝÕ ‘hÍi--­ ·TFU ‘H¼F.Óì ‘@O…/ÄÇ ‘¸S…/èÏ ¤6O… 6S…ÀWòWV%IÝ ‘p†%IïÕ ‘hÍiI-­ ‰ÇxAPž†žVÁáIÝ ‘p†%I]Ð ‘hÍiI-­ >ÏxA NÒNVêLIÝ ‘p†%I¤Ö ‘hÍiI-­ ×$xA¯B¯V–¹IÝ ‘p†%IîÖ ‘hÍiI-­ ÃÈxAàØÙVÄ‘IÝ ‘p†%I%Ø ‘hÍiI-­ ®xA ÙÏÙV`‘·‘-Ý ‘p†%-Ø ‘hÍi--­ 7ÙÆÙ ‘H¼F.Óì ‘@O…/ÖÏ ‘¸S…/IÆ ®,O… (vS…Pè‚èVö‘n’IÝ ‘p†%IŒØ ‘hÍiI-­ ïÈxAè?éVÎ’C“-Ý ‘p†%-ƒØ ‘hÍi--­ §è6é ‘H¼F.Óì ‘@O…/†® ‘¸S…/BÐ 1O… Æ+S…P‚V “,”IÝ ‘p†%IãØ ‘hÍiI-­ ÉxA?VŸ”(•-Ý ‘p†%-ÚØ ‘hÍi--­ §6 ‘H¼F.Óì ‘@O…/ÖÏ ‘¸S…/KÐ ®,O… .<S…àV˜•ê•IÝ ‘p†%I¸Ø ‘hÍiI-­ .<xAˆD2Þ$–+–.–(v$–+–.–2–ô##+–š@­#$7û¬#.–š@­#$7|ã#O– #¼#P4o5Vy–—Äð ‘`†%Ä2 ‘X£—Ä±Ç í4%5 ‘°¦—Æš­ .5@5 ‘§™%Ç9& š­xA 9&¨— ’Ǫ— ±Ç¬—@:_;Vy–—Äð ‘`†%Ä2 ‘X£—Ä±Ç Ý:; ‘°¦—Æš­ ;0; ‘§™%Ç9& š­xA 9&¨— ’Ǫ— ±Ç¬—+– š@­#$7š­#.–š@­#$79&#®—8‹#ª#ðy{V˜|˜ë©- ‘H†%ëÛ ‘¸ܘë‚Ý ŸzÁz ‘€¦—í©- Ðzäz ‘÷~™%î9& ©-xA 9&¨—+–8š@­#$7©-#.–š@­#$79&#à˜Hà#ÿ#+–Hš@­#$7¹­#.–š@­#$79&#s™(5#T#+–(š@­#$7Ø­#.–š@­#$79&#ç™ 0 #O #G¯HVBš›Äm  ‘`†%Äs ‘X£—Äs® -HeH ‘°¦—Æ® nH€H ‘§™%Ç9& ®xA 9&¨— T®ª— s®¬—P8o9VÔ›¦œÄð ‘`†%Äs ‘X£—Ä±Ç í8%9 ‘°¦—Æ® .9@9 ‘§™%Ç9& ®xA 9&¨— ’Ǫ— ±Ç¬—@AVÔ›¦œÄð ‘`†%Äs ‘X£—Ä±Ç @Õ@ ‘°¦—Æ® Þ@ð@ ‘§™%Ç9& ®xA 9&¨— ’Ǫ— ±Ç¬—ÐEïFVÔ›¦œÄð ‘`†%Äs ‘X£—Ä±Ç mF¥F ‘°¦—Æ® ®FÀF ‘§™%Ç9& ®xA 9&¨— ’Ǫ— ±Ç¬—ÐGïHVÔ›¦œÄð ‘`†%Äs ‘X£—Ä±Ç mH¥H ‘°¦—Æ® ®HÀH ‘§™%Ç9& ®xA 9&¨— ’Ǫ— ±Ç¬—ÐOïPVÔ›¦œÄð ‘`†%Äs ‘X£—Ä±Ç mP¥P ‘°¦—Æ® ®PÀP ‘§™%Ç9& ®xA 9&¨— ’Ǫ— ±Ç¬—°äÏåV\2žÄ´( ‘`†%Äs ‘X£—Äs® Må…å ‘°¦—Æ® Žå å ‘§™%Ç9& ®xA 9&¨— ïȪ— s®¬—+– š@­#$7®#.–š@­#$79&#ìž / #N # <?=VGŸ Äð ‘`†%Än  ‘X£—Ä±Ç ½<õ< ‘°¦—Æ5® þ<= ‘§™%Ç9& 5®xA 9&¨— ’Ǫ— ±Ç¬—+– š@­#$75®#.–š@­#$79&#Ï („ #£ #+–(š@­#$7T®#.–š@­#$79&#I¡ - #L #`./Vt¡¢Äð ‘`†%Ä  ‘X£—Ä±Ç ý.5/ ‘°¦—Ƙ® >/P/ ‘§™%Ç9& ˜®xA 9&¨— ’Ǫ— ±Ç¬—ðACVt¡¢Äð ‘`†%Ä  ‘X£—Ä±Ç BÅB ‘°¦—Ƙ® ÎBàB ‘§™%Ç9& ˜®xA 9&¨— ’Ǫ— ±Ç¬—+– š@­#$7˜®#.–š@­#$79&#œ¢ ‚ #¡ #+–š@Å#$7(v#.– š@Å#$7w#½¢× #ö #+–š@Å#$7û¬#.–š@Å#$7{{#ߢ Ö#õ#@0_1V £¬£Äð ‘`†%Ä ‘X£—Ä±Ç Ý01 ‘°¦—Æ)¯ 101 ‘§™%Ç9& )¯xA 9&¨— ’Ǫ— ±Ç¬—+– š@­#$7)¯#.–š@­#$79&#2¤ +#J#+–š@Å#$7H¯#.– š@Å#$7w#S¤ €#Ÿ#+– š@­#$7O¯#.–š@­#$79&#™¤ Õ#ô#+– š@­#$7n¯#.–š@­#$79&#ç¤ *#I#+– š@­#$7¯#.–š@­#$79&#+¥ #ž#+– š@­#$7¬¯#.–š@­#$79&#o¥ ~##æçV¼¥n¦Ä¸ ‘`†%Ľ ‘X£—Ä Ä -ç>ç ‘¸¦—Æ˯ GçVç ‘¯™%Ç9& ˯xA 9&¨— êê— Ĭ—+– š@­#$7˯#.–š@­#$79&#§%#D# àdáV.§½§Ä¸ ‘h†%ļ ‘`£—Ä Ä á&á ‘H¦—Æê¯ /á>á ‘¿™%Ç9& ê¯xA 9&¨— êê— Ĭ—0ˆôˆV0¨µ¨Äö ‘h†%ļ ‘`£—Ä Ä ¥ˆ¶ˆ ‘H¦—Æê¯ ¿ˆΈ ‘¿™%Ç9& ê¯xA 9&¨— jǪ— Ĭ—+–š@­#$7ê¯#.–š@­#$79&#©0z#™#+–0š@­#$7 °#.–š@­#$79&#‚© y#˜#@å%æV婪†¸ ‘`†%†¸ ‘X£—†.Ä ·åØå ‘°¦—ˆêà áåüå ‘§™%‰9& êÃxA 9&¨— 9&¬— .Ä «+– š@­#$7êÃ#.–š@­#$79&# «@n##@Œ:ŽVN«ì«Äö ‘@†%Ä· ‘¸£—Ä Ä  ‘°¦—Æ°Ä `u ‘§™%Ç9& °ÄxA 9&¨— jǪ— Ĭ—+–@š@­#$7°Ä#.–š@­#$79&#n¬Ã#â#+–š@­#$7û¬#.–š@­#$7û¬#}¬@¸#×#pvjxVÁ¬B­Ä’& ‘@†%Ä ‘¸£—Ä Ä @ ‘°¦—ÆKÇ w¥w ‘§™%Ç9& KÇxA 9&¨— B3ª— Ĭ—+–@š@­#$7KÇ#.–š@­#$79&#§­@¹#Ø#‰:‹V®’®†ö ‘@†%†ö ‘¸£—†.Ä AЉР‘¨¦—ˆjÇ »Š‹ ‘Ÿ™%‰9& jÇxA 9&¨— 9&¬— .Ä «+–@š@­#$7jÇ#.–š@­#$79&#¯(²#Ñ#ÐV5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç ƒÌ ‘ ¦—Æ ¯ Õç ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬— fV5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç Ó ‘ ¦—Æ ¯ %7 ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬—@iVa°í°ÄE ‘X†%Ä÷ ‘P£—Ä Ä  ‘¨¦—Æ ¯ (: ‘Ÿ™%Ç9& ¯xA 9&¨— ÍǪ— Ĭ—°!Ù"Va°í°ÄE ‘X†%Ä÷ ‘P£—Ä Ä {"" ‘¨¦—Æ ¯ ˜"ª" ‘Ÿ™%Ç9& ¯xA 9&¨— ÍǪ— Ĭ—p#¶$V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç #$l$ ‘ ¦—Æ ¯ u$‡$ ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬— %æ&V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç S&œ& ‘ ¦—Æ ¯ ¥&·& ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬—Ð')V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç ƒ(Ì( ‘ ¦—Æ ¯ Õ(ç( ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬—*F+V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç ³*ü* ‘ ¦—Æ ¯ ++ ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬—0,v-V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç ã,,- ‘ ¦—Æ ¯ 5-G- ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬— 2f3V5¯Ù¯Äð ‘X†%Ä÷ ‘P£—Ä±Ç Ó23 ‘ ¦—Æ ¯ %373 ‘—™%Ç9& ¯xA 9&¨— ’Ǫ— ±Ç¬—+–(š@­#$7 ¯#.–š@­#$79&#]±H#&#+–Hš@­#$7’Ç#.–š@­#$79&#Ò±(° #Ï #P–V/²³Äð ‘X†%ÄE ‘P£—Ä±Ç L ‘ ¦—ÆÍÇ Ug ‘—™%Ç9& ÍÇxA 9&¨— ’Ǫ— ±Ç¬—ÐV/²³Äð ‘X†%ÄE ‘P£—Ä±Ç ƒÌ ‘ ¦—ÆÍÇ Õç ‘—™%Ç9& ÍÇxA 9&¨— ’Ǫ— ±Ç¬—+–(š@­#$7ÍÇ#.–š@­#$79&#»³ ­##Ì##`67V´è´Äð ‘`†%Äî  ‘X£—Ä±Ç ý657 ‘°¦—ÆìÇ >7P7 ‘§™%Ç9& ìÇxA 9&¨— ’Ǫ— ±Ç¬—>/?V´è´Äð ‘`†%Äî  ‘X£—Ä±Ç ­>å> ‘°¦—ÆìÇ î>? ‘§™%Ç9& ìÇxA 9&¨— ’Ǫ— ±Ç¬—ÐCïDV´è´Äð ‘`†%Äî  ‘X£—Ä±Ç mD¥D ‘°¦—ÆìÇ ®DÀD ‘§™%Ç9& ìÇxA 9&¨— ’Ǫ— ±Ç¬—ÐMïNV´è´Äð ‘`†%Äî  ‘X£—Ä±Ç mN¥N ‘°¦—ÆìÇ ®NÀN ‘§™%Ç9& ìÇxA 9&¨— ’Ǫ— ±Ç¬—+– š@­#$7ìÇ#.–š@­#$79&#žµ™$#¸$# ›¶œVõ¶ë9Þ ‘h†%ëë# ‘Xܘë‚Ý ô›œ ‘H¦—í9Þ œ<œ ‘@™%î{{ 9ÞxA {{¨—+–š@Å#$79Þ#.–š@Å#$7{{#&¶(T&#s&#p”h•V]¶®¶ë6 ‘X†%ë×$ ‘Hܘë‚Ý •%• ‘ ¦—í6 .•?• ‘—™%î9& 6xA 9&¨—€™Ä™Vä¶4·“­ ‘p†%›Ö 6xA 9&¨—ЙºšVo·À·Ó6 ‘X†%Ó×$ Lšqš ‘°¦—Õ6 zš‘š ‘§™%Ö9& 6xA 9&¨—+–(š@­#$76#.–š@­#$79&#ý·0B'#a'#s|tV8¸¸ëB3 ‘P†%ë’& ‘@ܘë‚Ý ‡sÚs ‘¸¦—íB3 tIt ‘¯™%î9& B3xA 9&¨—+–0š@­#$7B3#.–š@­#$79&#Ǹ@v(#•(#À|›}V+¹©¹ë8 ‘@†%ë€' ‘°ܘë‚Ý G}X} ‘¨¦—í8 a}r} ‘Ÿ™%î9& 8xA 9&¨—°‡ô‡V º‰º“­ ‘p†%"× 8xA 9&¨—+–@š@­#$78#.–š@­#$79&#ëº(Ë(#ê(#+–(š@­#$7ïÈ#.–š@­#$79&#d»X )#?)#+–Xš@­#$7É#.–š@­#$79&# pbdVð»a¼úÝ‘p†%ú\Ñ‘h´Fú-­ íbYc ‘P—U‰Ç íbYc‘¨¼FÓì `cêc ‘H—UÐ `cêc‘Ø~¼FÓì ©-xA 9&¨—à—Ž™V·¼C½úÝ‘p†%úhÓ‘h´Fú-­ ]˜ɘ ‘P—U¼Ó ]˜ɘ‘¨¼FÓì ИZ™ ‘H—UÐ ИZ™‘Ø~¼FÓì Ø­xA 9&¨— ®ίV³½%¾úÝ‘p†%úñÓ‘h´Fú-­ ® ¯ ‘P—UEÔ ® ¯‘¨¼FÓì ¯š¯ ‘H—UÐ ¯š¯‘Ø~¼FÓì 5®xA 9&¨—º®»V|¾¿úÝ‘p†%úWÔ‘h´Fú-­ }ºéº ‘P—U’Ô }ºéº‘¨¼FÓì ðºz» ‘H—UÐ ðºz»‘Ø~¼FÓì T®xA 9&¨—0ÉÞÊV„¿Å¿úÝ‘p†%ú¤Ô‘h´Fú-­ ­ÉÊ ‘P—UßÔ ­ÉÊ‘¨¼FÓì ÊªÊ ‘H—UРʪʑØ~¼FÓì š­xA 9&¨— ÐÎÑVë¿–ÀúÝ‘p†%úþÔ‘h´Fú-­ Ð Ñ ‘P—U Õ Ð Ñ‘¨¼FÓì ÑšÑ ‘H—UРњёØ~¼FÓì ¹­xA 9&¨—°R^TV%Á²ÁúÝ‘p†%ú™Õ‘h´Fú-­ -S™S ‘P—UÝÕ -S™S‘¨¼FÓì  S*T ‘H—UÐ  S*T‘Ø~¼FÓì ’ÇxA 9&¨—àNŽPV#ÂqÂúÝ‘p†%ú›Ö‘h´Fú-­ ]OÉO ‘P—UèÏ ]OÉO‘¨¼FÓì ÐOZP ‘H—UÐ ÐOZP‘Ø~¼FÓì 6xA 9&¨—ˆ§ˆV¤Â!Ãú€'‘x†%ú"× Wˆlˆ ‘`—U–È lˆˆ ‘X—UÐ 8xA 9&¨—0×ÞØVƒÃõÃúÝ‘p†%úúבh´Fú-­ ­×Ø ‘P—UØ ­×Ø‘¨¼FÓì ØªØ ‘H—UРتؑØ~¼FÓì ®xA 9&¨— æNèVLÄÝÄúÝ‘p†%úHØ‘h´Fú-­ ç‰ç ‘P—UƒØ ç‰ç‘¨¼FÓì çè ‘H—UÐ çè‘Ø~¼FÓì ïÈxA 9&¨— þNVRÅöÅúÝ‘p†%ú¯Ø‘h´Fú-­ ÿ‰ÿ ‘P—UÚØ ÿ‰ÿ‘¨¼FÓì ÿ ‘H—UÐ ÿ‘Ø~¼FÓì ÉxA 9&¨—Àœ*žV~ƵÆlÏ ‘pܘ‚Ý ‘`èÆ{{ Q¤‘Ð~vGwÑ‘à~}G]Ð {{¨—€t¢uVîÆ$ÇlÏ ‘pܘ‚Ý ‘oèÆ9& uWu‘Ø~vGБè~}G]Ð 9&¨—HÇ(vOÇVÇ[Ç2ÞOÇVÇ[Çz¬OÇVÇ[Ç`Ç45#G5#ïzïVnÇ—Ç"9Þ ‘p†%"T4 ‘`ܘ"‚Ý IïSï ‘P¦H$9Þ 9ÞxAqV¥ÇÎÇB9Þ ‘p†%BT4 AK ‘`¦HD9Þ 9ÞxAVÇš@ 4#[Çš@ 4#$79Þ#ÜÇ@_6#r6#`dŒdVLÈÙÈÔ“­‘x†%ÔÇÐ ÛxAd×dVRÉßÉÀ“­‘p†%ÀÇÐ ÛxA {)|VXÊäÊ"Û ‘@†%"f5 ‘°ܘ"‚Ý Ú{ü{ ‘ð~¦H$Û ÛxAVÇš@ 4#[Ç@š@ 4#$7Û#TË{ˤ6#[Ç$7¨á#–Ë¢ËH7#K#LV»ËôËu; ‘x†%·6 ‘pÍi3È ØKòK ‘XËi® ®xA Ȫ— 3Ȭ—[Ç$7®#Ìr7#…7#VÇš@<4#[Çš@<4#$7o1#@Ì0kÌ·7#[Ç0$7ùÅ#Ì¢ËI8# †VÒÌ/Í"iÆ ‘x†%"Ê7 ‘hܘ"‚Ý Yc ‘X¦H$iÆ iÆxA[Ç$7iÆ#qÍÍ8#à8#jV„ͲÍîÿ8‘p†%î‰Ò =G‘hËiðŸÆ rÆxAVÇš@ 4#[Çš@ 4#$7rÆ#ÌÍ¢Ëo9#° VàÍÎBŸÆ ‘x†%Bÿ8 Ýç ‘h¦HDŸÆ ŸÆxA[Ç$7ŸÆ##Ι9#¬9#VÇš@ 4#[Çš@ 4#$7(v#/ÎXR:#e:#p7 8V|ÎäÎ"•¡ ‘¨†%"Ë9 ‘˜ܘ"‚Ý â7ó7 ‘¦H$•¡ •¡xAVÇš@ 4#[ÇXš@ 4#$7•¡#1Ϣ˗:#[Ç$7RÆ#VÏ(öÏ<;#pw xVÐïЄ: ‘P†%ª: ‘HÍi Ä ×wæw ‘@Ëiˆ ˆxA Rƪ— Ĭ—[Ç($7ˆ#±Ñ(ÕÑb;#[Ç($72#øÑ Òˆ;#[Ç$7È#(Ò{Ë<#P¼PV6Ò`ÒÔ“­‘x†%Ô­Ö U­xAÀPQVoÒ™ÒÀ“­‘p†%À­Ö U­xAQRV¨ÒÑÒ"U­ ‘`†%"›; ‘Pܘ"‚Ý ÜQîQ ‘¸¦H$U­ U­xA[Ç$7U­#ßÒ0>#,>#Q ‘¨ܘ"‚Ý ~~ ‘ ¦H$€' €'xA@lV6ØÍØÔ“­‘x†%Ô¨È €'xAp·VHÙßÙÀ“­‘p†%À¨È €'xAVÇš@ 4#[ÇHš@ 4#$7€'#ZÚ{Ë‹?#[Ç$7K[#xÚ{˱?#[Ç$7Ñ[#™Ú»@#Î@#© ªV§ÚÐÚ"ÃÈ ‘p†%"Ä? ‘`ܘ"‚Ý Ù©ã© ‘P¦H$ÃÈ ÃÈxAP¯|¯VÞÚÛÔ“­‘x†%ÔÛ× ÃÈxA€¯ǯVÛAÛÀ“­‘p†%ÀÛ× ÃÈxAVÇš@ 4#[Çš@ 4#$7ÃÈ#PÛ¿A#ÒA#'»Z»V[ÛÛ" ‘x†%"í@ ‘`ܘ"‚Ý û¬xA`ÈŒÈVŒÛ³ÛÔ“­‘x†%Ôä× û¬xAÈÔÈV¿ÛæÛÀ“­‘p†%Àä× û¬xAVÇš@$4#[Çš@$4#$7û¬# à`-bVòÛ¬ŸÝ‘p†%ŸÇБh´FŸ-­ Xa†a‘°¼FÓì Šab‘P—U§\Ñ Šab‘ˆ¼FÓì ÛxAPMNV{ÜLŸÝ‘p†%ŸgÖ‘h´FŸ-­ ÈMöM‘°¼FÓì úMxN‘P—U§›Ö úMxN‘ˆ¼FÓì ×$xAàŒVàÜuÝŸK>‘x†%Ÿ¨È Yr‘`—U§"× €'xAîÝòÝ P8PVøÝ$ÞÓ­ ‘x†%ÃAÄ ‘pPeÃAÄ ùÊ2Þ ùÊ4Þ îFîV6ÞVÞ™“­ ‘x†%™»Ï ‘pPe™»ÏðñòVYÞyÞ“­ ‘x†%»Ï ‘pPe»ÏÀ]æ]V|ÞGI“­ ‘x†%IIÆ ‘pPeIIư¥Ö¥VœÞ¼Þ›“­ ‘x†%›»Ï ‘pPe›»Ï ñêñV¿ÞÙÞ89Þ ‘p­g89Þ ‘hèÞ89Þ 9ÞxA`¥ª¥VëÞß&9Þ ‘p­g&9Þ ‘hèÞ&9Þ 9ÞxAßß6ß­#%­#:ßWO#Bß6ß¡Ý#%¡Ý#:ßcO#Kß6ßiÃ#%iÃ#:ßoO# 2Vwß˜ß G9Þ ‘p†% GU­ 2ÞxAp‚V ßÅß ,¡Ý ‘p†% ,U­ 2ÞxAp‚V×ßà ÓhÊ ‘p†% Ót­ 2ÞxAà:Và=à jU­ ‘p†% jU­ ‘hGà jlP 2ÞxA@ Và=à ?U­ ‘p†% ?U­ ‘`Gà ?P 2ÞxAPKKVà=à ZU­ ‘p†% ZU­ ‘hGà ZžP 2ÞxA@PzPVMàpà à“­ ‘p†% àU­ ‘`Pe àU­ 2Þ2Þ 2Þ4Þ€P‚QVzàà &“­ ‘h†% &U­ ‘XPe &U­ QqQ ‘°­à .9Þ 2Þ2ÞÀ]Ä^V²àÔà +·6 ‘`†% + È ^¸^ ‘HÝà 5¡Ý +^|^‘¸6ß ª¡Ý(TN>^G^ « ƒ^¸^‘ 6ß µ¡Ý(TN“^œ^ ¶ 2ÞxA0_:`Vá8á ËÚE‘h†% ËU­ F_-`‘`Aá Í¡Ý k_’_‘PAá Ð¡Ý ¡_-`‘@6ß ª¡Ý(TN±_¾_ « 2ÞxA°lGmVCájá Æ ¯‘p†% ÆU­‘h€á Æ9Þ 2ÞxA'm]nV„á²á û ‘p†% ût­ ‘`Öá ûU­ 2ÞxA@ìRìVÚá&â ÓãÍ ‘p†% ÓÄ o1xA0íRíVXââ G9Þ ‘p†% GJÄ o1xA@òRòVÈâã ,ià ‘p†% ,JÄ o1xA@E¥EVà=à ® ‘p†% U­ ‘hGà 9Þ 2ÞxA°EðEV>ãjã '® ‘p†% 'U­ ‘hGà '9Þ 2ÞxA@|b|Và=à yU­ ‘`†% yU­ ‘XŠã y±P 2ÞxAp›’›V‘ã¹ã Üt­ ‘`†% Üt­ ‘XŠã ܱP 2ÞxA ¦§VÑãüã SXÈ ‘p†% St­ ‘h€á S9Þ p ‘`ÿU T9Þ ‘X6ß UhÊ 2ÞxAðKJLVäaä jJÄ ‘p†% jJÄ ‘hGà jlP o1xAPL/MVäaä ?JÄ ‘p†% ?JÄ ‘`Gà ?P o1xAТ£VŽä¾ä Î'Ð ‘p†% Ît­ ‘hGà Î9Þ 2ÞxA E Væä å ¿U­ ‘hAá ¿¡Ý ‘`ÿU ¿9Þ 2ÞxA,åà56V5å^å u“­‘p†% uU­ ùÊvå)áàá 9Þ 2ÞxAÀãåãV{åÆå ËÄ ‘hAá ËãÍ ‘`ÿU Ë9Þ o1xAí%íVæZæ ¿JÄ ‘hAá ¿ià ‘`ÿU ¿9Þ o1xA§5§Væ¸æ Ët­ ‘hAá ËhÊ ‘`ÿU Ë9Þ 2ÞxAÏæ%Öæ%úæ%#ç%4ç%gç%›ç%¬ç%Üç%íç%è °QÅQV'èÊLý“­‘x†%ýâБpbèýâÐ À+xAièm覗(v#ÀØVtè”è áçO ‚ÝxA ·V èÊè gçO‘p†% g]Ð ‚ÝxAèèìè0>9Þ#ýè0>9Þ#%9Þ# é%9Þ#%é#é0>,# VHé±é#8!Æ ‘x†%#8²Ï T~xA 1VHé±é#1!Æ ‘x†%#1AÒ T~xA6ßê0êÐU#:ßiO#°ëÞëV8ê{ê ÃNQ ‘`6ß ÃãÍâUÀëØë Ä‘püU o1xA&ë0ê V#:ßuO#€®V2ëRë ÃÊQ ‘`6ß Ã$ÅV¨ Ä‘p5V (vxA—ë0êBV#:ßO#@nV¢ëÁë ÃFR ‘`6ß ÃhÊTVPh Ä‘pnV 2ÞxA PãsãVìHì Ú|Ï ‘x†% ÚÌÑ o1xA CVuì˜ì ÚŽÏ ‘x†% Ú&Ò (vxA¢3¢V£ìÄì ÚÐ ‘x†% ÚŽ× 2ÞxA*`ì|ìVÎì í º‘x=í ºãÍ‘pÖá ºo1 o1xA+AíYí ‡(v (vxA,Öá ‡ÏÄ&-cí ˆ(v+gí˜í ‡2 2xA,Öá ‡yÅ&-cí ˆ2*©VºíÔí º‘x=í º$Å‘pÖá º(v (vxA*°Vßíî º‘x=í º\Ò‘PÖá º2 2xAPkŠkV4îtî j’Š‘p­î jDÓ‘hÖá j’Š ’ŠxA lJlV²îÎî j(v‘x­î j$Å‘pÖá j(v (vxA°l†mVÛîï j2‘x­î j\Ò‘PÖá j2 2xA*€¢™¢V4ïLï º‘x=í ºhÊ‘wÖá º2Þ 2ÞxAVï^ï$7iÃ#+¦êôê-ÐU iÃxA,Àz-iÔï$7ÏÄ#+[ë‡ë- V ÏÄxA,Àz-ÏĨï$7¡Ý#+Éëôë-BV ¡ÝxA,Àz-¡Ý €ã–ãV»ï ð6…Ï‘x†%6ÕÑ ˆã”ã‘pÀz7…Ï iÃxAPfV?ðmð6—Ï‘x†%6/Ò Xd‘pÀz7—Ï ÏÄxA@¢V¢Vð¬ð6Бx†%6—× H¢T¢‘pÀz7Ð ¡ÝxA½ðÂð³@\8#ÐÞVïð.ñ%q Ï ‘x†%%qiÆ \8xATñ³@¯X#@K‡KVvñ°ñ%›;‘x†%%ÂpÖ ›;xA* KáKVÑñ ò%Ó‘x†%%ÓpÖ‘h³@%Ó›; ›;xA ‰ä‰V0òjò%¯äW‘p³@%¯›; ›;xA‹ò³@›;#KžKVvñ°ñ%qñÏ ‘x†%%qyÖ ›;xAð‰ŠV0òjò%H¯X ‘p³@%H›; ›;xA³òPDóýY#³@ÝZ#Àƒ…VKóõó%¶,[ ‘x†%%¶+×   ‘`Ve%¸K[ K>xA`Š¡‹V…ô3õ%æ²[ ‘x†%%æ+× à ‘`Ve%èÑ[ K>xAÒõ³@ŽZ#à…†VÞõö%Â9Þ‘x†%%±È 9ÞxA* †N†V ö1ö%Ó‘x†%%ӱȑp³@%Ó9Þ 9ÞxA<ö³@9Þ#††VÞõö%qúÏ ‘x†%%q4× 9ÞxANöH³@K>#P†^†Vâö‰÷%qÐ ‘x†%%q=× K>xAø³@¨È#DóK[#£øDó±È#…Ñ…V­ø%Sx? ‘xDó%S±È w…Ç… ‘XVe%V9ÞÉø³@ºÈ#DóÑ[#YùDó±È#°‹6ŒV­ø%ñž? ‘xDó%ñ±È '‡b‡Vfùƒù%` ‘x†%%`F×  ‘pDó%a9Þ€‡‘‡Vˆù1ú%„¨È ‘x†%%„O× K>xA`‰ž‰VÀúüú%äW ‘x†%%pÖ ›;xA'ðŒ"Vfùƒù%è ‘x†%%èX× üŒ ‘pDó%é9ÞÀÑVˆù1ú% ¨È ‘x†%% a× K>xAÀÑVûÌû%ºÈ ‘x†%%j× K>xAiünürüH~üþ]#ð:;V…ü°ü&¥¬]‘x¾ü&¥(v‘pÃü&¥(vÈüHíü(v#ðü(v#qR9Þ#óüø^#ùü(v#8þü9Þ#@:߇O#H ;Á;VýMý&Àþ]‘x¾ü&À(v‘pÃü&À(v 7;·;‘¨óü&Áþ] /_yý*Ð;X<V{ý¼ý&Ô‘x†%&ÔóÒ /_yýæý ìý(v#èÞ(v#­g(v#ïý(v#%òý *P={=Vþý7í&î‘x†%&îÓ‘hܘ&îU­'€=2EV þaþ& ‘x†%&óÒ ‘hܘ&U­ P ‘`qR&9Þ ‘X…þ& 9Þ ‘ˆÿU&9Þ ‘€Œþ& 9Þ ‘ø~‘þ&"9Þ >‹B ‘°“þ&(v €‘H¦—&^9Þ‘@•þ&_(v °‘ ¦—&^9Þ‘˜•þ&_(v à‘à~¦—&^9Þ‘Ø~•þ&_(v  ‘ð~™þ&$(v /_yý'ðEÍIVœþÁþ&c ‘xóü&cÓ€J›JVÊþíþ&ó(v‘x†%&ó Ó J@KVôþ6ÿ&2(v ‘x†%&2)Ó °J:K ‘Xóü&3ø^ ‘PVe&5(v /_yý'@K…WV[ÿ€ÿ&h ‘xóü&hÓJ[JV‰ÿ©ÿ&n(v‘p#9&nU­‘h‘þ&n9Þ $JUJ‘`PW&p(vòÝ '`<†<Vµÿ'# ‘x†%'#IÆ ‘póü'#üÒ ]¤68*<=V?Œ'³‘`†%'³üÒ‘X‘þ'³(v ]¤våEÌE È#Ùd9Þ#ò0Eƒ8#<“­#(A Ä#)K ]·]VR“ÚE ‘p†%ÚE ÚE/{`í‡íV¾P ‘p†%P P/{P¢V$ŸÛ ‘X†%Û Û/{ðJKVúW±b ‘p†%±b ±b/{ð—þ—V”ú Ð ‘x†% Ð Ð/{®â®V@¡ƒ8 ‘X†%ƒ8 ƒ8/{`ÂnÂVâiæÈ ‘x†%æÈ æÈ/{HB íîVÏúöT4 ‘x†%öðÑ Éíøí ‘hø9Þ 9Þ2ÞPî„îV.f9Þ‘x†%f»Ï6?ÐIïJVH’)óT4 ‘x†%)ó È ‘pA)ó Ä æI²J ‘h E)øû¬ J²J ‘@E)ø±b P ‘Ëi)ø® ‘ ‘þ)ø9Þ ÚEvå ĺ K ‘x­î³ºÈ ‘°Öá³K> K>xA'`Ž+V¬Jp ‘xËipºÈ ‘pƒpºÈ wŽ" ‘¨¦—sK> K>xA09VØZK> K>xA*@ºV¶s‘¸¦—sK> K>xA0;VFbÉ9Þ 2ÞxA‹F ° Á Vo‹F‡(v‘x†%‡IÆPëqëVŽ´~U­‘h†%~AÄ ùÊxA Š1ŠVÀý~RÆ‘x†%~’Ò 2xA@ŠQŠV }~‰Ç‘x†%~¾Ð ©-xAP£`£Vo‹F‡2Þ‘x†%‡®À àBõBVÈÿò9&‘~¦—ò9& 9&xAPlolVQꤪ‘p†%ê‚Ý ‚ÝxA ¤ªª—€ŸVg•êU­‘p†%êU­ U­xA U­ª— ÂV§ÏòU­‘`¦—òU­ U­xA¨v¨VÛ ò{{‘p¦—ò{{ {{xAÀšîšV/ q ꎲ‘p†%êU­ U­xA ޲ª—Dó ð]þ]V— ¾ (XIÆ‘x†%(XIÆ (vxAÊ  ¦"¦VÎ Ÿ`,cU­ ‘`†%,c‚Ý#î 0>Vïf g ê(v ‘x†% ê(v$Vg/g Ò(v ‘x†% Ò(v$V5gXg Š(v ‘x†% Š(vÐIéIVò ! Í(v ‘x†% Í(v ‘pe Í(v"$!")!,!3!(v .8!@! .2w#Qw#8!š@w#$7{{#@!š@w# fLjVI!k!pk ‘x„!p€Ñ @‘pˆDs(v‘l†!t·® áfLj‘k#9w‰Ñ‘€Œ!~(v gg¨g‘¨ªH{{ U­•!`sBwV—!·!‹‘x„!‹€Ñ „s2w‘pˆDŽH¯‘l†!·®‘h­à·®‘gÌ!‘2Þ Ôsv‘f#9”‰Ñ‘ø~Œ!œH¯ Zt›t‘ ªH{{ U­•!`pqpVÑ!ï!42Þ‘Ì!42Þ7ퟡV"'"¶ë#‘x;"¶DÖ‘p¦H¶(v p‘h[¹9Þ >Ÿ¡‘gÌ!»2Þ‘f#9‰Ñ ïŸ0 ‘ ªH{{ t­="P°­²V?"d"Ïë#‘x;"ÏDÖ‘p¦HÏH¯  ‘h[Ò9Þ Ž°£²‘gÌ!Ô2Þ‘fv"ד­‘e#9á‰Ñ „±ű‘ ªH{{ t­=" ¡P¡V{"˜":2Þ‘x¦H:(v ,¡J¡‘pÌ!;(v¨"¬"èÆ2Þ¯"´"·"2Þ¾"È"Ñ"â"ô"####-#>#I# W# b# o# {# „#Ž#š#õ. # .°#Ö{#ÐkAlVµ#És¿{{‘Ú#¿ýz‘hèÆ¿‚Ý ‚ݨ—¯"í{# |#´"š@åz#$7·®#·"š@åz#$7¯#·"Ú#ýz#èÆ¤ª#  qœqVß#GP“­‘p†%P–Ñ‘h´FP–Ñ .q•q‘`¶MPÃÈ‘PÀMPÃÈòÝ PjÈkVý#$$¥À ‘x†%¥€Ñ‘h#9¥t­ jj¸k‘QªU­‘€VeªU­P¡Õ£V/$T$ÆÀ ‘p†%ÆDÖ‘`PWÆU­ Б ªHÇ{{ ¢¢‘¦HÇ9Þà£^¥V^$7í½ë#‘x†%½DÖ‘hPW½U­ ú£N¥‘`$¾9Þ‘€Q¿t­‘ð~Ve¿t­ƒ$iü$(v•$¡$§$¬$×$9Þ#­à9Þ#à$ÊQ#Ïæ{O#€üÍVç$E%!dT~ ‘x×$!d9Þ ’ü½ ‘pŠ%!p9Þ ‘`–%!q9Þ ‘P %!r9Þ ‘ˆª%!|9Þ ‘€»%!|9Þ ‘ø~­à!|9Þ ‘÷~Ç%!|“­ ‘Ð~Ì%!†9Þ ‘Ø}Û%!hÊ ‘È}à$!•$Å (v=} 2?}°ÁVâ%7&!¾9Þ ‘x†%!¾!Æ (v=} 2?}°%Va&¾&!ûÛ ‘x†%!ûÆ Ã ‘`'!ü‚ (v=} 2?}0V 'i'!Ÿ‚ ‘x†%!Ÿ!Æ  ‘pŠ%! 9Þ ‘`–%!¡9Þ ‘PÛ%!£¡Ý ‘˜¬'!¤9Þ ‘¸'!¤9Þ ‘Ç%!¤“­ (v=} 2?}€’VÄ'(!Ä9Þ ‘x†%!Ä!Æ (v=} 2?}@V;(‹(!µT~ ‘x×$!µ9Þ 0 ‘`°(!·T~ (v=} 2?}$V´()!Њ ‘x†%!Ð!Æ (v=} 2?}$V+)ƒ)!Èአ‘x†%!È!Æ (v=} 2?}°)(á)‚#å)$Å#ð)9Þ# ÏæO#(û)iü$Å#'*ÏÄ#¦HyÅ#:ß{O#P É V+*~*!¶‚‘h†%!¶‚‘`Ùd!¶ÃÈ (v=} 2?}¦*(á)‚#99Þ#$Æ#   ò V+Á+!š‚ ‘x$!Æ (v=} 2?} Æ=,' NV?,à,!6 ‘x†%!6eÒ 6E ‘pHB!89Þ ‘`U-!:ÃÈ (v=} 2?} Æ=,@+,VZ-û-!"= ‘X†%!"š‚ (v=} 2?} Æ=,3I3Vu./!š‚ ‘p$!Æ ‘hiü!’ФŠ'323!‘xµŠ (v=} 2?} Æ=,P3ÿ3VÃ/h0! š‚ ‘x$! Æ ‘pê0! 9Þ ` ‘hê0!9Þ (v=} 2?} Æ=,44Vó0•1!Ù9Þ‘x†%!Ù¿Ò (v=} 2?} Æ=, 2(á)‚#99Þ#$!Æ# $V€23!… ‘x$!!Æ (v=} 2?} !Æ=,@RV3.4!Ù9Þ‘x†%!ÙJÒ (v=} 2?} !Æ=,`.V 4=5!"„‡ ‘X†%!"… (v=} 2?} !Æ=,'P~V®5K6!6 ‘x†%!6nÒ fu ‘pHB!89Þ ‘`U-!:ÃÈ (v=} 2?} !Æ=, ~i~V¼6X7!… ‘p$!!Æ ‘hiü!’ФŠG~R~!‘xµŠ (v=} 2?} !Æ=,p~VÈ7i8! … ‘x$! !Æ ‘pê0! 9Þ  ‘hê0!9Þ (v=} 2?} !Æ=,Þ80›‡#å‡#¡$0š@<~#$7º‡#X9(á)‚#99Þ#$!Æ# §$0š@<~#$7ˆ#Ò9(á)‚#99Þ#$!Æ# 0TVK:è:!±*Æ ‘x†%!±SÒ (v=} 2?} !Æ=,`|VY;ö;!¬’Š ‘p†%!¬SÒ (v=} 2?} !Æ=, 2V3.4!Ë9Þ‘x†%!ËSÒ (v=} 2?} !Æ=,@äVg< =!¤9Þ ‘p†%!¤SÒ¤Š{ƒ!¨‘xµŠ (v=} 2?} !Æ=,@€V®5K6!†… ‘X†%!†ˆ ¸€ð€ ‘°’=!‡… (v=} 2?} !Æ=,[V™==>!… ‘X†%!ˆ (v=} 2?} !Æ=,`£VÁ>c?!ï*Æ ‘X†%!ïˆ (v=} 2?} !Æ=,ã?iü(v#+‰/»/!’(v,†%!’5Ïì?(EáŠ#ð)9Þ# @ á)‚#å)$Å#ÏæO# @@(á)‚#99Þ#$Æ# ,´,V½@fA!¤9Þ ‘p†%!¤¶Ò¤ŠK,S,!¨‘xµŠ (v=} 2?} Æ=,À,Ü,VãA„B!¬’Š ‘p†%!¬¶Ò (v=} 2?} Æ=,à,;-VùB¡C!š‚ ‘X†%! ‹ (v=} 2?} Æ=, -(/VDnD!¾¨Æ ‘˜†%!¾ ‹.ÀSÀ!È‘HÚS ð/‘@æSóSƒ./!É‘x T ƒ.//‘PT (v=} 2?}\\Vó0•1!Ë9Þ‘x†%!˶Ò (v=} 2?} Æ=,Ð\ô\V”D5E!±*Æ ‘x†%!±¶Ò (v=} 2?} Æ=,]À]V?,à,!†š‚ ‘X†%!† ‹ x]°] ‘°’=!‡š‚ (v=} 2?} Æ=, gµgVªELF!òÏ‘x†%!öÒ (v=} 2?} Æ=,Àg5hVÂFdG!—’ ‘X†%!— ‹ (v=} 2?} Æ=,vSvVàGŠH!ùÇ ‘X†%!ù ‹ (v=} 2?} Æ=,I(á)‚#99Þ#$Æ# @-›-VùB¡C!Nš‚ ‘X†%!NØŽ (v=} 2?} Æ=, 4È6V”I4J!s ‹ ‘¨†%!sØŽ ‘ iü!s’Š ‘'*!s(v ‘è~³@!s2¤Š"505!u‘PµŠ (v=} 2?} Æ=,ð67VªELF!Ҳϑx†%!ÒÑÒ (v=} 2?} Æ=,¬J0T#s#¡$0š@<~#$7ØŽ#§$0š@<~#$7 ‹#*KHá)‚#99Þ#$ ‹# @hähVôKêL!¤9Þ ‘p†%!¤2Ó¤Š{hƒh!¨‘xµŠ (v=} 2?} ‹=,ðh iV´M¢N!¬’Š ‘p†%!¬2Ó (v=} 2?} ‹=,`iBkVdOUP!ÓïÆ ‘x†%!Ó;Ó ‘pQ!Ó’Š ‘`;}!Ó(v ‘¸9}!Ó2  ‘°Q!Õ’Š ‘ˆ%Q!Ö(v ‘à~-Q!×2 (v=} 2?} ‹=,@opV5Q#R!†…“ ‘¸†%!†’ Áop ‘ð~’=!‡…“ (v=} 2?} ‹=, p¤pVåRÚS!…“ ‘¸†%!’ (v=} 2?} ‹=,`vÁvV£T—U!Ç ‹‘¸†%!Ç’ (v=} 2?} ‹=,ÐvâvVjVYW!Ë9Þ‘x†%!Ë2Ó (v=} 2?} ‹=,XHá)‚#99Þ#$ ‹# '°pÞqV5Q#R!6 ‘x†%!6VÓ ÆpÕq ‘pHB!89Þ ‘`U-!:ÃÈ (v=} 2?} ‹=,àqîrVâXÐY!"y” ‘¸†%!"…“ (v=} 2?} ‹=,’ZP”#z•#¡$Pš@<~#$7¯”#][Há)‚#99Þ#$ ‹# ðrèuV(\]!s’ ‘ˆ†%!s¯” ‘€iü!s’Š ‘ð~'*!s(v ‘È~³@!s2¤Š tt!u‘PµŠ (v=} 2?} ‹=,§$Pš@<~#$7’# ' CVÖ]'^! ‘x†%!Æ P ‘à~Š%!!9Þ ‘Ð~–%!"9Þ ‘À~ %!#9Þ ‘ø}ãg!$9Þ ‘ð}­à!$9Þ ‘ï}Ç%!$“­ …  ‘p E!û¬ §  ‘˜E!Û (v=} 2?}@  VM^ž^!D¤7 ‘¸†%!D8Ò.ÀS€!Q‘HÚS °/‘@æSóSt  !Q‘x T t  /‘PT (v=} 2?}Ð6á6VÄ^!_!ïÆ‘x†%!ïÈÒ (v=} 2?} \q\Vd_G!Š“­‘x†%!Š5Ï‘p´F!Š5Ï 4\e\‘h G!ŒIÆ O\e\‘`G!ŒIÆi_iV‘_3`!â!Æ‘x†%!â¶Ò (v=} 2?} Æ=,ðuvV©`Va!ÿÆ‘x†%!ÿ_Ó (v=} 2?} Æ=,p V×a b!7ÎÅ ‘xŠ%!79Þ ‘p–%!89Þ ‘hb!99Þ ‘`(b!:9Þ ‹ü ‘X¬'!<9Þ ‘@3b!=9Þ ‘¿Ç%!=“­ ‘°¸'!?9Þ ê V?brb!%9Þ ‘xƒb!%9Þ ‘pb!%9ÞP:¦:Vžbøb!š’Š‘p:c!šÒ‘h¦—!šIÆ d: :‘ óü!ž]¤ (vxA ú yýŸ—(vEcKcTc(v[clctc(v{cKcTc‰c–c(êcú #$T~#÷c<¡#(à4Vd„d G@š ‘pêc Gú  (v=} 2?} ú yý$Væd^e Š‚¡ ‘x†% Š Ò (v=} 2?} ú yý®V­e‹( @š (v=} 2?}@ÑVûetf ¾•¡ ‘x†% ¾¤Ò ‘p'* ¾(v (v=} 2?} ú yý'àÚVÄf?g ˜ ‘x†% ˜¤Ò ‘p™g ˜9Þ ðÔ ‘h¤g ™9Þ ‘H­g š9Þ ¦Ô ‘ µg ¡9Þ (v=} 2?} ú yýàÿVÂg9h Ñ9Þ ‘x†% Ñ Ò (v=} 2?} ú yý'')V‡hi ª ‘x†% ª¤Ò ‘pµg ª9Þ ) ‘˜Yi ®T~ ‘ø~ci ¯9Þ ‘°~’= ·š‚ à ‘¨}li Ä ‹ 1!I! ‘ }Ve ÎØŽ ¢')‘¨wcG»Ï‘¸wmG»Ï X(®(‘˜vvG­Ò‘¨v}G­Ò  ‘ðz’= å ‹ @ ‘àzQ æ’Š ‘°yVe çØŽ ‘¨y;} ç(v ‘€y9} ç2 Æ#Þ# ‘èzVe îØŽ (v=} 2?} ú yý'@/ü2Vqiúi û ‘x†% û¤Ò ‘piü û’Š ‘`;} û(v ‘¸9} û2 p ‘°pj ü9Þ ‘ø~tj ýš‚ ‘è~|j þ9Þ ° ‘Ø};@ ØŽ Q2f2 ‘Ð}Ve  ‹ (v=} 2?} ú yý 9:Vjk ó5£ ‘x†% ó¤Ò ‘pek óIÆ ³9ý9 ‘hiü ö’Š (v=} 2?} ú yý (vgk:C:Vikêk ã’Š ‘p†% ã Ò ‘hËi ãIÆ (v=} 2?} ú yý (vBl wfwVDl¿l "„: ‘x†% " Ò ‘p;} "IÆ (v=} 2?} ú yý (vgk@y§yVmm ëp¤ ‘x†% ë Ò ‘pek ëIÆ Syy ‘hiü î’Š (v=} 2?} ú yý (vgkëmíü(v#ðü(v#0@eV÷m ‘ú #nKV7nmn 59Þ‘x†% 5Ò‘pzn 59Þì?(ÀzŠ#†nP¬¡#ê¡#Kc@š@ò™#$7Ë¡#®n8'*‚9#Þn ‹#TcPš@ò™#$7 ¢#ãnHiü’Š#'*(v#ÞnÔ¢#^ì`Vobo SBÇ ‘°†% S ¢ ‘ˆ³@ S2 ¤^x_ ‘€’= U ‹ ‘ð~|j U9Þ à ‘è~’= XØŽ (v=} 2?}Šo8ë¢#£#lc8š@ š#$7 ‹#¯89Þ#0tc0š@ š#$7ØŽ# pH¤#¤#J¤# 89Vpâp &Ë9 ‘¸†% &5£ ‘°'* &(v ­8è8 ‘¨Þn ( ‹ ó8B9 ‘Þn .Ô¢ ‘˜iü .’Š (v=} 2?}Kc0š@"š#Þn ‹#TcHš@"š#iü’Š#ÞnÔ¢#‰cš@"š#qH$7¬]#'qH¥# ¥#¬¥#°x2yV£qNr ª: ‘¸†% p¤ èxùx ‘°Þn ˆ (v=} 2?} !Æ=,Kc0š@"š#Þnˆ#TcHš@"š#iü’Š#ÞnK¥#är8b¥#¥#lc8š@ š#$7ˆ#¯89Þ#0tc0š@ š#$7º‡#‰cš@"š#  ÖVcsÞs ´@š (v=} 2?} ú yý0 >V8t0t Ðú °:á:Vhtžt ´]¤ ‘x†% ´Ò' =K=V«t7í à ‘x†% ÃüÒ ‘hܘ ÃU­`J{JVÙtíþ È(v ‘x†% ÈÓWø[Vu¯u Z5£ ‘p$ ZÆ ‘hiü [’Š ‘XCv \ÓÆ  ‘¸­à hÃÈ ‘€Lv iš‚ ‘ð~|j jÃÈ +Yø[ ‘À~li m ‹ ‘Ð}Rv xÃÈ iYµY ‘à}’= nØŽ µY¿Y ‘Ø}’= u ‹ (v=} 2?} Æ=, ÓÆ¬—ð`’gV[v§v ªBÇ ‘P’= ª ‹ ‘H|j «9Þ ‘@iü ¬’Š ‘°'* ­(v ‘ˆ¦H ®2 @ ‘€Þv °9Þ ‘è~­à ±9Þ  ‘~’= ³’ ‘à}ív ·9Þ Ð ‘è|Q º’Š ‘à|%Q º(v ‘¸|-Q º2 ‘È{Lv À…“ ‘¸zõv Ã’ ‘Èvw Ó9Þ @ ‘˜y’= į” p ‘Èx’= Æ’ !f.f ‘y’= Ð’ (v=} 2?}°y~V w­w Zp¤ ‘p$ Z!Æ ‘hiü [’Š ‘XCv \ÓÆ   ‘¸­à hÃÈ ‘€Lv i… ‘ð~|j jÃÈ K{~ ‘À~li mˆ ‘Ð}Rv xÃÈ ‰{Õ{ ‘à}’= nº‡ Õ{ß{ ‘Ø}’= uˆ (v=} 2?} !Æ=, ÓÆ¬—èÆ%/x:xAxGxÀz[Æ#\x‘Æ#pVaxÃx$ïú ‘x†%$ïwÒ‘pÍi$ï Ä ‘h y$òÊ7 ‘` y$óiÆ Ûå‘HÀz$öŸÆ rÆxA Ĭ— ú •!àPVy@y$üŸÆ‘x†%$üwÒ‘p y$üiÆ ôJ‘`³@$ÿrÆ ‘X6ß$ Ï rÆxAQy@¸V[yy@lÏ ‘`ܘ@‚Ý ‘XŸy@TÐAÊs›H‘p[Ê ‚Ý=,#Íy¡Vïf g êz¬ ‘~†% êz¬$Vg/g Òz¬ ‘~†% Òz¬$V5gXg Šz¬ ‘~†% Šz¬"Ñy ÉäÔy Èìñy ­z1Ý2 ­2-­ ‚ã`zzz‡d­#qR9Þ#“z‡d¡Ý#qR9Þ#™z‡d¡Ý#qR9Þ#"£z¨z$7U­#¯82Þ#´z@$7®,#¯8©-#){ $7®,#¯8÷­#{$7(v#¯8™&#œ{$7®,#¯8(v#Ù{$7®,#¯8z¬#| $71#¯8ì+#r|$7†®# 1z| 2Þ³|·|$7U­#¯8(v##Ä|ðIJV”e¹e »·® ‘|†% »·® ‘xe »·® +|È|ä| $7U­#¯8U­#ó|$7U­#¯8H¯#"}}$7U­#¯8±&#,}$7U­#¯89(#\}$7U­#¯8Q(#‚}$7U­#¯8Ä*#¨}$7U­#¯8o1#×}$7U­#¯8û¬#ã}($7U­#¯82°#ƒ$)~-~#9–¸#ÿU9Þ#à.àVX~{ê&2° o1xA'àçãèV£~ï~¾ ‘`†%¾ÃÑ ‘X³@¾o1.v¹Ð Á‘p¹ ! ‘@%ÅãÍ o1xA$V uI2° ‘x×$I9Þ o1xA3Vª€Û ‘x†%ÛÃÑ ‘hPeÛJÄ& ‘X EÞû¬& ‘°EÞP& ‘‘þÞ9Þ& ‘ˆÿUß9Þ o1xA3V<€‹€¤ ‘x†%¤ÃÑ ‘p™g¤9Þ o1xA$Vº€âY9Þ ‘x†%YçÑ o1xA3VT ‘x†%ÃÑ ‘pÿU9Þ o1xA FbFVƒZæ~2° ‘x6ß~ãÍ ‘pqR~9Þ ‘h×$~9Þ o1xAÙ#9 ¼#ÿU9Þ# œVœVá‚I޲ ‘x×$I9Þ 2ÞxA'p/ŸV3‚i‚Û ‘x†%Û|× ‘hPeÛU­ ¶Ÿ ‘X EÞû¬ èŸ ‘°EÞP @! ‘‘þÞ9Þ p! ‘ˆÿUß9Þ 2ÞxA'0Ÿ[ŸV‘‚½‚¤ ‘x†%¤|× ‘p™g¤9Þ 2ÞxA`¢r¢VÉ‚˜ßY9Þ ‘x†%Y × 2ÞxA'£ª£Vð‚ƒ ‘x†%|× ‘pÿU9Þ 2ÞxA'0¦§V0ƒXƒ¾ ‘`†%¾|× ‘_³@¾2Þ.t½ !Á‘p޽ à! ‘H%ÅhÊ 2ÞxA ' âgâVaƒ­ƒà ‘x†%àÃÑ o1xA â×âVÙƒ*„ìÄ ‘h†%ìÃÑ ‘`Šãì±P o1xAàâãV[„¬„Ä ‘x†%ÃÑ ìâã ‘p6ßãÍ o1xA€ì·ìVÝ„aä½JÄ ‘h†%½çÑ ‘`Šã½±P o1xAÀì÷ìV*…HìJÄ ‘x†%çÑ Ììñì ‘pAáãÍ o1xAðš›Vw…Ÿ…޲ ‘p¨…U­ 2ÞxA£G£Vª…Ø…t­ ‘x†%|× £A£ ‘p6ßhÊ 2ÞxA'¤G¤Væ…†à ‘x†%à|× 2ÞxA€¤·¤V†¹ãìt­ ‘h†%ì|× ‘`Šãì±P 2ÞxA0©g©VE†ÄìU­ ‘x†% × <©a© ‘pAáhÊ 2ÞxAßn† DFVs†Á† ˆ2°‘pVe ˆwÈ "‘Xú† Š2° o1xAP›œVý†&‡ ‘޲‘p¨… ‘U­ P"‘X8‡ ”޲ 2ÞxA?‡E‡M‡6ßNQ#pj9Þ#0à…àV{‡{ê:–¸ ;à{à‘xpj=9Þ o1xApâ˜âVÇ&ˆ)“­ ‘x†%)tÎ o1xA ãFãV‹ˆÓˆãÍ‘x†%tÎ o1xA+þˆF‰—9Þ o1xA,†%—tÎ5Vv¹‘p¹*ðèýêVq‰¼‰É‘x†%ÉÞÑ ÿèôê‘pñ‰Ë9Þ‘hãgÑ9Þ‘ û‰Ó9Þ‘˜6ßÓhÊ Dé­é‘Pû‰Õ9Þ \é­é‘H6ßÚhÊ ­é§ê‘@û‰ß9Þ‘¸Šà9Þ €"‘°6ßâhÊ o1xA6VŠuY–¸‘xpjY9Þ&‘pñ‰[9Þ‘hdŠ]9Þ‘P6ßahÊ&‘Hãgd9Þ&‘@6ßehÊ o1xA3VoŠ‹€” ‘x†%”ÞÑ ‘p»Š”9Þ ‘hÄŠ”9Þ& ‘`ñ‰–9Þ ‘Xãg—9Þ ‘°û‰¤9Þ ‘¨Š¤9Þ ‘ 6ߨhÊ o1xA$VÕŠ,‹[ˆÄ ‘x†%[tÎ ‘p»Š[9Þ ‘hÄŠ[9Þ& ‘`ñ‰\9Þ ‘Xf‹^9Þ ‘@s‹a9Þ ‘¸û‰c9Þ ‘°Šd9Þ o1xApF¸FV~‹Zæz–¸‘x6ßzãÍ‘ppjz9Þ o1xAÑ‹6ßFR#pj9Þ#`œ.VÜ‹‚Y ¼‘xpjY9Þ oœ$‘pñ‰[9Þ‘hdŠ]9Þ‘P6ßahÊ Éœ‘Hãgd9Þ Òœ‘@6ßehÊ 2ÞxA+ Œ/Œ—9Þ 2ÞxA,†%—cÏ'`Ÿã V7Œ½‚” ‘`†%”…× ‘X»Š”9Þ ‘PÄŠ”9Þ wŸÚ  ‘Hñ‰–9Þ ‘@ãg—9Þ ‘˜û‰¤9Þ ‘Ф9Þ ‘ˆ6ߨhÊ.t½°" ‘p޽ 2ÞxAð Ø¡V`Œ”Œ[ˆÄ ‘x†%[cÏ ‘p»Š[9Þ ‘hÄŠ[9Þ ð" ‘`ñ‰\9Þ ‘Xf‹^9Þ ‘@s‹a9Þ ‘¸û‰c9Þ ‘°Šd9Þ 2ÞxAà¡¢V¾ŒâŒhÊ‘x†%cÏ 2ÞxAP¤x¤VêŒ*)“­ ‘x†%)cÏ 2ÞxA* §-©VMuÉ‘x†%É…× /§$©‘pñ‰Ë9Þ‘hãgÑ9Þ‘ û‰Ó9Þ‘˜6ßÓhÊ t§ݧ‘Pû‰Õ9Þ Œ§ݧ‘H6ßÚhÊ ݧר‘@û‰ß9Þ‘¸Šà9Þ #‘°6ßâhÊ 2ÞxA 'PäåV€­ƒ1 ‘x†%1ÞÑ \äå ‘pñ‰29Þ ±äå ‘`ãg49Þ ‘XÉ69Þ o1xA' ¥ä¥VÓ†1 ‘x†%1…× ,¥Þ¥ ‘pñ‰29Þ ¥Þ¥ ‘`ãg49Þ ‘XÉ69Þ 2ÞxA'ëKëVøŽJ ‘xdŠJ9Þ$ŽÀ V)ŽJŽ…hÊ‘p­à…9Þ‘hãg…9Þ ä‘`6߉hÊ SVZŽsŽ9hÊ‘h­à99Þ‘`ãg99Þ*p+pV|ޛޔ‘x6ß”hÊ‘pci”9Þ‘hãg”9Þ*0p[pV©ŽÅŽp‘x6ßphÊ‘pcip9Þ‘hãgp9Þ`ë£ëVÐŽìŽMhÊ‘h6ßMhÊ‘`ciM9Þ‘X­àM9Þ‘PãgM9Þ!o1÷Ž ò@òV$j fià ‘x†% fià ‘pÙd fÃÈ o1xA$V˜ß %“­ ‘x†% %ià o1xA$7U­#¯8[7#%r|S‡diÃ#qR9Þ#r|$7AÄ# U­€‡‡diÃ#qR9Þ#°$79Þ#¯8“­#¾$79Þ#¯89Þ# o1Íô8$7U­#¯82#!(v‘  V$‘H‘ fÏÄ ‘x†% fÏÄ ‘pÙd fÃÈ (vxA!(vT‘Ð õ V$‘H‘ º$Å ‘x†% º$Å ‘pÙd ºÃÈ (vxA!2]‘ = V€‘¼‘ fyÅ ‘x†% fyÅ ‘pÙd fÃÈ 2xAà‘$79Þ#¯89Þ#A“­#õ‘0$7(v#¯82# T~’ T~g’²’$7IÆ#¯8RÆ# (v×’ 2Ü’ dÆù’7Ê7 •WQ“‹“$7(v#¯8(v# 𯖓7rÆ rÆ©“µ“X$7ØŽ#¯8(v#(A2#0r|$7æÆ# IÆv”|”8$7’Š#¯8(v#A2#È”$79Ç#¯8BÇ# (võ” 2þ”•8$7U­#¯8B3#E•8$7U­#¯8O;# ©-€•½•@$7¤6#¯86# r|$7ÄÇ# ¤6–P– $7®,#¯8U­#–$7®,#¯8'á# ÚEÌ–ç–$79Þ#¯8®#r|$7FÈ# OÈô– ±b0—g— $7t­#¯8t­#~—‡diÃ#qR9Þ# 8«— B3ò— K>˜ ýY™˜ K>²˜"?™r|$7ÝÈ# æÈE™ Ðb¥™š $71#¯8Æ+#[šP$7®,#¯8.<#Éš @/VÓšF‚z¬ ‘p#9‚U­ P) ‘®PW1z¬àÍVôš4F‡'á ‘p#9‡U­ ðÇ ‘¬PW1'á V›aFŒ(v ‘p#9ŒU­ 0  ‘¨PW1(v!‚Ý6›+©yÉsê8Ê ‚ÝxA,Ëiê‚Ý!2Þ@›`yVßde z“­ ‘x†% zhÊ 2ÞxA®V«dÎd ºhÊ ‘x†% ºhÊ ‘pÙd ºÃÈ 2ÞxA82Þ9ÜÍàVH›˜ß ¨9Þ‘p†% ¨U­ 2ÞxA@cVq›Åß 7¡Ý ‘p†% 7U­ 2ÞxA@cVž›à DhÊ ‘p†% Dt­ 2ÞxA°5Ú5VÏ›þ› ¶“­‘p†% ¶U­ 2ÞxApl¦lV œjá Ò ¯ ‘p†% ÒU­ ‘h€á Ò9Þ 2ÞxA'PmƒmV:œ²á y ‘p†% yt­ ‘`Öá yU­ 2ÞxAM>MVpœ8á rÚE ‘p†% rU­ 2ÞxA०Všœüã úXÈ ‘p†% út­ ‘h€á ú9Þ 2ÞxA ›N›VÍœ&‡ ޲ ‘p†% U­ 2ÞxA ¢Ë¢Vúœ¾ä *'Ð ‘p†% *t­ ‘hGà *9Þ 2ÞxA`£‹£V2jã #® ‘p†% #U­ ‘hGà #9Þ 2ÞxA:f!o1o ã¹ãV˜ß z“­ ‘x†% zãÍ o1xAàëìV$j ºãÍ ‘x†% ºãÍ ‘pÙd ºÃÈ o1xA –¸š8o1ì3ìVÙ&â DãÍ ‘p†% DÄ o1xApð“ðV-žâ ¨9Þ‘p†% ¨JÄ o1xA DœDVzžÁ† ‹2° ‘p†% ‹wÈ o1xA ’ŠÌž8òv)w`Ÿ`+U­;†%+‚Ý  ¼õž"Ÿ 5íŸ ãÍ7Ÿ iÃcŸ $Å‘Ÿ ÏÄ›Ÿ \8§Ÿ §îÍŸ ÆðŸ 9Þ@  ™&G  z¬^  ®,c  ì+š  6¼  ›;Ö  9Þ÷  K>¡ ƒ8¡ hÊÊ¡ ¡ÝÓ¡ 2ÞÞ¡ 4æ¡ ÃÈ¢ Æ+ ¢ .<-¢ ác¢ ‚Ýp¢82Þ<ÜÍ82Þ<ÜÍ82Þ<ÜÍ 9&v¢ Ù+Œ¢ ÿ+«¢ ,Ë¢82Þ<ÜÍb ‰Çæ¢ f5$£ %,££ –-Ú£ ]O ¤ ôÐX¤1Ý2¾Ð2-­ ÍÏ㤠ßÏé¤ ® ¥ ÄÏ¥ ÖÏ)¥ AÄa¥ âÐi¥ LÑ¢¥1Ý2ÇÐ2-­ Ûn¦ \Ñצ ÐA§ {{X§ U­o§82Þ<ÜÍ ýzz§ Q(•§ Ä*³§ ŸÑѧ ¨Ñð§ 2°¨ NQQ¨ ÐU‹¨ –¸Ѩ 2°© PR© 9Þo© §Äz© @𢩠<¡ª ú Fª ÊQpª Vˆª Û¬ª !Æ« …M« ˆâ« 2{¬ š‚œ¬ …9­ µªÒ­ \8ü­ \8"® RÆD® B3b® @š„® »Ïú® ‹¯ š‚Ÿ¯ Æ8° ØŽŒ° ãÒ*±1Ý2­Ò2-­ þ]± ]¤º± ¬]ê± ø^ ² ]¤(² ¬]T² þ]r² ’©² ’“³ ’Š´ ’Š®´ …“Û´ ‹ŵ f¶ zÓé¶1Ý2Ñ2-­ “ÓN·1Ý2æÆ2-­ ¬Ó¡·1Ý2hÓ2-­ Ø­q¸ ¼Óȸ ÷­ ¹82Þ<ÜÍ 82Þ<ÜÍ n >¹ Ô¨¹1Ý2Ñ2-­ Ôû¹1Ý2(Ñ2-­ 5Ô€º1Ý2ñÓ2-­ 5®7» EÔu» m ´» iÔ=¼1Ý2 Ñ2-­ ‚Ô­¼1Ý2WÔ2-­ T®ƒ½ ’Ôའ2>¾ ¶Ôw¾1Ý2Ñ2-­ ÏÔɾ1Ý2¤Ô2-­ š­O¿ ßÔ\¿82Þ<ÜÍ Éj¿ Õ À1Ý2þÔ2-­ ¹­ûÀ ÕqÁ82Þ<ÜÍ H¯èÁ “­íÁ ?ÕóÁ HÕùÁ ¨Ð ŸÐ BÐ= –Ð_ 0РèÏŸÂ ðºÂ È>à ´Õ^Ã1Ý2Õ2-­ ÍÕÆÃ1Ý2™Õ2-­ ’Ç—Ä ÝÕïÄ ¾ÐHÅ82Þ<ÜÍ82Þ<ÜÍ Ö‡Å1Ý2]Ð2-­ 4ÖÚÅ1Ý2wÑ2-­ t­>Æ82Þ<ÜÍd82Þ<ÜÍ ¢<MÆ äW©Æ ¯XØÆ ‹Ö Ç1Ý2gÖ2-­ ×$¶Ç ›ÖüÇ ›;CÈ ¿Ö`È1Ý21Ñ2-­ fÐµÈ áÖ¾È82Þ<ÜÍG 9ÐÈÈ ×ÐÈ1Ý2Ð2-­ ®83É 79lÉ €'«É :YÊ ŽZ¼Ê ÝZÛÊ K[|Ë ,[—Ë Ñ[1Ì ²[OÌ ²[ìÌ ÐÍ ޲ÍÍ  ¼ìÍ FR Î BV#Î ޲FÎ ²×aÎ1Ý2‡Õ2-­ Ë×ÎÎ1Ý2îÖ2-­ Ä?#Ï í@@Ï82Þ<ÜÍ< sZÏ ØÄÏ1Ý2ú×2-­ ®{РعÐ82Þ<ÜÍ82Þ<ÜÍ ´(øÐ ZØ€Ñ1Ý2uÕ2-­ sØïÑ1Ý2HØ2-­ ïÈÄÒ ƒØ Ó82Þ<ÜÍ 82Þ<ÜÍ' )}Ó KÐÔ ÊØOÔ1Ý2¯Ø2-­ É7Õ ÚØ¦Õ õØÖ1Ý2¸Ø2-­Ö,!7‘BpàK,!3!Aà .8!@! .e#„#8!š@6#$7Œ#@!š@6# PpêVšÖQN‘h™%QŒ"e"e"î ¨"¬"èÆÒ¯"´"·"Ò¾"È"Ñ"â"ô"####-#>#I# W# b# o# {# „#Ž#š#õ. # .°#Ÿ#¯"¶#Õ#´"š@ö#$7"#·"š@ö#$7)#·"Ú##èÆ#èÆ%/x"Ä| ôÈ|?‡$Ž*@kV|ޛޔ‘x6ߔБpci”Ù‘hãg”Ù*p›V©ŽÅŽp‘x6ßpБpcipÙ‘hãgpÙ Ò@›öÉš¯“B LÉš €F‚Êð 0³ ¹ÖÊð H³ ¹Ö4F‡Êð `³ æÖÊð x³ æÖaFŒÊð ³ ×Ê𠨳 ×ßf$7#¯8#œd‡d.#qRz#!s¡d$V«dÎdf. ‘x†%f. ‘pÙdfò sxA"e"e#ëf$Vg/g Ò ‘|†% Ò$V5gXg Š ‘|†% Š$Vïf g ê ‘|†% ê"?™I’=@× ƒ×ˆ–å×hù½>OØE F"\Ø>bØb pD?g@l"$!>nØE F>€ØE F>‘ص& FAÀ£ØA˪Ø\"ºØ>ÌØE'  F>ÛØE( !F>éØE) "F>øØE* #F>Ù@+ $F"Ù> Ù]Z €" 8iBnè@µ:f>2Ù‹c * 8˜Cnÿ@A¨DÙ"LÙDZÙ»5@E>fÙb €D>uÙ@0 XFE~Ù3 ŒPA ŠÙF™ÙG¨Ù###H/­Ù™A:¸Ù"ÀÙ>ÄÙW< PF?\?aAlÎÙ -IÖÙÈ JÞÙ@ !#JâÙ@ '#J¨Ù 0#JëÙâ 2#JñÙ 8#ˆK 8JûÙn 8#JÚÈ :#JÚÈ @#˜J"Ú· B# J+Úß N#¨J1ÚV Q#°J?ÚE T#¸JGÚµ W#ÀJOÚµ _#ÈJVÚÛ }#ÐJaÚ ~#àJnÚV …#ÈJyÚs ‡#ÐJˆÚs #ØJ”ÚÈ ‘#àJ§Ús ™#èJ¶Úµ  #ðJÃÚµ ¦#øJÞÚ• ­#€JìÚ °#ÀK °JûÙ# °#JñÚ ²#ÈJúÚ¡ »#ÐJ Û¡ ¼#ØJÛ¡ ½#àJ3Û¡ ¾#èJFÛ À#ðJQÛŒ Â#øK ÂJûÙ# Â#J\Û Ã#€JkÛ¿ Æ#ˆJwÛ` É#ÀJ|Ûe Ï#À+Aí‡Û F•Ûx eG£Ûµ g#GªÛÈ n#G±ÛÈ o#GºÛÈ p#GÁÛµ v# GÑÛµ w#(GäÛµ z#0GôÛÈ {#8GÜÈ |#@GÜÈ }#HG ܵ #PG/ÜÈ €#XG<ÜÈ #`GIÜÚ „#hGPÜ+ ‡#pAÓWÜ "`Ü?ßAêwÜ FŒÜ AG¡ÜÈ H#G©ÜÈ I#G±ÜÈ P#G»Üµ V#?0A;ÃÜ F×Ü YG¡ÜÈ ^#G©ÜÈ _#Gëܵ b#?sA~öÜ FÿÜH SGÝ” T#L TG Ýn T#GÝn T#GÚÈ U#GÝî V#G)Ý W# G5Ý) X#(Aù;Ý FDÝ GMÝ/ #GRÝ/ #A@Yݼ85BnA@aÝ FnÝ DG{Ý E#G‚Ý: F#GŒÝ@ G# G˜Ý@ H#G Ý± P#Aš¦Ý F¹Ý G±ÜÈ #?¶MAÂÌÝ N×ÝéÝúÝ Þ?äAïÞ *F*Þp ·G8Þ ½#G=Þ( Å#hAFÞFTÞh GbÞ\ #GkÞ¶#GsÞµ#G{ÞE#G…ÞE #G’ÞE&#GœÞc )# G©ÞÛ ,#(G¬Þ¥-#8L-G Ý#-#GÝ#-#OÐ/#HP/G´Þâ1#L1G¾Þ#1#GÇÞ#1#GÕÞ 4#L4G Ý#4#GÝ#4#GÝÞA 8#XL8G¾Þ#8#GÇÞ#8#?h As åÞFñÞ€XGýÞ) Z#GßÈ`#G ßÈa#Gße d#Gß½ g#8G!ßÈv#@G*ßÝ y#HLyG¾Þc y#GÇÞc y#G4ßE#XGóü³ ‚#\G=ße ˆ#`?. A9 GßQTߨ°G¨Ùg ±#GßÈ´#G ßȺ#Gaßl ½#GmßE¿# GvßEÀ#!G~ߤ Â#(LÂG¾Þ) Â#GÇÞ) Â#G‰ßÈÉ#8G—ßq Ñ#@GŸßÈÔ#pGªßÈÕ#xG½ßEØ#€GÁßEÙ#GËßEÚ#‚GÕßEâ#ƒGÝßEè#„Gäße ë#ˆG)~± î#¨??lA| ïßFõß0 GŸßÈ+#GÙdµ.#Gûß@4#G à@5#Gàç 8#Gà 9# G'à0 <#(?ì A÷ +àR2 2 ? S?µ? A 6à TE2 2 ?5 A@ DàFKàG'* #GPW #Ap RàF]à IGhàÈK#GpàÈL#GyàÈM#GƒàÈN#8¶Bn? AÍ ŽàFšà`ŒG¨Ùg Ž#G¦à@š#G­àY  #G³à £#L£G¾Þ½ £#GÇÞ½ £#Gäße ¦#(G½àw ©#HG)~§ ¬#XAd ÀàŠLŠGÑàc Š#A‚ ÚàFäà;G)~±=#GÿU@>#8¶BnA¾ îàVNQáá5áMáAæ gá &Fá ‘G—áü ’#L ’G Ý ’#GÝ ’#?Û ?84BnA?Ÿá (F¶á AG¢fµ |#AaÍáAlÕáw"æáA~ïáFøáGâÈ#8µBnÇA¬â:L:GÑà#:#HËâ5K8-J?‡:.#J âu/#J'â¡0#J.âÒ1#J7âã2# J=âô3#(JÁ>*4#0??HKCâT¶2¶2µ2µ2p2p2@?E?zH†QâTE2¶2µ2E2@?¦H²`âTE2¶2µ2µ2µ2@?×H²oâ?èH²€â?ùHŽâ$TE2¶2µ2µ2µ2E2@?/H;œâ+TE2¶2µ2¶2µ2E2@8lBn#Awªâ ,U¶â` J¨Ù #JÂâ½ #JÉâ #JëÙÓ #?ÂAÍÎâ 'FÚâH 5Gæâ 7#Gíâ@ :#Góâ =#8 BnAËúâ A"ã ²L ²GÑà5 ²#?:AEã )F+ãX šGBã[ ¢#L ¢G¾Þ5 ¢#GÇÞ5 ¢#O† ¤#PH ¤G©ÞÛ ¦#O¢ ©#P ©GJã¶ ª#GXãc «#Gbã ¯#AÞfã FyãH G¡ÜÈ #G©ÜÈ #G±ÜÈ &#GŒãµ ,#G”ãÈ /# G›ãÈ 2#(G¤ãÈ 5#0GªãÈ ;#8G»Üµ >#@8BnE±ã@= ˆPE¿ã@? PVÌãi Ü€ WÖã¿8 , @ÄAÏæãUìãP0Jóü~1#Jòãn4#JùãÈ4#J äÈ4#Jä) 4# J(ä\4#(J.ä¦4#0J;ä@4#8JIäE4#å?öAUåFbå0Gpàµ#Ghàµ#G7,µ#Goåµ#GzåP# 8\BnAgåFåG6ß¶#Geµ#E¡åV  PE³å\> ˜PE¶åËG |DAÖÈåFNAÖåðå æ"æE:æâ ”PDDæ»{ESæEJ xD4h¡hVä)Uó)Xkæ"EYzæU;­àUµYˆæI;­àIµ&Z°(NYæ6\;ÞÙ6@;ªæ6EZ°(8\Yºæ ô¶;Êæ ô0;(ä ô\;­à ôµ;ÞÙ ô;Îæ ôE;òã õn;Óæ õE?ÄYÝæ ¶;Êæ 0;­à µ;ÞÙ ;Îæ E;òã n;êæ¡E;(ä¡\;Óæ¡EZ°(£¶Yöæ \;6ß  Zç ßY ç‡\;6߇ Yç µ;6ß  ;'ç EZç ßZ.ç µZæâ Z°( µY6畵;6ß• ;'ç•EYAç “—;ç “ß;.ç “µ?4YVç Ö ;ç Öß;.ç ÖµYlç äµ;ç äß;.ç äµYç ;ç ß;.ç µZç µZæâ Y¥çzµ;GàzZ°(|µYºç‚µ;Gà‚[ÈçHÈ,AáHš,ËiHÈ-¦—JÈ?ÈYÝç*µ;Aá* ;Ëi*µ\íç À;(ä À\;­à Àµ] èH,"èHg Y(èôEZ°(öE]<è[,"è[g YSè*;­à*µ&Ziè?µZ|è@ZGàCZËi5Z†!8Z€è:Z„è<&&Zè/Z•è0[èú@,Ëiúµ-°(üµY©èú¶;Aáú±;Ëiú¶Y¹è ëµ;ç ëµZ­à íµYÖè µ;ç ß;.ç µZç µ^°h†jVöè;¶_­à;µ_\Îæ;E_êêæ;E 0L.H`L> Lþ©iÊi&é©i¸iø`xòÀiÊiú`›".VÀLA`¾d ÔhõhqáhõhZ`..M[`*< @M/TIa`U/P“a»áiïi7`…Èa¨Ó.š€MBb¨b´aËÀ °M jjß jj>cùk jjþ`xbƒa$Ž.5àMA`[[bÿÿÿÿÿÿÿÿÿ—Í i!i§`€Û`£ç`Æócbÿÿÿÿÿÿÿÿÿ# N @N.×pN©.° NŒaéÊ.IÐN©bc.òOœb a a/$aR0aw< 0O `Oêdi{i %`Àø`ãaa)Ãdini `NÑ`qÝœdini ç`”ª`·¶pdini Ù`Ú~`ýŠ O †i‘iP†i‘i @` ^)†i‘i†`E7ajC 3jNj-3jCj 0`;`°GaÓS3jCj ` a? Æ‘i—i©`bÐ`…ÜŸ‘i—i Ãk‘i—i.a¨Ž4jŸjVO*UZ*\ é;Êæ0;6ß¶;òãn;êæE;ÓæEYé5µ;Aá5 ;Ëi5µ\(é Ç;(ä Ç\;­à ǵ\Hé I;Êæ I0;6ß I¶;òã In;Óæ IEZç KßZ.ç LµZç Lµ&&&&&&Zæâ X&Z­à aµ4 jÏkV<$`ËF$`R$d­jÏkIbÿÿÿÿÿÿÿÿÿž ÀO ðO.× P`Nå.°PPŒ`„¾aºÊ.I€Pbc.ò°Pœb aÝa $a# 0aH < àP Qêêjk %`‘ ø`´ a× aú Ãêjôj ` Ñ`B Ýœêjôj ç`e ª`ˆ ¶pêjôj Ù`« ~`Î Š @Q kkP kk @`ñ ^) kk†` 7a; C ´kÏk-´kÄk 0`^ ;` Ga¤ S´kÄk `Ú a Òk k`3 Ü`V è«k k Êkk k9`y ƒaœ Ž.õpQ `¿ ÿ`â `+  bÿÿÿÿÿÿÿÿÿ# aN / aq ;  Q ÐQÃ?kLk S`” Ñ`· Ýœ?kLk ç`Ú ª`ý ¶p?kLk Ù` ~`CŠ\XéF;6ßF¶;êæFEYbé(’$;Aá($;Ëi(’$Z¦—*’$A@wé?’$Y€éZ@;AáZÉ$;ËiZ@?@4ÐkàkVH%¢$ÖkÞk›_$ÖkÞk`/P“…$Y¥é \;ÞÙ @Z(ä¢\dé˜@e·é‘\Ééƒ;ÞÙƒ@;(äƒ\]Óév,Aávš,ËivÈ\çé;Aá±;Ëi 4àkslVŠB`f™Baµ¥Béîkük¿`Øò.!%RÀ`û/%a5;% llH%l l§¢$l l›_$l l`ak…$W%ll¨¢$ll”_$ll`a…$.š@R®`µ¨b´aïÀ pR PlVlßPlVl>kPlVlþbƒa%Ža%flsl¶^“k%Sw%¤%jlsl†„%jlsl!`\˜%6lBlÁ`’"\ê”;Êæ”0;(ä”\f€l×lVêÒ_µÊæÒ0_þ&êÒ@ Q“-êÒ@g#4êÔ\gF=êÔ\.š RÖ`i¨b´aŽÀ ÐR ÂlÈlßÂlÈl>kÂlÈlþbƒaÄŽ.šS×Q“¨b´aûÀ 0S Ïl×lßÏl×l>kÏl×lþbƒa1Žð'·l»lÚ`hú'\Fê”;Êæ”0;.䔦\[ê”;Êæ”0;;ä”@h_æM¶;­àMµ]qê ),€ê ) *,Pe )%*?î?**@î]‡ê !,€ê ! *,RÝ !/iÿèT;6ßT¶jàlnV–êè¦_‹Êæè0_ÁÞÙè@gc.äë¦g¬®êê¦gõ;äí@g–¿êì@g»Ñêî@k‘þì@gõýÞê¦H%mmî¢$mm›_$mm`a…$ m0m m0mž)m mù`=¨)Á) m0mú``Ë)b×) 0m¯m :m¯mZàêp Hmm immä)‚mŠm`ƒó)ž)˜m m`¦¨)Á) m¯m`ÉË)`ì×) ¯m@n `S S ÀS.*T`* @T./*pT"lèC* hnwnO*rnwn/`4Z*\õêÆ;ÊæÆ0;ÞÙÆ@Z(äÈ\jnÊpVë5\_WÊæ50g)°(7\  T ÐTgLë:@k ë:@gq‘þ:@é®n½n>`¾ò U @U pU.š UA`á¨b´aÀ àU ooßoo>kooþbƒa)Ž V @Všo2oFb´a`À #o2o *o2oß*o2o>k*o2oþbƒa–Ž.špVGb´aÍÀ  V 4ok4ok§p²pþbƒaªŽ ¿o,p!%¿opbaá;% ÊoäoH%ÊoÒo§¢$ÊoÒo›_$ÊoÒo`a…$W%Üoäo¨¢$Üoäo”_$Üoäo`a<…$šäoüo®b´aaÀ îoüo öoüoßöoüo>köoüoþbƒa—Ža% pp¶`Îw%¤%pp†„%pp!`ñ˜% p,p p,pp,pd`'" pW.š W^b´aJÀ ÐW ¿pÊpß¿pÊp>k¿pÊpþbƒamŽ."-Xh`¤,-aÇD-.š0XÊ`ê¨b´aÀ `X ´p¼pß´p¼p>k´p¼pþbƒaEŽ Zpcpmð'_pcpÎcpopi`|" X.šÀXkb¨b´aŸÀ ðX „p‰pß„p‰p>k„p‰pþ`ÕxbƒaøŽ."- Yl`/,-b8-aRD- ýnomð'ooΚ‰p¥pÊb¨b´auÀ p¥p ›p¥pß›p¥p>k›p¥pþ`«xbƒaÎŽfÐpÖpV'ës UÊæs0fàpæpVCëz UÊæz0\aëÞ;ÊæÞ0;ÞÙÞ@Z(äà\fðp5qVnë_Êæ0gN(äƒ\ PY.\5€Y‡aq~5.š°Yâb´a”À àY -q5qß-q5q>k-q5qþbƒaÊŽð'q$qä`ú'f@qiqVë‹_$Êæ‹0gZ.ä¦ Oqgq Tqgqž)Tqaq”`}¨)O*aqgq•` Z*fpqvqV—ëš UÊæš0f€q†qV°ë¡ UÊæ¡0YÏëa¡7Zâëa¡7&&ZJWaÖ7?¦7H²7êë:KX:JøëE:#J¦HÄ:#Aá7ì Uì  JÝù7 #K J Ý<8 #JÝ<8 #J:xA8 #JPW¶ #?Ö7AL8&ìAW80ìv?\8QCì gGUìlh#G[ì8i#GkìÕ8j#?•8Ftì9G‘ìÈ8:#G›ì¶;#G¡ì8<#?Í8R2¶8lCnïY¨ìa0Zâëa¡7Y³ìd0ZÊæf0\Àìa;¦Ha0Zâëa¡7YËì·¶;Êæ·0;­à·µ;ÞÙ·;Óæ·E[Öì án,Êæ á0,äì áE-òã ãn\ëì”;Êæ”0;òã”nYýì ¶;Êæ 0;(ä \;òã n;­à µ;æâ ;Îæ E;Óæ EZe µZí o:Zí EZ°( ¶&&Z'í 'E?5[;í ÿ¶,í ÿo:,í ÿpZ°( ¶[Pí 7E,€ê 7 *,RÝ 7/[`í CE,€ê C *]oí ô,Êæ ô0,òã ônXí EX’í+Eeží\±ía;âëa¡7YÄí U¶;Êæ U0;(ä U\;òã Un;­à Uµ;æâ V;Îæ VE;Óæ VEZí ZEZ°( X¶Zí Yo:&&Ze mµYÚí\;Êæ0;(ä\Z°(\XêíPEXûí§E]î.-Êæ00Y,îEZ°(EYHîá@ZˆDãlXUî&E\mîV;AáV$;ËiV’$\î};Aá}É$;Ëi}@\îŠ;¢îŠ@eªîE\Àî@;Íî@:YÔî¾µ;­à¾µ;Üî¾µZeÀµYæî°µ;­à°µYí;­à£µZ°(¥µYû;­àе&ZËi–µZ ZeµZ„虵Z&&ZèµZ•èµYïζ;ÊæÎ0;eε;Üîε;ÎæÎE;òãÏn;êæÏE;(äÏ\Z°(ѶY)ïm¶;Êæm0;6ßm¶;5ïmµ;­àmµ;Üîmµ;ÎænE;òãnn;(än\\=ï “;Êæ “0;òã “n;6ß “¶;æâ “;Óæ ”EZí –o:ZTï —"??'?A2?^ï Fpï @G‚ï@ A#\Žï ¬;Êæ ¬0;òã ¬n;6ß ¬¶;­à ¬µ;Óæ ­EZæâ ¯Zí °o:ZTï ±"?Y¥ïF¶;ÊæF0;­àFµ;égF:;eF ZÜîIµZ(äL\ZAáH¶ZÎæJEZòãKn&&ZÞÙOY¶ïÐE;ÊæÐ0;­àе;égÐ:;eÐ ;ÜîÑ ;ÎæÑp;òãѾ@;(äÑW&&ZÑïæ@?nYÛï Ên;Êæ Ê0;ÞÙ Ê@Zêï Ìö@?û@AAîï Føï bOA c#P cGòãn d#Gõ$ö@ e#Yð¶;Êæ0;eµ;Üîµ;ÎæE;òãn;(ä\ZÞÙYð°¶;Êæ°0;­à°µ;ÞÙ°;òã°n;(ä°\Yðà¶;Êæà0;eàµ;Üîàµ;ÎæàE;òãán;(äá\Y)ð¿¶;Êæ¿0;­à¿µ;ÞÙ¿;òã¿n;(ä¿\höé»\;ÞÙ»@Z(ä½\jq7†V5ðe¶_íàeµ_+!ége:gµ"eiµg£$Aáh¶ZÊæg0 Z.;€Zm ðZm;§q´q..<@[.énszsV`Ù$ò zs®s<zs„sW zs„sm;zs„sª s®ss®sX`ü$" €[ I‚]‚I‚]‚^`%" Nz¯z.9<°[bnG<Xzdz `B%".éà[ `e%òT<‰zšza›%b< |z„z|z„zc`¾%" \.o<@\lÃ<—¢?`á%Í< <—¢}<—¢ƒ`&“<a%ÁÄGbk%`+&w%¤%ÁĆ„%ÁÄ!`N&%`q&˜%mÚ<Î3‚J 3‚?‚3‚?‚m`”&".;p\0 à\.$<P]oý8°]4.â8^f.v7p^a Ð^ _a·&’7p';@_a p_ Ð_ 0` `.9À`l.v7ð`a a Paaï&’7m';]tpta €a Àa.9bo.v7@ba €b Àba''’7m';΀á€a.ý8ðbo.â8@cf.v7€ca Àc Œtua_'’7m';Ýtðta ðc @d d àd.9el.v7@ea pe ÿv€a—'’7m';H€^€a  e àe.9 fo.v7`fa  f àfaÏ'’7m';Ìyßya g.´?€gt`(Ú?‘°æ?a()ò?a¿)þ? ðg haâ)0@.V0iO`…*d krrqxrrZ`Î*..pi[`ñ*< °ia'+IaJ+Uao+a»v›v7`”+Èa·+Ó r«r r«rPr«rT)r«r†/‘°C.;9ðiWbÿÿÿÿÿÿÿÿÿm9z9³rÝrºbÿÿÿÿÿÿÿÿÿ’9aÚ+9 »rÝr ÅrÝrq©9ÖrÝr í`,¿9.5€jºbg`3,sbbÿÿÿÿÿÿÿÿÿ—.Ík§`µ,ób bÿÿÿÿÿÿÿÿÿ#  k l  l àl.Ì9 m ü`ë,æ9bþ9a-.:aG-::a¶-F:a.R:.t:pm $`L.:`•.Œ:aá.—:.á:°m P àmoÈ:n úo¤:@n Fl¼: pn  na/`:.Õ;Ðn (a;/û; o po.>;ào `q/X;bp;a”/ ;aô/¬;.t:Pp ^`P0Œ:aœ0—: p ðpaÒ0Æ; 0q.Õ;`q ea 1û;.á:q Ž ÀqoÈ:ðq úo¤: r Fl¼: Pr.?@ÐrZ`A1e@‘°q@`M2}@ Ps às.û<PtÙ`ä2 =`S3=aè3!= àt u..=`uÔ`14<= FupuI=Supuµ`z4W=a4c=qSuau¥`À4)aupu¥aã4C.p= u¶`5~= ÐuaO5‹=ar5—=a•5£=» ˜`¸5ÈaÛ5Ó v Pv..=€vâ.p=°v¶`þ5~= àva46‹=aW6—=az6£=»¹u½u˜`6ÈaÀ6Ó w Pw..=wû`ã6<= 'vSvI=4vSvµa,7c=q4vDv¥`O7)DvSv¥ar7C.p=Ðw¶`•7~= xaË7‹=aî7—=a8£=»m‚q‚˜`48ÈaW8Ó 0x..=pxÖ`z8<= Ûw xI=èw xµaÃ8c=qèwöw¥`æ8)öw x¥a 9C.p=°x¶`,9~= àxab9‹=a…9—=a¨9£=»Íј`Ë9Èaî9Ó yz9/xZxäbÿÿÿÿÿÿÿÿÿ’9a:9 7xZx =xZxq©9TxZx í`G:¿9 Py y.Ã@Ðyâ`j:Ý@ z.Õ;Pz Îa¹:û; €z Àzaï:¯@.š{ç`>;¨bÿÿÿÿÿÿÿÿÿ´a;À @{ €{ß28>k28þbƒaÃ;Ž °{.ŠBà{@`ú;™BéLZ¿`<ò.!%|À`B</%ag<;% b{H%bj§¢$bj›_$bj`a<…$W%s{¨¢$s{”_$s{`aÂ<…$.š@|®`ç<¨b´a =À p| ……ß……>`B=ùk……þbƒae=Ža%(…7…¶`œ=k%`Á=w%¤%+…7…†„%+…7…!`ä=˜%‹¬Á`>".:A |]`=>`A`s>xA`–>„Aa¹>A `}èAË{æ{ å=Ë{æ{äb/>.V}  ºx×xmqÇx×xZ..Ð}[ ~a?Ia+?UaP?a»ù{|7`u?Èa˜?Ó P~.?B°~.5Âbÿÿÿÿÿÿÿÿÿgbbÿÿÿÿÿÿÿÿÿ—.ÍP§bÿÿÿÿÿÿÿÿÿ bÿÿÿÿÿÿÿÿÿ#   ð @€ €€.Ì9À€ ü`»?æ9bþ9aÞ?.:/‘¨::a)@F:a‰@R:.t: $‘¨:`¿@Œ:a A—: |›| |›|P|›| 8)|›|†aAAC.á:P P €oÈ:° úo¤:à Fl¼: ‚ @‚adA`:.Õ;p‚ (aˆAû; °‚ ð‚.>;0ƒ `¾AX;bp;aáA ;aAB¬;.t:pƒ ^`ŠBŒ:aÖB—: °ƒ #ƒAƒa CÆ; #ƒ.ƒ #ƒ.ƒP#ƒ.ƒ r)#ƒ.ƒ†aCCC ðƒ.Õ; „ eafCû;.á:`„ Ž „oÈ:À„ úo¤:ð„ Fl¼:.A ….5à…³bgbbÿÿÿÿÿÿÿÿÿ—.Í †§b bÿÿÿÿÿÿÿÿÿ# `‡ ˆ Àˆ 0‰.Ì9 ‰ ü`œCæ9bþ9a¿C.:a D::aŒDF:aìDR:.t:Š $`"E:`kEŒ:a·E—:.á:PŠ P €ŠoÈ:°Š úo¤:àŠ Fl¼: ‹ @‹aíE`:.Õ;p‹ (aFû; õ~ õ~Põ~ 8)õ~†aGFC °‹ Œ.>;PŒ `jFX;bp;aF ;aíF¬;.t: Œ ^`6GŒ:a‚G—: àŒ 0a¸GÆ; 7}B} 7}B}P7}B} r)7}B}†aHC `.Õ; ea%Hû;.á:Ð Ž ŽoÈ:0Ž úo¤:`Ž Fl¼:Y@ðM¶;ÊæM0;6ßM¶;5ïMµ;­àMµ;TðNµ;ÜîNµ;ÎæNE;òãNn;(äN\ZeQµZAáP¶ZZðQµ\cðC;ÊæC0;6ßC¶;­àCµ;òãCn\oð u;Êæ u0;6ß u¶;­à uµ;òã unZç wß&&&&&&Zæâ Ž&Z.ç ’µ\€ð<;Êæ<0;6ß<¶;­à<µ;òã<nj@†#“Vð˶_[H6ß˶_K­à˵_^LégË:k˜ðѵgMÜîÒµgÏMAáͶgNeϵg;N(äÔ\ZÊæÎ0Z£ðеZÎæÓEZòãÕn.;ŽÚ .$<poý8Ð4.â80f.v7a ð 0‘asN’7p';`‘a ‘ ð‘ P’ °’.9ð’l.v70“a p“ °“a«N’7p';ð“a ” p”.9À”o.v7•a `• °•aÏN’7m';ƒ‘‘a.ý8ð•Û.â8P–f.v7 –a à– Œ~ŒaO’7m';VŒiŒa — `— °— ˜.90˜l.v7`˜a ˜ ¹0‘a?O’7m';‘‘a À˜ ™.9@™o.v7€™a À™ šawO’7m';&Ž9Ža 0š pšg¯OÑïÞ@.š šß`éO¨bÿÿÿÿÿÿÿÿÿ´a#PÀ К ›ß¥Œ«Œ>k¥Œ«ŒþbƒanPŽ 0›.ŠB`›@`¥P™B鴌Œ¿`ÊPò.!%›À`íP/%aQ;% ËŒåŒH%ˌӌ§¢$ˌӌ›_$ˌӌ`aHQ…$W%݌匨¢$݌匔_$ÝŒåŒ`amQ…$.šÀ›®`’Q¨b´a·QÀ ð› Û’á’ßÛ’á’>`íQùkÛ’á’þbƒaRŽa%ò’“¶`GRk%`lRw%¤%õ’“†„%õ’“!`R˜%øŒ Á`ÅR" œz9A‡h‡ëbÿÿÿÿÿÿÿÿÿ’9aèR9 I‡h‡ O‡h‡q©9`‡h‡ í`S¿9 `œ œ.Ã@Àœé`ASÝ@ ðœ.Õ; Îa{Sû;.IPíbc.ò°œb a±SaÔS$a÷S0aT< ž @žêއ¥‡ %`eTø`ˆTa«TaÎTÃއ˜‡ `óTÑ`UÝœއ˜‡ ç`9Uª`\U¶pއ˜‡ Ù`U~`¢UŠ pž °‡»‡P°‡»‡ @`ÅU^)°‡»‡†`êU7aVC 5Q-5E 0`2V;`UVGaxVS5E `®VaäV   ž 0Ÿ.T>ÀŸú`Wn>`ŸXz>`oY’>`’Yª>‘ ¶> 0    .ïY¡zb-ZaZiZa$ZuZa¹ZZ.û<€¡S`ÜZ =`†[=aÏ[!= ¢ `¢..= ¢Ô`\<= ˆ6ˆI=ˆ6ˆµ`a\W=a„\c=qˆ'ˆ¥`§\)'ˆ6ˆ¥aÊ\C.p=ࢶ`í\~= £a6]‹=aY]—=a|]£=»µŽ¹Ž˜`Ÿ]ÈaÂ]Ó @£ £..=À£â.p=ð£¶`å]~= ¤aA^‹=ad^—=a‡^£=»‚ˆ†ˆ˜`ª^ÈaÍ^Ó P¤ ¤..=Фû`ð^<= ñˆ‰I=þˆ‰µa9_c=qþˆ ‰¥`\_) ‰‰¥a_C.p=¥¶`¢_~= @¥aØ_‹=aû_—=a`£=»˜`A`Èad`ÓèA\‰}‰V`‡`Bå=\‰}‰äb/>aª`G>.ŽZp¥h`Í`¤Z ð¥.6[p¦I`(bL[.ÉZЦ?`HcßZahd[ `§ ð§ €¨ © p© Щ.Vª Ž é‰Šmqý‰ŠZ..Pª[ ªaÄdIaçdUa ea»›©7`1eÈaTeÓ.Ã>Ъ ‘å>`weñ>bÿÿÿÿÿÿÿÿÿý>.á:« ¨ @«oÈ:p« úo¤: « Fl¼: Ыaœe#[ ¬ P¬  ¬.I?Ь œ`¿ek?bÿÿÿÿÿÿÿÿÿƒ?aâe?.V­ ·..0­[ p­afIa?fUadfa»*87`‰fÈa¬fÓ °­.Ià­ÿbc.ò®œb aÏfaòf$ag0a:g< @® p®êÝŠôŠ %`ƒgø`¦gaÉgaìgÃÝŠçŠ `hÑ`4hÝœÝŠçŠ ç`Whª`zh¶pÝŠçŠ Ù`h~`ÀhŠ  ® ‹ ‹P‹ ‹ @`ãh^)‹ ‹†`i7a-iC ^y-^n 0`Pi;`siGa–iS^n `Ìiaj Y­ðà µ;­àà µ;égà :ZeÅ µ\¶ð%;Êæ%0;6ß%¶;e%µ;òã%nZ½ð'µf0“y›VÄðÏ _%j6ßÏ ¶_¿k­àÏ µ_TlégÏ :g mòãÒ ng/meÓ µZ澄 0.BkЮ× `žm\k P¯..=ЯÈ `Vn<= U“ƒ“I=f“ƒ“µaŸnc=qf“t“¥`Ân)t“ƒ“¥aånC.p=°¶`o~= @°a>o‹=aao—=a„o£=»0—4—˜`§oÈaÊoÓ.û<p°Ê `ío =`\p=a¸p!= а ±..=P±Ô`q<= Y•ƒ•I=f•ƒ•µ`JqW=amqc=qf•t•¥`q)t•ƒ•¥a³qC.p=±¶`Öq~= À±ar‹=aBr—=aer£=»Š™Ž™˜`ˆrÈa«rÓ ð± 0²..=`²â.p=²¶`Îr~= À²as‹=a's—=aJs£=»Ç•Ë•˜`msÈasÓ ð² 0³..=p³û`³s<= ;–f–I=H–f–µaüsc=qH–W–¥`t)W–f–¥aBtC.p=°³¶`et~= à³a›t‹=a¾t—=aát£=»õšùš˜`uÈa'uÓ.ý8´Ú .â8p´f.v7À´a µ PµaJu’7p';€µa °µ ¶ P¶  ¶.9жl.v7·a 0· `šךa‚u’7m';©š¿ša `·  ·.9à·o.v7 ¸a `¸  ¸aºu’7m';™™a и ¹ @¹.Ã@p¹ß `òuÝ@  ¹.Õ;й Îa,vû;.ukºä `bv£kn¯k.ŽZpº2‘°¤Z àº.6[P»I.ÉZ°»?`…vßZaBw[ 0¼ °¼ 0½ °½ ¾ P¾.V¾ Ž s”””mq€”””Z..о[ ¿ažwIaÁwUaæwa»þ— ˜7` xÈa.xÓ.Ã>P¿ `Qxå>`txñ>bÿÿÿÿÿÿÿÿÿý>.á:¿ ¨ À¿oÈ:ð¿ úo¤: À Fl¼: PÀa™x#[ €À ÐÀ Á.I?PÁ œ`¼xk?bÿÿÿÿÿÿÿÿÿƒ?aßx?.V€Á ·..°Á[ ðÁayIaú b_;zÛðú ¶_ªzàðú _{èðú ¶_ˆ{íðû µ 0Â.;`Âþ Âm; ›©›..<àÂ.éÖ›â›V`÷{ò ⛜<â›ì›W â›ì›m;â›ì›ª œœœœX`|" à ˟áŸËŸáŸ^`=|" PÃ.9<€ÃbnG<;G ``|".éÀà `ƒ|òT<l}a¹|b< _g_gc`Ü|" ðÃ.o<0ÄlÃ<Ÿ$Ÿ?`ÿ|Í< <Ÿ$Ÿ}<Ÿ$Ÿƒ`$}“<a%CŸFŸGbk%`I}w%¤%CŸFŸ†„%CŸFŸ!`l}%`}˜%mÚ<PŸµŸJ µŸÁŸµŸÁŸm`²}".;pÄ0 ÀÄ.$<Åoý8PÅ4.â8Åf.v7Æa Æ àÆaÕ}’7p'; Ça PÇ ÀÇ È €È.9ÀÈl.v7Éa @É €Éa ~’7p';ÀÉa ðÉ PÊ.9°Êo.v7Ëa PË  Ëa1~’7m';ОÚžaj ‘¤Vôð :_i~Þ> b_Ø~ñ _G ñ àË.;Ì @Ìm;* 3 ..<Ì.éZ f V`¶ò f — <f p W f p m;f p ª ‰ — ‰ — X`Ù" ÐÌ é£ÿ£é£ÿ£^`ü" X¡»¡.9<ÍbnG<b¡n¡ `€".é0Í `B€òT<“¡¤¡ax€b< †¡Ž¡†¡Ž¡c`›€" `Í.o<ÍlÃ<7£B£?`¾€Í< <7£B£}<7£B£ƒ`〓<a%a£d£Gbk%`w%¤%a£d£†„%a£d£!`+%`N˜%mÚ<n£Ó£J Ó£ߣÓ£ߣm`q".;ÀÍ0 Î.$<`Îoý8 Î4.â8àÎf.v70Ïa €Ï ÀÏa”’7p';ðÏa Ð pÐ ÀÐ Ñ.9@Ñl.v7pÑa  Ñ ÿ£o¤aÌ’7m';D¤W¤a ÐÑ Ò.9PÒo.v7Òa ÐÒ Óa‚’7m';aj ¤7©Vñ :_<‚%ñ G’_¾‚)ñ µ_@ƒÛð ¶_ƒàð _D„èð ¶_Æ„íð µ @Ó.;pÓ  Óm;À¤ɤ..<ðÓ.éú¤¥V`‰…ò ¥5¥<¥¥W ¥¥m;¥¥ª )¥5¥)¥5¥X`¬…" 0Ô ÿ¨©ÿ¨©^`Ï…" `Ô.9<ÔbnG<o¦{¦ `ò…".éÐÔ `†òT< ¦±¦aK†b< “¦›¦“¦›¦c`n†" Õ.o<@ÕlÃ<M¨X¨?`‘†Í< <M¨X¨}<M¨X¨ƒ`¶†“<a%w¨z¨Gbk%`Û†w%¤%w¨z¨†„%w¨z¨!`þ†%`!‡˜%mÚ<„¨é¨J é¨õ¨é¨õ¨m`D‡".;€Õ0 ÐÕ.$< Öoý8`Ö4.â8 Öf.v7 ×a  × ð×ag‡’7p';0Øa `Ø ÐØ 0Ù Ù.9ÐÙl.v7Úa PÚ ÚaŸ‡’7p';ÐÚa Û `Û.9ÀÛo.v7Üa `Ü °ÜaÇ’7m';¨¨ar@©õ¬V0ñI .;ðÜL Ým;D©X©..<pÝ.éo©{©V`û‡ò {©¬©<{©…©W {©…©m;{©…©ª ž©¬©ž©¬©X`ˆ" °Ý »¬Ó¬»¬Ó¬^`Aˆ" :ª›ª.9<àÝbnG<DªPª `dˆ".éÞ `‡ˆòT<uª†ªa½ˆb< hªpªhªpªc`àˆ" @Þ.o<pÞlÃ< ¬¬?`‰Í< < ¬¬}< ¬¬ƒ`(‰“<a%3¬6¬Gbk%`M‰w%¤%3¬6¬†„%3¬6¬!`p‰%`“‰˜%mÚ<@¬¥¬J ¥¬±¬¥¬±¬m`¶‰".; Þ0 ðÞ.$<@ßoý8€ß4.â8Àßf.v7àa @à €àaÙ‰’7p';°àa àà á @á pá.9°ál.v7àáa â w«Û«aŠ’7m';ǫ۫a @â €â.9Àâov7Û«ð«a Û«ð« Û«ð«a5Š’7\EñYZ#9\‡†Z‘þ[@ZVñ]bZ9}]bZ[ñ^µZ;}]bZ`ñ^µ&&&&&&&Z%fl Zeñf”†&&&&Z%l Zhñl&&Z%l Zeñ”†&&Z%5l Zeñ5”†&&Z%Jl ZhñJl&&ZjñEZ‘þ:&&Zjñ9EZ‘þ8:&&Z%Hl ZhñHl&&Zpñ†VZxñˆ:Z„ñ‰b&Zñ¡b8lCnAË•ñ YŸñðE;°ñð‡;·ñð‡;»ñð ;Âññ‡;Æññ ZVñôbZÍñóE?bYÔñÕl ;Þ>Õb\âñ<;ܘ<b;;}<b;[ñ<µ;9}<b;`ñ=µXôñL:^­?»VòÃE.…ðâÊ/‘Àw…aYŠ…a’Š&…aµŠ2…aƒ>… @ã ã ðã Pä På Pæ  æ àæ ç D®P®"‡D®P®ic,‡`äŽD‡`P‡`*\‡ Pç °ç è pè Ðè é `é."‡é`c,‡`bD‡`…P‡`¨\‡ Àé ·¯ °si…/‘ðvu…ä<·¯įflî< Ú¯ °mi‡Ú¯߯f ðé Pê °ê ðês‰…aà•… ëmi‡Í¸Ò¸ä<ª¸·¸lî< Pë àë Pì Àì í."‡Píc,‡`+8‡`ND‡`qP‡`”\‡ í €îs§…a̳… pï `ð."‡ ñc,‡`‘D‡`'‘P‡`J‘\‡mi‡Ð±Õ±ä<­±º±lî< àñ @òsÃ…a‚‘Ï… ò àò 0ó €ó Ðó."‡ô5c,‡`Í‘D‡`ð‘P‡`’\‡mi‡ˆµµ5ä<^µrµ5lî< 0ô €ôsß…aK’ë…ä<H¯U¯Jlî< °ômi‡k¯p¯J àô Põnû… °õ ðõ 0ö pö °ö ðö."‡ ÷$c,‡`–’D‡`¹’P‡`Ü’\‡ P÷ ÷."‡Ð÷0c,‡`“D‡`7“P‡`Z“\‡ ø pøn† Àø ù."‡@ùCc,‡`’“D‡`µ“P‡`Ø“\‡ Ѳq³ û²q³s3†a”?†ä<û²³Hlî< %³q³mi‡%³*³H."‡€ùšc,‡`H”D‡`k”P‡`Ž”\‡.Ÿ†Àù»`Æ”­†`é”ņ`2•цa{•é†nõ† l­ ® l­³­a#–P†/‘ˆw\† ”­©­ š­©­ä<š­©­š‘ˆwî< 0ú `úm‡³­Ú­©Ã<hºnºæbÍ< <hºnº}<hºnºƒ`n–“< ú.ŠBÀúíb™Ba“–¥B阺¤º¿`¶–ò.!%ðúÀb/%aÙ–;% ¤º»ºH%¤º­º§¢$¤º­º›_$¤º­º`a—…$W%²º»º¨¢$²º»º”_$²º»º`a4—…$.š û®b¨b´aY—À Pû »»ß »»>k »»þ`|—xbƒaŸ—Ža%»'»¶bk%`Ö—w%¤%!»'»†„%!»'»!`ù—%`˜˜%.€ûÁ`R˜"iò ;2ò \;;ò ¶;Vñ b?aR2¶2br0½ù½VDò¨ D½à½ D½à½k‘þ¬@gˆ˜¢î¬@ D½à½H%D½M½µ¢$D½M½›_$D½M½`a˜…$ Z½ؽgç˜(ä¶\.š°û¶b´a™À àû Z½`½ßZ½`½>kZ½`½þbƒaS™Ž ü ƒ½ؽgŠ™òã¸nm都½ÀmƽؽÄ,æ½ù½È`­™7cO?i~ùt@× Wò¤¼åפ¾>¶òA (FALÃòNÐòáòòò>óy D8…B–?Š@"$!:f>ó³ ¨DA¾ÍáAÉÕáw"æá>,ó³ °DVÌãôÜ€ @ùA£ØAªØ\"ºØE>ó³ ¨PETó³ °P>góV `F8bB–#Amyó+FŠó@éG›óùë#G¤óùî#G±óùñ#G¾óùô#GÇóÙ÷# GÍóëý#(JÙóÙ#8Aäwé"ÙAöåó Fóó^Gôù`#Gôùm#>ôù pO>ôù xO>.ôù `O>>ôù hO>Pôù €O>dôä ŒO>nôä ˆOExôÊ ¼PAäYݼEˆôÊ ¸PEœôÿ ØP?"\ØEªôù ÐPE·ô5 ÈP?ùEÍô5 ÀPDZÙ[5@AkWÜ "`ÜN ×ÝéÝúÝ ÞN Qáá5áMáN †äžä°äÄäN 6å*å>å]äôÓ,8ÞÓõ?úAFÞFTÞh GbÞI #GkÞÆ #GsÞù#G{Þ#G…Þ #G’Þ&#GœÞØ)# G©Þ5 ,#(G¬Þ‹-#8L-G Ýõ-#GÝõ-#O¶/#HP/G´ÞÈ1#L1G¾Þõ1#GÇÞõ1#GÕÞ÷4#L4G Ýõ4#GÝõ4#GÝÞ'8#XL8G¾Þõ8#GÇÞõ8#?NAYÎÙ-IÖÙÈJÞÙä!#JâÙä'#J¨ÙÏ0#JëÙ2#JñÙ¯8#ˆK8JûÙ‰ 8#JÚ`:#JÚ`@#˜J"ÚÇ B# J+ÚÒ N#¨J1Ú³Q#°J?ÚT#¸JGÚùW#ÀJOÚù_#ÈJVÚ5 }#ÐJaÚú~#àJnÚ³…#ÈJyÚ} ‡#ÐJˆÚ} #ØJ”Ú`‘#àJ§Ú} ™#èJ¶Úù #ðJÃÚù¦#øJÞÚŸ ­#€JìÚô°#ÀK°JûÙõ°#JñÚϲ#ÈJúÚ« »#ÐJ Û« ¼#ØJÛ« ½#àJ3Û« ¾#èJFÛÏÀ#ðJQÛyÂ#øKÂJûÙõÂ#J\ÛÏÃ#€JkÛÉ Æ#ˆJwÛe É#ÀJ|ÛÀÏ#À+AÚŠÙF™ÙG¨Ùñ##Hý­Ù™A¸Ù"ÀÙA‡ÛF•ÛxeG£Ûùg#GªÛ`n#G±Û`o#GºÛ`p#GÁÛùv# GÑÛùw#(GäÛùz#0GôÛ`{#8GÜ`|#@GÜ`}#HG Üù#PG/Ü`€#XG<Ü`#`GIÜõ„#hGPÜF ‡#p?úA wÜFŒÜ AG¡Ü`H#G©Ü`I#G±Ü`P#G»ÜùV#?K AV ÃÜF×ÜYG¡Ü`^#G©Ü`_#GëÜùb#?Ž A™ öÜ FÿÜH SGݯ T#L TG ݉ T#G݉ T#GÚ` U#GÝ V#G)ÝÊ W# G5Ý9 X#(A ;ÝFDÝ GMÝý #GRÝý #8E B–AP aÝ FnÝ DG{ÝŸ E#G‚Ý F#GŒÝä G# G˜Ýä H#G ÝÁ P#Aª ¦ÝF¹ÝG±Ü`#?Æ MArÌÝ ?× Aâ Þ*F*Þp·G8Þú½#G=Þ Å#h8 B–A Ÿá(F¶áAG¢fù|#A@ gá&Fá‘G—áV ’#L’G Ýx ’#GÝx ’#?5 Aˆ ïáFøáGâ`#8ùB–ÇA¶ â:L:GÑàõ:#HÕ â5K8-J?‡D .#J âz /#J'⦠0#J.â× 1#J7âè 2# J=âù 3#(JÁ>/ 4#0?I HU CâTÆ 2Æ 2ù2ù2ÿ2ÿ2ä? H‹ QâT2Æ 2ù22ä?« H· `âT2Æ 2ù2ù2ù2ä?Ü H· oâ?í H· €â?þ H Žâ$T2Æ 2ù2ù2ù22ä?4 H@ œâ+T2Æ 2ù2Æ 2ù22ä8q B–#A| ªâ,U¶â`J¨ÙÏ #JÂâ #JÉâ#JëÙ.#?Ç AÒ Îâ'FÚâH5GæâÊ7#Gíâä:#Góâ=#8B–Aúâ A'ã²L²GÑà:²#??AJã)F+ãXšGBã`¢#L¢G¾Þ:¢#GÇÞ:¢#O‹¤#PH¤G©Þ5 ¦#O§©#P©GJãÆ ª#GXãØ«#GbãÇ ¯#?ÝAèåÞ FñÞ€ XGýÞž Z#Gß` `#G ß` a#GßÕ d#Gß- g#8G!ß` v#@G*ßR y#HL yG¾ÞØ y#GÇÞØ y#G4ß #XGóü# ‚#\G=ßÕ ˆ#`?£A®Gß QTߨ °G¨ÙÜ ±#Gß` ´#G ß` º#Gaßá ½#Gmß ¿# Gvß À#!G~ß Â#(L ÂG¾Þž Â#GÇÞž Â#G‰ß` É#8G—ßæ Ñ#@GŸß` Ô#pGªß` Õ#xG½ß Ø#€GÁß Ù#GËß Ú#‚GÕß â#ƒGÝß è#„GäßÕ ë#ˆG)~! î#¨?Ï?AñïßFõß0 GŸß`+#GÙdù.#Gûßä4#G àä5#Gà\8#Gà9# G'à <#(?aAl+àR2y25?~S?„A6à T2y2y?¥A°DàFKàG'*y#GPWy#AàRà F]à IGhà` K#Gpà` L#Gyà` M#Gƒà` N#8Æ B–?2A=Žà Fšà` ŒG¨ÙÜ Ž#G¦àä š#G­àÉ  #G³à} £#L £G¾Þ- £#GÇÞ- £#GäßÕ ¦#(G½àç ©#HG)~ ¬#XAÔÀà ŠL ŠGÑàØ Š#AòÚà Fäà ;G)~Á =#GÿUä >#8Æ B–Aîà VA9fãFyãHG¡Ü`#G©Ü`#G±Ü`&#GŒãù,#G”ã`/# G›ã`2#(G¤ã`5#0Gªã`;#8G»Üù>#@8B–]õÛ,8ÞÛõ,VÚÜx ,"õÜõ&-¦—߯ &-¦—àÆ Y/õù;8Þ,?1@úf¾f¾VHõ U(äI T8Þõ_Йjõ ¾d¾ ¾d¾à¾¾TéÌ"¾Y¾TÕ` šà`-šëmY¾]¾]põä,8Þäõfp¾ľVŒõ" U(ä"I T8Þ"õ_Pš®õ" t¾¾ x¾¾ x¾·¾&Tm·¾»¾(] èH,"èHÜ]<è[,"è[Üjоl¿V´õdõ_Šš(ädIgÓš8ÞfõmÇݾì¾h @ü 4¿K¿mÜ4¿A¿k püg ›¦—nõmÜV¿^¿o4p¿Ô¿VÌ7`?›×7`u›ã7mÇ€¿¿wmܿԿzYzæUÊ;­àUù\Ýõ;(äI;eùZGà!ÊYˆæIÊ;­àIù&Z°(NÊ\üõx;(äxI;öxù&&Zö|ù[ÈçH`,AáH×,ËiH`-¦—J`?`YÝç*ù;Aá*5;Ëi*ù]$ö¨,­à¨ù-9öªùYAö~Æ ;(ä~I;kÛ~’;eù;Üîù;Îæÿ;]öùZ'â‚Z°(Æ ?É \cö,;(ä,I;e,ùZGà.Ê\‡ö†;(ä†I;™ö†ù&&Z£öŠùYé5ù;Aá55;Ëi5ù]¯ö´,­à´ù-9ö¶ùYSè*Ê;­à*ù&Ziè?ùZ|è@ÊZGàCÊZËi5ÊZ†!8ÊZ€è:ÊZ„è<Ê&&Zè/ÊZ•è0Ê[èúä,Ëiúù-°(üùjà¿?ÃVÄö•Æ _«›(ä•I_Úœe•ù_„Üî•ù_àÎæ–ÿg<ž]öšùg…žkÛ™É g©ž°(˜Æ mÇ(À8Àœ  ü ý.€ý `>Ÿ'`ÓŸ3a1 ?.ðý!`V  8À[ÀLEÀ[ÀZ`Ÿ Z.@0þ[` N pþaø [a¡ga@¡sÍ[ÂiÂ7`e¡Úaˆ¡å.u°þ£`«¡`ã¡‹ àþ ÿ àÀñÀåÀñÀ€qÜåÀñÀ¯¨åÀñÀ.`¢µa>¢ËmÜ/Á:Á§ @ÿ Àÿ.#@©`a¢1`ø¢=`£I`z£U`£a`À£maã£ya/¤… À @mÇÁÁˆ À 0.— Š`ž¤¡`Á¤­a¥¹..`D¥ Á³ÁLÁ³ÁZ`¢¥Z.@p[`Å¥N Ð/T[aû¥g/Q“sÍŸÂ7` ¦ÚaC¦å.Æ0`f¦Ð`‰¦Ü `  Â$ Â$ÂqùÂ$»¨Â$Â9`¬¦µ`ϦÀaò¦ËmÜ5Â@ÂŽ\Þö9;(ä9I;e9ùZGà;Êf@ÃïÄVýö±_§(ä±I_q§ç±Æ _¨e±ùgu¨]ö´ùg÷¨kÛ³É mDžÓ÷ À ð.H ¹`©R`d©^a­©j.P;`Ò© “ùÃL Ã¹ÃZ`ªZ.@€[`+ªN °aNªs/T[asªg͆ĔÄ7`˜ªÚa»ªåÆüÃXļ`ÞªÐ`«Ü üÃ;Ä üÃ;Ä *Ä;Ä /Ä;Äqù/Ä;Ä»¨/Ä;Ä9`$«µ`G«Àaj«ËmÜcÄkÄ¿fðÄíÅV÷Ã_«(äÃI_ëçÃÆ _¬5ïÃù_U¬eÄùmÇÅÅÊ ÅÝÅu-ŃÅÎ`‹¬`®¬‹ -ÅpÅ -ÅpÅ _ÅpÅdÅpÅ€qÜdÅpů¨dÅpÅ.`Ѭµaô¬ËƇÅÝÅÐ`­Ð`:­Ü ‡ÅÌÅ ‡ÅÌÅ »ÅÌÅ ÀÅÌÅqùÀÅÌÅ»¨ÀÅÌÅ9`]­µ`€­Àa£­ËmÜÝÅíÅÑrðÅÇV;÷S U(äSI_Æ­5ïSù QeSù.HàV`®^aX®j. ;`}® ôÅÆLÆÆZ`Æ®Z.@`[`é®N  a¯[aB¯gag¯sͱÆÀÆ7`Œ¯Úa¯¯å.àWU'aÒ¯?. !Q HÆhÆLUÆhÆZQZ.@`[QN  /P[a÷¯g/T“sÍåÆôÆ7`°Úa?°åf€Ç ÉVZ÷Õ_b°(äÕI_«°çÕÆ _ã°5ïÕù_±eÖùgu±|÷Øùg豂÷ÙùmÇÅÇÒÇÛ.Æàá`²Ð`T²Ü 0 € Ð.  où0 ».¨` 9`°²µ`æ²Àa³Ë ÂÈõÈ ÂÈõÈgR³kÛäÉ gv³ˆ÷åÆ mÜõÈþÈêY÷î;(äîI;kÛî’;çïÆ ;5ïïù;eïù;Îæïÿ;ˆ÷ïÆ ;|÷ðù;‚÷ðùZ'âóZªHò\³÷F;(äFI;eFùZGàHÊ\×÷[;(ä[I;5ï[ù;e\ùjɇÍVû÷ _™³(ä I_.´ç Æ _{´5ï ù_Oµe ù_ýµÎæ ÿg¶kÛÉ g¹¶|÷ùgܶ‚÷ùg²·ªHZˆ÷Æ mÇÉ’É.u `þ·`4¸‹ À  ð  ÜÉíÉáÉíÉ€qÜáÉíɯ¨áÉíÉ.`j¸µa¸ËmÜFÊNÊ    .& !`°¸&`ù¸+&‘ˆ7&`¹C&`@¹[&`v¹s&`™¹&a¼¹‹&     mÇ\ËkËù `  ° .Ó& û.¤&P _`º®&a+ºÆ&.° H`Pº kË–ËLxË–ËZ`®ºZ.@[`ѺN Pa»[a*»gaO»s̵ͧÌ7`t»Úa—»å.— ``º»¡a¼¹.à.`(¼ ÚËúËLçËúËZ`q¼Z.@ [`”¼N `/Q[aʼg/T“sÍäÌóÌ7`ï¼Úa½åÆÌnÌÿ`5½Ð`X½Ü Ì]Ì Ì]Ì LÌ]Ì QÌ]ÌqùQÌ]Ì»¨QÌ]Ì9`{½µ`ž½ÀaÁ½ËmÜnÌvÌjͽÍVø¥³_ä½(ä¥Ig¾1Ú§³mǚͦͩmܭ͵ͫY8ø;1Ú³iRø±;(ä±I\gør;(ärI&Zø€ùjÀÍpÎV‰ø±_=¾(ä±I_s¾1Ú±³ ÐÍàÍ ,ÐÍÖÍ´`¼¾,mÇàÍìÍ·$,óÍ[ι`ß¾/, üÍ[Î<,Î[ι`¿F, Î[Îa%¿S,mÜ[Îeκ4pÎðÎV$,`[¿/, ƒÎëÎ<,˜Îëι`¤¿F, ¤ÎëÎaÇ¿S,jðÎÏV¤øO³_À(äOIgFÀnÚQ³mÇúÎÏSmÜ ÏÏUY¼øH;nÚH³\Óø5;(ä5I;nÚ5³j ÏNÐVäø[_iÀ(ä[I_ŸÀnÚ[³ 1ÏJÏX.1ÏAÏ^`ÕÀf.mÇJÏVÏas.VÏÕÏj`øÀ}.`Á‰.$,ÕÏ;Ðk`>Á/, ÞÏ;Ð<,ñÏ;й`aÁF, ýÏ;Ða„ÁS,mÜ;ÐEÐlYüøÕ;(äÕþ/;ùÕ0?0@N? 0@} Yù%ù;(ä%IZ7ù'ù\Dùú;(äúI;ùú0Z ïý} Z^ùü`ZgùþùYtùÞù;(äÞþ/Z‘þèäZ•ùæ`Z™ùçùrPÐPÒV®ùŽ_ºÁ(äŽIg)Âù} gaÂÆù‘ù  ×/¤Ð¬Ð¢`„Âå/`§Âñ/90ÿÐ#Ò£`ËÂC0`ÃO0a%Ã[0aIÃg0aÃs0.€0Ð!`¢ÃŽ0nš0n¦0aÅò00ÀÐÙÐ¥aèÃ,04PÒýÒVmC` ÄxC`AÄ„CmÇ`ÒlÒõ lÒëÒ$,}ÒëÒù`Ä/, †ÒëÒ<,™ÒëÒ¹`³ÄF, ¥ÒëÒaÖÄS,mÜëÒýÒúYâùáù;(äáI;kÛá’;Æùâù;ôùâx ;úãõZúçùZ'úåx Z-úåx Z8úæõ&&ZBúíù&&Zç Ò ZIú:Zbã Z¾óùZ.çù&Z¦—.Æ &ZÎæòZQúñõZçóÆ Y`ú¾:;©Þ¾x ZIúÀ:Ywú¨ù;Iú¨4Z.ç«ùZçªÒ ? 4@?Y“úûù;çûÒ ;.çûùZçýùY¹èëù;çëùZ­àíùY¹ú;(äI;bã ;­àù;ÎæYÏú;ù;(ä;I;kÛ;’;ôù<x ;ú=õZãú?ùZ±Û?ùZ8úAõZ'ú@x &&ZBúKù&&Zç\Ò Z.çZùZ¾óZùZégZùZëúZùZ‘þZùZùú[ZIú^:&Z­àVùYÖèù;çÒ ;.çùZçùYAç“ó5;ç“Ò ;.ç“ù? YVçÖ5;çÖÒ ;.çÖù\û–;ç–Ò ;.ç–ù;­à–ù;ég—ùZ û™5\)ûZ; ûZ5;çZùYAûaù;­àaùZçcù\^û;çÒ ;.çù;égùZ û5\|û˜;(ä˜I;kÛ˜’;ôù™x ;úšõZ'úœx Z8úõZ-úœx &&&&ZQú¥õZEW§Æ Z­à¨ùZ‘û©Z˜ûª&Zç±Ò ZIú³:Zb㸠Z.çµùZùú¶iÈõt;(ätI;8ÞtõY¢û=ù;ç=Ò ;.ç=ùZç?ùrÓÛÙVÃûÉ_ Å(äÉI_(ÆÆùÉùg`ÆkÛËÉ g„ÆôùÍ5 g¨ÆúÎúgÌÆªÛÌùZãúÌùàAÓkÓÞ`ïÆé.¬2à`Ǻ2`•ÇÆ2`¹ÇÞ2`ÝÇê2aÈö2a8È3a[È3aáÈ3 À €aÉ(3 0 ÐaMÉ63apÉB3a“ÉN3a¶ÉZ3«3ÃÓÇÓ`Ùɹ3aüÉÅ3.Ò30`Êà3.4p`BÊ4axÊ54B4"Ô2Ô`®ÊP4aäÊ\4i4NÔYÔ&`Ëw4`P˃4`sË4b›4  a©Ë‚3aÍËŽ3ÌæÔ%Õ`ÌÕcàcë.¨4ðänæ4nò4a&Ìþ4mÜ}Õ”ÕG p ðaIÌ5 p ðaÌ&5a¤Ì25aÍ>5a%ÍJ5aHÍV5akÍb5.Ò3``a¢Íì3«3õÕÖ_`Ú͹3™5/ÖUÖa`Χ5`5γ5amο5B4;ÖUÖ `¥ÎP4aÝÎ\46ÖÖèÖs`Ï)6bA6ø5ÖÖÙÖ™`6Ï6Ì5ÖÖÙÖÙ`lÏÚ5f6ãÖèÖŸ`¢Ï|66èÖ×u`ÅÏ)6`ûÏ56`YÐA6ø5èÖîÖ™`Ð6`ÅÐ6Ì5èÖîÖÙ`#ÑÚ5`YÑæ5‰6îÖñÖŸ`·Ñ—6aíÑ£6f6ûÖן`Ò|6 ×× 6ׇ×.°6°„`3Òº6`VÒÆ6.ø5à`yÒ6`œÒ6Ì59×<×Ù`¿ÒÚ5`âÒæ5pf6 ’ ¤×®×aÓˆ5mÇâ×õ×.ë6`ç`(Óõ6c7c 7a„Ó%7a§Ó17aÝÓ=7 °  ` ÐaÔM7/‘~Y7/‘ˆ~e7.Ì7¬`#Ô×7pÇ@wmÜ|ÙˆÙz èØ!Ù«`Ô pa¢Ô‹7aÅÔ—7aèÔ£7«3OØSØ´` Õ¹3a.ÕÅ3.Ò3 µ`QÕà3ð7tØ}ض`tÕþ7a—Õ8iØûÒ;6ßÒÆ ;òûÒ`?;ÎæÒ&&Z¤óÖù?bYûû-Æ ;bã- ;òû-`?Zü0ùZ°(/Æ ZIú1:Zü2Æ [üÊù,óâÊ@,+üÊ@-‘þÎä-1üÌù-5üÍ?? @@ë[7üšä,óâš]Aü¦,óâ¦@,+ü¦@,1ü¦ù-Oü¨ù-Tü©@-5üªYWüÊ:;bãÊ ZIúÌ:YoüµÆ ;Iúµ:Z.ç¸ùZç·Ò \Šüß;Êæß A;(äßI;RÝßäZ÷äá£B?AAAæã UìãP 0JóüÉA 1#Jò㉠4#Jùã` 4#J ä` 4#Jäž 4# J(äI 4#(J.äÔA 4#0J;ää 4#8JIä 4#`?[`ýL:,uýLåG-°(L:?Y|ý ; ýJGZIú:[‘ý¸ù,­à¸ù-°(ºùY¦ý4 ;(ä4I;­à4ùZ‘þ6ÊZÞÙ6Ê&&ZIú::Y¿ýp ;(äpI;­àpù;æâpÊZbãr YÜý{ ;(ä{I;­à{ù;æâ{ÊZç}Ò Zbã~ [òýËåG,(äËI,ÞÙËÊYþ:;çÒ ;.çù\þ$; ý$JG;bã$ ZIú&:\2þl ;(äl I;çl Ò ;bãl  ; ým JG\Gþ€ ;(ä€ I;ç€ Ò ;b〠 ; ý JG\[þ; ýJG;bã ZIú:^pÝ0ãVqþmÆ _ãÚ(ämI_?Û ýmJGg®ÛæâoÊg'Übãq Zòûp`?G‡Ý¦Ýs`]Ü%G`€Ü1Ga£Ü=G.vGv`ÈÜ„G`7ÝGa¦ÝœGaÞ¨GOG±ÝÐÝA`BÞ]GêGµÝÐÝ0`eÞøG.ÁGPaˆÞÙGmÜÐÝØÝJmÇØÝäÝL.ÃH€M`«ÞÑH`ßÝH`>ßéHa·ßõH.„Hà…`Úß’H`#àžH`ZàªHa¾à¶H.5H r`áàCH`*áOHaaá[HH÷ÝÞ8`†áHa½á)H.p8`àá Þ<ÞL*Þ<ÞZ`)âZ.@°[`LâN ða•â[a¸âgaÝâsÍ`ânâ7`ãÚa%ãå 0 `INÞSÞ;`HãI`kã&IpÁG : žÞ²Þ £Þ²Þ2I£Þ­ÞŽ`ã@I.„HЙ`³ãžH`êãªHaä¶H.5H0 r`EäOHa|ä[HHß"ß8`¡äHaØä)H. 8`ûä "ß@ßL.ß@ßZ`DåZ.@Ð [`gåN !/T[a°åg/P“sÍ’â â7`ÕåÚaøåå P! !IRßcß;`æI`>æ&IpÁGÐ!:pÜ"TpÇ0"VOG‹ß¼ßd`cæ]G.êG`"0`†æøG.ÁG"a©æÙG À" ð".YI #2`ÌæcIaïæ{I P# €#gç°(|Æ e?Óß±à~`Hçs?akç‹?aŽç—?.¼?°#7a±çß?aþçê?o@à#Þ`!è@()@%à@àäu@CàGà8`Wèƒ@œ@Gàà9azè¶@Ò3Wà‚à¸aèì3 $ @$Zç€Ò p$ˆIÉà áŒmÜÉàÑàt mÇÑàçàv mÜòàúàx mÇúàáz ÃIâL⎠âLâ â7â â-âþI$â-⌠`ÀèJ`ãèJaé JþI7âLâ‘ `)éJaLé Ju@7â;âaoé@e?4á âša’é‹?aµé—?.¼? $7aØéß?a%êê?o@Ð$Þ`Hê@()@…á áämu@£á§á8œ@§áêá9a~ê¶@Ò3·áßá¸a¡êì340ããV ?`Äê+?`úê7?`0ëC? @ãvã %ajëQ?\‡þö;6ßöÆ ;òûö`?;àýöZèÆø&&Z¤óüùZ‘þýùZ­àûù&&ZÌ! sS&&ZÌ! sS?xSAƒSDÙ"LÙ\Ÿþæ;6ᑒ ;eæù;»þæ;>çù;Ì!çxSfãËäVÁþ _ë6ß Æ _Ãëòû `?g ì¤ó ù.ðR0%" `0ìSbSazìS €% À%aîì,Saí8Sa[íDS & @&a~íRS p&  &.ŠSà& `¡í”S`Äí Sb¬S`çí¸S ' P' €' °'.ŠSð' ` î”S`-î Sbÿÿÿÿÿÿÿÿÿ¬S`Pî¸SfÐ䀿VÜþ. _sî6ß. Æ _¼îe. ùgòîæâ0 ÊZòû1 `?.0(7 `ï áäåLîäåZ`MïZ.@`([`pïN (a“ï[a¶ïgaÛïsÍæ-æ7`ðÚa#ðå.ðRÀ(9 `FðúRbÿÿÿÿÿÿÿÿÿSaiðS ) P)aÝð8Sa'ñ,SaJñDS ) Ð)amñRS * 0*.ŠSp* `ñ”S`³ñ Sb¬S`Öñ¸S °* à* + @+.ŠS€+ `ùñ”S`ò Sbÿÿÿÿÿÿÿÿÿ¬S`?ò¸SY¥çzù;GàzÊZ°(|ùYºç‚ù;Gà‚Ê[ûþ,`,óü,×, ÿ,ä-°(.`YÿO ;(äOI;­àOù;ÎæOZbãR ZçQÒ j€æaéV+ÿs Æ _bòÊæs A_Óò(äs I_óæâs Ê_VóÎæs kAÿz gäóev ùgTôGÿw ÔÜgwôbãx  Z°(u Æ ZIúy :'W¢æ°æ} `Àô5WW¢æ°æ†`åôWa õWmǰæÌæ~ À+ ð+gAõ„!€ `.BW ,‡ bZWadõeWqWñæ^ç‹ `šõW`½õ‹Waõõ£Wa+ö¯W çLç çLç2Iç%ça`Nö@I /çLçi4/çLçb`qöw4`”öƒ4`·ö4 P, ‡è—èm܇è—è mu@oçsç œ@sçµç‘ aïö¶@Ò3ƒç®ç¸a÷ì3 €, °,g5÷Gà” ÊmÜèèŸ .¨Bà,¬ `Z÷²B`¤÷¾B.Ï@ -ðbñ@.C`-å`í÷$C.ËB-JbÿÿÿÿÿÿÿÿÿñBa#øýB Ð-.IC.èlaC.mC@.éb„CmÇ«è³èõ p..$, .ù`Fø/, Ð.<,÷èGé¹`|øF, éGéaŸøS,mÜGéOéúYÚíI;Êæ A;(äIZ°(IYUÿ= Æ ;Êæ= A;(ä= I;æâ= Ê;Îæ= Z ý@ JGZeA ùZbãB  Z°(? Æ jpé>íVhÿ± Æ _ÕøÊæ± A_¥ù(ä± I_Ûù­à± ù_7úÞÙ± Ê_°úÎæ² _gûòã² ‰ .À[/µ `ÖûÚ[aùûæ[ @/.ó[/º `/ü\aTü1\aü=\aýüI\a3ýU\'WÇéÒéF `iý5WWÇéÒé†`ŽýWa³ýWmÇÒéàéH àéåêe?êÒêJ `Öýs?aùý‹?aþ—?.¼?à/7a?þß?aŒþê?o@0Þ`¯þ@()@Uêiêäu@lêpê8`åþƒ@œ@pê¯ê9aÿ¶@Ò3€ê¨ê¸a+ÿì3 @0 „ëëmÜ„ëëO mÜë!ëX p0 °0 à0 8ëoë ?8ëoëg bÿÿÿÿÿÿÿÿÿC? 8ëoë 8ëoëaNÿQ? 1 @1 p1  1 ˜ë¼ë ?˜ë¼ë_ `qÿ+?bC?.¨BÐ1n `”ÿ²B.Ï@ 2ðbñ@.Cp2å`Êÿ$C.ËB 2JbÿÿÿÿÿÿÿÿÿñBaýB à2.IC 3èlaC.mCP3éb„CmÇWìfìõ €3.$,°3ù à3<,¸ìí¹ Äìía#S,mÜííú'Wí!í½ Wí!í†`YW/QWYºæôÆ ;Êæô A;(äôI;­àôù;ÞÙôÊ;Îæô;òãõ‰ ;ÓæõYýì Æ ;Êæ  A;(ä I;òã ‰ ;­à ù;æâ Ê;Îæ ;Óæ Ze ùZí bZí Z°( Æ &&Z'í '?E [;í ÿÆ ,í ÿb,í ÿÿZ°( Æ [`íC,€êC£B]oí ô,Êæ ô A,òã ô‰ Y}ÿ Æ ;Êæ A;(ä I;e ù;Üî ù;Îæà ZdŠÆ ùZbãÇ Â ZIúÉ :ZÿÆ ùZ°(Å Æ Z™ÿÆ ùZçÈ Ò ZüÊ Æ &&Z£ÿä :Z°ÿå  &&Z¹ÿô ùZ®õö Zùú÷ &&ZGà ÊYÁÿ'ù;ç'Ò ;.ç'ùZç)ù\Üÿ»;(ä»I;ç»Ò ;bã» ;5ï¼ù;ðÿ¼ùZ.ç¿ùZøÿÀùZÁùZÂùZ ÃùZIú¾:Ylçäù;çäÒ ;.çäùY32ù;ç2Ò ;.ç2ùZç4ù\Qã;(äãI;çãÒ ;bãã ;5ïäù;ðÿäù;®õäZ.ççùZøÿèùZéùZêùZ ëùZeî ZIúæ:Zní:Y{ ;(ä I;bã  ;­à ù;Îæ YÄí UÆ ;Êæ U A;(ä UI;òã U‰ ;­à Uù;æâ VÊ;Îæ V;Óæ VZí ZZ°( XÆ Zí Yb&&Ze mùj@íûV Æ _~Êæ A_^(ä I_xe ù_RÜî ù_çÎæ _) òã ‰ g0 °( Æ ]íû 4.p4 `Ÿ  í²íLŸí²íZ`û Z.@°4[` N ð4ag [aŠ ga¯ sÍ?ôMô7`Ô Úa÷ å.a05 bÿÿÿÿÿÿÿÿÿVa 5 ð5 P6 °6.ca7ü` }ab•abÿÿÿÿÿÿÿÿÿ¹aa= Åaaé Ñaa~ÝaaÞéa. b€7 $`b`]#ba©.b î î î î'Wî î 8`ß5WWî î†aW À7 8 `8 øÆø ?øÆø FbÿÿÿÿÿÿÿÿÿC? øÆø øÆøa'Q? 8 Ð8 9 P9 %õRõ ?%õRõ ?`^+?bC?.Tb9 P`]b`¤hb À9o;bð9 úoIC :FlaC P: €:aÚ÷a.À[°: (`þÎ[`ZÚ[a}æ[ ð: P;.Ð;) `³ sî”îL€î”îZ`üZ.@<[`N P<aU[axgasÍxõ†õ7`ÂÚaåå.a<) bÿÿÿÿÿÿÿÿÿVa = °= @>  >.ca?ü`}ab•abÿÿÿÿÿÿÿÿÿ¹aa+Åa/‘¸ÑaaÄÝaa$éa. bp? $‘¸b`Z#ba¦.b ÷îï ÷îï'W÷îï 8`Ü5WW÷îï†aW °? @ @@ äù'ú ?äù'ú FbÿÿÿÿÿÿÿÿÿC? äù'ú äù'úa$Q? p@  @ Ð@ A U÷|÷ ?U÷|÷ ?`G+?bC?.Tb0A P‘H]b`jhb `Ao;bA úoICÀAFlaC ðA Ba ÷a.À[PB (‘HÎ[`ÄÚ[açæ[ B ðB.ePC`›eb³ebÿÿÿÿÿÿÿÿÿ×ea@ãea ïe. b°C ^`é#ba5.b ðC @Dak f BöMö BöMö'WBöMö rWBöMö†aµW pD.À[ D e`ØÎ[`4Ú[aWæ[.TbàD Ž`]b`°hb Eo;b@E úoICpEFlaC  E F  F.tbG/ `æŽb`(šb`¦baT¾bawÊbaÕÖba âb.À[€GÎ `0Î[`ŒÚ[a¯æ[mdžï˜ïÕ .qWÀGÖ `å‹Wb—Wa£WaQ¯W ³ïàï ¸ïàï2I¸ïÂïa`t@I Ïïàïi4Ïïàïb`—ƒ4`Í4b›4 ðG ô,ômÜô,ôØ u@ððÜ að@.œ@ HÝ `ª@a6¶@.Ò3pH¸`Yà3a|ì3 ðRñ ðRñaŸ c2I–ð¥ðç `ÂLI¦c®ðRñì `øÔc`àcaQìca‡øcaªdaÍdaðdsc®ðÁðÁ` caI ™cð7ÁðÈðÂ`l  8a¢ 8\dÚðâðÏ5dÚðâð6ø5ÚðâðçmÌ5ÚðâðÙ6åðóðÎbA6f6îðóðŸ`Å |6\dóðûðÒ`è vd5dóðûð6`!Odø5óðûðç`T!6Ì5óðûðÙ`Š!æ56þðñÑ`À!56`ö!A6‰6þðñŸ`"—6a<"£6f6ññŸ`_"|6\dññÜ`‚"vd5dññ6`¥"Odø5ññç`È"6Ì5ññÙ`ë"æ56ñ4ñÛ`#56`1#A6‰6ñ#ñŸ`g#—6a#£6f6/ñ4ñŸ`À#|6 ÀH I.d@Ið `ã#±d`,$½d`O$ÉdbÕdar$áda•$ída¸$ùdaÛ$eaþ$ea!%emu@rñvñæ.Ò3€IçaD%ì3sc²ñ¾ñé`g%caŠ%™cð7¾ñÅñê`­% 8aÐ%8\dØñàñù5dØñàñ6ø5ØñàñçmÌ5ØñàñÙ6ãñòñøbA6f6íñòñŸ`ó%|6\dòñúñü`&vd5dòñúñ6`9&Odø5òñúñç`\&6Ì5òñúñÙ`&æ56ýñòû`¢&56`Å&A6‰6ýñòŸ`è&—6a '£6f6òòŸ`.'|6.6°I`Q'56`t'A6‰6òòŸ`—'—6aº'£6f61ò9òŸ`Ý'|6\dò"ò`(vd5dò"ò6`#(Odø5ò"òç`F(6Ì5ò"òÙ`i(æ52I9ò?ò `Œ(LI àIBeaò{òó `¯(he Jmu@ò„òõ pÒ3`Jõ sc²ò¾òö aå(™cð7ÂòÆò÷ a)8mÜÙòçòü .œ@Jÿ `+)ª@ac)¶@Ò3ó"ó¸a†)ì3 ÀJ Ka©)dc.@K `Î) -óXóL=óXóZ`?*Z.@€K[`b*N ÀKa«*[aÎ*gaó*sÍ“÷¢÷7`+Úa;+åmܦó®ó .¨BL `^+²B.Ï@PLðbñ@.C Lå`”+$C.ËBÐLJbÿÿÿÿÿÿÿÿÿñBaÊ+ýB M.ICPMèlaC.mC€Méb„CmÇÏ÷Ú÷õ °M.$,àMù N<,hùµù¹ tùµùaí+S,mܵùÂùúf û/ûV ¶  U(ä¶ I Tç¶ Ò Q6ß¶ Æ _#,· ó5YÊù;çÒ ;.çùZçù\ìA;bãA ;6ßAÆ ZçCÒ Z.çDùZçEùZüHùZæâFÊZòûG`?Y;ù;bã; ;òû;`?;6ß;yZ=ùZ=ùZü=ùZ†!=ùZIú>:Zü?Æ [#¨ä,óâ¨ù]-é,óâé@,+üé@,1üéù-Oüëù-Tüì@-5üí-=î\GT ;çT Ò ;bãT  ; ýU JG&&Zæâ\ ÊZòû^ `?r0û÷ýV`• ;(ä• I;ç• Ò ;6ß• Æ ;– ó5;}– gF,.ç˜ ùgi,„˜ ùgŒ,òû› `?g¯,bã™  gD- ýš JGZæâœ ÊŒzUûnûŸ `z-šz`-¦zaÀ-²z5dUûeû`ã-Cd`.Odø5Uûeûç`).6`L.6Ì5UûeûÙ`o.Ú5`’.æ5.2I@N  `µ.@I`Ø.LI.¿zpN¨ `û.Éz`1/ÕzaT/ázaw/ízaš/ùza½/{.5dàNE`à/Cd`0Od.ø5Oç`&06`I06.Ì5@OÙ`l0Ú5`0æ5.*{pOHa²0\{aû0h{aD1t{.œ@°O?ag1¶@.Ò3ðO¸aŠ1ì3mu@ üü>¥{@üMüQ`­1²{q@@üMü®`Ð1@m¾{„ü üV P `P.|Pª `ó1|`2+|`927| ÀP Úü ýGÚüíü\ `o21G ðü ý üü ýYIüü ýf `’2cI`µ2oIaØ2{IˆIxý¹ý« mÜxý€ýt mÇ€ý–ýv mÜ¡ý©ýx mÇ©ý±ýz ðP.ÃI Q­ `Q 9ýfý 9ýYýþI?ýYýŒ `û2J`3JaA3 Ju@?ýCý`d3ƒ@a‡3@þIØýçý‘ `ª3J`Í3Jað3 Ji¾ ;(ä¾ I;ç¾ Ò ;6ß¾ Æ ;.ç¿ ù;¿ ó5Z„à ùZbãÁ  Z ý JGfþRÿV£Î _4ÊæÎ A_\4(äÎ I_¥4çÎ Ò _Û46ßÎ Æ _$5.çÏ ùZÂÑ ó5^þuþÙ `G5i`j5u`5`°5aÓ5¥Œzþ-þÅ `ö5šz`6¦za<6²z5dþ$þ`_6Cd`‚6Odø5þ$þç`¥66`È66Ì5þ$þÙ`ë6Ú5`7æ52I-þ=þÆ `17@I`T7LImÇEþ_þÈ mÜmþuþÊ .¨B QÚ `w7²B`­7¾B.Ï@ÐQðbñ@.CRå`ã7$C.ËB0RJbÿÿÿÿÿÿÿÿÿñBa8ýB pR.IC RèlaCmCÈþRÿé`<8xCb„CmÇÈþÔþõ Ôþ<ÿ$,Ôþ<ÿù`_8/, Þþ<ÿ<,ñþ<ÿ¹`‚8F, ýþ<ÿa¥8S,mÜ<ÿRÿú4`ÿ„ÿVi…Ut…`Û8€…fÿŸÿVÔ  U(ä I Tç Ò Q6ß Æ i¹â ;6ßâ Æ ;eâ ùr ÿä Vøð _$9(äð I_m9çð Ò _96ßñ Æ _³9}ñ gí9.çó ùg:bãõ  ZIúô :2I»ÿÒÿô `3:@I`V:LI ÐR Sgy:eø ù™5Òÿçÿø `Â:§5`å:³5a;¿5B4×ÿçÿ `+;P4aN;\4 öÿ i…öÿ ü `q;t…`”;€… PS €Sg·;Gàþ Ê.°Sþ `Ü;  8 L! 8 Z`%<Z.@àS[`H<N T/Q[ak<g/\“sÍ‚  7`<Úa³<åfð  V _Ö<Êæ A_=(ä I_h=ç Ò _±=6ß Æ mÇ    mÜ& .  .¨B@T `ú=²B`0>¾B.Ï@pTðbñ@.C Tå`f>$C.ËBÐTJbÿÿÿÿÿÿÿÿÿñBaœ>ýB U.IC@UèlaCmC~  éb„CmÇ~ † õ † î $,† î ù`¿>/,  î <,£ î ¹`â>F, ¯ î a?S,mÜî  úYæî°ù;­à°ùYíî£ù;­à£ùZ°(¥ùY-½ ;6ß½ Æ ;5ï½ ù;@½ ù;J¾ ù;Îæ¾ ZçÀ Ò Z(äÁ I&&Z°(Ì YTA ;(äA I;çA Ò ;6ßA Æ ;5ïB ù;@B ù;JB ù;ÎæB Z.çD ùZBúE ùZlF ù&&ZbãW  ZX ùZ X ùZeX ùZwX ùZ­àX ù&&Zo Æ Z‡r ùZp Æ &&Z“ ÊZGàŽ ÊYœQù;çQÒ ;.çQùZçSùYûîŠù;­àŠù&ZËi–ùZ ï›ùZeùZ„è™ùZïœù&&ZèùZ•èù\»© ;6ß© Æ ;£ð© ù;e© ù\Ö ;(ä I;ç Ò ;6ß Æ ;5ï ù;­à ùZ.ç ùZIú! :Zbã"  &&Z“. ÊZGà/ ÊYçù;6ßy;'çZçÒ Z.çùZæâÊZ°(ùY6ç•ù;6ß•y;'ç•YçÊ;çÒ ;.çùZçùZæâÊj - Vðâ _;?Êæâ A_©@6ßâ Æ _uB5ïâ ù_“C­àâ ù_DTðã ù_KDÎæã gE@å ùgLEJå ù.£‰pUí `oE±‰ F p ¾‰R p µa¥E؉LR a ¥`ÈEZWa p ¥aëEW¢‹ I ¶`F°‹  I a1F½‹aTFÉ‹awFÕ‹Í  ˜`šFÚa½Få.£‰ Uî `àF±‰ s ž ¾‰€ ž µ`)G̉aLG؉L€ Ž ¥`oGZWŽ ž ¥a’GW.¢‹àU¶`µG°‹ VaþG½‹a!HÉ‹aDHÕ‹ÍY ] ˜`gHÚaŠHå @V Vg­Hçð Ò àV 0W pW.°Wú Ì ì mLÙ ì Z@P ¢ [ P ¢ aÐH[aóHgaIsÍU d 7`=IÚa`Iå.àWú `ƒI ì   Lù   Z`ÌIZ.@ X[`ïIN `Xa%J[aHJgamJsͲ Á 7`’JÚaµJå  X Y.å‰`Y `ØJó‰`kLÿ‰aaM/Ša}N;Š ÐY @Z.XаZÌ `ŠOfŠ`èOrŠ`¸P~Š`=QŠŠaçQºŠa2RÆŠa{RÒŠmÇ‹ § L [.o‹@[M `žR}‹`ÁR‰‹aäR•‹.5dp[U`SCd`*SOd.ø5 [ç`MS6`pS6.Ì5Ð[Ù`“SÚ5`¶Sæ54Þ ä P `ÙS4`üS)4aT54B4Þ ä `BTP4aeT\4 \ €\aˆTàŠa«TìŠaÎTøŠ.]\ `ñT 0]pL`]Z.@][ À]aU[a7Uga\UsÍñ û 7`UÚa¤Uå.'Wð]\ `ÇU5W.W ^†`ìUW2I¤ ´ c `V@I`4VLI P^i4½ Û d `WVw4`zVƒ4 ú     aV*‹aÀV6‹.sc€^‚ `ãVc`Wca>W™c.5d°^+`aWCd`„WOd.ø5à^ç`¼W6`ßW6.Ì5_Ù`XÚ5`:Xæ5sc? I ƒ `rXc`•Xc5d? I +`¸XCd`ÛXOdø5? I ç`þX6`!Y6Ì5? I Ù`DYÚ5`gYæ56\ v … `ŠY)6`­Y56`åYA6‰6\ d Ÿ`Z—6a+Z£6f6q v Ÿ`NZ|6\dv y ‰ `qZjd`”Zvd5dv y 6`·ZCd`ÚZOdø5v y ç`ýZ6` [6Ì5v y Ù`C[Ú5`f[æ56~  ˆ `‰[)6`¬[56bA6f6ˆ  Ÿ`Ï[|6 @_ €_aò[R‹aA\^‹.À_ `f\ ® Lš ® Z`¯\Z.@`[`Ò\N @`a][a+]gaP]s͇ • 7`u]Úa˜]å.€`Ž ± Ñ mL¾ Ñ Z.@À`[ aa»][aÞ]ga^sÍÈ Ö 7`(^ÚaK^åmÜ) 2 œ mÜæ ô   @a  a b `b  b.$àbÓ b>.ÍŒcœbçŒan^óŒa‘^ÿŒa´^ aÙ^ @c pcK Ÿ %`"_Y`E_eah_qa‹_}5d ’  `°_Cd`Ó_Odø5 ’ ç`ö_6``6Ì5 ’ Ù`<`Ú5`_`æ5  c ª µ 'Wª µ @`‚`5WWª µ †`§`WaÌ`W õ  ™5õ  0`ï`§5`a³5a5a¿5B4õ   `kaP4a¡a\4 Ðc.$ dÐ b>.ÍŒ`dœbçŒaÄaóŒaçaÿŒa b a/b  d àdK# 3 %`xbY`›bea¾bqaáb}5d# &  `cCd`)cOdø5# & ç`Lc6`oc6Ì5# & Ù`’cÚ5`µcæ5 e > I 'W> I @`Øc5WW> I †`ýcWa"dW  - ™5 ! 0`Ed§5`hd³5a‹d¿5B4 !  `ÁdP4a÷d\4.Œ@eÜ `e!Œ`ce-Œ.FŒpeÝ `†ePŒ`©e\Œ`ÌehŒa*fŒŒ.dÀe+ `Mf™d`pf¥d`“fÉdbÿÿÿÿÿÿÿÿÿÕda¶fádaÙfídaüfùdageaBgeaege.Ò3fçaˆgì3scU a é`«gc`Îgcañg™cð7a h ê`hþ7`7h 8aZh8\d{ ƒ ù`}hjd5d{ ƒ 6` hCdø5{ ƒ ç`Ãh6Ì5{ ƒ Ù`æhÚ56† ” ø` i)6bA6f6 ” Ÿ`,i|6\d” œ ü`Oijd`rivd5d” œ 6`•iCd`¸iOdø5” œ ç`Ûi6`þi6Ì5” œ Ù`!jÚ5`Djæ56Ÿ ¹ û`gj)6`Šj56`­jA6‰6Ÿ § Ÿ`Ðj—6aój£6f6´ ¹ Ÿ`k|6\d¹  `9kjd`\kvd5d¹  6`kCd`¢kOdø5¹  ç`Åk6`èk6Ì5¹  Ù` lÚ5`.læ56Ç Ü `Ql)6`tl56`—lA6‰6Ç Ê Ÿaºl£6f6× Ü Ÿ`Ýl|62IÜ â  `m@I`#mLI.2IPf! `Fm@I`imLImÇú   * f ÐfaŒm²ŒaÛm¾Œ.g. `n  * L * Z`InZ.@Pg[`lnN ga¢n[aÅngaênsÍ ) 7`oÚa2oå.Ðg/ . N mL; N Z.@h[ PhaUo[axogaosÍd r 7`ÂoÚaåoåmÜ£ ° = .¨Bh `p²B`>p¾B.Ï@àhðbñ@.C0iå`Àp$C.ËB`iJbÿÿÿÿÿÿÿÿÿñBaöpýB  i.ICàièlaC.mCjé`qxCb„CmÇ ) õ @j.$,pjù` ‹ `z›Óµ˜µ8 > à b²µ`µ8 > `bzµa›†µI¶Å Ë ² `Ö›W¶ÜÅ Ë Ñbö¨Å Ë .bÀaù›ËmÜë  Ç     x Z ýÊ JGmÇ  Ì mÜp x Ø 4  ­ VĵUÓµ˜µ¦ « à b²µ`µ¦ « `bzµa0œ†µf° À Vnä  U(ää I˜µ¹ ¾ ç b²µ`µ¹ ¾ `bzµaiœ†µY„eä;Aáe¿µ;ËieäfÀ Ð V”ë  U(äë IȹÉ Î î bâ¹`µÉ Î lbÿÿÿÿÿÿÿÿÿzµa¢œ†µd]` ³]ªL,uýLåGd²s ³jÐ " V½ò I_äœÞÙò äk‘þö äZ(äô IZÊõ ùZ ý÷ JGjºN W 0 ÜN W c bö¨N W .bÀaË € ® myº© ® 6 Þ z Žºí ö ; Üí ö v bö¨í ö .bÀaUËs.ö z ; `Œ‰. „! ù!  „! é! myº’! ¢! S hg ;1Úg ³hÒz ;nÚz ³\Õ¼ Zòû¾ `?YãÏ &Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?&Zòûà `?Y÷é Z‘þë ä&&Z¾óú ù[ Pù,­àPù-$Rù[*hù,­àhù-Ijù[]Šù,­àŠù-$Œùj" 1 Vwg¯‘þä.Y¼`„ `çh¼&´9" @" n ` ž<´´9" @" Q`-ž´.u¼„ `Pž„¼&´e" l"  `sž<´´e" l" Q`–ž´ l" È"  l" È" Z…ù.À„'`¹ž ù" # L# # Z`ŸZ.@…[`%ŸN @…anŸ[a‘Ÿga¶ŸsÍ], k, 7`ÛŸÚaþŸå'W# $# '`! 5WW# $# †`F Wak W.€…1`Ž  5# S# LA# S# Z`× Z.@À…[`ú N †aC¡[af¡ga‹¡sÍž, ¬, 7`°¡ÚaÓ¡åX# ¤# 1b€p@X# ¤# [b€pN X# ¤# aö¡[a¢ga>¢sÍX# f# 7bÿßÚac¢åm‘¼¿# p) 4 p) µ+ m¨¼p) µ+ 5 @†.¯¾€†7a†¢½¾ À† ‡a«¢˾.Ú¾@‡ý `΢ç¾añ¢ò¾op‡``£ °‡.Là‡Z`J£Z@_- º- [`m£N _- º- a££[aÆ£gaë£sÍi- r- 7a¤å."¿ˆÿ `3¤/¿aV¤:¿ @ˆ pˆoþ¾ ˆ—`Œ¤ ¿a¯¤¿ Ј ‰o0‰w`Ò¤.@`‰[`¥N ‰a>¥[aa¥ga†¥sÍÛ, ä, 7`«¥ÚaÎ¥å ?/ [/ LK/ [/ Z`ñ¥ZqÚ¾L. / Œ`¦ç¾a7¦ò¾oÀ‰``Z¦@L. §. [`¦N L. §. aƦ[aé¦ga§sÍV. _. 7a3§å Ô. ñ. Lá. ñ. Z`V§Z.ð‰:b€  Š.LPŠZb€ Z.€Š; á/ û/ Lé/ û/ Z`y§Z.@ÀŠ[ ‹/T[aœ§g/P“sÍ*0 80 7`Á§Úaä§år1 %2 V‘e  Uòûe `?g¨¨g ùk€ ±h ùg>¨¾h ùZÎh ùZßi ÙZéi ÙZ÷i Ù @‹ ã1 %2 gt¨s ù¥{æ1 ê1 s `—¨²{q@æ1 ê1 ®`º¨@YHù;çHÒ ;.çHùZçJùY)Zù;(äZI;çZÒ ;bãZ ;¹ÿ[ùZ­à]ù&&Zòûg`?\<r;çrÒ ;.çrù;­àrù;égsùZ ûu5\]þ;(äþI;çþÒ ;pþ5;wÿ5;ÿ5;ÿù;ùZ¹ÿùZùZ­àù&&Z— ùZ¡ù&&Z¬2ùZ¶4ù]Áþ,(äþI,çþÒ ,.çþù,BúÿùZIú:\Ø€;ç€Ò ;.ç€ù;­àùZ ûƒ5Zç„ù]þí,(äíI,çíÒ ,.çíù,Búîù-Iúð:&-¦—ùÆ \æ;(äæI;çæÒ &&Z+ÚøÒ ZkÛùÉ Z˜ûúr02 Å8 V(o_ݨ(äoI_9©bão _o©®õo_Ò©9o_ ªùúpgFªçrÒ gȪ¹ÿtùg«­àtùg‚«tùgõ«tùgS¬tùZIús:u@p2 t2 w`±¬ƒ@.Ò3p‹xaÔ¬ì3›Ç¥2 Ê2 {a÷¬ÙÇ ¥2 Ê2 hÇ¥2 ª2 b`-­vÇ`P­‚Ças­ŽÇ °2 ¸2 ™5°2 ¸2 c`–­§5`Ì­³5aï­¿5B4°2 ¸2  `®P4a5®\4ÆÑ2 3 }`X®Ð`{®Ü Ñ2 3  Ñ2 3  õ2 3  ú2 3 qùú2 3 »¨ú2 3 9`ž®µ`Á®Àaä®Ë 3 43 sc&3 ,3 †`¯c`*¯c5d&3 ,3 +`M¯Cd`p¯Odø5&3 ,3 ç`“¯6`¶¯6Ì5&3 ,3 Ù`Ù¯Ú5`ü¯æ5 à‹ ŒZégŽù.öÇ@Œ`°È`B° Èø5L3 R3 u`e°6`ˆ°6Ì5L3 R3 Ù`«°Ú5`ΰæ5‰6•3 ™3 {añ°£6f6¦3 «3 {`±|6öǰ3 ³3 `7±È`Z± Èø5°3 ³3 u`}±6` ±6Ì5°3 ³3 Ù`ñÚ5`æ±æ5 pŒ\d\3 e3 ”` ²jd`,²vdaO²‚döÇe3 x3 “`r²È`•² È`¸²$ȉ6e3 i3 {aÛ²£6f6s3 x3 {`þ²|6\d}3 ‰3 –`!³jd`D³vdag³‚d5d}3 €3 6`гCd`­³Odø5}3 €3 ç`г6`ó³6Ì5}3 €3 Ù`´Ú5`9´æ5.öÇ Œ•`\´È`´ È`¢´$Èf6³3 ¸3 {`Å´|6.=ÈÐŒ™`è´GÈ` µSÈ`.µkÈ`dµwÈ`œµƒÈ`åµÈa.¶›Èad¶§Èa×¶³È `o‹Ú3 å3 `"·}‹`E·‰‹/‘Ð~•‹5dÚ3 à3 U`h·Cd`‹·Odø5Ú3 à3 ç`®·6`Ñ·6Ì5Ú3 à3 Ù`ô·Ú5`¸æ5 Ða:¸ÁÈar¸ÍÈ4$4 >4  `ª¸4`͸)4/‘Ð~54B4$4 >4 ‘Ð~P4/‘à~\4 Ž k4 ¡4 øÈk4 ¡4 !`ð¸É`¹ É`6¹É‘Ð~"É2Ik4 q4 `Y¹@I`|¹LI:ɹ4 ß4 (`Ÿ¹DÉ`¹PÉ`å¹\Éø5¹4 Æ4 ƒ`º6`+º6Ì5¹4 Æ4 Ù`NºÚ5`qºæ5‰6Æ4 Ô4 ˆ`”º—6a·º£6f6Ú4 ß4 ˆ`Úº|6:Éä4  5 )`ýºDÉ` »\Éø5ä4 ç4 ƒ`C»6Ì5ä4 ç4 Ù`f»Ú5f6ï4  5 ˆ`‰»|6 @Žo‹;5 F5 .`¬»}‹`Ï»‰‹aò»•‹5d;5 A5 U`¼Cd`8¼Odø5;5 A5 ç`[¼6`~¼6Ì5;5 A5 Ù`¡¼Ú5`ļæ5 €Žaç¼ÝÈa½éÈ4}5 5 2`B½4`e½)4aˆ½54B4}5 5 `«½P4/‘à~\4 °Ž Ã5 ü5 øÈÃ5 ü5 H`νÉ`ñ½ É`¾É`7¾"É2IÃ5 Ì5 `Z¾@I`}¾LI:É6 =6 O` ¾DÉ`þPÉ`ù¾\Éø56 6 ƒ`1¿6`T¿6Ì56 6 Ù`Š¿Ú5`­¿æ5‰66 +6 ˆ`ã¿—6aÀ£6f616 =6 ˆ`>À|6:É@6 P6 P`aÀDÉ`„À\Éø5@6 C6 ƒ`¼À6Ì5@6 C6 Ù`ßÀÚ5f6K6 P6 ˆ`Á|6 àŽÉ‹6 Ï6 ¦`%ÁŠÉ`HÁ•Éq2I‹6 ‘6 ð`kÁ@I  P.Ïɬ`ŽÁÙÉ`±ÁåÉ Ð aÔÁóÉa÷ÁÿÉ P .øÈÀþ`ÂÉ`> É2I=7 @7 `aÂ@Ið77 …7 `„Âþ7a§Â8 ð.$, ‘·`ÊÂ/, P‘.<,€‘¹`íÂF, °‘aÃS,[A3ù,Iú34-ç5Ò -ç6ù-.ç6ù[X¡ù,­à¡ù-°(£ùuÐ8 ç9 VnÕ,(äÕI,çÕÒ ,.çÕùvBúÖù-ÞÙØÊq2IØ8 ý8 Ù`FÃ@I`iÃLIqvØý8 )9 Ø`ŒÃƒØa¯ÃŽØaÒÙØqÒ3 9 $9 9`õÃà3q°Ø)9 99 ØaÄÈØoà‘Ø`;Ä 99 S9 LA9 S9 Z`qÄZ.@’[`”ÄN @’/Q[aÊÄg/P“sÍ9 9 7`ïÄÚaÅåqIS9 a9 Ü`5ÅI`XÅ&Io2Ip’Ý`}Å@I` ÅLIuð9 ; Vá,(äáI,çáÒ ,.çáùvBúâù-ÞÙäÊq2Iø9 : å`ÃÅ@I`æÅLIqvØ: I: ä` ƃØa,ÆŽØaOÆ™ØqÒ3-: D: 9`rÆà3q°ØI: Y: äa•ÆÈØo ’ä`¸Æ Y: s: La: s: Z`îÆZ.@Ð’[`ÇN “/Q[aGÇg/P“sÍ¡: °: 7`lÇÚaÇåqIs: : è`²ÇI`ÕÇ&Io2I0“é`úÇ@I`ÈLI[”?,Q?4,Ve@4-¨BÔÜ-²CÔÜA¼u; @ VÆLw@ÈuýLåGwÉ8ÞL:‘àoÜL_ùxWÉáLkùxÉçLkù 9; â;  `“xÊîÝLqšÜS; f; L`4ʧÜ`WÊ²Ü “ À“-íL ð“xzÊŒþL: 0” `”  ” à”-ŒþL: @•  • –x°ÊòL: `– °–-ûL: à–xÓÊòL: — K> Œ> xöÊûL: P—xËL:xOË L:xrËûL:  — ê= 8> -L: З 0˜ €˜x¨ËûL:-L:-%L: À˜xÞË%L:-L: ™ = ¡= xÌûL: @™x$ÌûL:LLG8Þ:L#GîÝL#u@ ÝA V/LUuýLåGwZÌ8ÞL:‘ðoÜLpùx}ÌçL|ù J@  @  U@ ›@ x ÌîÝLqšÜU@ s@ L`Å̧Ü`èÌ²Ü £@ ºA  À@ ¤A x ÍEL: Ä@ ŠA  p™xTÍŒþL: A QA  A QA xŠÍòL: A QA  .A QA x­ÍûL:  ™xÐÍL: Й šxÎŒþL: 0š QA ŠA x)ÎûL:-íLLLG8Þ:L#GîÝL#\K[;ç[Ò ;¹ÿ[ù;Bú[ù^àA åC VZ½_LÎ(ä½I_¨Îbã½ _Þέà½ù_uÏw¾_ØÏÎæ¾gÐçÀÒ gHйÿÂùg¹ÐÂùgÑ~Âùg&Ñ ÃùZIúÁ:ZÂùu@B B Æ`Iу@.Ò3`šÇalÑì3.sc šÈ`Ñc`ÅÑcaÒ™c К › 0› `› ÷B C Xá÷B C Þ`FÒbá`iÒná`ŒÒzá ›g¯Ò‘þäù À› ð› œ.\dPœæ`ÒÒjd.5d€œ6`õÒCd.ø5°œç`Ó6Xá[C cC è`;Óbábzá\d•C C þ`^Ójd`Óvd5d•C C 6`¤ÓCd`ÇÓOdø5•C C ç`êÓ6` Ô6Ì5•C C Ù`0ÔÚ5`SÔæ56¤C ³C ý`vÔ)6`™Ô56bA6f6®C ³C Ÿ`¼Ô|6\d³C ¶C `ßÔjd`Õvd5d³C ¶C 6`%ÕCd`HÕOdø5³C ¶C ç`kÕ6`ŽÕ6Ì5³C ¶C Ù`±ÕÚ5`ÔÕæ56¿C ÖC `÷Õ)6`Ö56‰6¿C ÂC Ÿ`=Ö—6auÖ£6f6ÏC ÖC Ÿ`˜Ö|6rðC ·E V‰“_»Ö(ä“I_*×ç“Ò _™×¹ÿ“ù_õ×”ù_RØ”ù_°Ø~”ùg Ù –ùgCÙ¬–ù4D +D š`fÙ4`œÙ)4aÒÙ545dD &D ÿ`õÙCd`+ÚOdø5D &D ç`aÚ6`—Ú6Ì5D &D Ù`ÍÚÚ5`Ûæ5 DD ŒD øÈID ŒD £`9ÛÉ`\Û"É2IID \D `Û@I`¢ÛLIuŒD äD ¤`ÅÛ`èÛ‹ ŒD ÓD  ŒD ÓD  ÂD ÓD ÇD ÓD €qÜÇD ÓD ¯¨ÇD ÓD .`ܵaBÜË àœ E ·E geÜ ©ùZég¨ù\dE $E ®`ˆÜvd5dE $E 6`«ÜOdø5E $E ç`ÎÜ6Ì5E $E Ù`ñÜÚ5`Ýæ5öÇ'E 9E ¬`7ÝÈ`ZÝ È`}ÝÈf64E 9E {` Ý|6\d>E AE ²`ÃÝjd`æÝvd5d>E AE 6` ÞCd`,ÞOdø5>E AE ç`OÞ6`rÞ6Ì5>E AE Ù`•ÞÚ5`¸Þæ5öÇFE UE °`ÛÞÈ`þÞ È`!ßÈf6PE UE {`Dß|6 UE ¤E  ZE ¤E ÉZE ¤E µ`gߊÉ`Šß É`­ß«Éq2IZE mE ð`Ðß@I`óßLI^ÀE HG V¶D U(äDI_à­àDù_ràÎæDgÖàbãF .£‰F`ù౉ ÊE õE ¾‰×E õE µaBá؉L×E æE ¥`eáZWæE õE ¥aˆáW.¢‹P¶`«á°‹ €aáὋaâÉ‹a'âÕ‹ÍŸF £F ˜`JâÚamâå.5H°Faâ[HHõE F 8`µâHaØâ)H.ž8`ûâ F $F LF $F Z`DãZ.@@ž[`gãN €ž/P[a°ãg/T“sÍÙF èF 7`ÕãÚaøãå Àž ðžI6F CF ;UI`ä&IpÁG0Ÿ: oF ŽF  oF ŽF  oF ŽF i4oF …F HUw4`@ä4YÓ:Ò ;(ä:IZç<Ò YêžÒ ;(äžIZÎæ¡Z'â¡Zç Ò Zëú¢ùZ¢ùZ‘þ¢ùY Ò ;(äI;Îæÿ;'âÿZkÛ„É ZçƒÒ Y P;(äPI;çPÒ ;ÎæP]0 “,8Þ“õ,(ä“I]I Ä,8ÞÄõ,(äÄI,EWÄÆ ,­àÄù,‘ûÅ,˜ûÅ]] š,8Þšõ,EWšÆ ]u ¡,8Þ¡õ,­à¡ù] ¨,8Þ¨õ,‘û¨]§ ¯,8Þ¯õ,˜û¯]Á ¶,8Þ¶õ,Û ¶Yâ _Ò ;(ä_I;kÛ_’;Îæ`ÿ;'â`ÿZçbÒ ^PG J V ÔÒ _cä(äÔIgÒäçÖÒ dG õI ÀípG €G Ù`õäÎíaåÚí €G õI çí€G õI Ûa;åîn îa‡åîJî‹G 8I ¨`ÐåXî`ædîa*æ|î `Ÿ Ÿ ÎG H •îÑG öG ‰èîÕG çG Ybÿÿÿÿÿÿÿÿÿ(ïqÈîÕG ØG È`bæÑî`…æÜîq4ïØG ÜG É`¨æ=ï`ËæHïqTïÜG àG Ê`îæ]ï`çhïqtïàG ãG Ë`4ç}ïq”ïãG çG Ìbÿÿÿÿÿÿÿÿÿ¨ï´ïçG ëG Z`Wç½ïbÿÿÿÿÿÿÿÿÿÈï ÀŸ ðŸ.Ôï  ‘`zçâï`Ãçîï`ççúï` èða/èðmÜH *H d ` •î—H ÅH qèî›H ´H Ybÿÿÿÿÿÿÿÿÿ(ïqÈî›H ŸH È`RèÑî`uèÜîq4ïŸH ¤H É`˜è=ï`»èHïqTï¤H ©H Ê`Þè]ï`éhïqtï©H ®H Ë`$é}ïq”ï®H ´H Ìbÿÿÿÿÿÿÿÿÿ¨ï´ï´H ºH Z`Gé½ïbÿÿÿÿÿÿÿÿÿÈïmÇI I |öÇZI {I ³`jéȉ6ZI ]I {`é—6a°é£6f6wI {I {`Óé|6   I ÚI  I ÚI .°6À À`öéÆ6pf6ð ’ø5±I ÆI `,ê6öÇàI õI Í`Oê È`rêÈø5àI ãI u`•ê6Ì5àI ãI Ù`¸êæ5‰6ãI æI {`Ûê—6aþê£6f6ðI õI {`!ë|6\ ³;ç³Ò ;.ç³ù;/ ³ù;æâ´Ê;ég´ùZ û¶5^ J èK V6 _Dë(äI_ ëbã _Öë­àù_ ìæâÊgFìçÒ g|ì¹ÿùgíìùgí~ùg3í‘þùZIú:Zùu@PJ TJ `~íƒ@.Ò3 ¡a¡íì3.scP¡ `Äíc`úícaDî™c €¡ °¡gzîëú-ù.¶õð¡/`°îÀõ`ÓîØõ` ïðõ.f6@¢»`@ï|6.\d€¢-`vïjda™ï‚d.5dÀ¢6`ÏïCd.ø5£ç`òï6Ì5'K *K Ù`ðÚ5[L Ð`,ËiÐ`[] ;`,óü;×,HB;`-°(=`- ÿ>ä[k ·ä,óâ·`rðK ëL Vv À_8ð(äÀI %L àL  3L àL gnð Ì} ø;L ÍL Î`’ð)øaµð4øqø÷;L }L C`ØðøoKø@£C`€ñXøo@p£»`£ñ@  £oBWУGaÆñeW??.8AßB–?Aß86áB–?6á4=@× — ƒûå×ðL ÃO Eõ D àPAOŠÙF™ÙG¨Ùf##Hr­Ù™A}¸Ù"ÀÙEþ ™ èPA¤â:L:GÑà·:#?¼AÇFÞFTÞh GbÞ  #GkÞ‰#GsÞ~#G{Þ9#G…Þ9 #G’Þ9&#GœÞÊ )# G©Þ@,#(G¬ÞM-#8L-G Ý·-#GÝ·-#Ox/#HP/G´ÞŠ1#L1G¾Þ·1#GÇÞ·1#GÕÞ¹4#L4G Ý·4#GÝ·4#GÝÞé8#XL8G¾Þ·8#GÇÞ·8#?AÎÙ-IÖÙÈJÞÙ‘!#JâÙ‘'#J¨ÙD0#JëÙ˜2#JñÙq8#ˆK8JûÙA8#JÚ›:#JÚ›@#˜J"Ú‘B# J+Ú¹N#¨J1ÚQ#°J?Ú9T#¸JGÚ~W#ÀJOÚ~_#ÈJVÚ@}#ÐJaÚ¼~#àJnÚ…#ÈJyÚˆ‡#ÐJˆÚˆ#ØJ”Ú›‘#àJ§Úˆ™#èJ¶Ú~ #ðJÃÚ~¦#øJÞÚª­#€JìÚ¶°#ÀK°JûÙ·°#JñÚD²#ÈJúÚ™»#ÐJ Û™¼#ØJÛ™½#àJ3Û™¾#èJFÛDÀ#ðJQÛ;Â#øKÂJûÙ·Â#J\ÛDÃ#€JkÛ¶Æ#ˆJwÛW É#ÀJ|ÛÛÏ#À+"ÙA£‡ÛF•ÛxeG£Û~g#GªÛ›n#G±Û›o#GºÛ›p#GÁÛ~v# GÑÛ~w#(GäÛ~z#0GôÛ›{#8GÜ›|#@GÜ›}#HG Ü~#PG/Ü›€#XG<Ü›#`GIÜ­„#hGPÜþ‡#pA‰£ØA”ªØ\"ºØA¦WÜ "`Ü?²A½wÜFŒÜ AG¡Ü›H#G©Ü›I#G±Ü›P#G»Ü~V#?AÃÜF×ÜYG¡Ü›^#G©Ü›_#GëÜ~b#?FAQöÜ FÿÜH SGÝg T#L TG ÝA T#GÝA T#GÚ› U#GÝÁ V#G)Ýñ W# G5Ýü X#(AÌ;Ý FDÝ GMÝr #GRÝr #A‘YÝ ¼8BŠAaÝ FnÝ DG{Ýb E#G‚Ý} F#GŒÝ‘ G# G˜Ý‘ H#G Ý„ P#Am¦ÝF¹ÝG±Ü›#?‰M:fAœÌÝ N ×ÝéÝúÝ Þ?¾AÉÞ*F*Þp·G8Þ¼½#G=ÞîÅ#h8úBŠAŸá(F¶áAG¢f~|#A'ÍáA2Õáw"æá"\ØAKgá&Fá‘G—áa’#L’G ݃’#G݃’#?@A“ïáFøáGâ›#8~BŠÇHÂâ5K8-J?‡1 .#J âl /#J'☠0#J.âÉ 1#J7âÚ 2# J=âë 3#(JÁ>! 4#0?6 HB CâT‰2‰2~2~2g 2g 2‘?9?q H} QâT92‰2~292‘? H© `âT92‰2~2~2~2‘?Î H© oâ?ß H© €â?ð Hü Žâ$T92‰2~2~2~292‘?& H2 œâ+T92‰2~2‰2~292‘8c BŠ#An ªâ,U¶â`J¨ÙD #JÂâ´ #JÉâ #JëÙI#?¹ AÄ Îâ'FÚâH5Gæâñ7#Gíâ‘:#Góâ÷ =#8 BŠA”úâ A ã²L²GÑà, ²#?1 A< ã)F+ãXšGBãR ¢#L¢G¾Þ, ¢#GÇÞ, ¢#O} ¤#PH¤G©Þ@¦#O™ ©#P©GJ㉪#GXãÊ «#Gbã¹ ¯#?Ï AÚ åÞFñÞ€XGýÞ Z#Gß›`#G ß›a#GßÓd#Gß+g#8G!ß›v#@G*ßD y#HLyG¾ÞÊ y#GÇÞÊ y#G4ß9#XGóü!‚#\G=ßÓˆ#`?• A  GßQTߨ°G¨ÙÎ ±#Gß›´#G ß›º#GaßÓ ½#Gmß9¿# Gvß9À#!G~ß Â#(LÂG¾Þ Â#GÇÞ Â#G‰ß›É#8G—ßß Ñ#@GŸß›Ô#pGªß›Õ#xG½ß9Ø#€GÁß9Ù#GËß9Ú#‚GÕß9â#ƒGÝß9è#„GäßÓë#ˆG)~î#¨?D?Ø "$!Aê ïßFõß0 GŸß›+#GÙd~.#Gûß‘4#G à‘5#GàU8#Gà}9# G'àž<#(?ZAe+àR2r2x?wS?~?‚A6à T92r2r?£A®DàFKàG'*r#GPWr#AÞRàF]à IGhà›K#Gpà›L#Gyà›M#Gƒà›N#8‰BŠ?0A;ŽàFšà`ŒG¨ÙÎ Ž#G¦à‘š#G­àÇ #G³à{£#L£G¾Þ+£#GÇÞ+£#GäßÓ¦#(G½àå©#HG)~¬#XAÒÀàŠLŠGÑàÊ Š#AðÚàFäà;G)~„=#GÿU‘>#8‰BŠA,îàVNQáá5áMáATfãFyãHG¡Ü›#G©Ü›#G±Ü›&#GŒã~,#G”ã›/# G›ã›2#(G¤ã›5#0Gªã›;#8G»Ü~>#@8 BŠE · QE ~ ðPE( ~ øPE6 ~ QYæî °~;­à °~Yˆæ Iñ;­à I~&Z°( NñYíî £~;­à £~Z°( ¥~Y¥ç z~;Gà zñZ°( |~]] š,8Þš·,EWš‰]I Ä,8ÞÄ·,(äÄ ,EWĉ,­àÄ~,‘ûÅ9,˜ûÅ9]u ¡,8Þ¡·,­à¡~] ¨,8Þ¨·,‘û¨9]§ ¯,8Þ¯·,˜û¯9]Á ¶,8Þ¶·,Û ¶9] èH,"èHÎ [B ·-8Þ·[V *·,g *~-8Þ,·-o -~-]ö-~-EW.‰]0 “,8Þ“·,(ä“ ]u  ,8Þ ·]<è[,"è[Î Yûî Š~;­à Š~&ZËi –~Z ï ›~Ze ~Z„è ™~Zï œ~&&Zè ~Z•è ~[èú‘,Ëiú~-°(ü~yðL $O V† O‰wéñ­àO~xò]öR~xhò'*T¼xŒò8ÞS·x¯òeR~xDó°(Q‰o;P§\`góI M 7M M 7M  µ`óaÀó™VM (M  ¥`ãód¦(M 7M  ¥aôÀvÛN $O  ¶`)ô„ ÛN $O a_ô‘a‚ôa¥ô©ëçN ëN  ˜`Èôøaëôqí:M QM ](Í:M AM Éq9AM EM Ê`õBqYEM IM Ë`2õbbmqyIM MM Ì`Võ‚bq™MM QM Íb­q¹QM ]M ^`zõ €§ °§oçà§e`õôaÀõÿa ö a,öaOö qΔM ¬M 1aröÛ ¨ ÅN ÛN  ÅN ÛN (LÅN ÛN 8qíN 5N Eq,N  N È`¨ö@qÍ N $N É`ËöÖ`îöáq9$N (N Ê`÷MqY(N .N Ëbÿÿÿÿÿÿÿÿÿmq™.N 5N Íb­ :N mN  ?N \N qÍCN GN n`4÷Ö`W÷áq9GN KN o`z÷M(L\N mN rqaŸN «N ~`÷jz0O O V” ƒwÀ÷¦ ƒxwö÷° ƒxw,ø£Ûƒxq¹DO SO †`bøÂqaqO O Œ`…øj{O ÃO V¹ 9]=@× Æ Öå×ÐO HP zÐO óO V& KU+üKKTôKŽx¨ø‘þMŽ|: nŽ,+ün«A™£ØA¤ªØ\"ºØ?°@µAÀåó Fóó^GôŽ`#GôŽm#zP HP VI awËøóâaPwù+üa«-TðcŽqtP P e`7ù‚?µ?UA¤úâ Þ==@× X (å×PP ®f >· E ¸D?J@O"$!> l 0FAw£ØA‚ªØ\"ºØ>Ò Ÿ$ Ð@¤H°â5K8-J?‡.#J âi/#J'â•0#J.âÆ1#J7â×2# J=âè3#(JÁ>4#0?$H0CâTU2U2l2l2V2V2bM?["\Ø"Ù?nHzQâT[2U2l2[2b?šH¦`âT[2U2l2l2l2b?ËH¦oâ?ÜH¦€â?íHùŽâ$T[2U2l2l2l2[2b?#H/œâ+T[2U2l2U2l2[2b>é j ˜OAuù  F hQG?‡ÄR#G âìS#G bT#G Y#G Z#(?ÉAÔ# Tà2l?åAð6  FG %O&#P&GX U'#G\ à(#G¦H2)#?7ABFÞFTÞh GbÞ† #GkÞU#GsÞl#G{Þ[#G…Þ[ #G’Þ[&#GœÞÖ )# G©ÞÏ ,#(G¬ÞÈ-#8L-G Ý2-#GÝ2-#Oó/#HP/G´Þ1#L1G¾Þ21#GÇÞ21#GÕÞ44#L4G Ý24#GÝ24#GÝÞd8#XL8G¾Þ28#GÇÞ28#?‹A–ÎÙ-IÖÙÈJÞÙb!#JâÙb'#J¨Ù 0#JëÙL2#JñÙì8#ˆK8JûÙØ8#JÚ2:#JÚ2@#˜J"Ú' B# J+ÚO N#¨J1Ú² Q#°J?Ú[T#¸JGÚlW#ÀJOÚl_#ÈJVÚÏ }#ÐJaÚ7~#àJnÚ² …#ÈJyÚ ‡#ÐJˆÚ #ØJ”Ú2‘#àJ§Ú ™#èJ¶Úl #ðJÃÚl¦#øJÞÚ9 ­#€JìÚ1°#ÀK°JûÙ2°#JñÚ ²#ÈJúÚE »#ÐJ ÛE ¼#ØJÛE ½#àJ3ÛE ¾#èJFÛ À#ðJQÛ¶Â#øKÂJûÙ2Â#J\Û Ã#€JkÛ¤Æ#ˆJwÛc É#ÀJ|ÛàÏ#À+AŠÙ F™Ù G¨Ù. ##H:­Ù™AE¸Ù"ÀÙAW‡Û F•Ûx eG£Ûl g#GªÛ2 n#G±Û2 o#GºÛ2 p#GÁÛl v# GÑÛl w#(GäÛl z#0GôÛ2 {#8GÜ2 |#@GÜ2 }#HG Ül #PG/Ü2 €#XG<Ü2 #`GIÜD „#hGPÜ• ‡#pA=WÜ "`Ü?IATwÜ FŒÜ AG¡Ü2 H#G©Ü2 I#G±Ü2 P#G»Ül V#?šA¥ÃÜ F×Ü YG¡Ü2 ^#G©Ü2 _#GëÜl b#?ÝAèöÜ FÿÜH SGÝþ T#L TG ÝØ T#GÝØ T#GÚ2 U#GÝX V#G)݈ W# G5Ý“ X#(Ac ;Ý FDÝ GMÝ: #GRÝ: #AbYݼ8Ÿ B Aª aÝ FnÝ DG{Ýù E#G‚ÝE F#GŒÝb G# G˜Ýb H#G Ý P#A ¦Ý F¹Ý G±Ü2 #?U:fA2 ÌÝ N×ÝéÝúÝ Þ?T A_ Þ*F*Þp·G8Þ7½#G=Þ„ Å#h8 B A› Ÿá(F¶áAG¢fl|#A½ ÍáAÈ Õáw"æáAÚ gá&Fá‘G—áð ’#L’G Ý ’#GÝ ’#?Ï A" ïáFøáGâ2#8lB ÇAP â:L:GÑà2:#8o B #Az ªâ,U¶â`J¨Ù  #JÂâÀ #JÉâ #JëÙN#?Å AÐ Îâ'FÚâH5Gæâˆ 7#Gíâb:#Góâ =#8 B A‚úâ A% ã²L²GÑà8 ²#?= AH ã)F+ãXšGBã^ ¢#L¢G¾Þ8 ¢#GÇÞ8 ¢#O‰ ¤#PH¤G©ÞÏ ¦#O¥ ©#P©GJãUª#GXãÖ «#GbãÅ ¯#?Û Aæ åÞFñÞ€XGýÞœ Z#Gß2`#G ß2a#Gߨd#Gß0g#8G!ß2v#@G*ßP y#HLyG¾ÞÖ y#GÇÞÖ y#G4ß[#XGóü&‚#\G=ߨˆ#`?¡ A¬ GßQTߨ°G¨ÙÚ±#Gß2´#G ß2º#Gaßß½#Gmß[¿# Gvß[À#!G~ßÂ#(LÂG¾Þœ Â#GÇÞœ Â#G‰ß2É#8G—ßäÑ#@GŸß2Ô#pGªß2Õ#xG½ß[Ø#€GÁß[Ù#GËß[Ú#‚GÕß[â#ƒGÝß[è#„Gäߨë#ˆG)~$î#¨? ?OAïïßFõß0 GŸß2+#GÙdl.#Gûßb4#G àb5#GàZ8#Gà‚9# G'à£<#(?_Aj+àR2w2}?|S?l?‡A’6à T[2w2w?¨A³DàFKàG'*w#GPWw#AãRàF]à IGhà2K#Gpà2L#Gyà2M#Gƒà2N#8UB ?5A@ŽàFšà`ŒG¨ÙÚŽ#G¦àbš#G­àÌ #G³à€£#L£G¾Þ0£#GÇÞ0£#Gäߨ¦#(G½àê©#HG)~¬#XA×ÀàŠLŠGÑàÖ Š#AõÚàFäà;G)~ =#GÿUb>#8UB A1îàVNQáá5áMáAYfã FyãH G¡Ü2 #G©Ü2 #G±Ü2 &#GŒãl ,#G”ã2 /# G›ã2 2#(G¤ã2 5#0Gªã2 ;#8G»Ül >#@8 B ?ñAüb R2à8bB 8B A'v  F„ -O9D#PDG’ UE#Gž àF#G¢fbI#G¦ bN# >® l P>» l P>Í l OYæ6†;ÞÙ6b;ªæ6[Z°(8†YÝ —†;Ñï—bZ(䙆Yí KU;(äK†;þ KU;­àKl;ÜîKl;ÎæLV;'âLV;"ÚL' Z°(NU[ÈçH2,AáH±,ËiH2-¦—J2?2Y©èúU;Aáú ;ËiúU^PP xP V¥U Uþ ¥U T­à¥l QÜî¥l RÎæ¥V X'â¦V_ZùÑï¦bZ°(¨UZ(䩆.ìP¨«`ùú.¹€¨›bÓ °¨ pP xP ¶pP xP >‚pP xP þbša¤ù¥hP nP ¬li^€P ŠP V`[ Uç`U T­à`l Q“˜û`[ R“Ñïab^P  P V0u[_ÛùçuU_þù­àul Q>ul_!úqRul X“Ñïvb^ P °P VE~[_Wúç~U_zú­à~l Q>~l_úqR~l X“Ñïbh\‡[;(䇆;ç‡U;>‡l;qR‡l^°P ÞP Vq•[ Uç•U_Óú­à•l Q>•l RqR•l_ûÑï–b.ìਙ`Aûú.¹©›bÓ @© ÖP ÞP ¶ÖP ÞP >‚ÖP ÞP þbšafû¥DÈP ÔP ™U_QkRw^àP èP V…§[ Uç§U T­à§l Q™§l R §l X“˜û¨[ Y“Ñï¨b^ðP øP V§±[ U»±U T™±l QñU R ±l X“˜û²[ Y“Ñï²b] è H,"è HÚ[Ë;¤,(ä;†]<è [,"è [Ú4Q ¼Q Vx0`û†0s‘0(ŽQ "Q Fq£"Q oQ G`Óû°(¼oQ wQ H]Óév,Aáv±,Ëiv2\çé;Aá ;ËiwyÀQ ÏR VõN¤wöû(äN†w,ükÛN¹=-P¤(ŽØQ çQ R 4R >R -c`qf7R >R cF7R >R !`büZ >R IR -dqfBR IR dFBR IR !`…üZ IR TR -e¢qfMR TR eFMR TR !`¨üZ TR _R -fÃqfXR _R fFXR _R !`ËüZ _R jR -gäqfcR jR gFcR jR !`îüZ jR uR -hqfnR uR hFnR uR !`ýZ uR €R -i&qfyR €R iFyR €R !`4ýZ(¼€R ˆR kPcG?‡¾=c#G9} c#PdG âÃ=d#G9} d#PeG'âÈ=e#G9} e#PfG.âÍ=f#G9} f#PgG7âÒ=g#G9} g#PhG=â×=h#G9} h#PiGÁ>Ü=i#G9} i#[‚b,/‚w,'*‚|- „b?jA‚¼Y5[;/w;'*|;¦HöZ  bZ\  àZ8Þ àZB |Z‘þ b?û@7[èúb,Ëiúl-°(ül[IÔà,/Ôw,bÔb-ž Öà[hàà,/àw,bàb-ž âà[~™[,8Þ™à[’|,/w,'*|,bb[¢ à,êï à-\ ¢à[¹¬à,/¬w,êï¬à,b¬b-\ ®à]ÍÍ,/Íw,êïÍà,¦HÍöyÐR ÝS VàŽ[wWýçŽww³ý8ÞŽö p©o‡ ©“aþ¹aIþÅalþÑaþÝ.HЩ `²þUaÕþkqíR ñR ‰aúþ.Sª/Pvq$S *S ä`ÿ1a@ÿG 0ªq‚S S Ú`vÿq¶%S *S Û‚%S *S þbša™ÿ¥ `ªq‚*S 4S å`Ðÿ ª GS §S ›GS pS `óÿ¨ Àª ðª(¡S §S qf¡S §S ÐF¡S §S !`O`9ZîS ¡S `\ûaqÊS S °`¢×aÅâ ‚S S q‚‚S ˆS ¦`ûq¶ŠS S §‚ŠS S þbša¥ S ¡S q‚S •S ±`UzàS ÑT Vò©wxç©wwÁ8Þ©ö-ªH«[o‡ «­a¹aWÅazÑaÝ.HP« `ÀUaãkqöS úS ‰aST IT a+vq$T 3T ä`N1aqG €«q‚!T 'T Ú`§q¶.T 3T Û‚.T 3T þbšaÊ¥ 3T IT q‚3T 9T å` °« WT µT ›WT €T `$¨ à« ¬(²T µT qf²T µT ÐF²T µT !`GObZîŽT °T `jûaqÊŽT žT °`°×aÓâ ‘T žT q‚‘T —T ¦` q¶™T žT §‚™T žT þbša,¥ žT °T q‚žT ¤T ±`cjàT U ViU_†­àilgÏÎæl[g'âl[ P°(kUj U rU VU U(ä† TkÛh'_?þ U_ˆ­à€l_«Üî€l_ÎÎæ€V;/€[gñ'âƒ[ P°(‚UYæî°l;­à°lYˆæIˆ ;­àIl&Z°(Nˆ Yíî£l;­à£lZ°(¥lY¥çzl;Gàzˆ Z°(|l];q,(äq†,kÛqh',_r[?¤]f,(ä†,kÛ€h']0 “,8Þ“2,(䓆]I Ä,8ÞÄ2,(äĆ,EWÄU,­àÄl,‘ûÅ[,˜ûÅ[]] š,8Þš2,EWšU]u ¡,8Þ¡2,­à¡l] ¨,8Þ¨2,‘û¨[]§ ¯,8Þ¯2,˜û¯[]Á ¶,8Þ¶2,Û ¶[[Œ¼2,(伆,¡¼Þ(,­½Þ(,­à½l-'*¿7?E YûîŠl;­àŠl&ZËi–lZ ï›lZelZ„è™lZïœl&&ZèlZ•èl}€U [ V·ÈUw)(äȆw%kÛÈh'w…¡ÉÞ(w ­ÉÞ(wm jõÉ[wû þ ÊUwj ­àÊlwÖ ÜîÊl,ÎæÊV,'âÊV,/Ë[x2 dŠÏlxU 8ÞÎ2x± ÿÏlxú ™ÿÏl-°(ÍU-‘ûÐ[-˜ûÐ[o«&@¬Ú`€ ¹& ¾U çU ï&ÊU çU µ`É ý&aì  'Æ&ÊU ØU ¥`Ô&'ØU çU ¥a20'.ã(€¬¶`Uñ( °¬ažþ(aÁ )aä),X 0X ˜` a*(ŽV *V Þqm'*V ™V ß`Mv'q='*V ™V ƒ`pF'`“Q'bÿÿÿÿÿÿÿÿÿ\' ™V W  žV ØV xà'*á7q­'žV ÊV â`¶'`(×'bâ'bí'q'žV ¬V È`K–'`o¡'qù'¬V ³V É`§(`Ë (q(³V ·V Ê`î"(`-(q9(·V »V Ë`5B(bM(qY(»V ¿V Ì`Yb(bm(qy(¿V ÊV Íb( ØV W q™(ØV W æa}Ò(q­'ØV W Ã`¡¶'`Å×'bâ'bí'q'ØV æV È`è–'` ¡'qù'æV ñV É`D(q(ñV õV Ê`h"(`Œ-(q9(õV ùV Ë`¯B(bM(qY(ùV ýV Ì`Ób(bm(qy(ýV W Íb( ଠøW X (¼øW X ë •X ÕX  •X ÕX (•X ™X `÷"(`-( ­ @­ p­  ­m¼KY WY ­'£Y ÇY #`=¶'``Ì'`ƒ×'q'£Y ¦Y È‘È~¡'qù'¦Y ªY É`¦ (q(ªY ®Y Ê`É-((9(®Y ½Y Ë(Y(½Y ÂY Ìqy(ÂY ÇY Íb( Z QZ  2Z QZ m¼2Z >Z +m¼‡Z “Z 0]Ň,(䇆,kÛ‡h'|âB¤,(äB†-kÛD¤Yä·U;(ä·†;kÛ·h';þ ·U;­à¸l;Üî¸l;Îæ¸V;'â¸Vj[ »\ VùÆU_ì(䯆_"kÛÆh'_Xþ ÆU_Ž­àÇl_ÄÜîÇl_üÎæÇV;'âÇVgZ°(ÉUX0*[ 9\ Ë`l0q='*[ 9\ Š`³Q'b\' *[ 9\  M[ 9\ qx0M[ ù[ z`Ö†0(ŽM[ \[ Fq£\[ ©[ G`ù°(¼©[ ¸[ H09\ ~\ Í`«0`?·0`bÃ0`…Ï0‘à~Û0`¨ç0có0fÀ\  ] V8_Ë(ä8† TkÛ8h'_ç8U_7­à9l_Z˜û9[[&}[,8Þ}ö[@v[,8ÞvöhZž[;(䞆;kÛžh';çžU;­àŸl;>Ÿl;qRŸlr] ›a VqÜ_”(ä܆_ÊkÛÜh'_e¡ÝÞ(_í­ÝÞ(_ojõÝ[_¾çÞU_l­àÞl;‘ûÞ[_˜ûÞ[gó'*â7g8Þá2g`~á2Zƒà[mŽK] ^] èm'^] É] é`–v'`¹'q='^] É] ƒ`F'`<Q'bÿÿÿÿÿÿÿÿÿ\'­'ß] ^ ê`œÌ'b×'bâ'bí'q'ß] æ] È`¿–'`ã¡'qù'æ] í] É`(`* (q9(í] ^ Ë`MB(bM( Эm93-^ 6^ ï ® 0® ¬_ ã`  ¬_ ã`  Ä_ ã` k3Ä_ ã`  `q†3`©’3bª3`̶3X0Ä_ Ì` ¢`ïl0q='Ä_ Ì` Š`'Q'b\' Ä_ Ì`  î_ Ì` qx0î_ Œ` z(Žî_ ö_ Fq£ö_ C` G`_°(¼C` K` H­'v^ ¢^ `‚¶'q'v^ z^ È`¥–'`È¡'qù'z^ Š^ É`ë(‘ø} (q(Š^ ^ Ê`"(c-(q9(^ ”^ Ë`1B(qY(”^ ™^ Ì`Tb(qy(™^ ¢^ Íb( ã` Ra ù'a a ú`w(‘ø} ((a a û`š"(mR3a &a ü9()a .a ü`½B( `®m93_ _  ®ù'…_ Ž_ (`à(`  (m(Ž_ “_ )mR3“_ ž_ +mR3ž_ ¬_ ,m9(Ta Ya +m¼}a ‰a 4f a _c VŒG_& (äG†_\ kÛGh'_’ çGU_ð ­àHl_&!‘ûH[_Š!˜ûH[X0Ãa Òb P`Ù!l0q='Ãa Òb Š`ü!Q'b\' Ãa Òb  æa Òb qx0æa ’b z`"†0(Žæa õa Fq£õa Bb G`B"°(¼Bb Qb Hf`c ±d V¢j_e"(äj†_›"kÛjh'_Ñ"çjU_#­àkl_e#˜ûk[X0€c d n`´#l0q='€c d Š`×#Q'b\' €c d  £c d qx0£c Od z`ú#†0(Ž£c ²c Fq£²c ÿc G`$°(¼ÿc d H4Àd #f Vk3`@$z3`v$†3`¬$’3`â$ž3`%ª3`P%¶3X0êd ùe ¢`®%l0q='êd ùe Š`Ñ%Q'b\' êd ùe  e ùe qx0 e ¹e z`ô%†0(Ž e e Fq£e ie G`&°(¼ie xe H~0f ›f VºÆ[^ f ®f VȾà Uà¾l?Ÿ??i?•?Æ?×?è?ët@× æØå×À®°f >IA ÀD8MB^?R@W"$!:fN×ÝéÝúÝ Þy°f ¸f V[,Ü-°(.ÜyÀf Ëf Vq9çU“"Ú9ÜAeÌÝ "\Ø÷=@× ‡å×Ðf íg Dë;Q@@"\Ø[ù¯,­à°,Üî°,ÎæÍ,'âÍ-dŠ °-°( ¯&-¯-ÿ°MA»£ØAƪØ\"ºØ?@yÐf ×g V#¯w:&þ #¯wp&­à#°w¹&Üî#°w'Îæ#Íw_''â$ÍxÐ'°(&¯->'° ð® ¯oGP¯@`(T`<(_`r(ua¨(€aË(‹ Bg ƒg a)—a$)¢yàg íg V)K@UçK¯T­àK°Æ¾=@× >Lå×ðg cÑ E›D QAOŠÙF™ÙG¨Ùf##Hr­Ù™A}¸Ù"ÀÙ"\ØW£¡ô 8­B§@²A½³FÄ(G8Þ #GÞ>##GÕ4#Gß;#GèP# FìG÷„#?(@-"$!"Ù?@@EA ý?UT}2z2„2¡2¢2¡2„?@„A£ØAšªØ\"ºØM?„:fWÄè @8­B§ WæÞ p'8­B§WÚ (8B§@A$/FBG8Þ #GGàI#?NTd2z2„2„?­WU¡Ö  (Wo•à Ð(8­B§Wƒ¿ Ð-WŸ¡» à-WÃãµ .8­B§Wá± À-Wû¡­ °.Wã§ à.W9£ °-WR¡Ÿ €/Wss” °/8­B§WŽã -W§ã† p,WÁã Ð+WÛ×z €+8­B§?èAóøQ ø !Gøë„"#GâÙ4##G'#$#G1ÚÖ%#GnÚÖ&#G„'# G$„(#(G`ó,#0G+„/#¨G;Ù0#°GIÙ1#¸GWÙ2#ÀGg4#ÈGIÜë5#èGPÜ<6#ðAáÍáAìÕáw"æáAþ‡Û F•Ûx eG£Û„ g#GªÛÙ n#G±ÛÙ o#GºÛÙ p#GÁÛ„ v# GÑÛ„ w#(GäÛ„ z#0GôÛÙ {#8GÜÙ |#@GÜÙ }#HG Ü„ #PG/ÜÙ €#XG<ÜÙ #`GIÜë „#hGPÜ< ‡#pAäWÜ "`Ü?ðAûwÜ FŒÜ AG¡ÜÙ H#G©ÜÙ I#G±ÜÙ P#G»Ü„ V#?AALÃÜ F×Ü YG¡ÜÙ ^#G©ÜÙ _#GëÜ„ b#8‹B§#A–fã FyãH G¡ÜÙ #G©ÜÙ #G±ÜÙ &#GŒã„ ,#G”ãÙ /# G›ãÙ 2#(G¤ãÙ 5#0GªãÙ ;#8G»Ü„ >#@Wgæp P&WqI^ ð#8­B§W}Z @1W¡V P1W«¡S €1WÀO 01WÑ¡K °1Wê¡H à1WýD  1W ¡@ 2W%; @28­B§W77 à#WB¡3 À2WUi+ ð28­B§Wb% `#WÖã¡ 8 Ø3 @¦A±æã UìãP 0Jóü` 1#Jò㈠4#JùãÙ 4#J äÙ 4#JäÐ 4# J(ä_ 4#(J.ä\ 4#0J;ä4 4#8JIä„ 4##8¡B§AXîàVNQáá5áMáA€gá&Fá‘G—á–’#L’G ݸ’#Gݸ’#?u?B8ÎB§AÙŸá(F¶áAG¢f„|#AûïáFøáGâÙ#8„B§ÇA)â:L:GÑà½:#HHâ5K8-J?‡·.#J âò/#J'â0#J.âO1#J7â`2# J=âq3#(JÁ>§4#0?¼HÈCâT¡2¡2„2„2í2í24?„?÷HQâT„2¡2„2„24?#H/`âT„2¡2„2„2„24?TH/oâ?eH/€â?vH‚Žâ$T„2¡2„2„2„2„24?¬H¸œâ+T„2¡2„2¡2„2„248éB§#Aôªâ,U¶â`J¨ÙD #JÂâ:#JÉâ”#JëÙ‹#??AJÎâ'FÚâH5Gæâ8 7#Gíâ4:#Góâ}=#8‰B§Ašúâ AŸã²L²GÑಲ#?·AÂã)F+ãXšGBãØ¢#L¢G¾Þ²¢#GÇÞ²¢#O¤#PH¤G©Þu¦#O©#P©GJ㡪#GXã‘«#Gbã?¯#8”B§?aAlÛä.UéäÓJ÷ä Ô#Aå :N 6å*å>å?¬A·UåFbå0Gpà„#Ghà„#G7,„#Goå„#Gzå# 8B§AåFåG6ß¡#Ge„#WnX P8­B§EwIö ðDDæ…{@„Dƒ…tD“…mD¡…fD¬…_Dº…XDÇ…CDÝ…<DZÙ…5Dë…QDð…-D…&D …D…‰E1æì ÐE=×ç 04EN×â à3EaÙ PQ[kd,8Þ;jðg Óh Vz‰}_G)Þ>‰#_})Ûð‰¡_³)àð‰¢_é)èð‰¡_!*íðŠ„ ‘ ˆŽо ‘ð~%ñ–¾gY*•E„g¥*°(Œ}gß*8Þdzzh h œ`+‡] èH,"èH YŽ„;`ã]<è[,"è[ ^àh yj Vï„k°(ñ„väh i ó`%+ i \j  i \j  €¯ À¯gH+‘þ 4 ° @° p°p‹ °  j \j Z¦ 4¦\j hj #U¯[¨d,8Þd,Gà„-ßd[»#î,8Þ#;?^€j ýl VÌ(}_•+Þ>(#_Ë+×(¢¾_P,ñ(¢_›,Þ)¢g4-êï,#g}-å,#g³-ê,#gé-‘þ-„g4.î-„gj.¦-„g .8Þ.dZ°(+} а ± åj Ol zéj òj <`Ã.‡ 0±Zó=d `± ±gæ.\ Adp¦бB ½k l g /GàR§¾g?/ùSîÕ×k Ük \`b/âjm Pm Vÿ©}_…/Þ>©#_Î/ñ©¢_0 ñ©¢Z°(«}jPm hn V¸}_`0%ñ¸z_–0)ñ¸„_Ì0Ûð¸¡_1àð¸¢_;1èð¹¡_r1íð¹„g©18Þ¼dgÌ1‘þ½„Z°(»} žm n  ªm n  ªm n z´m ºm É`ï1‡ ¿m æm ¦Òm æm Ïa2É òm n g52ùÑîÕòm öm Ô`X2â~pn “n Vê„^ n ÿn V)Í}_Ž2%ñÍz_Ä2)ñÍ„_ 3ÛðÍ¡_03àðÍ¢ XèðÍ¡ YíðÍ„°(Í}Z5Í# Än ùn  Än ùn  În ùn  ² án ùn gS3<Í„^o šo VDÐ}_v3%ñÐz_¿3)ñЄ_õ3ÛðС_+4àðТ_a4èðÑ¡_—4íðÑ„°(Ó}ZNÔÙvo &o Ö`Í4 ?o |o  ?o |o  Io |o  0² co |o gð4<Ú„¦|o ˆo ÞU¯^ o 5p VU'}_5%ñ'z_\5)ñ'„_’5Ûð'¡_È5àð'¢_þ5èð'¡_46íð'„gj65'¢°('}vºo Æo '` 6 äo p  äo p  îo p  `² p p gÃ6<'„¦p #p 'U¯^@p Õp Vg(}_æ6%ñ(z_/7)ñ(„_e7Ûð(¡_›7àð(¢_Ñ7èð(¡_8íð(„g=85(„°((}vZp fp (``8 „p ·p  „p ·p  Žp ·p  ² ¡p ·p gƒ8<(„¦·p Ãp (U¯^àp uq V{)}_¦8%ñ)z_ï8)ñ)„_%9Ûð)¡_[9àð)¢_‘9èð)¡_Ç9íð)„gý95)„°()}vúp q )` : $q Wq  $q Wq  .q Wq  À² Aq Wq gC:<)„¦Wq cq )U¯^€q r VŒ*}_f:%ñ*z_¯:)ñ*„_å:Ûð*¡_;àð*¢_Q;èð*¡_‡;íð*„g½;5*„°(*}všq ¦q *`à; Äq ÷q  Äq ÷q  Îq ÷q  ð² áq ÷q g<<*„¦÷q r *U¯^ r µr VŸ+}_&<%ñ+z_o<)ñ+„_¥<Ûð+¡_Û<àð+¢_=èð+¡_G=íð+„g}=5+„°(+}v:r Fr +` = dr —r  dr —r  nr —r  ³ r —r gÃ=<+„¦—r £r +U¯^Àr Us V²,}_æ=%ñ,z_/>)ñ,„_e>Ûð,¡_›>àð,¢_Ñ>èð,¡_?íð,„g=?5,„°(,}vÚr ær ,``? s 7s  s 7s  s 7s  P³ !s 7s gƒ?<,„¦7s Cs ,U¯^`s ¶s VÞd_¦?%ñžz T)ñž„_Ü?‘þž„Z°( dvjs vs ¢`@¦¢s ®s ªU¯^Às kt VØ3}_5@%ñ3z_k@)ñ3„_¡@Ûð3¡_ê@àð3¢_4Aèð3¡_jAíð3„g A534°(3}vás ís 3`ÅA t Mt  t Mt  (t Mt  €³ :t Mt gèA<3„¦Mt Yt 3U¯^pt u Vô.}_ B%ñ.z_AB)ñ.„_wBÛð.¡_ÀBàð.¢_ Cèð.¡_@Cíð.„gvC5.#°(.}v‘t t .`™C Ìt u  Ìt u  Út u  °³ ít u g¼C<.„¦u  u .U¯^ u Îu V /}_ßC%ñ/z_D)ñ/„_KDÛð/¡_”Dàð/¢_ÞDèð/¡_Eíð/„gJE5/Ö°(/}vAu Mu /`mE |u °u  |u °u  Šu °u  à³ u °u gE</„¦°u ¼u /U¯^Ðu ~v V,1}_³E%ñ1z_éE)ñ1„_FÛð1¡_hFàð1¢_²Fèð1¡_èFíð1„gG51Ö°(1}vñu ýu 1`AG ,v `v  ,v `v  :v `v  ´ Mv `v gdG<1„¦`v lv 1U¯^€v .w VJ4}_‡G%ñ4z_½G)ñ4„_óGÛð4¡_y V™8}_M%ñ8z_9M)ñ8„_oMÛð8¡_¸Màð8¢_Nèð8¡_8Níð8„gnN58Ù°(8}v±x ½x 8`‘N ìx  y  ìx  y  úx  y  д y  y g´N<8„¦ y ,y 8U¯^@y îy V³:}_×N%ñ:z_ O)ñ:„_COÛð:¡_ŒOàð:¢_ÖOèð:¡_ Píð:„gBP5:Ù°(:}vay my :`eP œy Ðy  œy Ðy  ªy Ðy  µ ½y Ðy gˆP<:„¦Ðy Üy :U¯^ðy žz VÏ<}_«P%ñ<z_áP)ñ<„_QÛð<¡_`Qàð<¢_ªQèð<¡_àQíð<„gR5<Ù°(<}vz z <`9R Lz €z  Lz €z  Zz €z  0µ mz €z g\R<<„¦€z Œz <U¯^ z ¿z Vé•d U%ñ•z T)ñ•„ Q¦•„^Àz |{ VŠ}_R%ñŠz_µR)ñŠ„_ëRÛðŠ¡_4SàðŠ¢_~SèðŠ¡_´SíðŠ„gêS5ŠÙ°(Š}váz íz Š` T *{ ^{  *{ ^{  8{ ^{  `µ K{ ^{ g0T<Š„¦^{ j{ ŠU¯^€{ =| V-Œ}_ST%ñŒz_‰T)ñŒ„_¿TÛðŒ¡_UàðŒ¢_RUèðŒ¡_ˆUíðŒ„g¾U5ŒÙ°(Œ}v¡{ ­{ Œ`áU ë{ |  ë{ |  ù{ |  µ | | gV<Œ„¦| +| ŒU¯^@| ü| VRŽ}_'V%ñŽz_]V)ñŽ„_“VÛðŽ¡_ÜVàðŽ¢_&WèðŽ¡_\WíðŽ„g’W5ŽÙ°(Ž}va| m| Ž`µW ª| Þ|  ª| Þ|  ¸| Þ|  Àµ Ë| Þ| gØW<Ž„¦Þ| ê| ŽU¯^} ½} Vy‘}_ûW%ñ‘z_1X)ñ‘„_gXÛð‘¡_°Xàð‘¢_úXèð‘¡_0Yíð‘„gfY5‘„°(‘}v!} -} ‘`‰Y k} Ÿ}  k} Ÿ}  y} Ÿ}  ðµ Œ} Ÿ} g¬Y<‘„¦Ÿ} «} ‘U¯^À} ß} V¡‚d U%ñ‚z T)ñ‚„ Q¦‚„^à} œ~ V¾x}_ÏY%ñxz_Z)ñx„_;ZÛðx¡_„Zàðx¢_ÎZèðx¡_[íðx„g:[5xÙ°(x}v~  ~ x`][ J~ ~~  J~ ~~  X~ ~~  ¶ k~ ~~ g€[<x„¦~~ Š~ xU¯^ ~ ] Váz}_£[%ñzz_Ù[)ñz„_\Ûðz¡_X\àðz¢_¢\èðz¡_Ø\íðz„g]5zÙ°(z}vÁ~ Í~ z`1]  ?   ?   ?  P¶ , ? gT]<z„¦? K zU¯^` € V|}_w]%ñ|z_­])ñ|„_ã]Ûð|¡_,^àð|¢_v^èð|¡_¬^íð|„gâ^5|Ù°(|}v  |`_ Ë ÿ  Ë ÿ  Ù ÿ  €¶ ì ÿ g(_<|„¦ÿ  € |U¯^ € Ý€ V)~}_K_%ñ~z__)ñ~„_·_Ûð~¡_`àð~¢_J`èð~¡_€`íð~„g¶`5~„°(~}vA€ M€ ~`Ù` ‹€ ¿€  ‹€ ¿€  ™€ ¿€  °¶ ¬€ ¿€ gü`<~„¦¿€ Ë€ ~U¯^à€ ÷€ VLpd U%ñpz T)ñp„ Q¦p„^ ¸ Vh\}_a%ñ\z_Ua)ñ\„_‹aÛð\¡_Ôaàð\¢_bèð\¡_Tbíð\„gŠb5\Ù°(\}v! - \`­b f š  f š  t š  à¶ ‡ š gÐb<\„¦š ¦ \U¯^À x‚ VŠ^}_ób%ñ^z_)c)ñ^„__cÛð^¡_¨càð^¢_òcèð^¡_(díð^„g^d5^Ù°(^}vá í ^`d &‚ Z‚  &‚ Z‚  4‚ Z‚  · G‚ Z‚ g¤d<^„¦Z‚ f‚ ^U¯^€‚ 8ƒ V¬`}_Çd%ñ`z_ýd)ñ`„_3eÛð`¡_|eàð`¢_Æeèð`¡_üeíð`„g2f5`Ù°(`}v¡‚ ­‚ ``Uf æ‚ ƒ  æ‚ ƒ  ô‚ ƒ  @· ƒ ƒ gxf<`„¦ƒ &ƒ `U¯^@ƒ øƒ VÐb}_›f%ñbz_Ñf)ñb„_gÛðb¡_Pgàðb¢_šgèðb¡_Ðgíðb„gh5b„°(b}vaƒ mƒ b`)h ¦ƒ Úƒ  ¦ƒ Úƒ  ´ƒ Úƒ  p· ǃ Úƒ gLh<b„¦Úƒ æƒ bU¯^„ ¸„ Vòd}_oh%ñdz_¥h)ñd„_ÛhÛðd¡_$iàðd¢_nièðd¡_¤iíðd„gÚi5dÙ°(d}v!„ -„ d`ýi f„ š„  f„ š„  t„ š„   · ‡„ š„ g j<d„¦š„ ¦„ dU¯^À„ x… Vf}_Cj%ñfz_yj)ñf„_¯jÛðf¡_øjàðf¢_Bkèðf¡_xkíðf„g®k5fÙ°(f}vá„ í„ f`Ñk &… Z…  &… Z…  4… Z…  з G… Z… gôk<f„¦Z… f… fU¯^€… 8† V6h}_l%ñhz_Ml)ñh„_ƒlÛðh¡_Ìlàðh¢_mèðh¡_Lmíðh„g‚m5hÙ°(h}v¡… ­… h`¥m æ… †  æ… †  ô… †  ¸ † † gÈm<h„¦† &† hU¯^@† ø† VVj}_ëm%ñjz_!n)ñj„_WnÛðj¡_ nàðj¢_ênèðj¡_ oíðj„gVo5jÙ°(j}va† m† j`yo ¦† Ú†  ¦† Ú†  ´† Ú†  0¸ dž Ú† gœo<j„¦Ú† æ† jU¯^‡ ¸‡ Vxl}_¿o%ñlz_õo)ñl„_+pÛðl¡_tpàðl¢_¾pèðl¡_ôpíðl„g*q5l„°(l}v!‡ -‡ l`Mq f‡ š‡  f‡ š‡  t‡ š‡  `¸ ‡‡ š‡ gpq<l„¦š‡ ¦‡ lU¯^À‡ qˆ VšS}_“q%ñSz_Éq)ñS„_ÿqÛðS¡_HràðS¢_’rèðS¡_ÈríðS„gþr5S„°(S}vᇠí‡ S`!s ˆ Sˆ  ˆ Sˆ  -ˆ Sˆ  ¸ @ˆ Sˆ gDs<S„¦Sˆ _ˆ SU¯^€ˆ 1‰ V¼U}_gs%ñUz_s)ñU„_ÓsÛðU¡_tàðU¢_ftèðU¡_œtíðU„gÒt5UÙ°(U}v¡ˆ ­ˆ U`õt ߈ ‰  ߈ ‰  íˆ ‰  À¸ ‰ ‰ gu<U„¦‰ ‰ UU¯^@‰ ñ‰ VÜW}_;u%ñWz_qu)ñW„_§uÛðW¡_ðuàðW¢_:vèðW¡_pvíðW„g¦v5WÙ°(W}va‰ m‰ W`Év Ÿ‰ Ó‰  Ÿ‰ Ó‰  ­‰ Ó‰  ð¸ À‰ Ó‰ gìv<W„¦Ó‰ ߉ WU¯^Š ±Š VüY}_w%ñYz_Ew)ñY„_{wÛðY¡_ÄwàðY¢_xèðY¡_DxíðY„gzx5YÙ°(Y}v!Š -Š Y`x _Š “Š  _Š “Š  mŠ “Š  ¹ €Š “Š gÀx<Y„¦“Š ŸŠ YU¯^ÀŠ n‹ VK}_ãx%ñKz_y)ñK„_OyÛðK¡_˜yàðK¢_âyèðK¡_zíðK„gNz5K„°(K}vአíŠ K`qz ‹ P‹  ‹ P‹  *‹ P‹  P¹ =‹ P‹ g”z<K„¦P‹ \‹ KU¯^p‹ Œ VAM}_·z%ñMz_íz)ñM„_#{ÛðM¡_l{àðM¢_¶{èðM¡_ì{íðM„g"|5MÙ°(M}v‘‹ ‹ M`E| Ì‹ Œ  Ì‹ Œ  Ú‹ Œ  €¹ í‹ Œ gh|<M„¦Œ  Œ MU¯^ Œ ÎŒ VbO}_‹|%ñOz_Á|)ñO„_÷|ÛðO¡_@}àðO¢_Š}èðO¡_À}íðO„gö}5OÙ°(O}vAŒ MŒ O`~ |Œ °Œ  |Œ °Œ  ŠŒ °Œ  °¹ Œ °Œ g<~<O„¦°Œ ¼Œ OU¯^ÐŒ ~ VƒQ}__~%ñQz_•~)ñQ„_Ë~ÛðQ¡_àðQ¢_^èðQ¡_”íðQ„gÊ5QÙ°(Q}vñŒ ýŒ Q`í , `  , `  : `  ๠M ` g€<Q„¦` l QU¯^€ 1Ž V¦C}_3€%ñCz_i€)ñC„_Ÿ€ÛðC¡_è€àðC¢_2èðC¡_híðC„gž5C„°(C}v¡ ­ C`Á ß Ž  ß Ž  í Ž  º Ž Ž gä<C„¦Ž Ž CU¯^@Ž ñŽ VÉE}_‚%ñEz_=‚)ñE„_s‚ÛðE¡_¼‚àðE¢_ƒèðE¡_<ƒíðE„grƒ5EÙ°(E}vaŽ mŽ E`•ƒ ŸŽ ÓŽ  ŸŽ ÓŽ  ­Ž ÓŽ  @º ÀŽ ÓŽ g¸ƒ<E„¦ÓŽ ߎ EU¯^ ± VêG}_Ûƒ%ñGz_„)ñG„_G„ÛðG¡_„àðG¢_Ú„èðG¡_…íðG„gF…5GÙ°(G}v! - G`i… _ “  _ “  m “  pº € “ gŒ…<G„¦“ Ÿ GU¯^À q V I}_¯…%ñIz_å…)ñI„_†ÛðI¡_d†àðI¢_®†èðI¡_ä†íðI„g‡5IÙ°(I}vá í I`=‡  S   S  - S   º @ S g`‡<I„¦S _ IU¯^€ .‘ V.>}_ƒ‡%ñ>z_¹‡)ñ>„_ï‡Ûð>¡_8ˆàð>¢_‚ˆèð>¡_¸ˆíð>„gîˆ5>„°(>}v¡ ­ >`‰ Ü ‘  Ü ‘  ê ‘  к ý ‘ g4‰<>„¦‘ ‘ >U¯^0‘ Þ‘ VQ@}_W‰%ñ@z_‰)ñ@„_ÉÛð@¡_ Šàð@¢_VŠèð@¡_ŒŠíð@„gŠ5@„°(@}vQ‘ ]‘ @`åŠ Œ‘ À‘  Œ‘ À‘  š‘ À‘  » ­‘ À‘ g‹<@„¦À‘ Ì‘ @U¯^à‘ ë‘ Vw¨} U%ñ¨z T)ñ¨„ QÛ𨡠Ràð©¢ Xèð©¡ Yíð©„Z°(«}Z5¬„^ð‘ û‘ V“Á} U%ñÁz T)ñÁ„ QÛðÁ¡ RàðÁ¢ Xèð¡ Yíð„Z°(Ä}Z5Å„^’  ’ V£Ú} U%ñÚz T)ñÚ„ QÛðÚ¡ RàðÚ¢ XèðÛ¡ YíðÛ„Z°(Ý}Z±Þ#^’ ’ Vºñ} U%ññz T)ññ„ QÛðñ¡ Ràðñ¢ Xèðò¡ Yíðò„Z°(ô}Z5õ„^ ’ +’ VÉ } U%ñ z T)ñ „ QÛð ¡ Ràð ¢ Xèð ¡ Yíð „Z°( }ZØ„ZÊæj€^0’ ;’ Vâ"} U%ñ"z T)ñ"„ QÛð"¡ Ràð"¢ Xèð"¡ Yíð"„Z°("}Z5"Ù^@’ K’ Vô#} U%ñ#z T)ñ#„ QÛð#¡ Ràð#¢ Xèð#¡ Yíð#„Z°(#}Z5#„^P’ Æ’ V }_+‹%ñz T)ñ„_a‹Ûð¡_—‹àð¢_Í‹èð¡_Œíð„g9Œ¢î4Z°(}vj’ v’  `^Œ¦¨’ ´’ U¯^Ð’ ñ“ V }_Œ%ñz_ÊŒ)ñ„_LÛð¡_‚àð¢_¸èð¡_îíð„°(}k‘þ4Z1 4vê’ ö’  `$ަӓ ß“ /U¯^” ‰” V7 4}_GŽ%ñ4z_Ž)ñ4„_ÆŽÛð4¡_àð5¢_Eèð5¡_{íð5„g±°(7} 0» `»gé5:„ » À» ð» ¼ g” |” g <;„^” • VP N}_/%ñNz_x)ñN„_®ÛðN¡_÷àðO¢_-‘èðO¡_c‘íðO„g™‘°(Q} P¼ €¼gÑ‘5T„ °¼ ༠½ @½ ÷”  • gô‘<U„^ • €• Vf g}_’%ñgz_M’)ñg„_ƒ’Ûðg¡_¦’àðg¢ Xèðg¡ Yíðg„k5g„°(g} A• z•  A• z•  K• z•  p½ b• z• gÉ’<g„^€• à• Vy h}_ì’%ñhz_"“)ñh„_X“Ûðh¡_{“àðh¢ Xèðh¡ Yíðh„k€ 5h„°(h} ¡• Ú•  ¡• Ú•  «• Ú•   ½ • Ú• gž“<h„^à• B– V‰ i}_Á“%ñiz_÷“)ñi„_@”Ûði¡_c”àði¢ Xèði¡ Yíði„g†”5i„°(i} – <–  – <–  – <–  н $– <– g©”<i„^P– ®– VŸ j}_Ì”%ñjz_•)ñj„_8•Ûðj¡_[•àðj¢ Xèðj¡ Yíðj„k$5j4°(j} p– ¨–  p– ¨–  z– ¨–  ¾ – ¨– g~•<j„^°– — V° k}_¡•%ñkz_ו)ñk„_ –Ûðk¡_C–àðk¢ Xèðk¡ Yíðk„gf–5k4°(k} Õ–  —  Õ–  —  ß–  —  0¾ ñ–  — g‹–<k„^— o— V x}_®–%ñxz_ä–)ñx„_-—Ûðx¡_P—àðx¢ Xèðx¡ Yíðx„gs—5x4°(x} 5— i—  5— i—  ?— i—  `¾ Q— i— g˜—<x„^p— Ï— VÔ ƒ}_»—%ñƒz_ñ—)ñƒ„_:˜Ûðƒ¡_]˜àðƒ¢ Xèðƒ¡ Yíðƒ„g€˜5ƒ4°(ƒ} •— É—  •— É—  Ÿ— É—  ¾ ±— É— g¥˜<ƒ„Yè ˜„Z`šã&Z{ݰè^З û™ Vñ }_Ș%ñz_–™)ñ„_ò™Ûð¡_;šàð¢_qšèð‘¡_§šíð‘„gÝš¢î”4°(“}vð— ü— –`› À¾.™k𾘠¿m‹‘˜  ™ ª P¿ €¿ °¿ à¿ Á™ Ú™ g%›<„¦Ú™ æ™ ¡U¯^š š V!‡d U%ñ‡z T)ñ‡„ Q‘þ‡„Y¥çz„;Gàz8 Z°(|„Yºç‚„;Gà‚8 ^ š “š V!„}_H›%ñ„z_k›)ñ„„_´›Ûð„¡_×›àð„¢ Xèð„¡ Yíð„„gú›5„„°(„}}mGš Rš „`œ‹mVmGš Rš †`Bœdmagœpm Xš š  Xš š  bš š  À uš š gŠœ<„„^ š ¿š V2!{d U%ñ{z T)ñ{„ Q‘þ{„^Àš )› VF!y}_­œ%ñyz_М)ñy„_Ûðy¡_<àðy¢ Xèðy¡ Yíðy„g_5y„°(y}}mÝš èš yVmÝš èš †a‚pm îš #›  îš #›  øš #›  @À › #› g¥<y„^0› G› V]!pd U%ñpz T)ñp„ Q‘þp„^P› »› Vp!l}_È%ñlz_ë)ñl„_4žÛðl¡_Wžàðl¢ Xèðl¡ Yíðl„gzž5l„°(l} €› µ›  €› µ›  Š› µ›  pÀ › µ› gž<l„^À› )œ V†!m}_Àž%ñmz_ãž)ñm„_,ŸÛðm¡_OŸàðm¢ Xèðm¡ Yíðm„grŸ5m²¾°(m} ï› #œ  ï› #œ  ù› #œ   À œ #œ g—Ÿ<m„^0œ œœ V!n}_ºŸ%ñnz_ÝŸ)ñn„_& Ûðn¡_I àðn¢ Xèðn¡ Yíðn„gl 5n„°(n} aœ –œ  aœ –œ  kœ –œ  ÐÀ ~œ –œ g <n„^ œ èœ V·!ñd_² %ññz T)ññ„_Õ ‘þñ„Z°(ódv­œ ¼œ õ` ¡¦Òœ Úœ ý`.¡¯^ðœ  VÅ!8}_Q¡%ñ8z_t¡)ñ8„ QÛð8¡ Ràð8¢ Xèð9¡ Yíð9„°(;}^ T V×!G}_ª¡%ñGz_Í¡)ñG„ QÛðG¡ RàðG¢ XèðH¡ YíðH„°(J}Yæ6_ ;ÞÙ64;ªæ6„Z°(8_ [ÈçHÙ,AáH‘u,ËiHÙ-¦—JÙ?ÙY©èú¡;AáúË ;Ëiú¡^` Öž Vé!V}_¢%ñVz_&¢)ñV„_‚¢ÛðV¡_ò¢àðV¢_P£èðW¡_†£íðW„"Ú]åg¼£ù!\åg2¤'Z#gh¤Ñï[4°(Y}vŠ › _`¤ ¹ í  É í Z‘þb}Zjñc„ Á 0Ág°¤(ät_ ./u`Át`Ó¤=ubIuaø¤Uu Á Àž Ìž –uÀž Ìž >buÀž Ìž þbzua.¥…u hž Ÿž  hž Ÿž  vž Ÿž  ÀÁ ‰ž Ÿž ge¥<…„¦Ÿž «ž ‰`ˆ¥¯^àž žŸ V"Ž}_«¥%ñŽz_Î¥)ñŽ„_¦ÛðŽ¡_s¦àð¢_¼¦èð¡_§íð„gN§(ä“_ gq§°(‘}ZÑï’4./uðÁ•bIua©§Uu  ‰Ÿ ”Ÿ –u‰Ÿ ”Ÿ >bu‰Ÿ ”Ÿ þbzuaß§…u P €Âg¨5œ„ °Â à à @à cŸ xŸ g9¨<„^ Ÿ ^  V "°}_\¨%ñ°z_¨)ñ°„_ȨÛð°¡_$©àð±¢_m©èð±¡_¶©íð±„gÿ©(äµ_ g"ª°(³}ZÑï´4./up÷bIuaZªUu  Ã I  T  –uI  T  >buI  T  þbzuaª…u Ðà ÄgǪ5¾„ 0Ä `Ä Ä ÀÄ #  8  gêª<¿„^`  #¢ V7"Ò}_ «%ñÒz_0«)ñÒ„_Œ«ÛðÒ¡_û«àðÓ¢_W¬èðÓ¡_³¬íðÓ„g­ÑïÖ4g6­(ä×_ Z°(Õ}vˆ  ”  Ù`Y­ ðÄ./u ÅÛ`|­=ubIua¡­Uu PÅ ¢ ¢ –u¢ ¢ >bu¢ ¢ þbzua×­…u Ë  ì¡  Ë  ì¡  €Åg®O"Ý<ZÝ< ÀÅ ðÅ Æ PÆ ß¡ ì¡ g2®<á„ €ÆgU®ã<¦ñ¡ ý¡ ì`y®¯r0¢ ‚£ V_"_œ®Ñï4_Ö®íü„vR¢ ^¢ `O¯ °ÆZ¢î4 àÆ Çgr¯m"½¾k‘þ4 ˆ¢ È¢ /u‘¢ ¼¢ bIua—¯Uu PÇ Ÿ¢ §¢ –uŸ¢ §¢ >buŸ¢ §¢ þbzuaͯ…u.¦€Ç!`°¯ °Çg:°u"(_ ./uàÇ,`]°=ubIua‚°Uu È `£ f£ –u`£ f£ >bu`£ f£ þbzua¸°…u.¦@È/`ï°¯YÏë aZâë a&&ZJW aC?Hêë :KX :Jøë„ :#J¦H¦ :#ANì Uì JÝf #K J Ý© #JÝ© #J:x® #JPW¡ #?CA¹&ìAÄ0ìv?ÉQCì gGUììh#G[ìýi#GkìB€j#?€Ftì9G‘ì5€:#G›ì¡;#G¡ìý<#?:€R2¡8-C§ïY¨ì aj€Zâë a?¦Y³ì dj€ZÊæ fj€\Àì a;¦H aj€Zâë a\±í a;âë a^£ V¦ V|"¼}_%±%ñ¼z_ê²)ñ¼„_´Ûð¼¡_™´àð¼¢_ù´èð½¡_Bµíð½„gÛµŽ"Á4°(¿}ZÊæÀj€.o€pÈÆ.O€ È f.ã~ðÈ a 0É pÉaÿµÿ~p­€ É a ÐÉ Ê @Ê pÊ.Š€ Ê l.ã~ÐÊ a Ë Å¥ 4¦ a7¶ÿ~m­€ ¦ ¦  a 0Ë `Ë.Š€Ë o.ã~ÀË a ðË L¥ Å¥ ao¶ÿ~m­€œ¥ °¥  avL¤ X¤ È`§¶ ~¤ ·¤  ~¤ ·¤  Œ¤ ·¤  Ì ¢¤ ·¤ gʶ<΄¦·¤ ä Ò`í¶¯^`¦ ᨠV™"×}_·%ñ×z_œ¸)ñׄ_¶¹Ûðס_ÿ¹àð×¢_7ºèðØ¡_кíðØ„ge»Ž"Ü4°(Ú}ZÊæÛj€.o€PÌá.O€€Ì f.ã~ÐÌ a Í PÍa§»ÿ~p­€€Í a °Í ðÍ Î PÎ.Š€€Î l.ã~°Î a àÎ O¨ ¿¨ aß»ÿ~m­€”¨ §¨  a Ï @Ï.Š€pÏ o.ã~ Ï a ÐÏ Ö§ O¨ a¼ÿ~m­€&¨ :¨  a^ð¨ q« Vª"ò}_O¼%ñòz_Û½)ñò„_õ¾Ûðò¡_>¿àðó¢_v¿èðó¡_Àíðó„g¤ÀŽ"÷4°(õ}ZÊæöj€.o€Ðü.O€0Ð f.ã~€Ð a ÀÐ ÑaæÀÿ~p­€0Ñ a `Ñ  Ñ ÐÑ Ò.Š€0Ò l.ã~`Ò a Ò ߪ O« aÁÿ~m­€$« 7«  a ÀÒ ðÒ.Š€ Ó o.ã~PÓ a €Ó fª ߪ aVÁÿ~m­€¶ª ʪ  a^€« å« V½"ö}_ŽÁ%ñöz_×Á)ñö„_ ÂÛðö¡_CÂàðö¢ Xèðö¡ Yíðö„gfÂ5ö„°(ö} §« ß«  §« ß«  ±« ß«  °Ó Ï« ß« Z<ö„^ð« R¬ VË"÷}_ŸÂ%ñ÷z_ÕÂ)ñ÷„_ÃÛð÷¡_AÃàð÷¢ Xèð÷¡ Yíð÷„gdÃ5÷#°(÷} ¬ L¬  ¬ L¬  !¬ L¬  àÓ 4¬ L¬ g‡Ã<÷„^`¬ ¬ V×"ø}_ªÃ%ñøz_àÃ)ñø„_)ÄÛðø¡_LÄàðø¢ Xèðø¡ Yíðø„goÄ5ø„°(ø} ‡¬ ¼¬  ‡¬ ¼¬  ‘¬ ¼¬  Ô ¤¬ ¼¬ g’Ä<ø„^Ь /­ Vè"ù}_µÄ%ñùz_ëÄ)ñù„_4ÅÛðù¡_WÅàðù¢ Xèðù¡ Yíðù„gzÅ5ù4°(ù} õ¬ )­  õ¬ )­  ÿ¬ )­  @Ô ­ )­ gŸÅ<ù„^0­ œ­ Vø"ú}_ÂÅ%ñúz_øÅ)ñú„_AÆÛðú¡_dÆàðú¢ Xèðú¡ Yíðú„g‡Æ5ú#°(ú} a­ –­  a­ –­  k­ –­  pÔ ~­ –­ gªÆ<ú„^ ­ ® V#û}_ÍÆ%ñûz_Ç)ñû„_LÇÛðû¡_oÇàðû¢ Xèðû¡ Yíðû„g’Ç5ûÖ°(û} Ç­ ü­  Ç­ ü­  Ñ­ ü­   Ô ä­ ü­ gµÇ<û„^® r® V#ü}_ØÇ%ñüz_È)ñü„_WÈÛðü¡_zÈàðü¢ Xèðü¡ Yíðü„gÈ5üÖ°(ü} 7® l®  7® l®  A® l®  ÐÔ T® l® gÀÈ<ü„^€® å® V/#ý}_ãÈ%ñýz_,É)ñý„_uÉÛðý¡_˜Éàðý¢ Xèðý¡ Yíðý„g»É5ý„°(ý} §® ß®  §® ß®  ±® ß®  Õ Ï® ß® Z<ý„^ð® R¯ VC#þ}_ôÉ%ñþz_*Ê)ñþ„_sÊÛðþ¡_–Êàðþ¢ Xèðþ¡ Yíðþ„g¹Ê5þ#°(þ} ¯ L¯  ¯ L¯  !¯ L¯  0Õ 4¯ L¯ gÜÊ<þ„^`¯ ů VP#}_ÿÊ%ñz_HË)ñ„_‘ËÛð¡_´Ëàð¢ Xèð¡ Yíð„g×Ë5„°(} ‡¯ ¿¯  ‡¯ ¿¯  ‘¯ ¿¯  `Õ ¯¯ ¿¯ Z<„^Я 2° V]#ÿ}_Ì%ñÿz_FÌ)ñÿ„_ÌÛðÿ¡_²Ìàðÿ¢ Xèðÿ¡ Yíðÿ„gÕÌ5ÿ„°(ÿ} ÷¯ ,°  ÷¯ ,°  ° ,°  Õ ° ,° gøÌ<ÿ„^@° ¥° Vp#}_Í%ñz_dÍ)ñ„_­ÍÛð¡_ÐÍàð¢ Xèð¡ Yíð„góÍ5„°(} g° Ÿ°  g° Ÿ°  q° Ÿ°  ÀÕ ° Ÿ° Z<„^°° »° V€#} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^À° ˰ V#} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^а 5± VŸ#}_,Î%ñz_uÎ)ñ„_¾ÎÛð¡_áÎàð¢ Xèð¡ Yíð„gÏ5„°(} ÷° /±  ÷° /±  ± /±  ðÕ ± /± Z<„^@± ¢± V®#}_=Ï%ñz_sÏ)ñ„_¼ÏÛð¡_ßÏàð¢ Xèð¡ Yíð„gÐ5Ö°(} g± œ±  g± œ±  q± œ±  Ö „± œ± g%Ð<„^°± »± VÄ#} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^À± ˱ VÑ#} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5#^б Û± Vå#} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^à± ë± Vù# } U%ñ z T)ñ „ QÛð ¡ Ràð ¢ Xèð ¡ Yíð „Z°( }Z5 „^ð± û± V$ } U%ñ z T)ñ „ QÛð ¡ Ràð ¢ Xèð ¡ Yíð „Z°( }Z5 „^²  ² V0$ } U%ñ z T)ñ „ QÛð ¡ Ràð ¢ Xèð ¡ Yíð „Z°( }Z5 Ö^² ² VI$} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^ ² +² V\$} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^0² ;² Vo$} U%ñz T)ñ„ QÛð¡ Ràð¢ Xèð¡ Yíð„Z°(}Z5„^@² K² V$ } U%ñ z T)ñ „ QÛð ¡ Ràð ¢ Xèð ¡ Yíð „Z°( }Z5 „^P² «² V”$ä}_HÐ%ñäz_~Ð)ñä„_ÇÐÛðä¡_êÐàðä¢ Xèðä¡ Yíðä„g Ñ5ä„°(ä} m² ¥²  m² ¥²  w² ¥²  PÖ •² ¥² Z<ä„^°²  ³ V¯$å}_EÑ%ñåz_{Ñ)ñå„_ÄÑÛðå¡_çÑàðå¢ Xèðå¡ Yíðå„g Ò5å„°(å} Ͳ ³  Ͳ ³  ײ ³  €Ö õ² ³ Z<å„^³ k³ VÀ$æ}_BÒ%ñæz_xÒ)ñæ„_ÁÒÛðæ¡_äÒàðæ¢ Xèðæ¡ Yíðæ„gÓ5æ„°(æ} -³ e³  -³ e³  7³ e³  °Ö U³ e³ Z<æ„^p³ ˳ VÐ$ç}_?Ó%ñçz_uÓ)ñç„_¾ÓÛðç¡_áÓàðç¢ Xèðç¡ Yíðç„gÔ5ç„°(ç} ³ ų  ³ ų  —³ ų  àÖ µ³ ų Z<ç„^г /´ Vå$è}_<Ô%ñèz_rÔ)ñè„_»ÔÛðè¡_ÞÔàðè¢ Xèðè¡ Yíðè„°(è}Z5è# ô³ )´  ô³ )´  þ³ )´  × ´ )´ gÕ<è„^0´ ‹´ Vü$é}_$Õ%ñéz_ZÕ)ñé„_£ÕÛðé¡_ÆÕàðé¢ Xèðé¡ Yíðé„géÕ5é„°(é} M´ …´  M´ …´  W´ …´  @× u´ …´ Z<é„^´ ë´ V%ê}_!Ö%ñêz_WÖ)ñê„_ ÖÛðê¡_ÃÖàðê¢ Xèðê¡ Yíðê„gæÖ5ê„°(ê} ­´ å´  ­´ å´  ·´ å´  p× Õ´ å´ Z<ê„^ð´ Kµ V%ë}_×%ñëz_T×)ñë„_×Ûðë¡_À×àðë¢ Xèðë¡ Yíðë„gã×5ë„°(ë} µ Eµ  µ Eµ  µ Eµ   × 5µ Eµ Z<ë„^Pµ «µ V5%ì}_Ø%ñìz_QØ)ñì„_šØÛðì¡_½Øàðì¢ Xèðì¡ Yíðì„gàØ5ì„°(ì} mµ ¥µ  mµ ¥µ  wµ ¥µ  Ð× •µ ¥µ Z<ì„^°µ  ¶ VO%í}_Ù%ñíz_NÙ)ñí„_—ÙÛðí¡_ºÙàðí¢ Xèðí¡ Yíðí„gÝÙ5í„°(í} ͵ ¶  ͵ ¶  ×µ ¶  Ø õµ ¶ Z<í„^¶ k¶ V`%î}_Ú%ñîz_KÚ)ñî„_”ÚÛðî¡_·Úàðî¢ Xèðî¡ Yíðî„gÚÚ5î„°(î} -¶ e¶  -¶ e¶  7¶ e¶  0Ø U¶ e¶ Z<î„^p¶ ˶ Vr%ï}_Û%ñïz_HÛ)ñï„_‘ÛÛðï¡_´Ûàðï¢ Xèðï¡ Yíðï„g×Û5ï„°(ï} ¶ Ŷ  ¶ Ŷ  —¶ Ŷ  `Ø µ¶ Ŷ Z<ï„^ж +· V%ð}_Ü%ñðz_EÜ)ñð„_ŽÜÛðð¡_±Üàðð¢ Xèðð¡ Yíðð„gÔÜ5ð„°(ð} í¶ %·  í¶ %·  ÷¶ %·  Ø · %· Z<ð„^0· ‹· V“%ñ}_ Ý%ññz_BÝ)ññ„_‹ÝÛðñ¡_®Ýàðñ¢ Xèðñ¡ Yíðñ„gÑÝ5ñ„°(ñ} M· …·  M· …·  W· …·  ÀØ u· …· Z<ñ„^· ë· V§%ò}_ Þ%ñòz_?Þ)ñò„_ˆÞÛðò¡_«Þàðò¢ Xèðò¡ Yíðò„gÎÞ5ò„°(ò} ­· å·  ­· å·  ·· å·  ðØ Õ· å· Z<ò„YÚí_ ;Êæj€;(ä_ Z°(_ ^ð· T» Vº%}_ß%ñz_á)ñ„_DâÛð¡_Ýâàð¢_=ãèð¡_ãíð„gùã&ê4gä-ê4gmä4ê_ °(}ZÊæj€.o€ Ù.O€pÙ f.ã~°Ù a ðÙ 0Úa£äÿ~p­€`Ú a Ú ÐÚ Û PÛ.Š€€Û l.ã~°Û a àÛ º 2» aÛäÿ~m­€» »  a Ü @Ü.Š€pÜ o.ã~ Ü a ÐÜ º “º aåÿ~m­€kº ~º  a.Ò¨ÝaKåø¨v³¸ ¿¸ "`å 0Ý `Ý Ý ÀÝ V¹ h¹ g¤å<%„ ðÝ ÞgÇå=ê'_ ./uPÞ0`êå=ubÿÿÿÿÿÿÿÿÿIuaæUu €Þ –º ¬º –u–º œº >bu–º œº þbzuaXæ…u =¹ M¹  =¹ M¹ gæòã8ˆ ¦h¹ t¹ B`²æ¯^`» R½ VË%F}_Õæ%ñFz_ïç)ñF„_ÐèÛðF¡_,éàðF¢ XèðF¡ YíðF„gˆé5FÙ°(F}ZÊæFj€.o€°ÞF.O€àÞ f.ã~0ß a €ß Àßa«éÿ~p­€ðß a à `à  à àà.Š€0á l.ã~pá a °á ðáaãéÿ~m­€ ½ ½  a â `â.Š€ â oã~½ 0½  a ½ 0½  ½ 0½ aêÿ~ ÿ» 1¼  ÿ» 1¼  ¼ 1¼  Ðâ ¼ 1¼ g+ê<F„Yà% ”‘u;Êæ ”j€^`½ R¿ Vú%H}_Nê%ñHz_hë)ñH„_6ìÛðH¡_’ìàðH¢ XèðH¡ YíðH„gîì5H‘u°(H}ZÊæHj€.o€ãH.O€0ã f.ã~€ã a Ðã äaíÿ~p­€@ä a pä °ä ðä 0å.Š€€å l.ã~Àå a æ @æaIíÿ~m­€ ¿ ¿  a pæ °æ.Š€ðæ oã~¿ 0¿  a ¿ 0¿  ¿ 0¿ amíÿ~mT®õ½ ù½ H ÿ½ 1¾  ÿ½ 1¾  ¾ 1¾  ç ¾ 1¾ g‘í<H„^`¿ RÁ V&J}_´í%ñJz_Îî)ñJ„_¯ïÛðJ¡_ ðàðJ¢ XèðJ¡ YíðJ„ggð5JÙ°(J}ZÊæJj€.o€PçJ.O€€ç f.ã~Ðç a è `èaŠðÿ~p­€è a Àè é @é €é.Š€Ðé l.ã~ê a Pê êaÂðÿ~m­€ Á Á  a Àê ë.Š€@ë oã~Á 0Á  a Á 0Á  Á 0Á aæðÿ~ ÿ¿ 1À  ÿ¿ 1À  À 1À  pë À 1À g ñ<J„Y'& ”‘u;Êæ ”j€^`Á Rà VC&L}_-ñ%ñLz_Gò)ñL„_óÛðL¡_qóàðL¢ XèðL¡ YíðL„gÍó5L‘u°(L}ZÊæLj€.o€ ëL.O€Ðë f.ã~ ì a pì °ìaðóÿ~p­€àì a í Pí í Ðí.Š€ î l.ã~`î a  î àîa(ôÿ~m­€ à à  a ï Pï.Š€ï oã~à 0à  a à 0à  à 0à aLôÿ~m™²õÁ ùÁ L ÿÁ 1  ÿÁ 1   1  Àï  1 gpô<L„^`à kà V[&|} U%ñ|z T)ñ|„ QÛð|¡ Ràð}¢ Xèð}¡ Yíð}„Z°(}^pà {à Vp&ž} U%ñžz T)ñž„ QÛðž¡ Rà🢠Xè🡠YíðŸ„Z°(¡}Z5¢„[‡& ¾„-]ä Á…-Êæ Àj€\& ”;Êæ ”j€;]ä ”…]·& Ð,Í& Є-Êæ Òj€-]ä Ó…^€Ã ÑÇ VÕ&P}_“ô%ñPz_÷)ñP„_¢øÛðP¡_tùàðQ¢_úùèðQ¡_VúíðQ„gïú5T„°(S}.áµðïYaûîµoo€Pð Å.O€ ð f.ã~0ñ a Àñ òa8ûÿ~p­€Pò a €ò ó €ó ô.Š€Pô l.ã~ô a Ðô õapûÿ~m­€ƒÇ –Ç  a @õ õ.Š€àõ o.ã~ ö a `ö  öa¨ûÿ~m­€Æ .Æ  a EÄ WÄ  JÄ WÄ (¶TÄ WÄ  É Ðö ÷.(¶P÷_oo€÷ ×.O€À÷ f.ã~ð÷ a ø CÆ »Æ aàûÿ~m­€’Æ ¦Æ  a Pø €ø °ø àø.Š€ ù l.ã~Pù a €ù »Æ Ç aüÿ~m­€ Ç Ç  a °ù ðù.Š€0ú oã~Ç 4Ç  a Ç 4Ç  Ç 4Ç a<üÿ~(¶äÄ èÄ  Ú ûÄ 7Å  ûÄ 7Å  Å 7Å  `ú *Å 7Å Z<a„]ï& ³-Êæ µj€^àÇ |É Vÿ&i}_`ü%ñiz_zý)ñi„ QÛði¡_Hþàðj¢ Xèðj¡ Yíðj„°(l}.í¹útoo€Àú ¹.O€ðú f.ã~@û a €û Àûakþÿ~p­€ðû a ü `ü ü Àü.Š€ý l.ã~0ý a `ý êÈ EÉ a£þÿ~m­€6É EÉ  a ý Ðý.Š€þ oã~EÉ ZÉ  a EÉ ZÉ  EÉ ZÉ aÇþÿ~\';`ã\''Œ;(äŒ_ ;‘þŒ4Z`ŽãZ9'ã\@'-;W'-ã;(ä-_ Z‘þ/4\^'F;9'Fã;`FãZ‘þH4r€É cÑ Vu'Àgëþm"ý¾gÿ‘þÂ4p§»@þÉ #Ë iË ./u þÌ`rÿ=ubIua—ÿUu Ðþ >Ë DË –u>Ë DË >bu>Ë DË þbzuaÍÿ…u ÿ `ÿZøëÏ„ Àÿ.¾»0Ó`È»`<Ô»p§»‘ù»eÍ @Î ’`a¼n¼ eÍ @Î  eÍ @Î  ÉÍ @Î  ÉÍ 3Î }mÎ Î 9VmÎ Î †a™pm.(¼Ð”nJ¼ ±Ð 8Ñ  ±Ð 8Ñ g¼ ׄgà( ׄg6 ׄ8;B§8„B§?;Aš•ñ A4wé8_ €§)#=@× 'Ç=å×pÑ øä N×ÝéÝúÝ ÞNQáá5áMázpÑ }Ñ Vá'(Uuý(ã"YˆæI»;­àIÍ&Z°(N»AÆYݼ"ÙAØ£ØAãªØ\"ºØYzæU»;­àUÍ[ù'Í,­àÍ[ (},Q„,Ve„-(Í-°(}-"(Í&&-*(¬-1(¬"ÀÙ?‰@ŽA™FÞFTÞh GbÞÝ #GkÞe#GsÞÍ#G{Þø#G…Þø #G’Þø&#GœÞ¬ )# G©Þÿ,#(G¬Þ-#8L-G Ýu -#GÝu -#OJ/#HP/G´Þ\1#L1G¾Þu 1#GÇÞu 1#GÕÞ‹4#L4G Ýu 4#GÝu 4#GÝÞ»8#XL8G¾Þu 8#GÇÞu 8#?âAíÎÙ-IÖÙÈJÞÙÆ!#JâÙÆ'#J¨Ùc0#JëÙœ2#JñÙC8#ˆK8JûÙ(8#JÚ‚:#JÚ‚@#˜J"ÚmB# J+ÚxN#¨J1ÚÛQ#°J?ÚøT#¸JGÚÍW#ÀJOÚÍ_#ÈJVÚÿ}#ÐJaÚŽ~#àJnÚÛ…#ÈJyÚG ‡#ÐJˆÚG #ØJ”Ú‚‘#àJ§ÚG ™#èJ¶ÚÍ #ðJÃÚͦ#øJÞÚi ­#€JìÚˆ°#ÀK°JûÙu °#JñÚc²#ÈJúÚz »#ÐJ Ûz ¼#ØJÛz ½#àJ3Ûz ¾#èJFÛcÀ#ðJQÛ Â#øKÂJûÙu Â#J\ÛcÃ#€JkÛ˜ Æ#ˆJwÛ9 É#ÀJ|Û Ï#À+AnŠÙ F™Ù G¨Ù… ##H‘­Ù ™A}¸Ù A§‡Û F•Ûx eG£ÛÍ g#GªÛ‚ n#G±Û‚ o#GºÛ‚ p#GÁÛÍ v# GÑÛÍ w#(GäÛÍ z#0GôÛ‚ {#8GÜ‚ |#@GÜ‚ }#HG ÜÍ #PG/Ü‚ €#XG<Ü‚ #`GIÜ” „#hGPÜå ‡#pAWÜ "`Ü?™A¤wÜ FŒÜ AG¡Ü‚ H#G©Ü‚ I#G±Ü‚ P#G»ÜÍ V#?êAõÃÜ F×Ü YG¡Ü‚ ^#G©Ü‚ _#GëÜÍ b#?-A8öÜFÿÜHSGÝNT#LTG Ý(T#GÝ(T#GÚ‚U#GݨV#G)Ý»W# G5ÝØX#(A³;ÝFDÝ GMÝ‘ #GRÝ‘ #8äBfAïaÝFnÝ DG{Ý>E#G‚Ý}F#GŒÝÆG# G˜ÝÆH#G Ý`P#AI¦Ý F¹Ý G±Ü‚ #?eM:fA/ÌÝ ?}AˆÞ*F*Þp·G8ÞŽ½#G=Þ­Å#h8¹BfAÄŸá(F¶áAG¢fÍ|#AæÍáAñÕáw"æá"\ØA gá&Fá‘G—á ’#L’G ÝB ’#GÝB ’#?ÿAR ïáFøáGâ‚#8ÍBfÇ?ŽA… â:L:GÑàu :#H¤ â5K8-J?‡ .#J âN /#J'âz 0#J.â« 1#J7â¼ 2# J=âÍ 3#(JÁ> 4#0? H$ CâTe2e2Í2Í2I 2I 2Æ?ø?S H_ QâTø2e2Í2ø2Æ? H‹ `âTø2e2Í2Í2Í2Æ?° H‹ oâ?Á H‹ €â?Ò HÞ Žâ$Tø2e2Í2Í2Í2ø2Æ? H œâ+Tø2e2Í2e2Í2ø2Æ8E Bf#AP ªâ,U¶â`J¨Ùc #JÂâ– #JÉâð #JëÙ#?› A¦ Îâ'FÚâH5Gæâ»7#GíâÆ:#GóâÙ =#8å BfAãúâ Aû ã²L²GÑà ²#? A ã)F+ãXšGBã4 ¢#L¢G¾Þ ¢#GÇÞ ¢#O_ ¤#PH¤G©Þÿ¦#O{ ©#P©GJãeª#GX㬠«#Gbã› ¯#?± A¼ åÞFñÞ€XGýÞr Z#Gß‚`#G ß‚a#Gßµd#Gß g#8G!ß‚v#@G*ß& y#HLyG¾Þ¬ y#GÇÞ¬ y#G4ßø#XGóü‚#\G=ßµˆ#`?w A‚ GßQTߨ°G¨Ù°±#Gß‚´#G ß‚º#Gaßµ½#Gmßø¿# GvßøÀ#!G~ßí Â#(LÂG¾Þr Â#GÇÞr Â#G‰ß‚É#8G—ßÁÑ#@GŸß‚Ô#pGªß‚Õ#xG½ßøØ#€GÁßøÙ#GËßøÚ#‚GÕßøâ#ƒGÝßøè#„Gäßµë#ˆG)~î#¨?c?º"$!AÌïßFõß0 GŸß‚+#GÙdÍ.#Gû߯4#G àÆ5#Gà78#Gà_9# G'à€<#(?<AG+àR2T2Z?YS?Í?dAo6à Tø2T2T?…ADàFKàG'*T#GPWT#AÀRàF]à IGhà‚K#Gpà‚L#Gyà‚M#Gƒà‚N#8eBf?AŽàFšà`ŒG¨Ù°Ž#G¦àÆš#G­à© #G³à]£#L£G¾Þ £#GÇÞ £#Gäßµ¦#(G½àÇ©#HG)~÷¬#XA´ÀàŠLŠGÑଠŠ#AÒÚàFäà;G)~`=#GÿUÆ>#8eBfALîàVAfã FyãH G¡Ü‚ #G©Ü‚ #G±Ü‚ &#GŒãÍ ,#G”ã‚ /# G›ã‚ 2#(G¤ã‚ 5#0Gªã‚ ;#8G»ÜÍ >#@8ð BfAã¼Y¥çzÍ;Gàz»Z°(|ÍYºç‚Í;Gà‚»YSè*»;­à*Í&Ziè?ÍZ|è@»ZGàC»ZËi5»Z†!8»Z€è:»Z„è<»&&Zè/»Z•è0»[èúÆ,ËiúÍ-°(üÍy€Ñ *Ó V8((u w(uý(ã"T'*(„xKû(u x°((u -îÝ(}o@(T+a¤AaíLo `'oêð`pø @.’pZ`¦ .ù [`É àaÿa" aG,†ÕÑ ßÑ 7`l“ažoÞ `²ì.·P†`×ÅaüÑo€`oêÀ`hø.ù[`ž @aÔa÷ a,† Ò Ò 7`A“adž ÌÒ âÒ ’ÙÒ âÒ Z`‡ z0Ó UÖ VT((Uuý(ã"wª8Þ(u ‘ÐoÜ(è"xÍç(ô" sÓ Õ  †Ó üÔ -îÝ(}o€(`ð+`6a\Aa¥LoÐ`ßoê`(ø `.’Z`^ .ùÀ[` a·aÚ aÿ,†¥Ó ¯Ó 7`$“aGžoÞ@`jì.·p†`Åa´Ño `×oêà` ø.ù [`V  `aŒ a¯  aÔ ,†ÙÓ ãÓ 7`ù “a ž ›Ô ±Ô ’¨Ô ±Ô Z`?   Õ *Ö  Õ Ö xb E(u $Õ üÕ   x« Œþ(u „Õ ÄÕ  ŽÕ ÄÕ xá ò(u ’Õ ÄÕ   Õ ÄÕ x û(u Ðx' (u  0x] Œþ(u ` ÄÕ üÕ x€ û(u -í(øL(G8Þu (#GîÝ}(#z`Ö ¬Ü Vo((Uuý(ã"w£ 8Þ(u ‘ÐoÜ(ù"xì á(#x" ç(# Ö ƒØ  -îÝ(}oÀ(`¤ +`Ú 6a# Aal Lo `¦ oêP `ï ø   .’Ð Z`% .ù [`H @ a~a¡ aÆ,†¾Ö ÈÖ 7`ë“ažoÞ€ `1ì.·° †`VÅa{Ñoà `žoê `çø.ù` [`   aSav a›,†òÖ üÖ 7`À“aãž Ã× Ù× ’Ð× Ù× Z`  à  -í(ø P x)Œþ(u    à  0  € -Œþ(u à  @  xrò(u ð @-û(u px•ò(u ° òÚ 4Û x¸û(u àxÛ(u x (u x4û(u  ŽÚ ßÚ -(u P À xjû(u -(u -%(u `x %(u -(u   1Ú DÚ xÃû(u àxæû(u L(G8Þu (#GîÝ}(#z°Ü ½Ü VŠ(5Uuý5ã"[ (,},Q,„,Ve,„-*(.¬-1(/¬yÀÜ MÝ V¯(5u wuý5ã"wR8Þ5u xˆ°(5u ÄÜ KÝ  ïÜ KÝ xÑû5u úÜ KÝ xîÝ5}´5yPÝ  Ý VÆ(5u w,uý5ã"wO'*5„xr°(5u -îÝ5}(´vÝ Ý 5y Ý Þ Vß(5u w»uý5ã"wÞ'*5„xû5u x7°(5u @-îÝ5}(´ÀÝ ÏÝ 5zÞ Íß Vù(5Uuý5ã"wZ8Þ5u ‘ðoÜ5 #x}ç5# KÞ ‘Þ  ^Þ ŒÞ x îÝ5}(´^Þ mÞ 5 ”Þ ªß  °Þ ”ß xÅE5u ´Þ |ß  pxŒþ5u ß Dß  ß Dß xDò5u ß Dß  ß Dß xgû5u  xŠ5u Ð xÀŒþ5u 0 Dß |ß xãû5u -í5øL5G8Þu 5#GîÝ}5#zÐß øä V)5wuý5ã"wÔ8Þ5u ‘àoÜ5#xá5'#xSç5'# ùß £à  `xÕîÝ5}(´à #à 5  À-í5ø ðxúŒþ5u 0 `   à-Œþ5u @   x0ò5u ` °-û5u àxSò5u  $ã gã xvû5u Px™5u xÏ 5u xòû5u   Àâ ã -5u Ð 0 €x(û5u -5u -%5u Àx^%5u -5u  bâ uâ xû5u @x¤û5u L5G8Þu 5#GîÝ}5#?z 8HBf?H8iBf?i8O Bf?O 8Á"Bf?Á")g=@× +).Gå×å µ DZÙ;5@@"\ØVÌãUÜ€ @ZAe£ØApªØ\"ºØN†äžä°äÄäN×ÝéÝúÝ ÞNQáá5áMáN6å*å>å4å å V.TU¬#XAûÀàŠLŠGÑàŽ Š#AÚàFäà;G)~*=#GÿU¦>#8B/A±îàVA`gá&Fá‘G—áv’#L’G ݘ’#Gݘ’#?U?? 8®B/A¹Ÿá(F¶áAG¢fZ|#AÛÍáAæÕáw"æáAøïáFøáGâN#8ZB/ÇA&â :L :GÑà :#HEâ5K8-J?‡´.#J âï/#J'â0#J.âL1#J7â]2# J=ân3#(JÁ>¤4#0?¹HÅCâT22Z2Z2ê2ê2¦?@?ôHQâT@22Z2@2¦? H,`âT@22Z2Z2Z2¦?QH,oâ?bH,€â?sHŽâ$T@22Z2Z2Z2@2¦?©Hµœâ+T@22Z22Z2@2¦8æB/#Añªâ,U¶â`J¨Ùy #JÂâ7#JÉâ‘#JëÙM#?<AGÎâ'FÚâH5Gæâ›7#Gíâ¦:#Góâz=#8†B/Apúâ Aœã²L²GÑ௲#?´A¿ã)F+ãXšGBãÕ¢#L¢G¾Þ¯¢#GÇÞ¯¢#O¤#PH¤G©ÞU¦#O©#P©GJãª#GX㎠«#Gbã<¯#AXfãFyãHG¡ÜN#G©ÜN#G±ÜN&#GŒãZ,#G”ãN/# G›ãN2#(G¤ãN5#0GªãN;#8G»ÜZ>#@8‘B/?ðAûÛä.UéäÓJ÷ä`Ô#AÎå:?$A/UåFbå0GpàZ#GhàZ#G7,Z#GoåZ#Gzå~# 8ŠB/A•åFåG6ß#GeZ#Yöæ ÿ;6ß FZç  Y ç‡ÿ;6߇FYçZ;6ßF;'ç@Zç Z.çZZæâ›Z°(ZY6ç•Z;6ß•F;'ç•@YAç“¡;ç“ ;.ç“Z?®YVçÖL;çÖ ;.çÖZYlçäZ;çä ;.çäZYç›;ç ;.çZZçZZæâ›Yºç‚Z;Gà‚›[Èç HN,Aá H},Ëi HN-¦— JN?NYÝç *Z;Aá *L;Ëi *Z\íçÀ;(äÀÿ;­àÀZYÚíÿ;Êæ;(äÿZ°(ÿ]0  “,8Þ “,(ä “ÿ]I  Ä,8Þ Ä,(ä Äÿ,EW Ä,­à ÄZ,‘û Å@,˜û Å@]]  š,8Þ š,EW š]u  ¡,8Þ ¡,­à ¡Z]  ¨,8Þ ¨,‘û ¨@]§  ¯,8Þ ¯,˜û ¯@]Á  ¶,8Þ ¶,Û  ¶@[˜) @,6ß F,8Þ \ é;Êæ;6ß;òãÎ;êæ@;Óæ@Yé 5Z;Aá 5L;Ëi 5Z\(éÇ;(äÇÿ;­àÇZ\HéI;ÊæI;6ßI;òãIÎ;ÓæI@ZçK Z.çLZZçLZ&&&&Z­àaZ&&&ZæâX›Y¹èëZ;çëZZ­àíZYÖèZ;ç ;.çZZçZYzæU›;­àUZ\Žï¬;Êæ¬;òã¬Î;6߬;­à¬Z;Óæ­@Zæâ¯›Zí°%ZTï±*?®?/A:^ïFpï@G‚ï¦A#YSè*›;­à*Z&Ziè?ZZ|è@›ZGàC›ZËi5›Z†!8›Z€è:›Z„è<›&&Zè/›Z•è0›] è H,"è Ht]<è [,"è [t\Šüß;Êæß;(äßÿ;RÝߦZ÷äáC?`\Ÿüí;Êæí;(äíÿY³üë;Êæ;ÞÙ¦;Æü@Z.ä ëZýÞëYÙüFC;ÊæF;ÞÙF¦ZýÞHë[Pí7@,€ê7C,RÝ7[‚¦,/‚<,'*‚”- „¦?AALù  F hQG?‡›R#G â S#G ¦T#G !Y#G -Z#(? A«# T·2Z?¼AÇ6  FG %OÙ&#P&GX '#G\ ·(#G¦H)#?Ab R2·8¦B/89B/ADv  F„ -OVD#PDG’ E#Gž ·F#G¢f¦I#G¦ ¦N# Ap¼[¦)ë,/ë<,'*ë”,³)ë@-‘þî¦-Bí”- î¦-8Þï·-\ ï·[½)X,6ßXF,³)X@[Í) ,6ß F-8Þ hÛ) ˆÿ;6ß ˆF[IÔ·,/Ô<,bÔ¦-ž Ö·[~™@,8Þ™·Y©è ú;Aá ú*;Ëi ú[’”,/<,'*”,b¦[¢ ·,êï ·-\ ¢·[ê)·,/·<,êï··,³)·@Yü)›;6ßF;çZZæâ›\=ï“;Êæ“;òã“Î;6ß“;æâ“›;Óæ”@Zí–%ZTï—*[`íC@,€êCC]oíô,Êæô,òãôÎy å õï V* ,wJÊæ ,wö(ä ,ÿwÛe ,ZwƒÜî ,ZwÎæ -@wRòã -Îxå )* 0Zx!0* 2@x,!°( /-8Þ 1o$p 6`ˆ!2`÷!>a-"J ð 0.WpÔ`v"e så å ­€å å µ`¿"»aâ"Çr€å Žå ¥`#€ÔŽå å ¥a(#î.û°¶`K#  àa”#a·#"aÚ#.p¨ê ¬ê ˜`ý#}a $ˆ  `.Wâ.ûÀ¶`C$  ðay$aœ$"a¿$.pçå ëå ˜`â$}a%ˆ  `.W û`(%e Qæ |æ ­^æ |æ µaq%Çr^æ mæ ¥`”%€Ômæ |æ ¥a·%î.ûà¶`Ú%  a&a3&"aV&.p–î šî ˜`y&}aœ&ˆo”@ 'Èa‡'Ô ð.M0`ª'\.)` ‹`Í'6að'Ao bÿÿÿÿÿÿÿÿÿoŸÀ[bÿÿÿÿÿÿÿÿÿÂa(Ía8(Øq ¾é Ôé ñ`n(qp¾é Âé ‰`‘(}aÇ(ˆ qiÔé øé ó`ê(va )Œ @ q˜äé êé Ú`C)¥q±ñé øé ÛNñé øé  þ`f)[bfa‰)q p qØê ,ê ÷`À)å    Zê ^ê q+Zê ^ê ýbÿÿÿÿÿÿÿÿÿN5ê Iê aã) 9ê Iê q˜9ê ?ê ¦`*¥q±Aê Iê §NAê Iê  þbfa<*q.SÐ Ùbm.ü!œbas*"a–*.a¹*:aÞ*F P! !ô!ç 8ç %`'+`J+am+a+&Í!ç +ç  `µ+Û`Ø+ç¦!ç +ç ç`û+´`,Àz!ç +ç Ù`A,ˆ`d,” À! Hç Sç 3Hç Sç @`‡,AÔHç Sç †`¬,âaÑ,î qê ‚ê lqê wê 0`ô,z`-†a:-’Eqê wê  `p-Sa¦-_©Sç Yç Ù`É-³`ÿ-¿‚Sç Yç ÃNSç Yç  .a".qoÌð! F‘@Ú`E.æa|.ò 0" °"o/# Ibÿÿÿÿÿÿÿÿÿ]bÿÿÿÿÿÿÿÿÿi p#  #.áÐ#`².ï.º$Œ`Õ.Èaø.Ô P$.M$`/\.)À$ ‹`>/6aa/Aoð$ bÿÿÿÿÿÿÿÿÿoŸ %[bÿÿÿÿÿÿÿÿÿÂa„/Ía©/Øq ¯ì Åì ñ`ß/qp¯ì ³ì ‰`0}a%0ˆ `%qiÅì éì ó`H0vak0Œ  %q˜Õì Ûì Ú`¡0¥q±âì éì ÛNâì éì  þ`Ä0[bfaç0q Ð%qØõì í ÷`1å & Jí Ní q+Jí Ní ýbÿÿÿÿÿÿÿÿÿN%í 9í aA1 )í 9í q˜)í /í ¦`w1¥q±1í 9í §N1í 9í  þbfaš1q.S0&bm.üp&œbaÑ1"aô1.a2:a<2F °& ð&ô6ë Më %`…2`¨2aË2aî2&Í6ë @ë  `3Û`63ç¦6ë @ë ç`Y3´`|3Àz6ë @ë Ù`Ÿ3ˆ`Â3” ' ]ë hë 3]ë hë @`å3AÔ]ë hë †` 4âa/4î Ví qí lVí fí 0`R4z`u4†a˜4’EVí fí  `Î4Sa5_hë që `'5§`]5³vhë që ÊNkë që  9`€5fa£5q.ÀP' bÿÿÿÿÿÿÿÿÿîaÆ5úa6aE6 à' p(Íë šë S`{6Û`ž6ç¦ë šë ç`Á6´`ä6Àzë šë Ù`7ˆ`*7” ð( p)  ) Ð)aM72Z²ë ºë X`‡7haª7€.*ZbÿÿÿÿÿÿÿÿÿÇ. 0*¨‘@ `Ï7 `*oì*úoéÀ*Fl ð*lví †í a`8z`;8†a^8’Eví †í  `8S P+ °+.ºð+ibÿÿÿÿÿÿÿÿÿôa¤8.Ÿ0,·`Þ8­ Åî éî rÒî éî Z`:9€.Q`,[`]9_ ,/Qla€9x/^“„p“ï —ï 7`¥9}aÈ9ˆqšç ¹ç  Mbÿÿÿÿÿÿÿÿÿ_(ÿšç žç  Èqkžç £ç  É`ë9q‹£ç ¨ç  Ê`:Ÿ(«¨ç ­ç  ËqË­ç ³ç  Ìbÿÿÿÿÿÿÿÿÿßqë³ç ¹ç  Íbÿ À,q ¹ç Äç  O`1: -o/@- Qbÿÿÿÿÿÿÿÿÿ]bÿÿÿÿÿÿÿÿÿi p-  -.áÐ-`T:ï.º.Œ`w:Èaš:Ô P..M.`½:\.)À. ‹`à:6a;Aoð. bÿÿÿÿÿÿÿÿÿoŸ /[bÿÿÿÿÿÿÿÿÿÂa&;ÍaK;Øq ´í Êí ñ`;qp´í ¸í ‰`¤;}aÇ;ˆ `/qiÊí îí ó`ê;va <Œ  /q˜Úí àí Ú`C<¥q±çí îí ÛNçí îí  þ`f<[bfa‰<q Ð/qØõí î ÷`À<å 0 Jî Nî q+Jî Nî ýbÿÿÿÿÿÿÿÿÿN%î 9î aã< )î 9î q˜)î /î ¦`=¥q±1î 9î §N1î 9î  þbfa<=q.S00bm.üp0œbas="a–=.a¹=:aÞ=F °0 ð0ôè )è %`'>`J>am>a>&Íè è  `µ>Û`Ø>ç¦è è ç`û>´`?Àzè è Ù`A?ˆ`d?” 1 9è Dè 39è Dè @`‡?AÔ9è Dè †`¬?âaÑ?î Vî qî lVî fî 0`ô?z`@†a:@’EVî fî  `p@Sa¦@_Dè Mè `É@§`ÿ@³vDè Mè ÊNGè Mè  9`"AfaEAqÀMè Ûè  bÿÿÿÿÿÿÿÿÿîahAúa‹Aa®A Vè Ûè  _è Ûè Íiè vè S`ÑAÛ`ôAç¦iè vè ç`B´`:BÀziè vè Ù`]Bˆ`€B” {è Ûè  Žè Ûè lŽè žè a`£Bz`ÆB†aéB’EŽè žè  ` CS žè Ûè  µè Ûè ºµè Ûè ibÿÿÿÿÿÿÿÿÿôŸµè Ûè ·`/C­QÂè Ûè [`RC_ Âè Ûè pÒè Ûè 7`uC}(ÞÛè êè  V(ó%é 4é  YoHP1 a`˜CR.1ðb*.¶Ð1å`ÎCÄ.k2Jbÿÿÿÿÿÿÿÿÿ‘aD @2.ép2èl]:* },6ß },5ï }Z,@ }Z,J ~Z,Îæ ~@-V* €Z-8Þ -(ä ‚ÿ-kÛ ƒ9-a* „@-e €Z-m* „@&&-x* ”Z[~* ¸@,6ß ¸,5ï ¸Z,e ¸Z-8Þ º-(ä »ÿ-kÛ ¼9-‚÷ ½Z-m* ¾@-a* ¾@&&-x* ÎZjð ÿù V™* @_'DÊæ _E6ß _óE5ï Z_ÔF@ Z_GJ Z_ëGÎæ @  2 3 °3 4.M@4 '.)€4 ‹`£H6aÙHAoÀ4 bÿÿÿÿÿÿÿÿÿoŸ5[bÿÿÿÿÿÿÿÿÿÂaüHÍa6IØo P5ñ`YIa|I0qpÖó Úó ‰a¡Iˆ €5qiïó ô ó`ÄIvaçIŒ À5q˜ô ô Ú`J¥q±ô ô ÛNô ô  þ`@J[bfacJq ð5qØ%ô Nô ÷`šJå 6 |ô €ô q+|ô €ô ýbÿÿÿÿÿÿÿÿÿNXô lô a½J \ô lô q˜\ô bô ¦`óJ¥q±dô lô §Ndô lô  þbfaKq.HP6 '`MKR`…K^.6ðb*¶ƒô ªô å`ÎKÄ.kÐ6Jbÿÿÿÿÿÿÿÿÿ‘añK Ñø Ýø éÑø Ýø èl 7 `7.M 7 ..)à7 ‹`L6aJLAo 8 bÿÿÿÿÿÿÿÿÿoŸ`8[bÿÿÿÿÿÿÿÿÿÂamLÍa§LØo °8ñ`ÊLaíL0qpöð úð ‰aMˆ à8qiñ 5ñ ó`5MvaXMŒ 9q˜!ñ 'ñ Ú`ŽM¥q±.ñ 5ñ ÛN.ñ 5ñ  þ`±M[bfaÔMq P9qØEñ nñ ÷` Nå €9 "ù &ù q+"ù &ù ýbÿÿÿÿÿÿÿÿÿN|ñ ñ a.N €ñ ñ q˜€ñ †ñ ¦`dN¥q±ˆñ ñ §Nˆñ ñ  þbfa‡Nq.H°9 .`¾NR`öN^.à9ðb*¶)ù Lù å`,OÄ.k:Jbÿÿÿÿÿÿÿÿÿ‘aOO @: à:.µ9p; 9`rOÉ9`•Oß9aËOõ9aîO:aNP :aªP:n!: <oW@< ‡`ÎPe €<.­°<µ`Q»a'QÇ.rà<¥`JQ€.Ô=¥amQîû#ò dò ¶`Q  #ò dò aÆQaéQ"aR.p/ò 3ò ˜`BR}aeRˆo)@= Ž`ˆR6aÑRAo€= bÿÿÿÿÿÿÿÿÿoŸÀ=[bÿÿÿÿÿÿÿÿÿÂa SÍaCSØo >ñ`ySaœS0qpŠò Žò ‰aÁSˆ @>qi£ò Éò ó`äSvaTŒ €>q˜µò »ò Ú`=T¥q±Âò Éò ÛNÂò Éò  þ``T[bfaƒTq °>qØÕò þò ÷`ºTå à> ºô ¾ô q+ºô ¾ô ýbÿÿÿÿÿÿÿÿÿN ó  ó aÝT ó  ó q˜ó ó ¦`U¥q±ó  ó §Nó  ó  þbfa6Uq ? @?amUD:(Þ.ö Eö  Ÿq‹Eö Iö  ¢`£U”`îUŸq«Iö Rö  ¤`V´(óRö Zö  ¥.Mp? ;.)°? ‹`\V6a’VAoð? bÿÿÿÿÿÿÿÿÿoŸ0@[bÿÿÿÿÿÿÿÿÿÂaµVÍaïVØo €@ñ`Wa5W0qpø  ø ‰aZWˆ °@qi ø Fø ó`}Wva WŒ ð@q˜2ø 8ø Ú`ÖW¥q±?ø Fø ÛN?ø Fø  þ`ùW[bfaXq AqØUø ~ø ÷`SXå PA ¬ø °ø q+¬ø °ø ýbÿÿÿÿÿÿÿÿÿNˆø œø avX Œø œø q˜Œø ’ø ¦`¬X¥q±”ø œø §N”ø œø  þbfaÏXq.H€A ;`YR`QY^.ÀAðb*.¶Bå`šYÄ.k0BJbÿÿÿÿÿÿÿÿÿ‘aÐY pB ðB `C.R:ÐC A`óYj:` )# G©Þ" ,#(G¬Þ€ -#8L-G Ýj -#GÝj -#O« /#HP/G´Þ½ 1#L1G¾Þj 1#GÇÞj 1#GÕÞì 4#L4G Ýj 4#GÝj 4#GÝÞ 8#XL8G¾Þj 8#GÇÞj 8#?C AN åÞ FñÞ€ XGýÞÌ Z#Gßl `#G ßl a#Gß d#Gß g#8G!ßl v#@G*߸ y#HL yG¾Þ> y#GÇÞ> y#G4ß+ #XGóüú ‚#\G=ß ˆ#`? A Žà Fšà` ŒG¨ÙÌ Ž#G¦àG š#G­à   #G³àT £#L £G¾Þ £#GÇÞ £#Gäß ¦#(G½à¾ ©#HG)~î ¬#XA« Àà ŠL ŠGÑà> Š#AÉ Úà Fäà ;G)~ =#GÿUG >#8gB…A îà VN Qáá5áMáA- gá&Fá‘G—áC ’#L’G Ýe ’#GÝe ’#?" ?ï 8{ B…A† Ÿá(F¶áAG¢f2|#A¨ ïáFøáGâl#82B…ÇAÖ â:L:GÑàj :#Hõ â5K8-J?‡d.#J âŸ/#J'âË0#J.âü1#J7â 2# J=â3#(JÁ>T4#0?iHuCâTg2g22222š2š2G?+?¤H°QâT+2g222+2G?ÐHÜ`âT+2g2222222G?HÜoâ?HÜ€â?#H/Žâ$T+2g2222222+2G?YHeœâ+T+2g222g222+2G8–B…#A¡ªâ,U¶â`J¨ÙŒ #JÂâç#JÉâA#JëÙý#?ìA÷Îâ'FÚâH5Gæâú7#GíâG:#Góâ*=#86B…AHúâ ALã²L²GÑà_²#?dAoã)F+ãXšGBã…¢#L¢G¾Þ_¢#GÇÞ_¢#O°¤#PH¤G©Þ" ¦#OÌ©#P©GJãgª#GXã> «#Gbãì¯#AfãFyãHG¡Ül#G©Ül#G±Ül&#GŒã2,#G”ãl/# G›ãl2#(G¤ãl5#0Gªãl;#8G»Ü2>#@8AB…? A«Ûä.UéäÓJ÷äÊÔ#AÏå :N 6å*å>å?ëAöUåFbå0Gpà2#Ghà2#G7,2#Goå2#GzåE# 8QB…A\åFåG6ßg#Ge2#DZÙ5@+VÌã Ü€ @2?hf  ¦ Vz.q UÊæq¥ZýÞs̆9=@× .ÿkå×° R DZÙ;5@@"\ØVÌãUÜ€ @ZAe£ØApªØ\"ºØN†äžä°äÄäN×ÝéÝúÝ ÞNQáá5áMáN6å*å>åYöæ  ;6ß ì Zç À?AÎÙ-IÖÙÈJÞÙ’!#JâÙ’'#J¨Ù™0#JëÙÙ2#JñÙr8#ˆK8JûÙe8#JÚ¿:#JÚ¿@#˜J"ÚµB# J+ÚÀN#¨J1Ú! Q#°J?Ú@T#¸JGÚZW#ÀJOÚZ_#ÈJVÚ¦ }#ÐJaÚõ~#àJnÚ! …#ÈJyÚ> ‡#ÐJˆÚ> #ØJ”Ú¿‘#àJ§Ú> ™#èJ¶ÚZ #ðJÃÚZ¦#øJÞÚ` ­#€JìÚ·°#ÀK°JûÙî °#JñÚ™²#ÈJúÚl »#ÐJ Ûl ¼#ØJÛl ½#àJ3Ûl ¾#èJFÛ™À#ðJQÛ<Â#øKÂJûÙî Â#J\Û™Ã#€JkÛŠ Æ#ˆJwÛ+É#ÀJ|Û0Ï#À+"ÙA¤ŠÙF™ÙG¨Ù»##HÇ­Ù™AÒ¸Ù "ÀÙAä‡ÛF•ÛxeG£ÛZg#GªÛ¿n#G±Û¿o#GºÛ¿p#GÁÛZv# GÑÛZw#(GäÛZz#0GôÛ¿{#8GÜ¿|#@GÜ¿}#HG ÜZ#PG/Ü¿€#XG<Ü¿#`GIÜÑ„#hGPÜ"‡#pAÊWÜ"`Ü?ÖAáwÜFŒÜ AG¡Ü¿H#G©Ü¿I#G±Ü¿P#G»ÜZV#?'A2ÃÜF×ÜYG¡Ü¿^#G©Ü¿_#GëÜZb#?jAuöÜFÿÜHSGÝ‹T#LTG ÝeT#GÝeT#GÚ¿U#GÝåV#G)ÝW# G5Ý X#(Að;Ý FDÝ GMÝÇ #GRÝÇ #A’Yݼ8,B®A7aÝFnÝ DG{݆E#G‚ÝÒF#GŒÝ’G# G˜Ý’H#G Ý¨P#A‘¦ÝF¹ÝG±Ü¿#?­M:fA”ÌÝ ?ÅAÐÞ*F*Þp·G8Þõ½#G=Þó Å#hAFÞFTÞh GbÞ  #GkÞ­#GsÞZ#G{Þ@#G…Þ@ #G’Þ@&#GœÞD)# G©Þ¦ ,#(G¬Þ†-#8L-G Ýî -#GÝî -#O±/#HP/G´ÞÃ1#L1G¾Þî 1#GÇÞî 1#GÕÞò4#L4G Ýî 4#GÝî 4#GÝÞ"8#XL8G¾Þî 8#GÇÞî 8#?IATåÞFñÞ€XGýÞ Z#Gß¿`#G ß¿a#GßM d#Gߥ g#8G!ß¿v#@G*ß¾y#HLyG¾ÞDy#GÇÞDy#G4ß@#XGóü› ‚#\G=ßM ˆ#`? A GßQTߨ°G¨ÙH ±#Gß¿´#G ß¿º#GaßM ½#Gmß@¿# Gvß@À#!G~ß… Â#(LÂG¾Þ Â#GÇÞ Â#G‰ß¿É#8G—ßY Ñ#@GŸß¿Ô#pGªß¿Õ#xG½ß@Ø#€GÁß@Ù#GËß@Ú#‚GÕß@â#ƒGÝß@è#„GäßM ë#ˆG)~™ î#¨?™?R "$!Ad ïßFõß0 GŸß¿+#GÙdZ.#Gûß’4#G à’5#GàÏ 8#Gà÷ 9# G'à <#(?Ô Aß +àR2ì 2ò ?ñ S?Z?ü A 6à T@2ì 2ì ? A( DàFKàG'*ì #GPWì #AX RàF]à IGhà¿K#Gpà¿L#Gyà¿M#Gƒà¿N#8­B®?ª Aµ ŽàFšà`ŒG¨ÙH Ž#G¦à’š#G­àA  #G³àõ £#L£G¾Þ¥ £#GÇÞ¥ £#GäßM ¦#(G½à_ ©#HG)~ ¬#XAL ÀàŠLŠGÑàDŠ#Aj ÚàFäà;G)~¨=#GÿU’>#8­B®A±îàVA± gá&Fá‘G—áÇ ’#L’G Ýé ’#GÝé ’#?¦ ?õ8ÿ B®A Ÿá(F¶áAG¢fZ|#A, ÍáA7 Õáw"æáAI ïáFøáGâ¿#8ZB®ÇAw â:L:GÑàî :#H– â5K8-J?‡.#J â@/#J'âl0#J.â1#J7â®2# J=â¿3#(JÁ>õ4#0? HCâT­2­2Z2Z2;2;2’?@?EHQQâT@2­2Z2@2’?qH}`âT@2­2Z2Z2Z2’?¢H}oâ?³H}€â?ÄHÐŽâ$T@2­2Z2Z2Z2@2’?úHœâ+T@2­2Z2­2Z2@2’87B®#ABªâ,U¶â`J¨Ù™ #JÂâˆ#JÉââ#JëÙž#?A˜Îâ'FÚâH5Gæâ7#Gíâ’:#GóâË=#8×B®Apúâ Aíã²L²GÑà²#?Aã)F+ãXšGBã&¢#L¢G¾Þ¢#GÇÞ¢#OQ¤#PH¤G©Þ¦ ¦#Om©#P©GJã­ª#GXãD«#Gbã¯#A©fãFyãHG¡Ü¿#G©Ü¿#G±Ü¿&#GŒãZ,#G”ã¿/# G›ã¿2#(G¤ã¿5#0Gªã¿;#8G»ÜZ>#@8âB®Y ç‡ ;6߇ì \ é;Êæž;6ß­;òãe;êæ@;Óæ@?£A®æãUìãP0Jóü]1#Jòãe4#Jùã¿4#J ä¿4#Jä 4# J(ä 4#(J.äh4#0J;ä’4#8JIä@4# “Z-u/ •„9z@ ± Vy/ ¬wºÊæ ¬žxoºlä ®œ  Pq(_ x  µ`¸ºŠ(`Ûº•(b (oW€ ¶bÿÿÿÿÿÿÿÿÿ‘ ° ð.<0€.å`€Œa»ÿ.Ž€b¨.7ЀœbQa4»]aW»iaz»uaŸ»  P/µ Ì %`è»=` ¼Ia.¼UaQ¼aµ ¿  `v¼`™¼"áµ ¿ ç`¼¼ï`ß¼ûµµ ¿ Ù`½Ã`%½Ï € Ø ã •Ø ã @`H½£nØ ã †`m½|a’½ˆ Ý ø Ý í 0`µ½+`ؽ7aû½CöÝ í  `1¾ag¾×ã í `оá`­¾í°ã í Êúæ í  9aо..° bÿÿÿÿÿÿÿÿÿ\aó¾ha)¿ta_¿€ ‚ p‚   S`•¿`¸¿"á   ç`Û¿ï`þ¿ûµ   Ù`!ÀÃ`DÀÏ À‚ ƒ @ƒ pƒagÀ’³2 : Xa¡ÀÙ.æ ƒZbÿÿÿÿÿÿÿÿÿ .³Ѓ¨`ÆÀ¼`éÀÇ „oš0„úoq`„ Fl‰ „ý   a` Á+`/Á7aRÁCöý    `uÁ Є ¦ ± k¦ ± ibÿÿÿÿÿÿÿÿÿ¥a˜Á±.P…·`ÒÁ^ ¦ Æ Ö¯ Æ Z`.Âä.ÿP…[`Q  …/QatÂ&/\“2Œ , 7`™Â™a¼Â¤qÓ•   ·`ßÂÝuÀ R V/ cUÊæ cžwÃlä cœ-u/ e„9oWÐ… gbÿÿÿÿÿÿÿÿÿ‘..† bÿÿÿÿÿÿÿÿÿ\aKÃhaÃt @† €†ö  S`¤Ã`ÇÃ"áö  ç`êÃï` Äûµö  Ù`0ÄÃ`SÄÏ?=@× ¤/üxå×` F N×ÝéÝúÝ ÞNQáá5áMá[0,0, 0"Ùy` g V0 ˆU/ «T“¢f wvÄ?‡ w™Ä â&x¼Ä0ƒ‘þ-  + d  + d oiÀ†7`áÄ[(0fˆ,Aáf,=0f”,¨…f”-?0h¦"\Ø?”AŸWÜ"`ÜA±DÙ"LÙYG0ˆ;Aáë;=0ð;¨…ð?ðM[W0\+,/\«,b\,g0\±-8Þ^+?0A;6  FG %OM&#P&GX ð'#G\ +(#G¦H})#?‚AFÞFTÞh GbÞÑ #GkÞð#GsÞ}#G{Þˆ#G…Þˆ #G’Þˆ&#GœÞ« )# G©Þ ,#(G¬Þ-#8L-G Ý}-#GÝ}-#O>/#HP/G´ÞP1#L1G¾Þ}1#GÇÞ}1#GÕÞ4#L4G Ý}4#GÝ}4#GÝÞ¯8#XL8G¾Þ}8#GÇÞ}8#?ÖAáÎÙ-IÖÙÈJÞÙ!#JâÙ'#J¨ÙW0#JëÙ—2#JñÙ78#ˆK8JûÙ.8#JÚ”:#JÚ”@#˜J"Úx B# J+Úƒ N#¨J1Úæ Q#°J?ÚˆT#¸JGÚ}W#ÀJOÚ}_#ÈJVÚ }#ÐJaÚ‚~#àJnÚæ …#ÈJyÚK ‡#ÐJˆÚK #ØJ”Ú”‘#àJ§ÚK ™#èJ¶Ú} #ðJÃÚ}¦#øJÞÚm ­#€JìÚ|°#ÀK°JûÙ}°#JñÚW²#ÈJúÚy »#ÐJ Ûy ¼#ØJÛy ½#àJ3Ûy ¾#èJFÛWÀ#ðJQÛÂ#øKÂJûÙ}Â#J\ÛWÃ#€JkÛ— Æ#ˆJwÛ8 É#ÀJ|ÛŸÏ#À+AbŠÙ F™Ù G¨Ùy ##H…­Ù ™A¸Ù "ÀÙA¢‡ÛF•ÛxeG£Û}g#GªÛ”n#G±Û”o#GºÛ”p#GÁÛ}v# GÑÛ}w#(GäÛ}z#0GôÛ”{#8GÜ”|#@GÜ”}#HG Ü}#PG/Ü”€#XG<Ü”#`GIÜš„#hGPÜë‡#pAˆ£Ø A“ªØ \"ºØ?ŸAªwÜFŒÜ AG¡Ü”H#G©Ü”I#G±Ü”P#G»Ü}V#?ðAûÃÜF×ÜYG¡Ü”^#G©Ü”_#GëÜ}b#?3A>öÜFÿÜHSGÝTT#LTG Ý.T#GÝ.T#GÚ”U#GÝ®V#G)ÝÞW# G5ÝéX#(A¹;ÝFDÝ GMÝ… #GRÝ… #AYݼ8õBq A aÝFnÝ DG{ÝO E#G‚ÝF#GŒÝG# G˜ÝH#G ÝëP#AZ ¦ÝF¹ÝG±Ü”#:fA/ÌÝ ?ˆ A“ Þ*F*Þp·G8Þ‚½#G=Þ¸ Å#h8Ä Bq AÏ Ÿá(F¶áAG¢f}|#Añ ÍáAü Õá w"æáA gá&Fá‘G—á$ ’#L’G ÝF ’#GÝF ’#? AV ïáFøáGâ”#8}Bq ÇA„ â:L:GÑà}:#H£ â5K8-J?‡ .#J âM /#J'ây 0#J.⪠1#J7â» 2# J=âÌ 3#(JÁ> 4#0? H# CâTð2ð2}2}2H 2H 2?ˆ?R H^ QâTˆ2ð2}2ˆ2?~ HŠ `âTˆ2ð2}2}2}2?¯ HŠ oâ?À HŠ €â?Ñ HÝ Žâ$Tˆ2ð2}2}2}2ˆ2? H œâ+Tˆ2ð2}2ð2}2ˆ28D Bq #AO ªâ,U¶â`J¨ÙW #JÂâ• #JÉâï #JëÙ #?š A¥ Îâ'FÚâH5GæâÞ7#Gíâ:#GóâØ =#8ä Bq A“úâ Aú ã²L²GÑà ²#? A ã)F+ãXšGBã3 ¢#L¢G¾Þ ¢#GÇÞ ¢#O^ ¤#PH¤G©Þ ¦#Oz ©#P©GJãðª#GXã« «#Gbãš ¯#?° A» åÞFñÞ€XGýÞqZ#Gß”`#G ß”a#Gß´d#Gß g#8G!ß”v#@G*ß%y#HLyG¾Þ« y#GÇÞ« y#G4߈#XGóü‚#\G=ß´ˆ#`?vAGßQTߨ°G¨Ù¯±#Gß”´#G ß”º#Gaß´½#Gm߈¿# Gv߈À#!G~ßìÂ#(LÂG¾ÞqÂ#GÇÞqÂ#G‰ß”É#8G—ßÀÑ#@GŸß”Ô#pGªß”Õ#xG½ßˆØ#€GÁ߈Ù#GË߈Ú#‚GÕ߈â#ƒGÝ߈è#„Gäß´ë#ˆG)~î#¨?W?¹"$!AËïßFõß0 GŸß”+#GÙd}.#Gûß4#G à5#Gà68#Gà^9# G'à<#(?;AF+àR2S2Y?XS?}?cAn6à Tˆ2S2S?„ADàFKàG'*S#GPWS#A¿RàF]à IGhà”K#Gpà”L#Gyà”M#Gƒà”N#8ðBq ?AŽàFšà`ŒG¨Ù¯Ž#G¦àš#G­à¨ #G³à\£#L£G¾Þ £#GÇÞ £#Gäß´¦#(G½àÆ©#HG)~ö¬#XA³ÀàŠLŠGÑà« Š#AÑÚàFäà;G)~ë=#GÿU>#8ðBq ALîàVAfãFyãHG¡Ü”#G©Ü”#G±Ü”&#GŒã},#G”ã”/# G›ã”2#(G¤ã”5#0Gªã”;#8G»Ü}>#@8ï Bq ?°A»ù  F hQG?‡ R#G â&S#G T#G >Y#G JZ#(?A# T+2}?+A6b R2+8Bq 8VBq Aav  F„ -OsD#PDG’ ðE#Gž +F#G¢fI#G¦ N# ?+]Óév,Aáv,Ëiv”\çé;Aáë;ËiS[ÈçH”,AáH,ËiH”-¦—J”Y©èúð;Aáúë;Ëiúðyp Ö Vl0t+wÅ/t«w<Åbtoñð†w`aÅþ`„Å a©Å ‡q¸‹ • `N‹ • bfbqaßÅ| ™ · qÖ± · m¶± · !`Æ¿`'ÆÊ ¼ Ï  ¼ Ï q(Ä É gùÄ É þbnyà F V‡0{+w]Æ/{«w“Æêï{+Q“b{oñP‡~aÉÆ €‡q¸ó û `Nó û bfbqaÿÆ| ÿ # qÖ # m¶ # !`$Ç¿`GÇÊ ( ?  ( ? q(4 9 gù4 9 þbnå=@×  0,~å×P £T >ÿ0E 8F"\Ø>1b! @FAm£ØAxªØ\"ºØ?„@‰"$![ÈçH¿,AáHÑ,ËiH¿-¦—J¿AÊWÜ"`Ü?¿YÝç*b;Aá*ý;Ëi*b?bfP ±3 V#1q_}Ç2òqG _½È;òqY _6ÊVñrk21u¿glÊìÚ|Eg¸Ê81{EgËwÛzEgPË>1yEgœËG1xEgèËN1wEg4ÌV1vbg€ÌªHt¸ ° -  ¹ - Z‘þ”Z °‡ ˆgºÌ\1¶bg®Ï`1¶bgúÏd1¶bg–Ðh1¶bgÒÑm1¶bg–Òr1³EgúÓu1¶bZx1²Z|1´Z Z1µË @ˆgÔƒ1¾b €ˆgjÔƒ1Àb ø" c#  # c#  # c# Z†1úË c# È#  l# È# Z†1þË Ú& R' g¶Ô‹1 E R' Ê' gÚÔ‹1 E °ˆgþÔƒ1b àˆgJÕƒ1#b ‰g–Õƒ1'b @‰gâÕƒ1*b p‰g.Öƒ16b  ‰ Љ ŠgzÖƒ1Ab 0ŠgÆÖƒ1Fb `Šg׃1Qb Š ÀŠZ9öWýZ¦ XbZÝßXbZ1XbZ° XbZ£ÛXb ðŠg^׃1Zb ‹gª×ƒ1[b P‹gö׃1\b €‹gB؃1]b °‹gŽØƒ1^b à‹gÚØƒ1_bÖ5. :. fbð5. :. .b¨a&Ù³ Œ PŒZ¢îiZ b. ”. g]Ùƒ1kb Œg•Ùøëm¿gºÙ˜1nbZ‘þoZ Zœ1oZ ÐŒ 1 62 Z¢î„Z 1 M1 gÞÙƒ1ˆb M1 62 gÚøëŠ¿g;Ú˜1‹bg_Ú‘þŒZ ]©12,2ò2G ,;ò2Y ,‘þ3Z -¬6E-À16E-¦7Z -Ç15b-Ì17Z &-ƒ19b&-ƒ1;b&-ƒ1Hb&&-¤ãJ¿&-%ñLa -)ñLb-ƒ1Lb&&-Ò1Vt -×1Qb-›óQb-¾óQb-ŒãQb-á1Qb-»ÜRb-ÇóS€ -¡ÜT¿-©ÜT¿-±ÜT¿-”ãT¿-›ãT¿-ªãU¿&-%ñ]a -)ñ]b-ƒ1]b&-%ñ^a -)ñ^b-ƒ1^b&-%ñ_a -)ñ_b-ƒ1_b&-%ñaa -)ñab-ƒ1ab&-%ñca -)ñcb-ƒ1cb&-%ñea -)ñeb-ƒ1eb&-%ñga -)ñgb-ƒ1gb&&&-%ñja -)ñjb-ƒ1jb&-%ñla -)ñlb-ƒ1lb&-%ñoa -)ñob-ƒ1ob&-%ñqa -)ñqb-ƒ1qb?L R2Y 2M"Ù8bBm :f8‰Bm AZ wé]ç1¡,2ò¡G ,;ò¡Y ,‘þ¢Z -À1¥E-¦¤Z -Ì1¤Z -ÿ1¤Z &-ƒ1ªb&-ƒ1«b&&-¡Ü­¿-©Ü­¿-±Ü­¿-¾ó®b-»Ü®b&-%ñ°a -)ñ°b-ƒ1°b&-%ñ²a -)ñ²b-ƒ1²b&-%ñ´a -)ñ´b-ƒ1´b&&&-%ñ¹a -)ñ¹b-ƒ1¹b&-%ñºa -)ñºb-ƒ1ºb]2Ï,2òÏG ,;òÐY ,‘þÐZ -À1ÓE-¦ÒZ -Ì1ÒZ -ÿ1ÒZ - 2ÒZ &-ƒ1Øb&-ƒ1Ùb&-ƒ1Úb&&-¡ÜÜ¿-©ÜÜ¿-±ÜÜ¿-)2Ýb-ëÜÝb&-%ñßa -)ñßb-ƒ1ßb&-%ñáa -)ñáb-ƒ1áb&-%ñãa -)ñãb-ƒ1ãb&&&-%ñèa -)ñèb-ƒ1èb&-%ñêa -)ñêb-ƒ1êbrð3 £T V52_„Ú2òG _ Ü;òY _Ý‘þZ _PÝwÛE_ŠÝ81E_ÄÝìÚEZâÙZ Z'Z1ÚËZnÚËZÇ1bZbZ$bZ£ÛbZÁÛbZÑÛbZªÛ¿Z±Û¿ZºÛ¿ZG2 bZW2 ¿Ze2 ¿Zs2 ¿Zƒ2 bZ“2 ¿Z¡2 ¿Z¯2 ¿Z¿2 bZÎ2¿ZÛ2¿Zè2¿ .ê €m`þÝó `^Þþ n aºÞ /M [M aßÞL ^M ŠM aßY ŽaOßf 0Ž €Ž ÀŽ/‘ ¬ a›ß· açß ðŽ/‘ Ï aàÚ akàå /‘ ò a£àý aïà P € °/‘  a'á" asá- à/‘ : a«áE a÷áP g/âƒ1b P ‘ %ña g{â)ñbgÇâƒ1b  ‘ %ña gã)ñbg_ãƒ1b À ‘ %ña g«ã)ñbg÷ãƒ1b ð ‘ %ñ#a gCä)ñ#bgäƒ1#b ‘ ‘ %ñ+a gÛä)ñ+bg'åƒ1+b P‘ ‘ %ñ,a gså)ñ,bg¿åƒ1,b €‘ ‘ %ñ-a g æ)ñ-bgWæƒ1-b °‘ ‘ %ñ.a g£æ)ñ.bgïæƒ1.b à‘ ‘ %ñ/a g;ç)ñ/bg‡çƒ1/b ’ ‘ %ñ7a gÓç)ñ7bgèƒ17b @’ ‘ %ñ9a gkè)ñ9bg·èƒ19b p’ ‘ %ñ:a gé)ñ:bgOéƒ1:b  ’ ‘ %ñ;a g›é)ñ;bgçéƒ1;b Ð’ ‘ %ñAa g3ê)ñAbgêƒ1Ab “ ‘ %ñCa gËê)ñCbgëƒ1Cb 0“ ‘ %ñDa gcë)ñDbg¯ëƒ1Db `“ ‘ %ñEa gûë)ñEbgGìƒ1Eb “ ‘ %ñKa g“ì)ñKbgßìƒ1Kb À“ ‘ %ñLa g+í)ñLbgwíƒ1Lb ð“ ‘ %ñMa gÃí)ñMbgîƒ1Mb ” ‘ %ñNa g[î)ñNbg§îƒ1Nb P” ‘ %ñ]a góî)ñ]bg?ïƒ1]b €” ‘ %ñ`a g‹ï)ñ`bg×ïƒ1`b °” ‘ %ñba g#ð)ñbbgoðƒ1bb à”.i`•i`»ðr`Þð}añ“nža%ñ© A 5A aJñË –a‚ñØ 0–aÎñå `– Ж —/‘ ÿaò afò P— —/‘þ}#ažò. З/‘ ¾aÁòÉa óÔ ˜/‘ áaEóìa‘ó÷ 0˜/‘ aÉóaô `˜/‘ 'aMô2a™ô= ˜/‘ JaÑôUaõ` À˜/‘ maUõxa¡õƒ ð˜/‘ aÙõ›a%ö¦ ™ P™ €™/‘ µa]öÀa©öË °™/‘ Øaáöãa-÷î à™/‘ ýae÷ a±÷ š/‘  aé÷+ a5ø6 @š.‹  šk`mø” `àøŸ nµ aOùÀ ŸI ËI atùâ ›a¬ùï P›  › à›/‘ 5 aøù@ aDúK œ/‘ X a|úc aÈún @œ/‘ { aû† aLû‘ pœ  œ М/‘   a„û« aÐû¶ /‘ à aüÎ aTüÙ "ÀÙ8E€m AÖÍá AáÕáw"æáò9=@× ÷2ö‡å×°T Ák >W3E àD"\Ø>e3b èDAmÍáAxÕáw"æá>z3• P?šA¥^ïFpï@G‚ï¼A#"ÙE3¼ XQ>™3¼ P>£3  PA£ØAªØ\"ºØ>¶37 (P?<AGîïFøïbOYc#PcGòã{d#Gõ$7e#?€A‹öÜFÿÜHSGÝ¡T#LTG Ý{T#GÝ{T#GÚûU#GÝ V#G)ÝOW# G5ÝZX#(AWÜ"`ÜA;ÝFDÝ GMÝ= #GRÝ= #AH¸Ù"ÀÙA¼YÝ ¼8fBèAqaÝFnÝ DG{ÝÀE#G‚ÝHF#GŒÝ¼G# G˜Ý¼H#G ÝâP#AË¦Ý F¹Ý G±Üû #?çM:fEÁ3¼ hQEÎ37 `QDZÙ% 5@EVÌã8 Ü€ @WÖãS 8 P4 @XAcæã UìãP 0Jóü 1#Jòã{ 4#Jùãû 4#J äû 4#Jä: 4# J(ä 4#(J.ä  4#0J;ä¼ 4#8JIäE 4##8çBèAvîàVNQáá5áMáAžgá &Fá ‘G—á´ ’#L ’G ÝÖ ’#GÝÖ ’#?“?` 8ìBèA÷Ÿá (F¶á AG¢f |#AïáFøáGâû#8BèÇAGâ:L:GÑàÛ:#Hfâ5K8-J?‡Õ.#J â/#J'â<0#J.âm1#J7â~2# J=â3#(JÁ>Å4#0?ÚHæCâTç2ç222 2 2¼?E?H!QâTE2ç22E2¼?AHM`âTE2ç2222¼?rHMoâ?ƒHM€â?”H Žâ$TE2ç2222E2¼?ÊHÖœâ+TE2ç22ç22E2¼8Bè#Aªâ ,U¶â` J¨Ù} #JÂâX #JÉâ² #JëÙn #?]AhÎâ 'FÚâH 5GæâO 7#Gíâ¼ :#Góâ› =#8§BèAúâ A½ã ²L ²GÑàÐ ²#?ÕAàã )F+ãX šGBãö ¢#L ¢G¾ÞÐ ¢#GÇÞÐ ¢#O! ¤#PH ¤G©Þ“ ¦#O= ©#P ©GJãç ª#GX㯠«#Gbã] ¯#Ayfã FyãH G¡Üû #G©Üû #G±Üû &#GŒã ,#G”ãû /# G›ãû 2#(G¤ãû 5#0Gªãû ;#8G»Ü >#@8²Bè?AÛä .Uéä ÓJ÷ä  Ô#A@å:N6å*å>å?\AgUåFbå0Gpà#Ghà#G7,#Goå#Gzå¶# 8ÂBèAÍåFåG6ßç#Ge#Yç ;6ß J;'ç EZç + Z.ç Zæâ OZ°( YAç “p;ç “+ ;.ç “?ìYVç ÖP;ç Ö+ ;.ç ÖYlç ä;ç ä+ ;.ç äYç O;ç + ;.ç Zç Zæâ OY¥ç z;Gà zOZ°( |Yºç ‚;Gà ‚OY¹è ë;ç ëZ­à íYÖè ;ç + ;.ç Zç z°T wU VÜ3!UÊæ!.wŒüòã!{xÂüí$ß-æâ#O-Tï%•YÚí ;Êæ .;(ä Z°( ?X] èH,"èHxY³ü  ;Êæ .;ÞÙ ¼;Æü EZ.ä  ZýÞ  YÙü FÆ;Êæ F.;ÞÙ F¼ZýÞ H ? \Šü ß;Êæ ß.;(ä ß;RÝ ß¼Z÷ä áÆ[Pí7E,€ê7Æ,RÝ7=]<è[,"è[xz€U ÔX Vñ3XwøüÊæX.w|ýòãX{wJþíXßw¹þæâYOw2ÿ 4Y¼x«ÿ4^Ex4]¼xD#4]¼ƒ‘þ]¼xº(ä[x6ß\çoû0ca;! ²U 5X  `xr-4ix»çg+ - ýjÛ3 roËà’`=á`sí.“ž å`­¡.H@ž Jbÿÿÿÿÿÿÿÿÿnaøz €ž.°ž è` àž 0Ÿ €Ÿ °ŸxU.ç€x‹Â‚poIàŸƒ`ÁW`c* ‘ 5X …X  DX …X - ý™Û(3GX cX š(*}X …X žzàX ùZ V74©wSÊæ©.wÄí©ßw æâ©Owq 4ª¼Xòãª{xê4¯Ex64®¼x[(ä¬x¦#4®¼ƒ‘þ®¼xó6ß­çoûP ´a! Y iZ  !Y `Z xMQ4ºxƒç¸+ -Aÿ»EoË€ æ`ÌÕ`á`:í.“À  å`t¡.Hð  Jbÿÿÿÿÿÿÿÿÿnaªz 0¡.`¡ è`Í(3{Y ˆY ¿(*Z Z ã iZ ªZ  tZ ªZ (3tZ €Z í(*¢Z ªZ ò[;íÿç,íÿß,íÿ Z°(ç?fy[ _[ V^4IçUÊæI.T(äIw òãI{wP íJßw™ æâJOwè íJ x1 °(Lço¯¡R`T ¼aŠ Ò‚y4ý,òãý{,(äýf`[ Â[ V“4 _À òã { T4ê _ö =ê ‡u[ Â[ `, ’`O  u[ Â[  u[ Â[ m3u[ [ m*°[ Â[ i¯4¡;òã¡{;(ä¡Z‘þ£¼&&Z ý©ÛZíªß&&ZIܲo Zí³ß?fÐ[ J^ VÅ4_r òã{_» (ä ç[ J^  ç[ J^ m3ç[ ó[ .sÀ¡$n$– E\ \  E\ p\ m3E\ X\ «m*`\ h\ ­m*4^ J^ %4P^ ‡_ Vs` ~`N Ša„ – m^ ¢^  m^ ‘^ s¤s°m3m^ x^ «m*^ ‰^ ­ ¢^ ~_  ¢sÀsÌYÏë a¶Zâë a¶&&ZJW aë?»HÇêë :KX :JøëE :#J¦HX :#Aöì Uì JÝ #K J ÝQ #JÝQ #J:xV #JPWç #?ëAa &ìAl 0ìv?q QCì gGUìxh#G[ì¥ i#Gkìê j#?ª Ftì9G‘ìÝ :#G›ìç;#G¡ì¥ <#?â R2ç8°CèïY¨ì a.Zâë a¶Y³ì d.ZÊæ f.[‡&¾E-]äÁ5-ÊæÀ.\Àì a;¦H a.Zâë a¶\& ”;Êæ ”.;]ä ”5]·&Ð,Í&ÐE-]äÓ5-ÊæÒ.ià4‹;Êæ‹.Zòã{\ëì ”;Êæ ”.;òã ”{\±í a;âë a¶j_ îb Vò4*{_å Êæ*.gA (ä, P¢.-! ¢.ad :!o!£Å.÷ P£ f.‹£ a У ¤a‰ §p "@¤ a p¤  ¤ Ф ¥.Q!@¥ l.‹p¥ a  ¥ ia Îa aÁ §m "ºa Îa  a Ð¥ ¦.Q!P¦ o‹Îa ãa  a Îa ãa  Îa ãa aå § ` `  ` ` (t!` ` É €¦ °¦.—!à¦0b !„«!o!§×.÷ @§ f.‹p§ a  § ãa [b a §m "2b Fb  a Ч ¨ 0¨ `¨.Q! ¨ l.‹Ш a © [b ·b aA§m "§b ·b  a 0© p©.Q!°© o‹·b Ìb  a ·b Ìb  ·b Ìb ae§qt!£` ª` ÚlŠ! ª` Ç` qÂ!°` Ç` Ýa‰Ù! °` Ç`  µ` Ç` æ!½` Ç` ”`¬ü!.ûà©3aÏ!YÔî ¾;­à ¾;Üî ¾Ze ÀYæî °;­à °Yˆæ IO;­à I&Z°( NOYíî £;­à £Z°( ¥Yûî Š;­à Š&ZËi –Z ï ›Ze Z„è ™Zï œ&&Zè Z•è [èú¼,Ëiú-°(üYæ 6;ÞÙ 6¼;ªæ 6EZ°( 8Yï Îç;Êæ Î.;e Î;Üî Î;Îæ ÎE;òã Ï{;êæ ÏE;(ä ÏZ°( ÑçYöæ ;6ß JZç + Y ç ‡;6ß ‡JY6ç •;6ß •J;'ç •E[ÈçHû,AáH6(,ËiHû-¦—Jû?ûYÝç*;Aá*P;Ëi*\íç À;(ä À;­à À]‡ê!,€ê!Æ,RÝ!=Y©èúç;Aáúâ;Ëiúçjðb Mf V5:{_Êæ:._N(ä:g¿5=g­à=gdòã<{g‡‘þ>¼.Å%ªF`Àß%a4ë% Pª €ª.ø%°ª Ô`}& :c dc <&Gc dc  µ`³J&aÖV&&Gc Uc  ¥`ù!&Uc dc  ¥ac&äe f  ¶`?q& äe f au~&a˜Š&a»–&Ø&ée íe  ˜`Þå&að& ઠ—c ác ø%Ÿc Îc  â`$&c&Ÿc Îc  ¶`Gq& Ÿc Îc aj~&aŠ&a°–&Ø&¤c ¨c  ˜`Óå&aöð& « P«.ø%€« û`& øc "d <&d "d  µ`<J&a_V&&d d  ¥`‚!&d "d  ¥a¥c&f Mf  ¶`Èq& f Mf aë~&aŠ&/R–&Ø&f !f  ˜`1å&aTð&.ü&°«Ib 'b'aw"' à« že ¨e ¥(že ¨e  >`­¿((že ¨e þ`Ð(b(aó*(./'¬Hb@U'bÿÿÿÿÿÿÿÿÿa'`*m'bÿÿÿÿÿÿÿÿÿy'aM‘' @¬ €¬.Å'°¬ Ù`ƒÓ'.ž'ଠŒ`¹¬'aï¸'.à'­ Ùbú'.ò@­ œb aa5$aX0a}< p­  ­Ã¶d Íd  %`ÆÑ`éÝa éa/õœ¶d Àd  `Tª`w¶u¶d Àd  ç`šƒ`½I¶d Àd  Ù`àW`c Э Ød ãd )Ød ãd  @`&7Ød ãd  †`Kap Ée äe kÉe Ùe  0`“y`¶…aÙ‘DÉe Ùe  `RaE^b(ãd íd  Ù`hl(`‹x(;(ãd íd  Ã(ãd íd .a®*(.‡®M`Ñ’`ô 0® `®m3íd ùd m*.e @e …(@e De Olä™(4Pf yf VÂ!`>Í!atÙ! ]f rf  bf rf mæ!jf rf ”\ é ;Êæ .;6ß ç;òã {;êæ E;Óæ EYé5;Aá5P;Ëi5\(é Ç;(ä Ç;­à Ç\Hé I;Êæ I.;6ß Iç;òã I{;Óæ IEZç K+ Z.ç LZç L&&&&&&Zæâ XO&Z­à ar€f Éh V#5b_—Êæb._Aòãb{g°(ädg‘þe¼.û®gao! ×f g  ×f g Zíkß âf g  éf g Z ýoÛm3éf ñf pm*ùf g r g Œg  "g g g¥íwß À® ð®p3 ¯{m*wg g .š0P¯‡bÿÿÿÿÿÿÿÿÿÈ0bÿÿÿÿÿÿÿÿÿÔ0 €¯ °¯.Å'௠.ž'° Œaȸ'.à'@° bú'.òp° œb aëa$a10aV<  ° аÃÈg ßg  %`ŸÑ`ÂÝaåéaõœÈg Òg  `-ª`P¶uÈg Òg  ç`sƒ`–IÈg Òg  Ù`¹W`Üc ± êg õg )êg õg  @`ÿ7êg õg  †`$ aI  zh •h kzh Šh  0`l y` …a² ‘Dzh Šh  `è Ra!^1õg þg  `A!1`d!1á0õg þg  Ê(øg þg 9`‡!(aª!*(.+10± `Í!M1bÿÿÿÿÿÿÿÿÿY1að!e1a&"q1 p± °±œh 'h  S`I"ª`l"¶uh 'h  ç`"ƒ`²"Ih 'h  Ù`Õ"W`ø"cfÐh Öh V25™ UÊæ™.jàh ži VL5»E_#Êæ»._d#^5»ð9g­#òã½{gÐ#êï¾7.ü&ð±Éb 'b'aó#"' ² —i ži ¥(—i ži  >(—i ži þP(b(a)$*(\d5Ý;ÊæÝ.;êïÝ7f i Ïi Vv5ç UÊæç._`$ÞÙç¼m›7´i Êi êfÐi j V‡5î UÊæî._…$ÞÙî¼gª$êïð7›7æi ûi ñ`Í$±7YSè *O;­à *&Ziè ?Z|è @OZGà COZËi 5OZ†! 8OZ€è :OZ„è <O&&Zè /OZ•è 0OYzæ UO;­à Uj j Ák Vš5÷Egð$‘þù¼. 9P².~8€² [`=%Œ8 À²a`%™8aƒ%¥8a¨%±8Ø&Yj gj  7`Í%å&að%ð& šj ·j m&£j ·j  Z?¼n"t@× ©5u–å×0ÉÐk >6A ðDAL6 U'6J76d#KJûÙ‰#J¨Ù«#?ŽA™ì Uì  Jݱ #K J ݉ #J݉ #J:xô #JPW #Aÿ&ìA 0ìv?QCì gGUìCh#G[ìJi#Gkìj#"æá?OFtì9G‘ì‚:#G›ì;#G¡ìJ<#?‡R2M8C¤ï"$!:fA¶ŠÙF™ÙG¨ÙÍ##HÙ­Ù™Aä¸Ù"ÀÙ>>6 EH êë:KX:Jøë1:#J¦H8:#"\ØACæãUìãP0Jóüò1#Jòã4#Jùãš4#J äš4#Jä{4# J(ä,4#(J.äK4#0J;äç4#8JIä14##8B¤AŸîà VN Qáá5áMáAÇgá&Fá‘G—áÝ’#L’G Ýÿ’#GÝÿ’#?¼?‰ 8B¤A Ÿá(F¶áAG¢f9|#ABÍáACÕáwAXïáFøáGâš#89B¤ÇA†â:L:GÑà:#H¥â5K8-J?‡.#J âO/#J'â{0#J.â¬1#J7â½2# J=âÎ3#(JÁ>4#0?H%CâT229292J2J2ç?1?TH`QâT1229212ç?€HŒ`âT122929292ç?±HŒoâ?ÂHŒ€â?ÓHߎâ$T12292929212ç? Hœâ+T1229229212ç8FB¤#AQªâ,U¶â`J¨Ù« #JÂâ—#JÉâñ#JëÙ­#?œA§Îâ'FÚâH5GæâÜ7#Gíâç:#GóâÚ=#8æB¤AOúâ Aüã²L²GÑà²#?Aã)F+ãXšGBã5¢#L¢G¾Þ¢#GÇÞ¢#O`¤#PH¤G©Þ¼¦#O|©#P©GJãª#GXãØ «#Gb㜯#A¸fã FyãH G¡Üš #G©Üš #G±Üš &#GŒã9 ,#G”ãš /# G›ãš 2#(G¤ãš 5#0Gªãš ;#8G»Ü9 >#@8ñB¤?PA[Ûä.UéäÓJ÷ä¬Ô#Aå:N6å*å>å?›A¦UåFbå0Gpà9#Ghà9#G7,9#Goå9#Gzåõ# 8B¤A åFåG6ß#Ge9#>O61 HFE]6ç pQ>g6r 0PA}r6AO€6pWÖãž8  4 @84Ðk âk V„U’YÏëaíZâëaí&&ZJWaŽ?\Àìa;¦HaZâëaí?8|¬6¦,È6¦U,JW¦‰-†%¨ô-E©‰?A] èH,"èH¹]<è[,"è[¹|—6,­à9\±ía;âëaí‚Í6¼,È6¼U,JW¼‰zðk ²o Và6Gw&ï6G-ÊæI ³oò0³f.Âp³a °³ ð³. ´a`\&3a€&>a¶&I(Zçl ól ¬ €´ д µ o ,o (oo (o ¯(ocm om ·„tm |m abX’mž¢m µm a.µ0µa`Ù&Ë(Zµm Ám ¿(oEo Vo Áoò`µU. µa ൠ¶.P¶a`ý&3a!'>aW'I(Z n n ¬ °¶ · 0· Vo fo (oVo bo ¯(on ‹n ·„n ˜n abX’pž`·a.µ·a`z'Ë(ZÓn ßn ¿(oo o ÁXó6a1Y¨ìaZâëaíY³ìdZÊæfyÀo Ót V7n1 À·oið·r.ž ¸a`ž'¨o’P¸t.w¸f.Âà¸a 0¹ €¹.À¹a`Á'3aå'>a(I(Z½p Ép ¬ º pº  º ìr ür (oìr ør ¯(o3q ?q ·„Dq Lq abX’mžtq ‡q a.µкa`>(Ë(Z‡q “q ¿(os &s Á » @» €» À».òð»l. ¼a P¼ `s ±t .€¼a`b(3a†(>a¼(I(Zhs ts ¬ ༠0½ `½ wt ‡t (owt ƒt ¯(oÚs æs ·„ës ós abX’mžt .t a.µ½a`ß(Ë(Z.t :t ¿(o t ±t Á À½ ¾.ò@¾o.€¾a À¾ ¿.0¿a`)3a')>a])I(Zßq ëq ¬ ¿ à¿ À &s 6s (o&s 2s ¯(oQr ]r ·„br jr abX’mžr £r a.µ@Àa`€)Ë(Z£r ¯r ¿(oOs `s Á\7aZâëaízàt õy V!7yoÇpÀ|„öt þt abX’pž Àao’ÐÀ}.wÁf.Â@Áa €Á ÀÁ.ðÁa`¤)3aÈ)>aþ)I(ZÚu æu ¬ P  Â Рx x (ox x ¯(oSv _v ·„dv lv abX’mž”v ¨v a.µÃa`!*Ë(Z¨v ´v ¿(o7x Hx Á 0à pà °Ã ðÃ.ò Äl.ÂPÄa €Ä ‚x Óy .°Äa`E*3ai*>aŸ*I(ZŠx –x ¬ Å `Å Å ™y ©y (o™y ¥y ¯(oüx y ·„ y y abX’mža@+I(Zw  w ¬ ÀÇ È @È Hx Xx (oHx Tx ¯(orw ~w ·„ƒw ‹w abX’mž±w Åw a.µpÈa`c+Ë(ZÅw Ñw ¿(oqx ‚x Á4z ­z V`‡+(`½+3aó+>a,I(Zz (z ¬  È ÐÈ É ’z žz (o’z šz ¯(o†z ’z ·4°z { Vµ`L,À`•,Ë(ZÀz Ìz ¿(o{ { Á‚57,âër { ‡{ VJ7a_Ë,ï6aZâëaí"t{ ‚{ a`- "!=@× a7†¢å×{ š >¿7EC 8P?JR2W2XM?]@b"$!]Ñ70,;ò0W,¨…0X-ˆD=”"æáz{ Ú{ VÜ7Jw7-¨…JX ™{ Ú{ qiµ{ Ú{ P`€-}4à{ | Vi`£-r`Æ-}sˆy| | Vì7XˆU“ªHXˆT#9XyQø7X£\Àî@;Íî@ˆ"ÀÙy | ~ Vÿ7l~wü-8lXwX.8lºw¡.8lˆx/AáqXx40âqXx}0°(n~xE1Veox‘1$8n~-*8p— °É „| ¡| qq„| ¡| vl{ _} ‰} xí1.8¾~ m} ‰}  u} ‰} qqu} ‰} Ãl"{ –} °}  ›} °} qq›} °} Îl{[38ßy,Ëiß~,8ß,78ß—,¨…ßy,A8ßž-‘þá&&-H8ùX&-H8îX?bA‰•ñ "ºØ"Ù"\Ø?£A®£ØA‰ªØ\YO8$y;Ëi$~;S8$—;¨…$y;A8$žY\81y;Ëi1~;S81—;781—;¨…1y;A81žY`8 y;Ëi Ž;d8 b;¨… y;A8 žZ*8 —A”i8 j ~ Ž– Vr8>ˆ_2Ê >y_¹6­à>£_’92:>X_µ9†8>Cgt>ÍiBXgh?‘þA£góB°(@ˆ àÉ Ê PÊgCùg™ˆgRC‰8˜ˆkqÿUšïkŽ8•—ZS8”—Z›8–—Z¦8—— Ê Ë ‘€#9¿gŒC¦H~.¹pË `êCß` Dë. àË'`ÈDb%b0`ëDFn@Q "Ž ¬ g¦E°8 £ :Ž ÎŽ  @ÌgÜE¦ £ ÎŽ (  ÎŽ $  ÚŽ $ gÿE¸8 £ ( ¬  pÌZ¦ £  Ì ‘ö~#9#ãg"F¦H"ï àÌgGF°8*£ Í W‚ ­‚ Z¦*£ ­‚ ƒ  ­‚ ƒ  ¹‚ ƒ g}F¸8*£ @Í pÍZ¦*£ °Í ‘€#9×g F¦H~.øÎ`$G*`GG6. Î4`Hb%`%HFn@Q Ï °ÏaàHk ¡… 2‡ gI°8£ ¹… R†  @Ðg9I¦£ R† ¬†  R† ¨†  ^† ¨† g\I¸8£ ¬† 2‡  pÐZ¦£  Ð ‘€#97×gI¦H6~.øÑ:`¢Ibÿÿÿÿÿÿÿÿÿb`ÅI*`èI6. 0Ñ4`£Jb%b0`ÙJFn@Q cˆ ˆ  cˆ ˆ a”Kk `ÑgÌK°8;£  Ñ àÑgL¦;£ H‹ ©‹  H‹ ¦‹  T‹ ¦‹ g%L¸8;£ ©‹ +Œ  ÒZ¦;£ @Ò ‘€#9ËgHL¦H~. ÀÒ`¦Lb %b0`ÜLFn@Q 9 Õ‘ g—M°8£ T ñ  ðÒgºM¦£ ñ F‘  ñ B‘  ý B‘ gÝM¸8£ F‘ Õ‘  ÓZ¦£ PÓ ‘€#9þ¿gN¦HýŽ.CÀÓ`„NQ`§N]`õNi`Ou. PÔ`æOb %b0`/PFn@Q †” – gêP°8£ ž” B•  Õg Q¦£ B• ˆ•  B• …•  N• …• g0Q¸8£ ˆ• –  0ÕZ¦£ `ÕgSQ°82£ Õ ÀÕg‰Q¦2£ —Œ úŒ  —Œ öŒ  £Œ öŒ g¬Q¸82£ úŒ o  ðÕZ¦2£ Ö / ^ gÏQ¿8Á~q/ : Âl{ `Ö ‘ À gòQÆ8Ø~q‘ œ Ùl{jP— ë— VÌ8Xˆ UÊ Xy T­àX£ Q2:XX… ‘P†8[ögR°(Zˆiß8e;2òeE;;òeW;2:fX;†8fCZ#9h”?HASò8ÜFò8ÜG9Ü#G 9Ü#G9WÜ#G&9WÜ#8bC¡ÿ:ffð— ó˜ V49_:R2òE_pR;òW Q2:€X… ‘°_†8‚öû •˜ Þ˜ …`¦R`ÜR/‘Ð_6f™ š VF9Œ_ÿR2:ŒX… ‘À_†8Žöû ­™ ð™ ‘`HSc`~S`¡S*/‘à_6?y8bB¡A8bB¡@8bB¡B8bB¡"LÙAW9A _9bHp9[8HB¡gimli-0.19.0/fixtures/self/debug_inlined010066400017500001750000000607461343337721300164650ustar0000000000000000âa_æ ‚mzæ&2X# Œßµè ˆæB%ùáh›&xr¾*Su5,4v.-èwÖ1ÇxŸBˆDþˆ”Eý‰oJf“™Kf•MH–¢O€”‹EÀ(Áy ÃŒ“ÆS”Uƈ™xËSšçË…¼*Þ,¾.ß­Åîä ןí Ú€î¨è=ó\÷! ˜þR ©ÿ€ ˜Ù Iù ¹š \¾ ÿ ¢; “l –z ) Žè G!Ü §0#  1A# Ã4K/ «5á.  6é/ JA9 ôKa: ²[×E Á\F €~M ý®ÊU †˜ÙÒ Öš¨Ô mžÐ× [È€å ÒÉ^æ $×Òî 8þ§ý C Ñ G? dKt  [  a¯ ·»Gc ˆ½d ÈË£j æ[ oÑäo@‰p«B‘¢ ºæVú iAç<­ûdiÅÿêjä?kœ@އHÝŠ¬ÖÖ¤¬èÖ|­9×sáÚð2âóð2ãñ åØñÊåòñ6çòÁíUû5óþÉ? öv ÿ  ð # š{ ‡” ´¹ ~=&3  >L3 Ð>°3 6@}3 ™AÚ3 C¹4 ßCä4 ³D;5 4F6 ùF@6 ST•C RU³C WD YE Z>E heàI ÷g'K >Î!ç ’Ó6ë ŸÕë mÜè žÞiè §Ó ´' |C" €Ev tP] ’S IUé HWà LY ‡]µ ‹_  ·bö :À¶d AÆÈg NÈh Vç;ƒûdi›ÿêjº?kr@އæGÝŠà«ÖÖz¬èÖ[áÚðâóðãñóäØñ©åòñçò—íUû óþŸ? Ìv Õ  Æ # y{ ]” й T=&3 á=L3 ¦>°3  @}3 oAÚ3 ðB¹4 ¾Cä4 ‰D;5  F6 ØF@6 )T•C (U³C ñVD âXE ÛY>E ÷d±I GeàI Î!ç hÓ6ë uÕë CÜè tÞiè }Ó Š' RC" VEv JP] hS Ué Wà "Y ]]µ a_  bö À¶d ÆÈg $Èh lç1Yûdiqÿêj?kH@އ¼GÝŠCáÚððáóððâñÛäØñˆåòñôæòmíUûáòþu? ¢v «  œ # X{ 3” `¹ *=&3 â?}3 EAÚ3 _D;5 ÿS•C þT³C ÇVD ÁXE ±Y>E êÍ!ç >Ó6ë KÕë Üè JÞiè SÓ `' (C" ,Ev  P] >S õTé ôVà øX 3]µ 7_  cbö æ¿¶d íÅÈg úÇh çûdi5ÿêj @އ€GÝŠo  ` # ®Í!ç Ó6ë ÝÛè Ó ìB" äO] S ¸Và ÷\µ ª¿¶d ±ÅÈg ¥ç8ü†i* k['rà*auW,DvP-öwi3|œ4#ƒ~6õ~I77}A°‡ÁB'ˆ8D ‰uH‹‘Jt“»Kt•2MW–¹È¢æ‡ÍÇéüÐíyØîŽÛ÷î±ÝBöºþa ËÿŽ d ª U > µ{ ñþ  K ¦÷ N1# Ô[æE ¢~(M ¯ØU _3Gš ä4Ýš ƒÎ }ÈŽå ôÉmæ £ÎHç ÷Ó]ë ÒÜ9è  ö áCE N¶ âNç ÙP{ ÷S' ­Wæ ì]Ø Ù»Uc ª½d ŸÀØd ¦Æêg ºç$ñû†i  kC'rQ3|„4#ƒf6õ~177}à@°‡TH‹˜È¢æfÍÇéäÐíXØîmÛ÷î™ÝBöC ª 4 > Ðþ ü -1# >3Gš Ì4Ýš ì‚Î ‚ÎHç ÖÓ]ë ±Ü9è ëö ÀCE áM¶ ÊNç ¸P{ ÖS' ŒWæ Ë]Ø ~ÀØd …Æêg Èç]ýù j÷ü‘ikPl«Âl)Ïl% o¼ *o1 4o¹ §p2öoQ¿pï´p½„p§›p-qõ.20…¬<¥ŒD>Û’Km »qoZ½ŒåÀŽÂŒ/Äð‘dÅ­’ÀÅe˜áÉg›QÌ$f %¶ t(Å [+N ö+í µ<ú2 =XÇD ™pP „›ÖP ¿¤%S N¦ŠS ì§.T „©™T ^<Àž >‰Ÿ x?I  A¢ CŸ¢ «C`£ Ôp–º ‚>Ë %Ìñé (ÍAê ˆÏSç yÑâì |Ò1í ÜÔkë TÚçí WÛ1î ·ÝGè …ãô ˆädô ‰æ.ñ Œçˆñ êÂò ‚ëó [í?ø ^î”ø Sðjó VñÅó (óD÷ +ô‘÷ ªönú ¹÷Äú œù6ü «ú„ü €¶  ŽN ‘¤ ñ Á ( Ð t ÆDS ¾Q† ’Xô Ñ^æ zxÄ Þy4 G5. ¢¾že „Áãd ‹Çøg ZÉ—i Ýçßü‘iñ‹åÀÙ‘dÅN˜áÉå#f ã$¶ V(Å =+N Ø+í &XÇD pÏSç ¦Q† )5. lÁãd íçµü‘iFÏSç |Q† BÁãd  è›·ø©iÊîk¢ ®n2!ns8/Lï<´ŒßQÖ›/VZ ÓZú¤é^o©l˜ºÃoƒ½X†ݾø†€¿¨Š(À¹ŒÁ …Ã;‘ÅQ•ÅÇå—É™\Ëÿ›šÍüœàÍNžúÎ1ŸJÏ¢`ÒÖ­â×O´Ú†¶åÜ•»ØÝÒÀÑàÁúàåȰæSË«è³ÍÒéaÐWìÒÞ†ïÔéÏ÷ið€ý™ð©ýŽóEþiôÈþAø  ù~ `‹ ¥ú Ò ^#* b') ä( $dI ýQM ~‚DO 8Q žØQ ¦¯V g¶M[ è¸K] &»î_ ã¾æa -À£c XÁ e õßäh 0æo mçºo ªèZp çéúp $ëšq aì:r žíÚr ˜îjs wïás ´ð‘t ññAu .óñu kô¡v ¨õQw åöx "ø±x _ùay œúz #üáz `ý¡{ þa| Úÿ!} a~ žÁ~ Û A€ Ÿ! Üá  ¡‚ V aƒ “ !„ Ð á„  ¡… Ja† ‡!‡ Äᇠ¡ˆ >a‰ {!Š ¸አõ‘‹ 2AŒ oñŒ ¬¡ éaŽ &! cá   ¡ Ý!Q‘ ÷&j’ ß'ê’ l1ð— î8­œ ”;Š ¦@ˆ  @BR¢ ŒGL¤ p³¸ àÛè Çë.ö †ñÊö é÷Ôú øû ê& … T«GX ­{Y q­tZ 2¯u[ 1°ç[ }°E\ )±m^ ÓÁíd pÄéf Bâçl øâµm sã n äÓn 1å½p çå‡q ƒæhs 9ç.t Àçßq vè£r méÚu #ê¨v ¿êŠx uëPy üëw ²ìÅw 'íz ºíÀz (èŸø©i<èÂÙøÀi§6lÞpFcp¹!só!I‚:"Xz¦"|zÎ#3‚ 1‹×>øŒfRœ RËŸÛR;GS_oTµŸ¶V‰ ðVé£7Wb¡£W†¡ËXÓ£Z[)¥”[ÿ¨Ï[o¦;\“¦c]é¨p_ž©ª_»¬ñ_Dª]`hª…a¥¬Ûoƽ††4¿¶†V¿‡¿9Œ/ÁQŽ5ÂÆcÄè’ÝÅ–õÈ–˜FÊ¡›nÌœ­Í…[Îfž ÏåŸ;к¢ëÒ·ª}Õy®|Ùĵ‡Ü!·YÝ}»ÐݺÀÉàêÀòàʇè¦ÊèÊËGéØÎ„ëòÎëÆÐí·ßôèÙò0é¦ó9êµùQðxýð¡ý¦ómþõ<ÿYø& ­ùî Ñ) ëæ £ I¿ v#< ž(ë ü(p ÎbH ‚ŸN Ÿ‚qO poQ ‹ €R ʲøW F³KY g´2Z ´‡Z Ÿ¶©[ ^»C` Ž}a ¿Bb eÀÿc Áie “à\j °æ|o íçp *é·p gêWq ¤ë÷q áì—r î7s ºî¢s ÷ïMt 4ñu qò°u ®ó`v ëôw (öÀw e÷px ¢ø y ßùÐy û€z £ü^{ àý| ÿÞ| ZŸ} á~~ ? [ÿ ˜¿€ š \Z‚ ™ ƒ Ö Úƒ  š„ P Z… † ÊÚ† š‡ DSˆ ‰ ¾Ó‰ û“Š 8P‹ uŒ ²°Œ ï` ,Ž iÓŽ ¦“ ãS  !‘ ]"À‘ '¨’ (Ó“ ù1Ú™ 9Òœ ê<Ÿž âAñ¡  H·¤ 6qh¹ &à%é )ìRö èñôö øèú Yø,û ‚ ” k«}X 6­Z ˆ­¢Z J¯°[ •°`\ °°4^ A±^ ëÁ.e ˆÄùf ìÄwg yâo ”âcm ãEo ªãVo Åãn 4äo håìr ƒå3q þås ºæwt ÕæÚs Pç t ÷ç&s èQr èOs ¤éx ¿éSv :ê7x öê™y ëüx ŒëÂy 3ìHx Nìrw Éìqx ^í’z yí†z Ñí{ Sè±P E2X# z3_- )5L. ­ßÂè èd{ùáió&v9+´+¹u°,m‚©-Í2ù{CµŽ•C‚ˆ‘DÙE›ìF*êJ0—LŠ™LÇ•‹MõšçOþ—úP£—o‹[Â~ÂφÄ䓱ƥ”åÆà™§Ì©šäÌݼ`₾’âÆæc×?ôxÚxõé“÷²÷‚ +ÿ $Y õU ¡² Úñ ‡ ¡È W çd ‰ ÛŠ ¤j q öë Ÿ!ö ±"E ÿ0], ø1ž, 2X# Ç3i- …4Û, v5V. m6*0 gJ9 JL¡: -\ŸF ]ÙF çN $¤íR C§öS x¯,X ˆ—ÕÑ H˜ Ò Ø™¥Ó ˜šÙÓ o¾Ö /žòÖ ÖȨê QÉçå MÊ–î ˾é ãЯì z×“ï ¾Ù´í ßßÒè øâÖó üåöð Cé/ò òéŠò Îìø Æï2ó ›ò÷ öú ùýû þðþ ¢ÿ“þ ó} ø# ™ H 4 ð kG­ ¼Kf a[ va J¼ée þ¼¤c ¾f ŠËYj ©èBàù jþPl“ÂlÏl o¤ *o 4o¡ §pöo9¿p×´p¥„p›pì-qÝ.2l0…”<¥Œ#>Û’3m »YoZ½é˜pP l›ÖP ¨¤%S 7¦ŠS Õ§.T m©™T F<Àž é=‰Ÿ `?I  A¢ èBŸ¢ “C`£ ¼p–º ÷>Ë Ìñé ÍAê bÑâì eÒ1í =Úçí @Û1î nãô qädô ræ.ñ uçˆñ hêÂò këó Dí?ø Gî”ø <ðjó ?ñÅó óD÷ ô‘÷ “önú ¢÷Äú …ù6ü ”ú„ü i¶ x wN z¤ ª ( ¹ t cxÄ Çy4 ¾že BÉ—i ¹èƒü3j›´krA5æH^ç©"Ô«;Ö³ö×ÿ6Þ Õ õ Æ  ú;°2 B$4 +E}5 Ïqê hÔVí ­Öví CÝVî  ßŽè }Ý à ý RDR †Fr JQÚ hT‰ X% QZG ]^Ý ‘`ý ÁÉe Çzh ÖèPü3jh´k?A5³H^Z«/Ö€öÒÿ¢ õ “  Ç;°2 áÎqê 5ÔVí zÖví ÝVî íÞŽè JÝ  ý DR SFr QÚ 5T‰ ëW% ZG *^Ý ^`ý ÝÀÉe äÆzh ÿèØ rnÕaq é}þ­jé ÷kŽÂu/Ä–’ÀÅP›QÌž<ú2 ÄÔhë ŸÝDè Ù ®DP zXñ ¹^ã sÇõg (éÍkšÔhë uÝDè ¯ „DP PXñ ^ã IÇõg HéæÝMè bé×ÖkKlŸl mXÊo¬Üo¹/b 0sp=ËŒÄ=ÝŒƒl¤º×l²ºãnD½ (8 S)¦ Å)¹ ^*É €é¿Ök3l‡l m@Êo”Üo¡/bõ/sX=ËŒ¬=ÝŒkl¤º¿l²ºËnD½ì'8 5)¦ §)¹ élîm(Êo‰/b@=ËŒSl¤º³nD½¥éö ¿o·éol|ÜoÝ/s”=ÝŒ§l²ºÉé Bfl^ p8#Á¹0(…p>ò’ÙSCŸ5Xa£Í\w¨ï`3¬€m»Óé‚jl—pw#Áû0+…²>õ’TCŸtXa£ ]w¨.a3¬¿m!»¨$™ c%ò Ó/9" -0e" ]ž7R ´žBR  ŸMR bŸXR ¹ŸcR  nR g yR ƒ¥¡S ¼¨²T x± xy çéjjlp_#Áã0+…š>õ’TCŸ\Xa£ô\w¨a3¬§m!»Fž7R žBR ôžMR KŸXR ¢ŸcR ùŸnR P yR l¥¡S ¥¨²T ýw± ay êU·l,_p'o0qFêd m$ ˜m³Tq[ê†  mF  m‡êÂ@e Ïë ŒbÛ«¶r½ Út¿ ûvÁ yà 9~Ç f€EÉ 1µÎa ¹¶·b Öì›'³rÞ-/x?A‡êKŒ ëìí'Ör0.TxW?`‡DL¯ w·½` rÂjf PíAåÑø äôÿø í !§qŽ!zs»Q ›;Râ› V* ‹Vf ¯ZÀ¤/[¥Å^D©E_{©±í+–$]tè$΀R%Ýt¹%H€ &Ìy;ƒ‘h;VŒÏ;‘!<&ŽPN©š¢N™}UОŸYD¤ñYî¢q^¨YbÇ« G ¦ jGœ¥ iI”¨ ÇI&¨ $K$« ‚K¶ª mo» Ëokº ƒr ½ §t ¿ Èv Á ìx à —|ƒÇ é|Æ Ÿ}’Æ ~ Ç 3€6É þ´ºa ¶2b †¶§b Ëâ¢m ºåtq  çt Ièr öé”v Hëkš­¢ð„| ñu} Gñ›} ~û/ Åû‘ æî¼Ÿc íî”*Su,4v -èwuBˆõCþˆNJf“oKf•ïLH–wþR ÿ€ rl ÿ mè ‘[×E V~M Ó®ÊU 1È€å ±É^æ »Gc ^½d ûîÞþ Æ~ÛN öè#ò ý»äe ±¼Ÿc νf ï˜1Ë{ãD\‰a < Žïeßµè ¿F6 Ê`¦ ð€1Ë{ÂD\‰' < Ôñmk³­âñçeD®ôñ ÐfÚ¯g͸ôgбhˆµik¯hj%³õr O H¡ ˜ òùoæ½äôÇ„¾ѨAÓõç„"¾eªæÔ/õ…Y¾Ó…·¾põ³…x¾’®èØüõd‘-űWŒD $öÙ‹åÀÁ‘dÅ6˜áÉXÇD ‡öüÃ!’‡ÅÛšÌ)<Ñ2 ¯öèÂ]/Ä~’ÀÅ8›Q̆<ú2 8øÙœÐÍRøóÍtŸÕÏH¢}Ò¯¶ñÜ’ôÔþ;ù† gø FÎϘΦŸñÏz¢™Òá¶ÝŠË÷èиìêhùÄôñþmù£  u ¼øŸ1ÏÓøIŸVÏ ,ö üø6¡¤ÐùÓ¡ÀÐDùa¡ÿÐÓù_¶åÜBôÈþôø~ `úˆ©ÃÓ8«õÕÕ®OØwúWµ¨ÛcÀWàžÂ·ágʃç΀êLèó©I 9 ŒK-: “úÞ ÞA$4 øD}5 ”VD ¹úªNÔÆÉ/çlßÏïd½ º]oF û¹«ÖÖG¬èÖŽáåðWâþðWãñ&åãñïåýñ÷\ $~ ¿† µŸ âÇ T¤C €U¿C )û$¬ãÖû¬ûÖ¬áîð¬âñ¬ã/ñDåíñDæò°æ1òUq Tˆ æ ´ 7× Y>¦3 Œ?s3 ‹@³3 qCÚ4 Dï4 ‹F16 GK6 ±T®C ÕUÏC dY4E fZPE ŒdwI ¶eðI AûЬîÖâþðãñæýñ…æò*\ èŸ Ç 7>•3 j?e3 FCÆ4 `F6 ªU¿C adZI ‹eãI ¢û¯tØáÁð˜ä¾ñòçÂòa %H7 Øû*Ï8ë§Ï˜ë¾Øø;Ù%õÓÛäùPÜU÷6Ú ³ž ûû¢¿ÓßðÁ4áÜÍê7ü9ï@üj7æ1 Aüü´vÛÀ%àMÂ…áBÎUêWüµ”Û ÀCàÆÁ7âe£á.ÊoçZÎlêÑßð?ärñ¬çòï üñ?ý;p2 …RB ÷fPJ oü6µ˜ÛBÀGà}§áFÊsç|ÎpêÙüéäƒô íç)ù Œô°÷ ý¿º‡Ý¼ïÚü)ý#»±Ý¿‹ß|ýD»µÝ‘ý4¼÷ÝÛ½ßp\õE òý½NÞº¾Rß•JS9 xLs: O]6F þr½£Þ“Éç9߸ï\à–ð[ç9òcó-þ;ö»ÿ4¤ ZÜ Bk4 ©EÃ5 qG‹6 H=7 MIØ8 0Kø9 „WID ÞZZE þðüü2þ¢ÀÉà9ðxýGþÁâ[þfÁ$âœÁ7âëð?ýLñØýÿ5ÉñæÁÿÕà®ðmä²ñÐç²òK? Ï U =&3 Üÿ~à®ð3+áÚðÏáóðÏâñÃäØñgåòñÓæòxv 7{  ” 6¹ ?\3 ¯?}3 ÕS•C ÔT³C  XE ‡Y>E {…çaòÊ:íUû®òþ#ï@üI7æ1 -\ï„üiòþ¹ðööÿä"x œAÚ3 ,D;5 ]%+N €$™ K%ò ²/9"  0e" ²À+í òË'8 z'8 +5(Å „@*É ª–+© e,’! Õ½2¿# ãæ2p)  ì4L. ‚;¥2 )P;¥2 <|>°3 7?e3 1Y'E 3ZFE @dZI eàI ÁSBk4 mEÃ5 ZWID ؽB¹4 ”Cä4 ×E6 ®F@6 þGG‹6 «ZZE AwIý8 ZK: XËI)9 ®KI: ”MS; PU@ K S÷B ¥S[C Ó–`pG êÒ`€G  a‹G  PaÑG ëb—H 0  aÕG *c›H Ù€N }°žV ϱØV “³£Y —¹ß]  »v^ Ùךç I  haÕG c›H A:M €N H°žV š±ØV `³£Y d¹ß] »v^ ³×šç ]  ¹aØG TcŸH X:M ú€ N °CN §°¬V ù±æV ´³¦Y Á¹æ] Ê»z^ ¼a 8½…_ ðמç u ãaÜG ~c¤H oAM $$N ÚGN Ѱ³V ²ñV ³•X Õ³ªY ô»Š^ ¸¼a c½Ž_ Ø£ç ÞëEö ñçö .ø'û   bàG ¨c©H EM E(N û°·V D²õV ö³®Y ë¹í] ¼^ ò¼)a «½Ta 2بç ìIö Çñëö § .bãG Éc®H ·IM "±»V k²ùV  ´½Y ;¼”^ IØ­ç Á  VbçG ñc´H ÞMM l.N I±¿V ’²ýV $´ÂY \¼™^ pسç L i;L ] èh;L B `€”M u ¨€ÅN ü\N :  „P í .™hP \±›ÈP ËO"Q ~¶\[ =»ö_ ú¾õa DÀ²c oÁe âG¶M[ »î_ þæa  À£c 8Á e o˾é ÃÐ¯ì žÙ´í IY¤S †§T ¿ËÔé ÑÅì îÙÊí ãïó #æñ ê£ò õì ø íïKó Âò,÷ Dö6ú 6ùü – (6 [   he§T ~$‡¤S ï¤*S ¦‚S ЦS ´§!T (¨3T L©‘T À©žT íËäé ðÌ9ê AÑÕì DÒ)í ÚÚí Û)î Mãô Pä\ô Qæ!ñ Tç€ñ Gêµò Jëó #í2ø &îŒø ð]ó ñ½ó ðò7÷ óó‰÷ röHú ÷¼ú dù(ü sú|ü H¨ Wü VA Yœ ‰  ˜ l ’(¥GS a¨WT ^Ìê ²Ñõì Úõí ¾ã%ô ÂæEñ ¸êÕò ”íUø Œð…ó aóU÷ ïö…ú áùEü ÅÅ Çe  5 ¢Ü¥S ©ŽT ¾Ì5ê Ò%í íÚ%î äXô "ç|ñ ë ó ôíˆø ìð¹ó Áó…÷ O÷¸ú Aúxü %ø '˜ f h ¹²¥S 討T ÍT¥¡S ¨²T ;ݯ*V ÿµ*[ *¹^] ǺÄ_ {¾Ãa Å¿€c ðÀêd f½¯*V ¹^] Œz±ØV ÅÞµ*[ ¦ºÄ_ Z¾Ãa ¤¿€c ÏÀêd ä»¶9\ &º-^ ½_ @Ú¼a {½“_ “½ž_ ZmºÄ_ kaßzh ÷áéj çã´m ޤ1‘˜ ¨äÒm »„â×k ^äòm à%'uõ½ '&lyõÁ &-}TÄ †~äÄ  µ` ·£` @'‚eÍ  (Ê¡vÝ M¢ÀÝ ì¢^Þ Ô¤à ‰)>ýý ˜)”عç ê)•ÌZê éÑJí ÄÚJî õã|ô ùæ"ù ïêºô Ëí¬ø Ãðõ ˜ó©÷ &÷Ìú úŒü ü þÐ = | ü)éÕ²ë þL ÊEž –Y? Õ_2 î*ýòü +¿ Z,¾ i,Eá Á-ô‘ ô.¢G ˜[½ ­a• 8/¡Uf .\_ (0½w‹ !yó G0¦w‹  yó y4æ®u[ à45·°` d5ëÉ´i NÊæi —6 ¬âtm Ýãn ›åDq íæës *èbr íèöt ×édv )ë y fìƒw 577ît{ Ñ71ïµ{ ß8_ý•˜ Òý­™ w`Ÿ`ÐΑ©yÉsM¬sáàáýH>^5I“^æI±_¦êôêžQÀë[ë‡ëRÉëôë–RPgí˜í—Œƒ.ß–t ‰/»/„'3Ô†G~H‰{h‹K,³"5î{h<• tgimli-0.19.0/fixtures/self/debug_line010066400017500001750000003253031343337721300157630ustar00000000000000003‘{û /Users/fitzgen/src/gimli/src/Users/fitzgen/.multirust/toolchains/nightly/cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-0.5.3/src/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/liballoc/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcollections/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/num/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/fmt/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/iter/Users/fitzgen/.multirust/toolchains/nightly/cargo/registry/src/github.com-1ecc6299db9ec823/leb128-0.2.1/src/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/io/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/collections/hash/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/thread/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/hash/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/strlib.rsparser.rslib.rsmem.rspanicking.rsboxed.rsheap.rsptr.rsany.rsslice.rsslice.rsmod.rsmod.rscmp.rsclone.rsconvert.rsresult.rsmarker.rsbuilders.rstraits.rs option.rslib.rs impls.rs error.rs macros.rsvec.rsraw_vec.rsnonzero.rsrange.rs map.rs table.rs macros.rsops.rslocal.rs cell.rssip.rsmod.rsborrow.rsiterator.rs mod.rs str.rsmod.rs  óÉ @ ­òÓ}/€X­‚Ò}/®XÒf±‚ÇyÊ 0„  @¿ #£òÝ( À„ ó×hZxº´f óóÆ ` ù ƒ  æ º À à Ø€ à § óÇ  Æ ¼ @ ¶ óÇ p « »I  é  ­I ° óÉ à† ¨òÓ}/…X¨‚Ò}/®X×t¬‚Ç]Ï‚ Є  à é  u; ð! óÉ  ‹ £òÓ}/ŠX£‚Ò}/®XÜ‚§‚ÇyÔ  „  0 é  ƒI @ à óÇ p Ò »I  ¹ »ñ ° å » ÐÙ 6ÖÖÖÖÖÖ¬¬¬¬¬¬¬9< @Ù !G25>>>>>>>>>>;w<  €Û    ÀÙ #@  Šž ‚J#Ç @ ¾ ŸÉ#+!yÈ È   ¾  » P Ž º‚  ° † ‚t Ð Ž qº&&  À!È  ò ¬v "’ º‚  `"’ qº&&  P#– º‚  °#– qº&&   $š º‚  %š qº&&  ð%ª º‚  P&ª qº&&  @'ª $&O US ]x/ ^1¤|A*xPe!ÓØ+©|t3!ÓÛjIx? ^1˜-E ],™|A*xPe!Óæ+›|t3!Óé‘|9ÓïX   2ê åå. ­ à2‘ DœQ ä7xP@J; °5 µ óã  à5 ô ò   6Ì ƒ P6˜ 5åql(èšäq\,è›`ãq¥:蜟âq‡,èž^L\A#=!uuuuÑF >«  ?Ótj#è$¬ V‘:7Ït_,è$° `BÙ! €A‚ ,09Y  €B¶ :  àBñ ž C÷ ,09Q ž 5ýsV¾… J7-4 °Eá ,09QÐ ž %KE»ÿvò 8’1 °Hà  f  @Iˆ   €Ió    °I˜  3Y ðIÔ   J¦  ŸŸ pJ¯  ×ɃŸØ„aÿ PK Ù ‚‚ºW K¬ ååå . BuŸƒggô  @LÈ  »!% ðLº :  PM‚  ?T""& $w àNù  Öòft `O¦ ò(@ P ò  @P ß    €P ¥ 4’4i w Q“ » °Qü Ö ÐQò åî  RÍ èƒpú. ò ¬v €R‚  °C7'=' =z'=y'=x' =w'8 W¿    ÐWÈ  ò ¬v XÈ  ò ¬v PXÈ  ò ¬v XÈ  ò ¬v ÐXù  !+//<  YÈ  ò ¬v ÐY¦ Î& $/  p[È  ò ¬v °[È  ò äv ð[¾  @< `\· y¬F"F  ]€ ã À] ª ½óô­õz¬õ‚‹{uÃJuÿz‚ê‚–{ØhñÖ Ð^„  à^ ¤ ƒ _ô  åÇ  0_ Ê h׆åT‚õ‚‹{Èu+JW.)JW  @`È  ò ¬v €`Ë  ó# À`Í èƒpP. /I2)x'G<  0bÈ  ò ¬v pbù 7F&z5 ,v'_<   dÈ  ò ¬v `dÓ »  d¿ ƒ%gÅ àdô "H$4lU X   fï ƒvî÷K‘Š2/?'øn¯K"FÉ/*. Pj¤ |hx' Ðk¾ N  Plé ó pl Ñ   °l Å ò.$  Pm ø  m ú Ç|6R ëXQî p“ ÿ 0pï ÿ `p3 ŸW  qÏ Öòft  qÿ "H$4lU X  `sŠ $ƒu".oK‘í~2/?'•‚»&*7JY’[Pc  wŠ ÷{a”ˆCŸ4* yÚ §{a”ÙJ‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘1‘*¬ P‰ê —za”éCƒ,ƒ(6 ðŠù Öòft p‹ù !†25>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><  0®Ý ¤ya”ÛJ‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘4‘1‘*î Æ¤ !F25>>>>>>>>>>>>>>>>>>>>>>±<  ðÍà ¾wa”ÁJ‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘2‘/‘(d  Õþ Î412  àÖÈ  ò ¬v  ×È  ò ¬v `׆  ƒ’ ×Ê  ·va”È C¶vq,èÉ [(+ ÚÒ  ¯va”Ð CŸ,ªvn,èÕ `Ÿ)  ÀÜâ   Hºtò CuEšvr/_ï fwDBO ॠ®É·  0à9 ¯Ÿˆ×t‚  à„   àà uÿ’+  páç  .%  âß  » pâ¨ Õ  âë  »% àâ  ¼‘­ü  ㎠» Pã Ù »ÿ €ã5 ƒƒH  ã ù ƒ Àã Ê  » Pä° »‘L’%-S  åÈ  @å… w!’7  0æè  ,'  æÃ ÿ’+  €çè  < àç½ ×{ò©×{Ju¨‚Ú{.¦º“6w0 ò ðèÈ æ”¶~‚ÿÍX’gŸ…0]?!Y­ƒÉ3\KG[Zº  ëÉ »¹{tÿÆt Pë„  `ëÌ ó °ë  ƒêz‚ –I àë ¹ » ì à óÇ @ì Ò »I `ì ¹  €ì¼  »% Àì‚  ¼‘­ü í ¾  » 0í Æ ¼ `í€ ã íõ å*‘    î˜ º Pîå » îï õ“­×±s àîÙ KI ðîò ‚ ï¡ IŸ  €ï ž  ,f  ð ¯ æ-î pð § óÇ  ð ß  ¼€ Àð ú  ,f  Pñ ý æ&î  ñ· ž¹ ðñœ º  ò å »ã FX »I `òÈ  ò ¬v  ò…  ;÷u‚.©¡Œ  ­Ÿƒ$ Àóž  ƒgÊ ô¬  "Õua”ª FÔut,è« `Óut,è¬ ^ÒujAE_/« 2 Žf&   û¶  Ëua”´ @Ÿ) €ü!ã åu© XKIY­MY ¬KKK V‚{¬í"½{6Ó!ÚX!&!&u8úz"*;Ó!äX[%׃J% Є  àÈ  ðÈ  Á AÑ}­  €  ƒêz‚ –I °!½ ƒs  ! å? X".ÈTOY×SY×uu!u(  Zb7ò P€ 1  °!ú 0ó»µ  0!ž VPY®KK6%&r&   Ù »ÿ P5 ƒƒH p!¶  !z   !¤ óÜ{"--!ûXjô ð  Ú )­ P !µ &  Ð  ¹ »   å »ãX »¹ @ !à $) ;> ·zº!É ¸zJ­!Ç ·zº&<!ʺ¹   Ù KI 0 Ù J   !• !»~  #· ‚t  #° ‚t @!Ø ƒ `!¡ <ƒƒs 0!° ­ `!« ƒ  ¹ »« ° ¹ 3*  !µ # '[2öv?  P!µ # '[2öv?  €!à ƒ   ³  å  à Æ å~  @!´ L.(   Ï  ­  @   g  p$î ç1Ÿ'‹   ¡ 9Ÿ  Ð%ð ƒI à$û Ÿ!l·f *  Àï ½3sX `Ù J pò 3 °Á -Ñ}­  í ƒ%Ÿ! pÈ  ­‘   š ­  °Ñ  :yzt~4Ë @ ½ (; à — ó9äz¬"-/ ôX!vÈ à Ð ºÈ  4 ÷) Í P ë »)åJZX ` ­  ƒ!  © ƒ×z "-1 €XÖz#ª‚"ƒ{5 ‚XG#- hxf ž !.`Kf =uQG2FwF  qiK =y•ïš6&íMy F6‘zE@"#xB2V&*t"3$zÖ ÷X  0)² &*' à)ï [ItäW$ À*Ù J Ð*ò S @+!¡ <ƒƒs ,!£ ë}!•‚OÌ À,!« ƒ à,!Œ &ƒ~  @-!Í &ƒ~   -!½ 5@®ƒ„ À}‚!À Á}J­!¿ò ¿}‚&<!·º @/ ú B$$!w#"¯|,Ó ÔÈO#Ã=@ufì:q  3!„ ‚ó¬Ç  P3!ˆ G'»w‚ 4!Ø ƒ  4!ò ÷ž~¬âuã0x}fƒt‚ Ð6!î ƒs ð6!Ñ ƒ 7Í èƒpú. ò ¬v p7¡ r „ò *Q»».q@   9 ò +  : â ó P:!™ óÍyJ °: ³  å  ð:&¤ þ   ;&¿ ƒƒƒ,ƒ…pä  Ð;&Ó ƒ»zº `<'¢ óñ <'² 'JTW   =   ÿ P=&í ÿ €=&† ó9„].ZÎ~䃃ö¬‚Ð~6ŸÆ Y®V7Y¢É~‚ƒƒ”±‚Ë~6ŸÆ Y³Póóôz X%¼­Œ¿~X­­ÃX0åóy$º~yÖÐtƒYºÙ~ÉÌÖ´~tÈ#Y @E ‘ «|$W ÿXþ °E ¦ &&BW)]?U2 \!Ê ƒ  \!‰ º‚  Ð\!° ­ ]!… xáÃò º ð](× ‚J ^ Ò  ¤G=zúzz$ ð` © z-Su,x ¬­S4z%,v0 X›vSa7 ‰…ßÜ  g! ƒ Àg!– 1»  @h!£ ë}!•‚OÌ ðh!« ƒ i!á , `i!Ò E@;…f ñ Pk é »¸ kï õË­×±s ðkÙ KI lò ò  l é »H Plï õ“­×±s  lò ‚ °l é 9*8 mï [+.qtäW' Ànò n!“   p!Œ <à  °p!µ # '[2öv?  àq!¡ .4ó+ós  ðr!ò ž~¬âu0x‰uót% ðu!þ »Ç v!ø &  `v!Æ D  Ðv!Ê ƒ ðvÜ  »  w ¡ &  pwþ gå  °x ›  8!  @y ê +  °y Ù  ’2#&t. V>BW)]?U2  ~!„ ‚ó¬Ç  p~!ˆ G'»w‚  !Ê ƒ @!£ ë}!•‚OÌ @€!… xáù &ƒ~  `!î &  °â  ¼ `ºpòUq› eu!AE_/î Ùýu¨YA_;xi4xžS 0ˆÃ uÿ’+  ‰æ  >  ‰… ±H2_  ‹ç  ,'  @ŒÃ ÿ’4Vu* @Žç  ÎO& ð»  #&DÂtW¼ (=1¿tp9*xPe!Óº Átt-A*xPe!Ó À tÁt-9*xPe!Ó½ +Ätt3!Ó¿ X  €—Í èƒp- èƒp- èƒp+. 7F&z5 ,v'_<  ™È  ò ¬v Й¬  %uò sò Ëy<  €š¬  %uò sò Ëy<  0›Ê  #4D®tWÐ (=1«ts9*xPe!ÓÎ ­tt-A*xPe!Ó Ô t­t-9*xPe!ÓÑ +°tt3!ÓÓ X  ТÝ  &¡tCá +.t¦tt3!ÓÝ X   ¤ç  )—tCë +.tœtt3!Óç X  p¦ò  -‡tCû +.tŒtt3!Ó÷ X &VÉëst“ (,1ésb9*xPe!Ó‘ ësUA*xPe!Ó“ +îst3!Ó• X  À­Í èƒp- èƒp- èƒp+. 7F&z5 ,v'_<  ЯÈ  ò ¬v °¬  %uò sò Ëy<  À°Ÿ  #%ßsC£ #.täst3!Ó  X7ØsIª 21ƒÝst3!Ó¦ X  `´°  #ÎsC´ #.tÓst3!Ó° X   ¶Ç  &åã;¶stÈ (41¶s[A*xPe!ÓÆ +»st3!ÓÈ X  À¹Í èƒp- èƒp+. 7F&z5 ,v'_<  °»È  ò ¬v 𻬠 %uò sò Ëy<   ¼‚  Î& $/  @¾Ò  %åã¬s0× .1t°st3!ÓÓ X   ÀÝ  -å; stÞ (41 s[A*xPe!ÓÜ +¥st3!ÓÞ X  ÀÃè  %å–s0í .1tšst3!Óé X   Åø  #1†sJù %#.†s[7*xPe!Óö +‹st3!Óø X  ðÈÍ èƒp- èƒp+. 7F&z5 ,v'_<  àÊÈ  ò ¬v  ˬ  %uò sò Ëy<  Ð˺  7–uˆ *³q[A*xPe!ÓÉ+¸qt3!ÓËX  ÐÍ èƒp+. 7F&z5 ,v'_<  ÐÑÈ  ò ¬v Ò¬  %uò sò Ëy<  ÀÒÖ  I•Fx/ *•q^A*xPe!Óç+šqt3!ÓéX  ðÖÞ % 333,/9//9966O+t ÐßÞ ×Q,'A,z'A,r'A,o'A,l'A,h'A,d'A ,`'A#,]'A',Y'A*,V'A-,S*A1,O*Ä<  ÐéÈ  ò ¬v êÈ  ò ¬v PêÈ  ò ¬v êÈ  ò ¬v ÐêÈ  ò ¬v ëÈ  ò ¬v Pëý ‚ €ë” ò($  ì” Î412  àíÈ  ò ¬v  îœ ƒå @î¡ ­ pîÙ 4Ø$‚$  Pïá  oa”ß>  pðö ‹oa”ô@ ñ— Ø^&RZ9vB~ Úl°*ÑlqA*xPe!Ó¨Ôl®A*xPe!Ó«+Ïlt3*TÓ´X  Pùû Çg“.î}gX ø ¦ ž — Ÿ ¨ ¨ ¨ ¨ Ÿ Ÿ Ÿ e'ƒ$_~ ¦ ž ž — e… ag‡mè#èZ‘„¤ žudÅT žtd%O(Ez-#¼ :[&C“ S žtd  °É ;Y ± -  €é ó  ñ º Ðà ³I’1  Š eŸMÎ|ò ƒu  à ³I’1 p“ eŸMªrò ³I’1  œ lŸ'= æ 5˜oV¾çM‚ @à ˒1 pë R)  Ó &å @± 6+  Ðà ³I’1  ¥ lŸ'= î 5oV¾ïKƒ À ì ,09P  °!à ˒1 à"ó R)  p#à ³I’1 À$® eŸMrò ³I’1 ð&· eŸM†rò ³I’1  )À eŸMýqò ³I’1 P+É eŸMôqò ³I’1 €-Ò eŸMëqò 8’1 €/Û UŸ¼D  @0à 8’1 `1ä UŸ¼D   2à ³I’1 p3í eŸMÐqò 8’1 p5ö UŸD  @6ã  ƒÉ `6à 8’1 €7Š YŸ7 P8à 8’1 p9“ YŸ7 @:à 8’1 `;ž UŸôDŸqÈ 8’1 @=§ [Ÿ 7 >à 8’1 0?° YŸ7 @à 8’1  A¹ YŸ7 ðAà 8’1 C UŸ¼D  ÐCà 8’1 ðDÍ Y®Ÿ= ÐEà 8’1 ðF× Y„Ÿ= ÐGà 8’1 ðHã Y„Ÿ= ÐI)ò  0;­)y ðJ€ ã  K)â ­ã @K*± å0  Kþ H'  ÐL)± ºº ðLí ºº M ñ ÿ  @MÁ ƒ pM¸ ;  ÐMà 8’1 ðNý Y®Ÿ= ÐOà 8’1 ðP‡ Y„Ÿ= ÐQÍ èƒpú. ò ¬v 0R„ #åóî RÍ èƒp+. 7F&z5 ,v'_<  `TÈ  ò ¬v  T¬  %uò sò Ëy<  PU§ «"&&','5  ÀWÈ  ò ¬v X¹ Ê^wRZ9vU~ ·lÓ*®lqA*xPe!Ó˱l®A*xPe!ÓÎ+¬lt3*TÓ×X  Ð_Ü Ê^wRZ9vU~ ”lö*‹lqA*xPe!ÓîŽl®A*xPe!Óñ+‰lt3*TÓúX   gÿ Ê^wRZ9vB~ ñk™*èkqA*xPe!Ó‘ëk®A*xPe!Ó”+ækt3*TÓX  `o¢  ^wRZ9vB~ Îk¼*ÅkqA*xPe!Ó´Èk®A*xPe!Ó·+Ãkt3*TÓÀX  wÅ L^wRav4~ ¬kÝ*¤kgA*xPe!ÓØ+¢kt3*TÓáX  @| ø » p|æ  ^wRZ9vB~ ‹kÿ*‚kqA*xPe!Ó÷…k®A*xPe!Óú+€kt3*TÓƒX   „ˆ Ê^wRZ9vB~ éj¡*àjqA*xPe!Ó™ãj®A*xPe!Óœ+Þjt3*TÓ¥X  à‹ª ^wRZ9vB~ ÇjÃ*¾jqA*xPe!Ó»Áj®A*xPe!Ó¾+¼jt3*TÓÇX   “Ì ).<`3na2žjtà( jê*—jqA*xPe!Óâ šjuA*xPe!Óå+•jt3*TÓîX  p› Û »  ›ê TÇLtu$ Àœ’ 8íyB÷&‰ztö>Šz&3 0žÍ èƒpú. ò äv žÍ èƒp Ÿµ ƒðõ»»v…g¿~U/?'Ân!ð[   ¡9 »åâŒf | 0>u*Ÿ{Q. ࣼ Oi‚K  `¥¥ ž¹ °¥š º ॠù    ¦ Ò æ}ºW ÅXxK § Ê  » @§² É €§ï õËsÈ ð§Ù K ¨ò º ¨ñ ,' €¨ó )64`3na2÷it‡(ùi‘*ðiqA*xPe!Ó‰ óiuA*xPe!ÓŒ+îit3*TÓ•X  P°Î ƒðõ’» ô¡¼“g ~U/?'án!â[  °²š v^wRZ9vU~ Öi´*ÍiqA*xPe!Ó¬Ði®A*xPe!Ó¯+Ëit3*TÓ¸X  pº½ L^wRa²itÌ(´iÕ*¬igA*xPe!ÓÐ+ªit3*TÓÙX“ L^wRa‘ití(“iö*‹igA*xPe!Óñ+‰it3*TÓúX“ v^wRa2ðhtŽ(òhš*çhqA*xPe!Ó’êhA*xPe!Ó•+åht3*TÓžX  ÀÊ£ ^wRa2Ìht²(Îh¼*ÅhqA*xPe!Ó´Èh®A*xPe!Ó·+Ãht3*TÓÀX“ [wRa2ªhtÔ(¬hÞ*£hqA*xPe!ÓÖ¦h®A*xPe!ÓÙ+¡ht3*TÓâX  Ùç L^wRaˆhtö(Šhÿ*‚hgA*xPe!Óú+€ht3*TÓƒX“  ^wRa2çgt—(ég¡*àgqA*xPe!Ó™ãg®A*xPe!Óœ+Þgt3*TÓ¥X  Àäª Ê^wRa2Ågt¹(ÇgÃ*¾gqA*xPe!Ó»Ág®A*xPe!Ó¾+¼gt3*TÓÇX  àëÌ ^wRa2£gtÛ(¥gå*œgqA*xPe!ÓÝŸg®A*xPe!Óà+šgt3*TÓéX“ ).<`3na2üft‚(þfŒ*õfqA*xPe!Ó„ øfuA*xPe!Ó‡+óft3*TÓX  Ðú• ^wRa2Úft¤(Üf®*ÓfqA*xPe!Ó¦Öf®A*xPe!Ó©+Ñft3*TÓ²X“ [wRa2¸ftÆ(ºfÐ*±fqA*xPe!ÓÈ´f®A*xPe!ÓË+¯ft3*TÓÔX   Ù [wRa2–ftè(˜fó*ŽfqA*xPe!Óë‘f®A*xPe!Óî+Œft3*TÓ÷X  0ü Ø[&RZ9vB~ õe•*ìeqA*xPe!Óïe®A*xPe!Ó+êet3*TÓ™X  àž ^wRa2Ñet­(Óe·*ÊeqA*xPe!Ó¯Íe®A*xPe!Ó²+Èet3*TÓ»X“ [wRa2¯etÏ(±eÙ*¨eqA*xPe!ÓÑ«e®A*xPe!ÓÔ+¦et3*TÓÝX   &â ¢)IO*Q5gm!L2†etø(ˆe‚*ÿdqA*xPe!Óú ‚euA*xPe!Óý+ýdt3*TÓ†X  Ð.à .^ƒÉ´däËtµdtÞCQåu.h8IH##wdtï(‘dHø1‰dK*xB`$Óz):*bÓý‚d62Óÿžyÿctÿ(dHˆ1ùcK*xB`$Óz):*bÓòc62Óžyïct(ñcH˜1écK*xB`$Óz):*bÓâc62ÓŸžàc=2Ó ßc62Ó¡¬‰8ßc0_*xB`$ÓžX   D Š 9â4  D ‡ `k*ñ&  Fý ·  pFù #   Gò ? pG¤ 1:Öd¬ºØdZ®7L‘>U,@êX%‚fò å.  K%ð ƒI  K%Ò   ðK é ‚J#Ç PL ¾ ŸÉ#+!yÈ È 0MÍ èƒpP. /I2)x'G<   NÈ  ò ¬v àNù 7F&z5 ,v'_<  PÓ »  ÀP¿ ƒ gÅ QÓ »  @Q¿ ƒ%gÅ Q¡ L!  RÍ èƒpú. X&4'ÃB½tlã¥_Ž-9*xB`$Ó× çŸ_Ž-9*xB`$ÓÝ ç™_Ž-9*xB`$Óã ç“_Ž-9*xB`$Óé ç_Ž-9*xB`$Óï ç‡_Ž-9*xB`$Óõ ç_Ž-9*xB`$Óû çû^Ž-9*xB`$Ó!çõ^Ž-9*xB`$Ó‡!çØî^Q2Ó’!ží^=2Ó“!ÖX  àrÇ åå¡. ‡S2S €t’ .íyJ“‰zt÷!‰zt0# °uÍ èƒp  vÌ 3õž ÿ’4Vu* pxÍ ¸9& ðyê ¯"æ3  {¡ º" 0|‹ #ƒ;»ô  À|ê ‡ÿ’-   }¡ i  P~½ 3hq¼c7&©Ä",Y.3ž××!!#:C¢cf2ÓÞžp÷ Àƒ%µ 2Ü|%¤1­#uÞ| %¡äX  …%Ò $&3T  à…%Á » †%ð ƒI  †%Ò ô P†%ð ƒI ‡%ß »¼(Ë €‡%ƒ ƒs °‡ž ƒ"gÅ ˆù :v1  °ˆõ ä<‘w  `‰% !   ‰%® .¸  ð‰%Ç ã  Šý ‚t @Šý ‚t `Š%å 2¬|%Ô1­#u®| %ÑäX  °‹%ð &‘z  ðŒ%ç »· @Ó »  p¿ ƒ%gÅ À%‰ ƒs ð² 9â  `Žï .=sº  0Ù J @ò q  À%‘ ƒs àž Cx)  ¤ ju+Ðbò°$I01Ð`SK*xB`$Ó­X  p”ê %’-  p•¡   `–)¸  F!c&+= ð—€ ƒI ˜)± äò  0˜¬ =e ™Ô æ×8„  €™ž ƒ"gÅ ЙÒ |%’3  Àšé ÿ  ðš—  ÿ   › € þ  P›  .#'   œÈ æ·  `œØ æ(“×h‘Z†k‚  0È  @  ƒêz‚ –I pÚ /‚JÎrx#u+  0Ÿ£ ó `Ÿ“ ‘ ø}‚ˆXø}Ju‡‚û}.…º#¯!’­É*KG ^[]º  ð Ú 3!(v ࡎ » ¢ Ù »ÿ @¢5 ƒƒH `¢Ø ƒ €¢ ¹ ×  ¢ © ÿ Т Í &Àf ¼‘­ü P£† ‚f œ. ÿ £ »¹ ¤ß  » P¤¨ Õ €¤ë  »%  ¥° »‘L’%*S ¦,â » 0¦½ ×{ò©×{Ju¨‚Ú{.¦º“6»w. È  §È æ”¶~‚ÿÍX’gŸ…0]?!Y­ƒÉ3\KG[Zº  0©‚  ¼‘­ü p©Í èƒpÓ. IŸ  ªÞ 8 !af"[24  !ɲ3!z/%_×Q,Eo1#[ ®€ 1  ð®Í èƒpú. ò ¬v P¯Ó »  €¯¿ ƒ%gÅ Я™! '&4'+BUtlãÒ^Ž-9*xB`$Óª!çÚ\çØ\çØ\çÚµ^h2ÓË!ž´^=2ÓÌ!ÖX  »¡ 7 `»ë $;.\VËeS‚D™( ­.nÖ7Ø®c $ž  ÐÀ)¸  F!c&+= `€ ƒI pÂ)± äò   Â*Ö  å 1   ù ÃO' @Åï ò¬  pÅð cQ @Æ)› 1   Æç  ×iD `Çý  ƒr-ý X@Jò ‚ð `ÈÓ »  È¿ ƒ"gÅ àÈÒ! '34䡜äòv%B[tlã™]Ž-9*xB`$Óã"çÚ\çØ\çÚ‚]h2Óþ"ž]=2Óÿ"ÖX  @Ó# -Nñ\tŽ#(#.ñ\[9*xPe!Ó‹#+ö\t3!Ó#X  ÀÖ…# .»  ×Í èƒp+. 7F&z5 ,v'_<  àØÈ  ò ¬v  Ù¬  %uò sò Ëy<  ÐÙ—# 0ç\C›##.tì\t3!Ó—#X   Û¯# #*JÎ\W°#(=1Ë\e9*xPe!Ó®#Í\t-A*xPe!Ó ´#tÍ\-A*xPe!Ó±#+Ð\t3!Ó³#X  @ã¡# %W:d» €ä  å °äà 8’1 Ðå«# f  `æÍ èƒp- èƒp+. 7F&z5 ,v'_<  PèÈ  ò ¬v è¬  %uò sò Ëy<  @é½# #1FÀ\W¾#(=1½\h9*xPe!Ó¼#¿\t-A*xPe!Ó Â#t¿\-A*xPe!Ó¿#+Â\t3!ÓÁ#X  àðË# )²\NÐ#.1t·\t3!ÓÌ#X  Àò$ *oÓ[0®$*PÑ[t%*³$ÍuÓ *Å[^A*xPe!Ó·$+Ê[t3!Ó¹$X  Àø$ Aí[–"è’$¶ì[\,è“$`ë[¦:è”$u¦ àýã# Y»„  €þÍ èƒp+. 7F&z5 ,v'_<  PÈ  ò ¬v ¬  %uò sò Ëy<  @Ö# ¨"44' 7z'8  àÖ# ò3& z ÀÍ èƒpú. ò ¬v   Jtû /Users/fitzgen/.multirust/toolchains/nightly/cargo/registry/src/github.com-1ecc6299db9ec823/leb128-0.2.1/src/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/fmt/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/liballoc/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcorelib.rsmod.rsheap.rserror.rsany.rs pÐ 07 @“ ÿ pï ÿÕÌû /Users/fitzgen/.multirust/toolchains/nightly/cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-0.5.3/src/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libstd/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/liballoc/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcollections/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/../src/libcore/numlib.rsmem.rspanicking.rsboxed.rsheap.rsptr.rsany.rsslice.rsslice.rsmod.rs&îû /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internalinclude/jemalloc/internal/../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_pthreadjemalloc.c_types.h_size_t.h_uint8_t.hjemalloc_internal.h_int32_t.hOSAtomic.hmutex.harena.hstats.h_uint64_t.htcache.hticker.hchunk_dss.hextent.hprof.hckh.h_ssize_t.hnstime.hjemalloc.hbitmap.htsd.hquarantine.hatomic.hutil.h_uint32_t.h_pthread_types.h _pthread_t.h _uintmax_t.h hÍ ® °h» i´ÈuÈîÉ  Ê%¡}X çf ü| •<g‘özž ‡žY…‚Öz¬Ð{¬÷f~¦ äív‚Øž÷¬ ’É}<¸Ö|  Ç ž¬ "‚­{È Àò…z¬½x <dž=Ù jÔ ’  jÆ ÔÈ ôX ü| •<g‘özž ‡žY…‚Öz¬½¬“|< „ fóYÇzž‡È µ<˜  §¬ "‚­{È Àò  Ðk˜ “f ï‚!. —}ÖÒÖ‡ û‚…ž‚©zXܺŠ}Öãf ^Q¬ó}J  €lÒ éžóWg›}XY»‚Ç~Jñ|tðfzt àlè Ã~%È ž‚í~ò Ø!$Y É~¹‚Z‰‚‰ä Ž|Xò4 Ž|Xx¬ùJK Ž|XxùX ¬Yv©~žÙX nµ š|ÈíäüÉ }<‘„Ǹ{¬õfûXuztžþ‚ò‘ ‰~Xö‚Ÿ Š~Xyº!f.üž›~Í~‡¬ û‚…ž‚Ÿz‚ãf ^Q¬ó}<êtƒ|XÖu¹ŸŽ}X¼ÇXÒ{JŠºÜ{ðXgzººÈ¬  Ðpó M àpú M ðp ̶Xó¦}X±Xt‚Ä{ @q‹ x…YÃ}ÈÀf pqš M €q¡ M qå §qÈÄÖQÊwtÖä ÖstÖäí º‹tuÈ‚ ¬tÈ+¾Ö ¯z‚"„ Ÿ¨ æt‘ ¨xmºsJ ÖZ+žË È í}J°+ºººÊžvûQwtººtÖºó %íu< Ö`ÖšÈ.ÖÙäÍ ÿ tvt ÿ <‰v´ Êè|< ˜J=„:’L¬ Öù¡¼‚šÈ.ò€y’­~º ÊÉ}<¸Ö ÃÖ „xò JsX ÖZ í¬ÊÏ ±}X°+ É‚ $‚î‚  –|È  Îf Ãx‚ ü} ÀfY.tòšÈ.Öß  ² …rJ"„ g¨Î Ö êsfŸ˜ ä‘Öv‚×  ¬JÐtÈuÈ¿ ò îy ¨xÈmäsX ÖZ+ÖË ò í}<°+¦¬Öºt stºäÔ{X­¦ ÈY«ÈÞvž¦ ºÇvä „ÈZ ¥ºÂvÖ ºË£­”j­Ÿ¢z¬ÖºT½x <dž=ç“Öß| ÊÉ}<¸Ö ¿ ¨xÈmäs ÖZé #É}¬‘° í}ž°+ Ä ¬ Þxº¦. tsX ÖZé¬  „~¬ÊÏ ±}X¾+  Ì  О  °y‚î¬] ¬ þp  •|XîJ  –|È   Ξ ˆx‚ á±J  Ó|Ö ­Ö ’|Ö ü}& Àf À~ ÀfòYsYíºû Æ}¬ÁÉ}óf”zÒÖ‡‚ û‚…‚u©z‚$®uÖ Êè|< ˜J=„:’LDòÖÖºt5 Êè|< ˜J=„:’L $±~ÈJ ¸}È"ž £xä鬿“²vtÐ <‚|ž ^‘ztŒ ºôuž° Êè|< ˜J=„:’L˜ò½x <dž=“ ¼ž Þxº¦. tsX ZéÖ Š~¬… ±}¬°+ É  •|XîJ  –|È!  ÎÈ ¿v‚ Àfƒpt  Ò|X±J  Ó|Ö ­Ö Ï| Õ}Ö À‚òYíºô“  ’| îÖÿ~¶{ãf –Qtó}< ‹º  Ò|X±J  Ó|Ö Ñ}Ö ÀfžY ƒt ’| îÖ Ï| ±Ö Ï|ûÖ @†Ë !ËpfÄÖñ ƒŽsQ¼wt¬ä ‚stÖäü ‚ Î þo‚"„ g¨ ‚‘özž ‡žY…‚Öz¬ø¬Ñ|2 `Öšº.ÖÙäÍ ùt‡}t ù<}´ ôè|< ˜J=„:’v¬ Ö ³äÔ{t?¼‚šÈ.ä€y’ÌÈ‚!u_ä ÛÖØt‘äÊÌyu "Í~wHŸg ”}¾+ ÃÈþ) ¥xXt‘‘özž ‡žY…‚Özºˆ ä €y­}ž Õ<ÍyžQwf¬òÖºt¬Öºý Þtž×zäóf”zÒÖ‡ û‚…ž‚u©zºú  ãxÖ­{ Àò º­{È Àò ¹ ãq‚Ÿ$ÉÈ‚ ¸}“Öºt sf¬äÔ{f­‘òÏ|È Êè|< ˜J=„:’L ‡wȤ}f Ütšy É}<¸ÖÚÖ ¥{ À‚º É}<¸Ö â~Ö[š‚ à<÷yÈ Êè|< ˜J=„:’LDòÖºòÖòÖºtžÈ5Ÿ½x <dž=Ër¬½x <džgÙ "ö~<»„=ŸKx[ÓJ µzãf –Q‚ó}<èº 0“Ï wíqºš.Öeä_Øwf¬ä ‚sfÖäúÈ ÎÎzX—zX ³ÖÊÌyuÈ "Í~wVŸu ”}ò¾+ × f­}ž Õ<Ѻ eûq< Ö`ÖšÈ.ÖÙäÍ ð trtú´ Êè|< ˜J=„: L¬ º"—¡¼‚šÈ.ä€y Ù~ºÖºæÏ| Êè|< ˜J=„: L ‡òw¤}f Ütšy ØÉ}<¸Ö ÿ{Ö À‚º ØÉ}<¸Ö â~Ö[ º ío‚Ÿ$ÉÈX ¸}ñ à<ÂyÖºt5Ÿ½x <dž=ËÓ‚ Êè|< ˜J=’: L˜ò½x <dž=Ù "ö~<‘Ø=Ÿgx[žfòÖ5 ’è|< ˜J=„:’Lyò ÿ~Kä €›û ‘n  äžÑl人ʞvûÖäQyÖ wfºòžºt äsftºÔ{t­¦ ÈY«ÈÞvž¦ ºÇvä „ÈZ ¥ºÂvÖ ºË ež t­”j­Ÿ¢z¬òÖtòÖºtžÈÓ £xä鬿“²vtÐ <‚|ž ^‘ztŒ ºôužû  … ‡n îž×Çl人ʞvûÖ_ØwfÈ ‚sfºäÔ{f»¦ ÈY«ÈÞvž¦ ºÇvä „ÈZ ¥ºÂv¬Ö ºË£É”j­Ÿ¢z¬ÖºòÖºtÓ £xä鬿“²vtÐ <‚|ž ^‘ztŒ ºôužûòÖX  ¤ üm  ùž¼lººÊžvûäQyÖ wfºòžºt äsftºÔ{tå¦ Y«ÈÞvž¦ ºÇvä „ÈZ ¥ºÂvÖ ºË ež t­”j­Ÿ¢z¬òÖtòÖºtžÈÓ £xä鬿“²vtÐ <‚|ž ^‘ztŒ ºôužû @©É ÃmJ°ž†lȺºÊžvûÖQ¼”stºäÔ{J­¦ ÈY«ÈÞvž¦ ºÇvä „ÈZ ¥ºÂvÖ ºË£­”j­Ÿ¢z¬ÖºÖºÓ £xä鬿“²vtÐ <‚|ž ^‘ztŒ ºôužû ­à  Pž!tâžÆ|ȑ㺠t!°{f×ä¼~ “$0ž` Ö­!u×}¨ tŸ º‚3dt/ gt å}(ttt†|º„È ˆzøX&üy! È ìy”Xnu» ºt ‚Mät†u uuulº€ñ}<¾~È<r<K°¬÷~f‰tá~f ºxJ È! fà|<çž ¬z9ÔÈ ¸zÈX'w/ 7&2þy*‚ ŠzöX* s3†~¬Öttt á, ~Öt à ~äÖttt¨ºb äE3äµz"ï zãX*sÀÖUº+©t = è!uup 0 ) &Á}5Öt¨ä-ä -¨"¬z¹È Óy­X"Á}tt¨)Ø}tttt<ûX­J®}ܺ<ÚžÿtZó»öwt òÊÌÊÊôxŽfëvÙº û…X=©zº‰ ºÛv ãX zQ‚ó}Jmf‡ ºct 0½¨ ƒ}‰—{Èëf…ò×–zX¥{Ï‚éÖÛ>Tû /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkerninclude/jemalloc/internal/..arena.harena.c_types.h_ssize_t.h_size_t.h_uint32_t.hbitmap.hjemalloc_internal.h_uint64_t.hchunk_dss.hprof.htsd.htcache.hextent.h_int32_t.hOSAtomic.hmutex.hstats.hticker.hnstime.hjemalloc.hckh.hatomic.hutil.hquarantine.h_uint8_t.hprng.h_uintptr_t.h ¾– L½JƒÄJDÖ 2 Jv p¾¢ LBJ * Jv оä îyÈ–äó\X¬Xøy †È øy¬‹‚ p¿ô Þyò¥䃺íy¬ à¿–  ¹y†òuÈÓ¿!åùXLÙ{Öžäâ{tÍ}X¶º£Áy-¬Zò„Íy†äuÈÓ t\KKåÖXÿ{JÖð{tÀ}Xú×}Ȭ‡}ä ’É}<¸Öyt ’É}<¸äéf—~Ìyt½¢ <dž=Ërt½é¬›~t <dž=Ë @ñ y†ÖuÈí¾YYù ZÎ{J.À}Xú¯¨y¬Ú‚õ|ä ’É}<¸Öyt½Ì <dž=Ë ðÄÄ Žyùº×ƒ®{t2Í}X¶ºÎº{J4À}Xú×} ðÅÓ …~JuÈíÌKK˜~uÈÓk!å0XÝ}. ’É}<¸äyt ’É}<¸äyt½† <dž=Ër‚½† <dž=Ë €ÇÖ ŸúxŠÈ˜©{JÏÖ±{tÀ}‚úЄ©{JÏÖ±{žÀ}¬ÃºÕþxX… ÉŒ :ƒgŽÃx‚Å×ZázJ”òìztÍ}X¶º ›ÉxFº‚p‚ t=M *JXt% :X qt@#­x†äuȸ~¾KK‹~uÈà\KKåÈX{J-À}Xú×}Æ‚‰|ÛÖ §|ºÉ}<¸Öyt ’É}<¸äyt½ <dž=Ërt½† <dž=Ë Í¥  ­wž×º¼wtÇ‚ Àͱ  nòfŸwžåºýt““½ž`Éìw‚ó¤ßuמõ¬ ¡““½ºÂŸw‚ó¤5”X ƒvž º’vtñ ‚  ÏÛ  oòõuå ºuY…ƒuƒ×­ñ““½žÂŸ˜w‚ó¤ßu‰ ž  PÐŽ  ΄€ ½~ºÈ‚Œéòë~ƒ ­­­¯†ögƒT#.!RÈ=-JŠ‚ZƒqÔÈ àrò£ ºu¾}ž““½žÂŸw‚ó¤ßu ÓÉ  "± ºùs‚“ Ö5>È´yjJ= Ô–XuÚy.²ò‘ æw¥¬ ². •~Ju'O áJ  ~Jßu! € %Ñ~ž= ®#Š~f öt„sâ ãx"¢ž¿"Ðtäxºj¬=t Þ%gºò žtèt! –äît ö#ž¸xXnž!†<¾ž¼~XÍf!9<¾ž ¦X6•x<Ä<§ Õx„ž ü~X„<¦X J áô~JI2$>½<‹tò½ Kt³sÑ s=è~¥txºjJ=t –[òJMfºÂJ€t$!ë~¥º­ºíy$È ºr)˺Mƒ àÙŸ  «o×òtäp„.¿g,òuU!¯p @JÁÉ, @XÁÈÙž§<2L<¾Y„ž•<kJtò(€}t õXó²Y ,*ƒœotç–x‚Ì|X <XJ\ XƒŠzXj+”. ãtä´XÕvtXâ º¡“½žÂŸ˜w‚¤ßu pÝí Çw¿=»‚œpJ$Ƭºp<Èm‚úºóp™uë’y4¡<Úw‚;íX.%×’x<ñ7JÙ ¿xJƒ–|X ëžfX‚Z‚¢ƒ”pÖm†‚Kæp™òuºë’yÜ¡<Úw‚;í.­xJmÝ‚œpt$ÆÖºp<Þ‚jJJ XÃJæp @JÁ, @XÁºÙž§<2L<¾Y„ž•<kJtò+€}¬Ã‚ Ûoäm‚¤ïk¬m‚©‚%¾sÖ’x<ñÖ¬“ÇpJ @JÁ, @XÁºÙž§<2L<¾Y„ž•<kJtò(€}¬ßJîZ•{JíL½pfÔ J•t É}<¸Öyt ’É}<¸Öyä½x <dÖ=½rt½x <dž=½ t õK:’„õÙ  ãž ZJ÷Œ'tHXi‚"9<#‚Hä!f_‚JÖ!'< X òKqä Ðä® ªruÈê B.ó­[Œ>J±Xi‚7"yt<:‚±ž!f_‚JÖ&%!yt< X$ºKûqä ’É}<¸Öyt½x <dž=½Ó tÞX ˆr"×{Ö`ׂÍut ˆƒÃ|X ¾ž¨{žã  ©mÓJÄrJkJtò+Ý tUN)xÈ fÌm½‚Ê ô¼vÌ|º JXJ\ XƒŠzXj++t Ìò´XÕvžXâ ‚ç“ëäÊÐwòЭ˜w‚¤ßužÈ‚ pé² àr ¢ XárJ£ Œ·r×{¬öÖ”o# @JÁ, @XÁºÙž§<2L<¾=„X•<kJtò(€}t È®΃‘n€‚v tð~tó’òûmøºø~‚­‡…‚wòÌ|X <XJ\ XƒŠz‚j+ƒX ôrä´‚Õ ž óÿl"Xâ äË“ ÜzžŸ ¬Ö–xŸÂw‚ó²ßu–È ÁÖ @í™ ¼p2uò¬ ©xmäsX ÖZé¬ #É}¬w òí}J¾+ 纷p uȬ‘ ¨xmäs ÖZé¬ #É}¬w òí}t¾+ñJ¼åqÈ » XÈrJ¼ È×€mJ…× ^ƒÃ|X ¾ž¨{Ȧ½tºë ÖÌñqkJt<2¥ž »qtÇä Ár“žÿt ºËuf¶ ‚!Ðw<¾¼~X¹ ‚”w<!9<¾È¼~X)à fŠwX!9X¾º‚ X ФJ¬ÝqJÏqt‘t½  Ãvt[t§ t È¡ufà ‚!¦w<¾ž¼~Xã ‚êv<!9J¾È¨ Xáv<!9<ú}<)í f!™wX¾žÆ~‚ç f‘ …tãÙqJXÏqt‘t €[È tÎrJ³ J†ël¬õÜqttÈtŸ¬uò·G@$åÞl§‚u ôÓuòÌ| <XJ” žƒŠz¢++tÏò ôÉ}<¸Ö ËÖ ýw#  •|XîJ  –|È Îf Íxò} À‚YÂt­‡ Öt´‚ÏzÖ ÊÉ}<¸ÖõÖ ó n ½ Þxò¦< tsX ÖZéÖ ‚~¬ ’ù±}X¾+ îJ? Ûuº ýw!  •|Xî‚  –|È Îž Íxò}ò À‚±º çmºYÂt­‡Ùr É}<¸äÿ{ÖXâ ¬ËË Üzž¸ Àô¤pò½x <dž=Ë“ tñ¯Ür½x <dž=Ù ñ‚ Ðm#  Ò|X±J  Ó|ŽÖŸÂw‚ó¤ßuUÈ À‚ ®¬?ª}ºó¯ ºpYòtÃô“ ‘È ’|ŒÖ½¾ <dž=Ë Ô‚ ’|Ö î¬ Ï|Æ t  û· ’ 0û– ûož ûò[ˆJ„p< ýL õ¸çóoÖ J| õ<£mXÕž¬}<ãX¤pkJt<’Jî|X’< ÑxfµÈu>f ¬ Ðl‚u¢gßXÒÈyä·‚Üs© >Ê{º ‚ä] #_‚ÁpfÔ Jí>JȃŒltm‚¤ïk¬m‚©‚4‚ƒ„ízäÙxä þÏ Éo ûž[ŒJ¤òŒk‚ökÖý‚Ì|X <XX\ tƒŠzXj+ . ×pä´‚ÕvtXâ º¡“½žÂŸ˜w‚¤ßu `ÿâ v¼s  ÿŒ ’  ÿñ °ož ægXˆòmä׬änu°LKKÉè®n ’É}<¸Öyt½x <dž= ð “ ¿jÄÖÏjÖý‚Ì|X <XJ\ XƒŠzXj+ß. ˜pä´‚ÕvtXâ ‚¡“½žÂŸ˜w‚¤ßu  ã 'Êm䚺.äòäÆm<šÈ.Öóò“àluÈ uÈ!¬EÈÍ8òK<ù~ò׎júÌn ¼È(øX£oáf òóm.t òè|X ˜J=„: Lyò Êè|< ˜J=„: L ìò£$Ùx›fƒoÖÿ±jtØtâmty|x|½ t ÃvJ[t§ t È¡ufà ‚!¦w<¾¼~Xã ‚êv<!9‚¾È¼~X)í àvX!9<¾ÈÆ~Xç f‘ÎtuÈà«nJuÈáN±EYZKKƒ¬jýÈ¢Xªn .XJ\ XƒŠzXj+ÑX ¦n´XÕväXâ ºËË üxÈÉ}X¸ä=Ër‚ ÊÉ}<¸äyÖ ’É}<¸žyº½† <dž=ËXuŽº n<ßJtžÂŸ˜w‚ó¤ßu°ò—ˆm" ÊÉ}<¸ÖyÖ ÊÉ}<¸Ö¤Ãn¬ Àò¦mËt‚jJ´Kæ>\¡n¬êt–nX ’<î~Xêžg¡ßo<!9‚¾È¼~Xð<!–pX¾žü}XuÈ¿Ìm<uÈÀNÛEYZKKƒÍièõóuJÙrt‘»özž ‡<Y…‚Öz¬×¬âlò½† <dž=Ùr‚½è <dž=Ër‚½x <dž=Ër‚ ÊÉ}<¸ÖyÖ ÊÉ}<¸Ö”ÖxJÙrt‘»özž ‡<Y…‚Öz¬Ô¬ål½x <dž=Ùrt½x <dž=Ë €‚ò­{ò ÀòÀ{º Àò  0 ž •m/šÈ.ä¨h)²m `Öšº.ÖÙä ÁÈÄmt ¼JÌm´ Êè|< ˜=„:’L¬ Ö—¡¼‚šÈ.ä€y’t¿oƒ}1uȬ‘ ¨xÈmäs‚ Öhé #É}¬w í}t°+ú˜ ‡p³óÊÌyuÈ "Í~¡»Ÿu”}ò°+× ¬­}žÕ<‚z Êè|< ˜=„: L ¥…p)Ýw¤}fÜtšy ÊÉ}<¸ÖyÖ É}<¸ÖÃÖ Þxò¦< tsX ÖhéÖ ‚~¬  ±}‚Ì+ Ì ž ýw)º  •|ºî‚  –| Ξ Íxò} Àf!Y‚t Êè|< ˜=„:’L¹ ò­•ßn Àfº ÊÉ}<¸Ö à~$[ý#à<§ äÐlä Êè|< ˜=„:’L˜ò½x <dž=Ù Á}‚º  Ò|¬±‚  Ó|È!Ñ}Ö ÀžÛ¯ ºpYòt ë}´'½x <dž=½ À~t²*½x <dž=Ù "ö~<ç=Ÿg¢ Öm[ Ôf ’|íÖ  Ï|   É ‰hžûº˜hfê‚ P Ô M ` à ëgf— € ç hh÷ ° ó Øgfª Ð ú hügŠ  £ ¯g)Ùäßf=Ÿ××Ö›gÈ æf!.ïÝ1c¤gmú‚g‚ã‚   Ý Îhf ´X ° ä Çh¼X2 ÀhÃX2 mH“K‘Š„ô纆ʞfÖ䃑—f)ëX’fäì ƒY…ƒƒƒó»ù»ÉÉÉÉ»oüeÖ‰òyG ò " † ã|J ïd„tެîd¢t©Ù©Ù©?¢´huºÙÕh.¬¬z«hžuº²}¸Ö=Ë+î.ó–¬ ±  ººääääääääääääääääääääääääääääääää %æ$““ÕhºìÖ”hg ÊÉ}<¸ÖyÖ ÊÉ}<¸ÖyÖ ’É}<¸yº½x <dž=õ·¡¸hžË}ž¸ =õ•|žùtuÈ’|ò f<gœ e©žË}ž¸ =õ•|ÈùtuÈ’|ò f<g+ >hº‘âtuº©|ò–€vÉ=ü0zÖt< tÕhìŸhfu‚íË÷g ÊÉ}<¸ÖyÖ½x <dž=½å.h‚½x <dž=½rt½x <dž=½ø.  1 å  J ò…ë° ¬MuuT JsZ³K=‘x º. ªf< ÖJƒY A 02 ð *Öv^Jg ¡+–XŽwf÷‚/òŽtt$À}Xú÷ “vä"í f¯Év‚ð f ­wž[-J!Jbž¸X„vX <[!ÂJkº!JbȳX‰vXÄ<ªX’w" ¼f³X‘ž×v5ž J‘wÖõt‹wžxžæ|f)š Ö×óv<ÍÈ!"ÖUfÌXðvX!ï<U‚Ñ5ëvJ ¼fÙXë×v.ÄL <Üäv‚xæ|)Á Ö=ÌvÍf!"ÖUfóºÉv<!ï<U‚¼X ؆v<xÕ|f×"¯ ÖÌvu®žxtæ|<þ ä„tt:÷t ?¬CJ òI#u› tÿ{X¡“½žÂ w‚‡ú|t¤± Ð8 Ö Ì‚•{%óò {ïX°òu‚ƒ}ÒÖ¹|ÈÙt ’É}<¸äyt½† <dž=½à<  ð9 â À‚•{%óò {ïX°òu‚ƒ}ÒÖÅ|ÈÍt ’É}<¸äyt½† <dž=½à<  ; Ë ÈXºt!¬ÈòJ¬fääf¬Xtt× ­•u )XY<=>uÔ{QQf®t^Y/JQLJ´ŸÔt7ym(º¤Ÿ ñº ’è|<  ˜J/„:’Lyò 0O ƒ O6䟟[ž O  L»ËNøû /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internalbitmap.c_types.h_size_t.hbitmap.h ÐO Ë PuæK= P á Ë  JtYŸu¬ û /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_typesinclude/jemalloc/internal/../Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internalchunk.c_types.h_size_t.hjemalloc.hrtree.harena.h_int32_t.hOSAtomic.hmutex.hstats.h_uint64_t.htcache.hticker.hjemalloc_internal.hchunk_dss.h_ssize_t.hnstime.hextent.hbitmap.hprof.hckh.hatomic.hutil.h_uintptr_t.h PP ¦ •JÉ ž|tñ}‚ €P á M P ö LÁ Lº ¥JÉ Ó~t¼{Ö àP ¨ j ðP ² m Q   kä (Md‚7 ÀQ Î  äM<ktJltJmtJntJotJptJ mt‰7 ÐR Ž wú#‰JÐC=fó~tÐXö,ƒX)yE‘Jw<°‚ÐX fGº-fa ß àS © \Èú#‰JÐC=fó~tÐX Êf,,ƒX)kE‘Jw<°‚ÐX fGÖ<<R¬ àT é  ¬KK  U €  ÖK : €U Ë 0ÚÖšº.ÖÞ|ä ÷~$çS¶XÝ{QQQ +¬²ÖݳQQQ  ¬%ä "פ×8¤‘y< fÁååx9 ê~ÜäÔ Êè|< ˜J/„:’Lå|ò­ äJå­&+­ Ô~!®º Yå˜ó~CQQë_ìXåå  ¼~-ƺh Ò~6ͺ­ß$²~ ¯}* \#kä (Mdä0A Æ@E Y‰ À\ ¹ ë0 ] Þ 5 î|f$ìV‡¬}¬{t Á"®Ÿ’}$î‘ #­“}Qù___Ù­å ç|Èš‚‘#­­­ö|—UX¬‘Öí| \*k‚ (Md‚0A ©@Õ~å¤}ùUX ƒ¯}<ÓXå¬}‚X­Ø ¶|¬Ïº  a È ®|# \#kä (Mdä0AØ@YX2 `c ë ‹|  \#kä (Mdä0Aõ@" Àd Ÿ ×{* \#kä (Mdä0A ©@* 0f Æ J»Ê×  f ¾ L 5û /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internalinclude/jemalloc/internal/..chunk_dss.c_int32_t.hOSAtomic.hmutex.hchunk_dss.hprof.harena.h_types.h_size_t.hstats.h_uint64_t.htcache.hticker.hjemalloc_internal.hextent.hckh.h_ssize_t.hnstime.hjemalloc.hbitmap.h_intptr_t.h °f , j Àf 9 M7´û include/jemalloc/internal/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_typesjemalloc_internal.hchunk_mmap.c_types.h_size_t.h Ðf $ !ƒKMÖ®˜ ïƒZ Ø[­'ž‘ YXä*ò àg Ë Mvw(Úû /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internalinclude/jemalloc/internal/../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_pthread_int32_t.hOSAtomic.hmutex.hctl.cctl.h_types.h_size_t.h_ssize_t.hstats.h_uint64_t.htsd.htcache.hticker.hjemalloc_internal.hprof.hckh.harena.hchunk_dss.hextent.hnstime.hjemalloc.hbitmap.hquarantine.hatomic.h_pthread_types.h _pthread_t.h _uintmax_t.h_uint32_t.h ðg Š ?•Ÿ MûxÖ†È  àh ï ãzJ¡‡+­”,„~ ‡ø},ô\+(ýX. pfJ­ p­ ²»ÒzȾº €j © $5ÈØÛÛyJ ©ßy ¤% <% < » £ÊyJ ·tKºyž¨'L†žZò‘óɹXÌeä . m © JÝÆ -žÎxJ´¬Ôx  ¯JpX<¬ & pn ê L  n Ì  JÈžž o Ñ  w„ º¬hƒžŒwùº  o ¦ ¬pÔºòÖžž¿pÁº @p § «pÕºòÖžž¾pº àp ¨ ªpÖºòÖžž½pú €q © ©p׺òÖžž¼pĺ  r ª ¨pغòÖžž»pź Àr « §pÙºòÖžžºpƺ `s ž ´ožÐºÃo,ź Às ²  p!àºòÖ³pͺ pt ­ ¥p!ÛºòÖž¸pȺ  u ® ¤p!ܺòÖž·pɺ Ðu ° ¢p!ÞºòÖžµp˺ €v ³ Ÿp!áºòÖž²pκ 0w ´ žp!âºòÖž±pϺ àw µ p!ãºòÖž°pк x · ›p!åºòÖž®pÒº @y ¹ ™p!çºòÖž¬pÔº ðy » —p!éºòÖžªpÖº  z • L×® Àz ‰ Éo!·ºò-ÖžÜo¤º €{ ‹ Ço!¹ºò.ÖžÚo¦º @|  Åo!»ºò-ÖžØo¨º }  Âo!¾ºò.ÖžÕo«º À} ‚ L×® à} ÷ Ûo!¥ºò-Öžîo’º  ~ ù Ùo!§ºò.Öžìo”º ` û ×o!©ºò.Öžêo–º  € ý Õo!«ºò.Öžèo˜º à€ ð hK®  Û ÷o!‰ºò)ÖžŠpöº À Ý õo!‹ºò)Öžˆpøº €‚ ß óo!ºò)Öž†púº @ƒ á ño!ºò)Öž„püº „ ã ïo!‘ºò)Öž‚pþº À„ å ío!“ºò)Öž€p€º €… ç ëo!•ºò)Öžþo‚º @† é éo!—ºò)Öžüo„º ‡ ë ço!™ºò)Öžúo†º À‡ Ò €p!€ºò"Öž“píº €ˆ Ô þo!‚ºò"Öž‘pïº @‰ Ö üo!„ºò"Öžpñº Š Ø úo!†ºò"Öžpóº ÀŠ Ê ˆp!øºòÖž›påº p‹ Ì †p!úºòÖž™pçº  Œ Î „p!üºòÖž—péº ÐŒ Ð ‚p!þºòÖž•pëº €  p!ðºò"Öž£pݺ @Ž Ä Žp!òºò"Öž¡pߺ  Æ Œp!ôºò"ÖžŸpẠÀ È Šp!öºò"Öžp㺠€ ½ •p!ëºòÖž¨pغ 0‘ ¿ “p!íºòÖž¦pÚº à‘ ©  ð‘   ’ Û  ’ ò   ’ ‹  0’ ¡  @’ ¢  P’ … Ír¸ º•gÕr<° º Ð’ › ·rÎ º—ƒ<=Õ"»rÊ º ” µ Ÿ‘LŸjy  ” Ï Ÿ‘LŸjy   • æ JžžÖg JžžÖg Jòžž P– é JžÈ °– ê JÖž — ÷ JÖž p— ‚ JÖž З ‘ Áq ĺ†v ”Ù~‚,#”+¤%#»uâ 䑞ŽvXò äÉq¼º š ‡ L×®  š ƒ Jøuòˆ ¬fžž  š û L×® Àš ø Jƒvfý ¬fžž 0› ð hK® P› ë Jžž À› ì Jž 0œ í Jžž  œ ñ  árÈ£ ä®îr¬˜ ‚ 𜠹  MåŸè  È  MŸ¾  ` ×  ƒøsJ ¬ž‘ñÉy¸Y Y[Öžás¤ ºÂs© º  àž   ªy<×ÞXŸ»žLŸjy sÊ ¬   Ÿ ±  ˆy<×€XŸ»žLŸjyþrì ¬  `  Ó  $ýrJ‡ ºâxŸ’žN$X€ž“@…s‡ ºßr f  0¢   ÄtÖÅ º:Ê ¢zzÖðuÞX IÌt‚¿  sƒ €™z¬×©zXÌ ´tÁ <—tfË º £ ½   £yÁyJQ’wž‚ä ºsžºäò{¬ö ºÖȘuí º ŽyÖºÖºòÖX `¦ Ø   ˆy—y<Q’wfä ºsfºä‚¬žf=¢¢ óxäÖºÖºòÖX ð¨ ó   íx—y<Q’wfä ºsfºä¬žf=¢¢ ØxäÖºÖºòÖX €« õ  JòžÖòò ð« ö  Jòžž `¬ ÷  Jòžž Ь ø  JÖž 0­ ù  Jžž  ­ ú  Jòžž ® û  Jòžž €® ü  JòžÖòò ð® ý  Jòžž `¯ €  JòžÖòò Я þ  Jòžž @° ÿ  JòžÖòò °°    À° ‚   а ƒ  JòžÖòò @± „  Jòžž °± …   À± †   б ‡   à± ˆ   ð± Š   ² Œ   ²     ² Ž   0²    @² ‹   P² ã  JfžÖòò °² ä  JfžÖòò ³ å  JfžÖòò p³ æ  JfžÖòò г ç  JÈžž 0´ è  JfžÖòò ´ é  JfžÖòò ð´ ê  JfžÖòò Pµ ë  JfžÖòò °µ ì  JfžÖòò ¶ í  JfžÖòò p¶ î  JfžÖòò ж ï  JfžÖòò 0· ð  JfžÖòò · ñ  JfžÖòò ð· –   ÊzÈQÊwtÖä st¬ä ½<ø{J½zÈÐ ºŸÈžuÖ/¡“|ùõYkÁvÞ º zÖº ¶ˆò ÂzÖÖºë{óf Yñò• «z‚ÖºXä `» Å   ›zQ¼¢s‚ºäåfžž ›zäÖºÖºXtä `½ Ç   ™zQ¼¢s‚ºä3X´Jfžž ™zäÖºÖºXtä `¿ É   —zQ¼¢s‚ºäéfžž —zäÖºÖºXtä `Á Ë   •zQ¼¢s‚ºä3X¸Jfžž •zäÖºÖºXtä `à ý   pà Ÿ   €Ã Ñ   zÈQ¼wtt‚ä ºstt¬ä ø¬ îv<Y Ìž ¸|<  .K× þvÖ ˆXtºQ¼¢s‚ºä3J È|J‘„ žÖÖÌ üyäÖºtÖºtÖºÖºòÖºXt àÇ ê  P ïyž_y<Q’†sf¬ä Ù|J¾ ž éy¬žºÖºXä €É À ""Ï~tóô–5Y¤"ñòz¬ÿfñº‘X%Ih%.俺ÁäHº ½Å Xnt» ü|È•fg‘özž ‡žY…‚Özº ½¬“|<„ f‘‘Çzž ºÈZ¯}f"•{‚öŸu ”}ò°+æ ¬ ævt¬ þ{‚¾ ‚‘‘Çzž‡Èµ<´ ¶vS“‘Yº š ä­{È ÀfÁÈ  ³v¼ ò‚ "‚.Èÿz ÀòÀ{÷ò¹}Ì<´}Ƚ<¿x[ –}Àž ¨¶òu"ë~½=ŸY ö|òx+ú‚ ’ É}<¸Öþ~t“ ø|‚ú¬½x <dž= @  ¬ ¿¬«ÄÈÙJ ü|•<g‘özž ‡žY…‚Özº ½¬“|<„ tŸ‘Çzž ºÈZô¯}f"•{‚öŸg ”}ò°+Ù< ¥|‚ Úä¬ ".Èÿzò ÀòÀ{ò÷ò¹}Ì<´}ò½< ÞuòÀf¡ò[´‚u"ë~½=ŸYñ ’ É}<¸Öþ~tØ“òX½x <dž= À  ã ŸLé óYÇzž‡Èµ<| ‹vXƒK… t™,û /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386include/jemalloc/internalinclude/jemalloc/internal/..chunk_dss.hprof.hrtree.catomic.h_uint64_t.h_uint8_t.hrtree.harena.h_int32_t.hOSAtomic.hmutex.h_types.h_size_t.hstats.htcache.hticker.hjemalloc_internal.h_ssize_t.hnstime.hextent.hjemalloc.hbitmap.hckh.h `  OV?Ÿ=KMƒ®>’GgƒuU_góYVJ/Q¬/J¾ p ô ’svž  JX dofJX f à û nv‚  JX khÈfJX fÆ Öû /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_typesinclude/jemalloc/internal/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesstats.c_types.h_size_t.hjemalloc_internal.harena.hatomic.h_uint64_t.h_uint32_t.h_ssize_t.h P ò +ƒƒ ‚“:-.Y%Mmƒƒƒƒ®¬$¬$*/*  å=‘=* ******* D4D4****¬$¬$¬$¬$u׬$É),¬$&¬$׬$)¬'¬'¬'¬'¬'¬'Hæ{˜X¬'É #×9ŸÉ, r6s=s=så ®Ci±¬'É # )­  f < X¡(ý~òñ~¼âXhß~ôãòöõ òòpò÷ø~ò  ð3  ë0£Ö¬'È,¬,"¬,׬3u»¬,¬,¬,¬,¬,4¬,¬,¬,¬,4¬,¬,¬,¬,4¬,¬,¬,¬,4l#¬,¬,¬,"Ñ}Ö‚!‚$‘–‚$ -ã}- ÖJ+J+J+ä+ä+ä+ä+Éä+ä+ä+ä+×1"u"/ sÚj)à}ž<ÑÈÓ.®~Ͻ~Ö‚$‚$)(ä(ä-ÙJ+ä+ªU*Á~<<¿tÝ~¥.Ü~£é~Ö‚'‚$‚$(ä+ä-ÙJ+ä+ü_,î~<<’tŒô.ºô¤º~ä+ú~È.€¤¸~Ê óóòõôÉ~òòŸò6ò {¿û /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkerninclude/jemalloc/internal/../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_pthreadtcache.c_types.h_ssize_t.htcache.h_size_t.h_uint64_t.h_int32_t.hticker.hjemalloc_internal.hstats.harena.htsd.hOSAtomic.hmutex.hprof.hckh.hchunk_dss.hextent.hnstime.hjemalloc.hbitmap.hquarantine.h_pthread_types.h _pthread_t.h util.hatomic.h °T ! ¯ÓY¥¹gåqf¥ .’ƒå= €U Ù   ³‚ÏzÈiÖ  ß ´XÕvÖ ® tþvl Ùƒ­çuk"t‘XŸr‚ ™žë{äw‚k‚,º < ‚XJ” ƒŠzŸ*.l Ùƒ­½‘kt‘XŸr‚ ™žë{äw‚k‚­.‚éº<ȃ­It;‚!KgK  ñä àX ª   â‚ {È  è ´XÕvÖ ® tÏwò›íÈn®Êè‘gt‘ XŸv‚z‚–‚ ýȃx É< <XJ” ƒŠz­û.2ë~¬›º­ôõ~t‚$KgK  ä [ Ê Âžs< XKhÁ~X°Xu‚ `[ Š ôÆ~X°ºuºâ~ž Ð[ ’ À~кº¬X°~"Ù‚º}‚È‚z‚ ó~&€ò~ÖŽ/Éî~ä"'„å‘‹­ u‘~hg‘o²}‚ P^ ¡ ±} Ù‚º}È‚z‚ H'u> ×ôu‘~hg‘o<ËN  _ ª  ¶Q¼”stºòÍ}X™<Y Ìtš}< O ãJ  |yä ²žºQ¼”stºä3JÉ|tµfY ‚£}ž ªäÖº  ¶|È ­ÖÖºÖºÖºXò ðb º Ê® ž ‚`‚šÈ.ÖÙäÍ ì|t ”äú ¶‚è|X  ˜J=„:’Lˬ¡¼Xšº.ä€yX’4tÉ™%„Ž ¹<  ü| •<g‘özž ‡žY…‚ Öz¬Ð{¬¥°ºuÉÈ·Xâ~ž¾œJtYg¤x. Jí}  Ç ž¬ "­{È Àò  èz¬è|X  ˜J=„:’L íè|X  ˜J=’:’L Pf ‹ ÎY ‚‚~‚ €f â  ¯JÒ|3®å}tž‚õ}‚„‚ Ý}º¤ÖרÙ}‚©‚­é}ò‚. ™¬  ü| •tg‘özž ‡žY…‚ Öz¬½¬“|< „ f‘‘Çzž ‡È µ<|  º{  üò¬ "‚­{È ÀòÁÈ  Ðh ™ M àh »  ®x õÉ Œ}Xƒ[¼Ÿ=ÊŸK=†ò|È  i ç Lvò’YŠ Ði î Kp’YtŸu  j ÷ Q  7É}< ¸Ö EtÉ ×Öugx <dž=½ C.)¯’&‘„…½tfÈ‘r.l  ºû /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_pthread/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libkern/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_typesinclude/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386include/jemalloc/internal/..tsd.h_pthread_types.h_pthread_t.h_int32_t.hOSAtomic.hmutex.htsd.ctcache.h_uint64_t.hticker.hjemalloc_internal.hstats.hprof.hckh.h_types.h_size_t.harena.hchunk_dss.hextent.h_ssize_t.hnstime.hjemalloc.h bitmap.hquarantine.h_pthread_key_t.h Ðk  L ðk Ç ‚ütäñ{PtäŠ|J=È«‚Úº´òÍ|È´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬h «‚Úº´òÍ|<´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬X¦ʺ±Jß|Ö¦¬ʺ±Jß|Ö¦¬û Ào î Lð"t¬QÊwt¬ò tst¬ä“|<v2ä«‚Úº´òÍ|t´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬h «‚Úº´òÍ|<´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬X¦ʺ±Jß|Ö¦¬ʺ±Jß|Ö¦¬Â«‚Úº´òÍ|<´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬X¦ʺ±Jß|Ö¦¬û àt ù ˜Ï‚º_Øwtºä fstºäœ|<g*ä«‚Úº´òÍ|ž´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬h «‚Úº´òÍ|<´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬X¦ʺ±Jß|Ö¦¬ʺ±Jß|Ö¦¬Â«‚Úº´òÍ|<´fÌ|J´XÓ|tƒKX°¬ ¬Ï‚Jò{íºò¬X¦ʺ±Jß|Ö¦¬û z ¦ «‚Úºe‘YX°tºÊ‚ J °z ¼ –òíº‚fX¦t  { à XºXºº¸{tËX9˜û /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/include/jemalloc/internal/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/_types/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/i386/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_typesutil.cutil.h_uintmax_t.h_types.h_size_t.h_intmax_t.h_va_list.h { Ê ’<o¬ à{ 0<   | Ø Jq   | ì  :Ç1Ð~qXfƒ+ ä3cuCzJ…‚„ewúXŽY\V@E +   ~ ¾ ºP=•<þ„!!Umt§3ý¬ $å°õ~ ”¬ $ ?;Í3I¿E óÊO*ÒKö}.ŠÈI7e× ­í×gužÈ</¬äJ¬<òºGJÈrÒ}.®È ¬Öº¬J¬<rEÒ}tååš~(®ÈÒ}L®Ò}: ¯ÖÇ}‚ JKÈ ˜<š~‚ÕZ¼ªX%žžäžJ<¬<ºJJÈÈÖ¬žJ¬<%w%cÖ}8ªÈí}OŠ/«}ä zKÈ1tYKƒt@u#å¸}Aª(v%*Î}"ŠÈß}:ªÈ(ÖžJ<¬<$ºRVò,ž•Y=çJ%¬žžJ<¬<º7<ºžäJž<»vtˆÈ/YØ P— Ø c¯ ð— € if&^.ƒÖ ™ Œ r`&+ɬgimli-0.19.0/fixtures/self/debug_loc010066400017500001750000010517041343337721300156130ustar0000000000000000 7U7–\ƒ\¾ö\ 4T“4D_“D–_“E_“Eƒ_“¾ö_“ 1Q“1D^“Dš^“E^“Eƒ^“¾ö^“ :S :SDe\Ew\¾ö\Qe\Ew\¾ö\ïñP“QUPUdPr{T~ƒTwƒRw~~ƒTŽP“„Y–T–\¯»RÁåPÔÞRëP“Pž£P¹¾PÁåPÔÞRãöRëöP“ÁåPÔÞRÁåPÔÞRÁåPÔÞRëP“ëP“PÁÊPÔÞRãöR£¦RãöR£¦R³¹P^PPUS?ST“"T“"ASS"ASS5ARGkPZdRq‡P“‡‡P$P:?PGkPZdRi|Rq|P“GkPZdRGkPZdRGkPZdRq‡P“q‡P“‡‡PGPPZdRi|R$'Ri|R$'R4:P‡^PŠPŠPðòUÐSÚæSðúSÚÞQ Q¯ÚX Q¯ÆX Q¯ÆX Q¯ÆXP^U“^¦^“¾ã^“µ¶SeuUl¦^“¾ã^“ÆËSÖãS}‚S“P“¦^“¾Ë^“¡¦SÆËS¾ÆÆËSÖáSáãR­¾UðúUú.^0G^ðT“"U,SúT“ U8=U088=USEGS=EEGS'.^PgUg]PdT“dÕX“ÕvHKX“NÆX“ÆÎ_“ÎØX“k›S› U ªSk›S› U ªSoˆT“ˆ  ªT“µòP“òv@P“T“oªT“~K_“NÆ_“ØØ^~ƒ_“ˆ ] ]äU]]µÃP“<AUÝçUU>S>LvPLSÿvPÿSÊvPÊÓPñS:vP†‹\L_“*ùùÿS“:%:U»ÂS“ÉÎU‡‡ŒR“˜U ¢U˜  ¢Uª¬UàåU¢ªª¬U]“"]“U"U"Ulq\|†\BGP“TTP“^c\lq\cllq\|†\|†\††R’œU£¯\¬¯\,:ÍÓP¾ÓS¯¾_“¹¾S*,S"**,SÚßUYe\ù\ñRñùù\pSe^ÿ^^P ^`iUi”S›¥SmtP‡”U‚‡U£¥U›££¥UŒ”S°·U·×P¿×UÄ×PÌ×U  U ™ \™ Ï ]Ï c \Þ Ž \Ž ÷ v°÷ Ï \í >\K[\æd]dÝ\ô5\ò\-¥\ܹ\Í \ .\n€\  T“ Û ^“Þ ‘ ^“‘ ó \“ó í ^“K^“æÝ^“ôû^“ ¹^“¹v¨­^“­Óv¨Ó¹^“Í ^“ .^“Xnv¨n€^“€§v¨ yv°yQ*v°*fQfVv°V°Q°\v°\„Q§²Q¿¿Q¿åv°åèQë v° eQeÆv°ÆÑQÑLv°LLQLÍv°ÍÒQÙÙQÙ§v°§§Q§§v°\_å ô U  UÀÍUÏÝUäôS,Uþ$PäôS P“ P“*1R1FP14Rª¹UŽŸtñûty Š të ü tñt\ft  tk u tzˆtÙætñtZdtÒ Û ^“u £ ^“í í ^“KÊ^“ï^“ ¹^“¹v¨o^“Üî^“Í ^“ ^“n€^“€§v¨š £ Yí í YKÜÜîYÍ Y nn€Y-T € ^“.P^“¬é^“ò^“¥^“¾â^““µ^“Û ý \í .\û5\è ý \í .\û5\5Q-0^“05^“ý PQ# ( SF V SF V SB¬S¾S!7SCeS‰˜S“µS] c \.>\ÅéT c v°c §s Ð ]¬é]ñ](C]¾â]… ¬¬((¾¾§àéPÔâ\s § ]¬Å](4]… ¬¬((§˜ § \(4\Ééy¼ÅTÑâT—¾TUCC““§h—\°¾\Ce\‰˜\UCC§hx\CO\ xv°x§Ž—T¤µT… £ ^“í í ^“KÊ^“ï^“ ¹^“¹v¨o^“Üî^“Í ^“ ^“n€^“€§v¨š £ Yí í YKÜÜîYÍ Y nn€Y¡ £ \í  \u Ï \Í \n€\š £ Yí  Ya u Tu Ø YØ ß UÍ Yn€Yà í Qa u QÆ Ï R¶ Æ Tf¥T.T¶ Æ Tà à Q¶ Æ Tà à Q¶ à Tf¥T.T}¥U•Q ¥Qv}Rz}U S \Üî\0 S TH P QS S Q) 0 R- 0 T— à \Í \n€\à à R¤ à \à à RÍ \n€\ä SüR RÝäRáäSK[\-o\ \vyQX[\vyQ-o\ \DoT\dQgoQ=DRADTŸ¤[ÄÊ[ÄÊ[ØïS“¥ÜS“XnS“±ºTinTS“ ûS“€§S“S“ ûS“€§S“T¨­T ¨¨­TS“ÃÒUS“ˆ‘P˜§PÚÞP“ëëP“S“òûPˆ‘P-_€ˆˆ‘PS“˜§P˜¢P¢§RU&Y5LY?V[?VTyS“LtS“5]S“/2S8:S“:BS“irPm€TìT°  O\ѧÖÑÑ==  §P'5\ÖÑÑ==§éù^=L^ \ðyãìT$5TÂÚTm§§]]§€±\àñ\ \m§§§€“\ \“žž±Tž±T¹ÂTt…TKyTfpp‰T.§uÙ_0y_â_7C_e‰_.X_ˆ0077..§lyPJX^u«_0>_7C_ˆ0077§›«^7C^OyyBKTGXTp‰Tg“T„LLÍÍ55§—Ñ\…“\Íÿ\„LLÍͧ—§\ÍÙ\§²²ÌQÙÿQ²¿Q^gTL]T°ËUËè\èESE!v!C!SC!m!Pm!õ!võ!#"S­"°"P°"Ç"RÇ"$\$Á$Sé$&\&&S&&T&T&vT&W&SW&d&Td&Ë&PË&ö&vö&û&P''P'b'vb'r'Pr'±'v±'ý(\ )#)\#)5)v5)9)P9)p)vp)µ)Pµ)¿)U¿)3*v3*q*\°ÈTÈ]v¨]éUé T @ U@ ³ T³ ¶ U¶ ü ]ü !Qõ!&v¨&T&UË&Ý&Tr'±'T±'#)v¨#)5)U!*3*T3*“*v¨°ÄQ“Ä£]“Ç"$]“@%&]“±'ý(]“ )#)]“I*q*]“ö ^õ!#"^î#Á$^é$¾%^&T&^Ë&Ý&^r'±'^)( (^#)5)^!*q*^*"ž"\ž"ž"PÁ$é$\{"ž"P$„$R„$“*v ¼'Í't()(t #.#t«(¹(t)#)t‚#“#tä#î#t4(B(t“( (tK%\%t´%¾%tø#e$_“I*q*_“ø#e$_“I*q*_“$ $R $$v $ $R$$$ $Rø#$_“+$;$Uø#$_“Q*Z*Pb*q*PC$H$P“U$U$P“ø#$_“\$e$PQ*Z*P$$PI*Q*Q*Z*Pø#$_“b*q*Pb*l*Pl*q*Ro${$U±¶_ÐØ_ÐØ_þ$@%]“3*I*]“%&%TD*I*TëPþR+P“++R $¥$R¼$Á$RëPþR  R P“ëPþRëPþRëPþR+P“+P“++RëôPþR  R¥$¨$R  R¥$¨$Rµ$¼$R;ESE!v!C!SC!m!Pm!­"v­"°"P°"Ç"R&&S&&TT&W&SW&d&Td&z&PË&ö&vö&û&P''P'b'vb'r'Pr'5)v5)9)P9)“*vö !vˆ!i!]i!q!Sq!á!]í!õ!]­"Ç"]&&]T&z&]Ý&r']5)p)]^Ð á!_í!õ!_T&z&_Ý&b'_5)p)_³ ö Që á!\í!õ!\­"Ç"\&&\T&z&\Ý&r'\5)p)\!$!QY]v¨]fU³ÉU= @ U@ ³ T³ ³ Ur'±'T!*3*T^- = S  § U¦³Q- = QŽ — R}ŒP&I&P#)5)P}ŒP¦¦Q}ŒP¦¦Q}‰P&I&P#)5)P,&@&QD&L&QO&T&Q%&,&R)&,&QßéUé T  UË&Ý&Tù P  Q  QòöPöùPa Œ Tr'±'T!*3*TŒ Œ Rn Œ TŒ Œ Rr'±'T!*3*T‰'¦'P¡'©'R¬'±'R‚'†'P†'‰'P^ë ö \!!v!C!SC!m!Pm!­"v­"°"P°"Ç"R&&S&&TT&W&SW&d&Td&z&Pö&û&P''P'b'vb'r'P5)9)P9)“*v$!C!SC!m!Pm!­"v­"°"P°"Ç"RT&W&SW&d&Td&z&Pö&û&P''P'b'vb'r'P5)9)P9)“*v$!C!SC!m!Pm!­"v­"°"P°"Ç"RT&W&SW&d&Td&z&Pö&û&P''P'b'vb'r'P5)9)P9)“*v4!Y!Q­"Ç"Qd&z&Qb'r'Q\)p)Ti)k)Q“k)p)Q“ ''P'"'Q€!‹!Q“º"Ç"X·)¿)U«)â)^“ÿ)!*^“—)·)Q¨)«)^“«)·)^“š&¨&Rž&±&Q:"\"PM"W"Rd"{"R“{"{"PÉ$Î$Pä$é$P:"\"PM"W"R\"p"Pd"p"R“:"\"PM"W"R:"\"PM"W"R:"\"PM"W"Rd"{"R“d"{"R“{"{"P:"C"PM"W"R\"p"PÎ$Ñ$P\"p"PÎ$Ñ$PÞ$ä$P *Ö*UÖ*Á+v°Á+),S),e,]y,’,S¡,¥,U¥,Œ.v°Œ..U.Ð.v°Ð.D/S]/Ÿ/SŸ/¿/]¿/0v°0"0S"0²0v°²0ê0Sê0+1v°+1v1Sv1Ð1]Ð1é2v° *Ù*T¡,â-TŒ.Ð.T 0²0Tê0+1TG2§2T¸2Ç2T *´*Q“´*’+_“¡,z._“Œ.Ð._“"0²0_“ê0+1_“Ð1§2_“¸2Ç2_“++^+ó+]ä.D/]]/Ÿ/]²0Ø0]+1s1]¹*ó*_“¡,¶,_“--_“ƒ-._“Œ.Ð._“ 0²0_“Y2”2_“¸2Ç2_“Å*Ù*TŒ.Ð.T 0²0Tó*ó*]Ò*Ù*Tó*ó*]Œ.Ð.T 0²0T§.Å.PÀ.È.]Ë.Ð.] .¤.P¤.§.P´,¶,T--Tƒ-â-TY2”2T¸2Ç2T­,¶,P--Pn-ƒ-Pë-ò-Só,-]n-ƒ-]Ù-â-RÉ,Ù,Uê0+1U”2§2UÉ,Ù,Uó,ó,]É,Ù,Uó,ó,]É,Ö,Uê0+1U”2§2U1+1X1#1]&1+1]ú01Rþ01X'-b-TG2Y2T>-b-SW-_-]b-b-]7->-R;->-S«-Ö-TY2”2T¸2Ç2TÖ-Ö-R¸-Ö-TÖ-Ö-RY2”2T¸2Ç2Tl2”2U„2Œ2R2”2Re2l2Ri2l2U ..tp.z.tÛ1é1t:2G2t-0>0t–0 0tÔ/0_“§2¸2_“ð/ù/T³2¸2Tô.ú.^°+Á+v°Á+),S),e,]y,’,SÐ.ú.S]/Ÿ/SŸ/¿/]0"0S²0ê0SÄ+ã+Qy,’,Qä.ú.Q0"0QÕ0ê0Qâ0å0]“å0ê0]“n/w/Pr/…/Q,&,S,,]“ƒ,’,Xh1s1S_1™1_“´1Ð1_“N1h1Q\1_1_“_1h1_“//P/*/Qð23U373SF3À4S×4J6SW6;7Sð2 3T 373]F3À4]×4J6]W6;7]ð2 3Q 373\F3À4\×4J6\W6;7\ð23R373_F3À4_×4J6_W6;7_ð23X373^F3À4^×4J6^W6;7^M3\3U|3ƒ3UB7Q7U²4À4UÇ4×4Sý45Uá4ô4PÇ4×4S‰66P“6™6P“¬6³6R³6È6P³6¶6R,7;7Ux5†5tß5í5tä3î3tø56tb6p6t€7š7Uš7»7SÊ7ç8Sþ8Y;So;ß;S€7—7T—7»7_Ê7ç8_þ8Y;_o;ß;_€7”7Q”7»7^Ê7ç8^þ8Y;^o;ß;^Ñ7à7U88U`;o;UÙ8ç8Uî8þ8S&989U909Pî8þ8S§:­:P“­:·:P“Ê:Ñ:RÑ:æ:PÑ:Ô:RJ;Y;Uœ9­9t: :tz;ˆ;tÒ;ß;t:$:t€:Ž:t<0<U0<W<^f<¥<^«<ô=^ >~?^‹?o@^<-<T-<W<Sf<¥<S«<ô=S >~?S‹?o@S<*<Q*<W<]f<¥<]«<ô=] >~?]‹?o@]<'<R'<W<\f<¥<\«<ô=\ >~?\‹?o@\<$<X$<W<_f<¥<_«<ô=_ >~?_‹?o@_<W<Yf<j<Yj<©<v°©<¯<Y¯<¬=v°¬=µ=Yµ=¾=v°¾=Ã=YÃ=§@v°q<€<U <¥<Uv@…@Uæ=ô=Uû= >S1>C>U>(>Pû= >S½?Ã?P“Ã?Í?P“à?ç?Rç?ü?Pç?ê?R`@o@U¬>º>t?!?t==t,?:?t–?¤?tæ@õ@UAAU+D2DU»AÉAUÐAàASBBUêABPÐAàASyCCP“C‰CP“œC£CR£C¸CP£C¦CRD+DUzB‹BtÝBçBtòBCtVC`Ct±DQQ)Q]“gElES²EÀE^âEìE^F¸FY_HoHU}H„HUÁHäHUäHIvˆwIIUIeI^ÄIÒIUÒIJvˆwJ½J^½JÒJYáJLvˆwL L^ LâLvˆwâL M^ MCMY›MÖMvˆwÖMÿM^ÿMNYnNøNvˆwøNOYOO^OJOYJOjOvˆwjOzO^†O¦Ovˆw¦O¶O^ÂOÔOvˆwÔOòO^PPYP]P^]PwPY—PžP^ÇPÌP^²EjHvðvjHoH^}H„H^ÁHòH^òH Ivðv II^ÄI'J^'JAJvðvAJcJPáJ Lvðv L1LP›M›MP›M§Nvðv§NñN^ñN†Ovðv†O†O^†O¯RvðvjHoH^_HoHUÇHÎHPÎH¯Rv€wjHoH^_HoHUÇHÎHPÎH¯Rv€wÅGÔGR=PdPvðvdPrPR³D¼DTjHoH^_HoHUÇHÎHPÎH¯Rv€w@IlIvðvlI}IRjHoH^_HoHUÇHÎHPÎH¯Rv€wF FQøL'Mvðv'M9MQjHoH^_HoHUÇHÎHPÎH¯Rv€wÛFGvðvGGQH-HQjHoH^_HoHUÇHÎHPÎH¯Rv€wjHoH^_HoHUÇHÎHPÎH¯Rv€wjHoH^_HoHUÇHÎHPÎH¯Rv€w•JÄJvðvÄJáJRjHoH^_HoHUÇHÎHPÎH¯Rv€wgElESjHoH^}H„H^ÁHØH^_HoHU}H„HUÁHØHU@HFHP_HoHUwH}HR}H}HS}H„HU‰H‘HS“HÁHSÁHØHUÜDEE EP E¯RÞQRP“£RªR^R"RU~RƒR^R—R^R"R\“+R+R^“~RƒR^sRƒRPsR~R~RƒR^R—R^‘R—RPR—R^—R—RRARFRUžRªRU½TU]“UPU]“½TÇT]“óTU_U6U_ÐT×T_îTóT_ÇTÐTÐT×T_UUSPUVUQQ“Q“dR"dXptQ“txQ“ÐÝUÝ_KV_ü4SK^Sü4SKVSp€U€Î_p}T}»SàýUý/R/[\[U~v€~³_³@XOo\o„U„¥_¥ÂXÂØ\ØüUü_?XàúTúªSªvð~ýUO„S„ÂUÂüSü?Uà÷Q÷w_O„_Âü_àôRôw]O„]Âü](w^O„^Âü^ Ct+:S:CPnzPz@]@@P„Â]ü?]ý/R/[\[åUOo\o„UÂØ\ØüUýªSªOvð~O„SÂüSgÄQ“ý[SO„SÂüSE[SO„SÂüSèüTõ÷Q“÷üQ“[dP_qQ®U?v€®X?vø~øøPñøRV~v€~³_³@X„¥_¥ÂXü_?XZwt‰vð~ýU„ÂUü?UVw_Vw](E^CRRnpw?nzPz@]@@P„Â]ü?]X‰vð~ýU„ÂUü?U¿éQ“‰vð~ºU„ÂUü?UºU„ÂUü?U7:Q“¬P”®Q@X®åX++P$R$R@ZUZ¹\½r\zï\@WTW¶]¶¹Q½zQzš]š²Q²È]ÈïQ@TQT¹_½ü_zï_…¹S½zYzS²Y²ËSËïYRztZ¹\½/\zï\Z¹_½ü_zï_ÉU“Z¹_zï_ ¹_zï_¹ÇU“èêU“†PŠŸTür\üx_CCP/;R/;RðUÝ_ðT&LTd‘TÀíTðQdSðþRþ)\)ƒ_)-\wwPpwRƒÝ_ƒ‡PÓÓRÀÌQÀÌQðUT¥ÙT F TôUT¥ÙT F T!4P“ôT¥ÙT F TT¥ÙT F T1 F Y> A P“A F P“±µPµÅPn¥T“w z T“åùPéùT€ ž Už T ]T õ U€ › T› vˆ€ — Q— Û \€ ” R” Û SÛ ë \Q Ü \¤ ¨ P¨ ï vï ó SQ \ v\ ` Yé ë RQ õ R* Q ]` õ Uó - S- Q Q` Y Ù QB B Pµ µ P/ ; R¢ ® S/ ; R¢ ® Sê õ tê õ Q F UF < \< ‘ ]‘ ± U± I ]\ v]Ї] C TC C vˆ} ‡vˆ 8 Q8 ˜ S˜ g vè~g j _±  vè~  _\ k vè~k ç _ŠØ_ N_ . R. › _› § và~§ 6UŠÃvà~à U *và~*‡U + X+ * vð~* V _V ± ^± ã _ã I \J † u¢ ± tp © ^} 9 ]9 # v€# . ^. I R\ – v€– Q[мv€¼ [ #v€#‡[? N N U U ‡F < \< S ]© 5 ^5 S Sõ õ Pí õ RÎ I ]\ v]Ї]Ò ð t  _Î ã _ã I \p © ^} á ]± Ê Ê è p𠇳 ç ]³ Æ Q“d k vè~k § _ŠØ_ N_x § _ŠØ_ N_:NTGIQ“INQ“§°P«ÅQÔ Q]Ø ]N‡]ÿ 0T“Ô ú UØ UN‡Uç ú UØ UN‡U‚T“äóRèøTv]© á ^ddPQ]RQ]RšUš­S­¹SÀÐUÐHSÀÍTÍ_(_Ðà_ó*S*S!*TK[PpzUzS˜ØS˜·S®·TØÛTÛëPðúUú S S 1U1(S .T.ƒ_1J_VÞSVƒ_ÕSñST+;PPdUdë\÷\¢0\?P\}˜CPu#0T¸Ñ\¤°t`\¢#\ÿ tûbs(b_i_»ÒQÃ#\#TÀÔTP`U`ØSP]T“]`_“`q_“}¸S™¸S¯¸TÛëPU-S-N^NNUNÙ^ÙÙUÙ^õvð}õP8]8|Q|–^–½]½×^TÛv€~"‰u9Ap]kpt}R]kp"-S-N^NNUNÙ^ÙÙUÙm^"‰u9Ap]kpk22mR€”S£Yxv~x¹Y¹@v~@eQemS½(_((]ôx\’(\Ã;XÇÔPûxS2x_”ýSÇÔPÇÔPÃýX;Xíý_%_íý_%_2;_CN^NNUNx^ûýS2;_Cx_½Ö½(_((]ª°]¨®R\¬v~¬®YõS/f_fÇv˜~ÇUZUñ^½ÀR½ÀRAAFU/f_fÛv˜~ÀQÛvø}õ“S/f_fÛv˜~;XRXÛvè};XRXÛvè}U“^õ“SÀSõ“SÀSõ“SÀSãTõ“SÀS/f_fÇv˜~ÇUZU“^Àñ^õ“SÀS/f_fÇv˜~ÇUZõ“SÀS/f_fÇv˜~ÇUZU“^Àñ^ñô^û^õ“S9<Zõ“S9<Zõ“S9<Z¤¬Y8]8|Q|–^–º]&S&_ĺ_´ºSĺ_!8]8|Q|–^–º]-0^O US`P¯T0¯TS`PS`PO Uy}XàU˜v˜˜»UÔàUàTBv@BÁ_ÔF_àôQô1S1avPa^à1R“Uov¸4 _“ðTèëSS T”èSèëS*hhkR“qov”S.CQWhQ TÐÔQÐÔQ SÕþ^›»UÔàU>Bv@BÁ_Ô-_ »UÔàU¤¹Pã-_å-_-_$-TIYPp‡U‡² ^Ì %#^L$0%^p„T„² _Ì O#_$?$_L$0%_¦º\“в \“Ì z!\“ #%#\“L$0%\“´" #]$;$]‡º^‡º_¦º\“‡º^Ðh ^– ² ^Ì —!^L$0%^±º_Ðh _– ² _Ì —!_L$0%_¦º\“Ðh \“– ² \“Ì z!\“L$0%\“Ì !]±º_±º_µºP÷h ^– ² ^!z!^L$0%^÷þPþ0%v@¦º\“Ðh \“– ² \“!z!\“L$0%\“ž ² P÷h ^L$†$^¸$ú$^÷þPþ0%v@¦º\“Ðh \“L$†$\“¸$ú$\“€ – ]÷h ^L$†$^¸$ú$^÷þPþ0%v@b h P“÷þPþ0%v@  P - PL$†$P¸$ê$P - P  PL$†$P¸$ê$Pç$ú$Tó$õ$P“õ$ú$P“`$n$Rd$s$TP ` ^P ` P“ž ² P÷þPþ0%v@¦º\“² Ì ]’!—!]÷þPþ0%v@v!z!P“÷þPþ0%v@"!.!P"!1!P†$¸$Pú$ %P"!1!P"!.!P†$¸$Pú$ %P)%+%P“’$ $R–$¥$TT!t!^T!t!P“‹!—!_‹!—!_!—!P«!¼!_«!¼!T©" #S$L$SÀ!É!UC"¦"S©"º"SÓ!"""P“ "0%%"C"S×!ì!Q""TÀ!É!U‚"†"Q‚"†"Q$$-$_À!É!U$$-$TJ$L$_7$;$]7$;$]£#$S$$S0#w#w#z#S“€#0%…#£#S8#K#Rg#w#Qß#ã#Qß#ã#Q0%@%U@%[%S0%=%T=%q%^0%@%Q“@%K%Q“D%h%_%¤%U¤%¦&\%È%TÈ%&vP&¯&T¨%Â&^¨%È%TÈ%&vP&Ÿ&T¨%í%í%&&&&N&N&‡&‡&Ë&¨%&^¸%)&)&1&SŠ&&SÄ%&_Ô%&&]&&&\Ä%&&_&&&&Sg&‡&\Ä%Ô%_7&‡&SÐ&á&Uá&ô'^({(^Ð&ñ&T(k(T''T“á&ñ&T(k(Tî&ñ&T(k(Th({(Qt(v(T“v({(T“(((P#(2(Q8'ô'^'M'M'‹'‹'®'®'ì'ì'€("'Ž'Ž'–'Sï'ô'S"'ô'\/'ô'_:'‹']f'‹'^/'‹'_‹'‹'SÇ'ì'^/':'_œ'ì'S€(¢(U¢(M*vHM*x*U—*¦*UÕ*a+vH€(ž(Tž(~*\—*3+\€(›(Q“›(¾)^“€(”(R“”(¢(]“¢(ù(]“ù()v¼D)L)v¼a)a+v¼°(õ(Sõ(É)v@É)'*]'*I*QÕ*÷*Qo)ú)_!*‡*]—*3+]G+O+]¢( )^“¢( )^“°(õ(Sõ(a+v@k)o)_â( )_g)k)_¢(g)\ñ(ü(Tü(a+v°) )]*)L)])B)P)B)P*)L)\*)L)]ñ(ü(Tü(a+v°®)²)Q®)²)Q¾)ð)^“I*M*vHM*x*U—*¦*U]*~*\—*Õ*\÷*+\]*x*U—*¦*Ua*v*P³*Õ*\÷*+\÷*+\++T6+G+Pp++U+´+S´+-vP-„-S-–-vP–-ï-S..S .?.S†.¸.S/0/Sp+’+T4.M.Tp+Š+QŠ+¬+^ .0.^†.§.^p+‡+R“‡+·+\“ .A.\“†.§.\“/2/\“p+Ÿ+X“Ÿ+°+X“°+ .vL .M.X“†.Œ.X“Œ.”._“”.§.X“/+/X“p+„+Y„+¬+] .0.]†.§.]/4/]+’+T–+Ÿ+T—.§.T¬+·+\“Ç+ ,]P,1-]„--]Ò+,^,Ò,v¸Ò,Ö,^Ö,>/v¸è+ ,TP,Ò,TÊ,Í,^å,å,^Ç+ñ+\“Ç+ñ+\“Ò+ñ+^è+ñ+Tl,Ê,^Ê,Í,^û+G,G,J,P“P,>/U,w,R,,Q7,G,Uè+ñ+T¨,¬,Q¨,¬,QH-o-^å,î,^Ì-ï-S..SÔ-ï-S..SØ-í-PÎ.×.Tö./P/2/\“@/]/U]/E0ZS0®0Z®0Q1vHQ1t1Zt1T5vHT5 6],6<6ZV6Á6ZÁ6É6SÉ6â6Zâ6ù6vHù67Z7E7ZE7M7SM7R7ZR7h7]h7â7Zâ7ê7Sê7B8ZB8c8Sc8Š8XŸ8¼8Z¼8‡9vH‡99]¯9Ê9]þ9:Z::S:%:Z%:J:]]::Z:Æ:vHÆ:M;ZM;U;SU;h;XÂ;ä;Xä;'<vH'<3<Z3<;<S;<I<XI<P<SP<Y<Xa<f<Xf<l<Zl<t<_t<ˆ<Z <Å<]Å<Þ<vHÞ<ç<Zç<ï<Sï<=Z@/Z/TZ/Ÿ/_Ÿ/Ø/TS0Ï0_Q1c1_,636_36<6TV6¡6Th7Ó7_ï78_Ÿ8Î8_]::TÆ:;_";0;_@/»/QS0ª0QQ1‘1Q‘1}2^}2F3YF3R3SR3a3Ya3-5v¨-5l5Ul5Õ5_,6<6QV66Qh7Ù7Qï7ÿ7QŸ8¼8Q|99U¯9Ê9Uþ9:Q::^:%:Q%:J:_]::QÆ:";Q <Å<U@/W/RW//\S0s0\Q1{1\©7¹7\þ9%:\ÿ:;\@/]/X“]/0X“S01X“Q1^1X“^1,6v@,6<6X“V6t6X“6“6X““6Ù6v@Ù6Þ6X“7%7X“h7Æ7X“ï7V8X“Ÿ8£8X“¼8À8X“À8 9v@ 99X“I9U9X“|9]:v@]::X“Æ:;X“";U;X“'<3<X“f<Þ<v@Þ<ä<X“ä<ò<^“ò<=X“@/T/YT/Z1],6<6]V6…6]67]7R7]h7Ï7]Ù7|9]]:;]";h;]Â;Y<]f<ˆ<]Å<=]E1L1S“8š8S=9D9SØ;ß;S==S/²/Q,6<6QV6p6Q]::Qœ/²/Q,6<6QV6p6Q]::Qm::Uz:|:S“|::S“?6H6PC6V6U®6Ò6T»/ 0 050S6Þ6Þ6þ6S7Ù7Ù7â7S:Æ:Sf<=Ê/E0\6Ò6\Þ6þ6\7R7\Ù7ï7\:Æ:\f<ˆ<\Ý/6677f<f<=É6Ò6Pz<ˆ<_Ê/0\6¡6\7%7\Ý/6677=ð/0_7%7_»/Ø/S“ 00S‘: :Q :=v@%7R7_77Z50S0]þ67]²6Ò6y¨6®6Zf<l<Zl<t<_t<ˆ<Z6¡6T¥6®6Tw<ˆ<Ts0”0Qh7©7QÆ:ÿ:Q€0”0Qh7©7QÆ:ÿ:Qé:ÿ:T÷:ú:\“ú:ÿ:\“x77P|77Tß89_ª011,1_¼899)9_I9ä;ä;'<_Å<=Ô0¼8¼8I9I9Å<Å<=ù89PÓ<Þ<SÔ0¼8¼8I9I9=ç0÷0SI9U9S88\“11_ô;'<\U9|9S,1Q1])9I9]ã89y¼8Î8_Ö8ß8_Ñ<Þ<_A;X;_8";";'<'<Þ<Þ<=/8~8_X;h;_'<Y<_8";";'<'<=/8?8_'<3<_?8M8M8y8P3<Y<PM8V8P7;=;ZÞ<ç<Zç<ï<Sï<=Z";0;_4;=;_õ<=_Ê;ä;X~8Ÿ8]Â;ä;]©12_2l3v¸l3V4UV4^4S^4v4Uv4ê4]ê4Š5TŠ56^R7h7^|99T¯9Ê9TÊ9Ú9^Ú9þ9U%:J:^h;‡;U <Å<T©1}2^}22Y‹2F3YF3R3SR3a3Ya3-5v¨-5l5Ul5Õ5_|99U¯9Ê9U%:J:_ <Å<Up1{1\‚1e2\†1q2]22Z‹2®2Z®2V3vV3V3Z22S¥2=v n2t2Rj1p1Zþ9:Z::S:%:ZZ1c1_g1p1_:%:_†12]¦1«1ZÇ1à1Sà1ê1Z³1Ý1P³1Ý1PÇ1à1Sà1ê1Z†1«1]22S22SS22[22SS22[22SE22Q‹2º2Q†1«1]q22]‹2V3]S22[‹2ö2[–2×2R¾2:3QÈ283XÔ23US22[‹2ö2[·2Í2PS22[‹2ö2[·2Í2Pî2û2PS22[‹2ö2[S22[‹2ö2[S22[‹2ö2[S22[‹2ö2[S22[‹2ö2[n2t2Rn2t2R33\3V3\×23R×23R×23R×23R×23Rq22]‹2V3]q22]‹2V3]#3&3P/3V3Pƒ3S4ZS4a4]a4a4Zq22]a3a4\«3õ3T²3Õ3P¾3a4[Å3L4XÒ3'4QH4a4T«3õ3T«3õ3T·3Ë3Q«3õ3T·3Ë3Qí34S«3õ3T«3õ3T«3õ3T«3õ3T«3õ3Ta3a4\a3a4\44S4V4SÕ3?4P44]44]44]14S4]Õ3?4PÕ3?4PÕ3?4PÕ3?4PÕ3?4Pa3r3\a4s4\·4Æ4X·4Æ4Xô4û4v û45Q"5&5Q"5&5Q_5Ž5Q“&5-5v¨-5X5U|99U¯9Ê9U <Å<U:5X5U|99U¯9Ê9U <Å<U°<Å<P½<À<Q“À<Å<Q““9¯9P—9¯9QÕ5 6]R7h7]á5 6]R7h7]å56P~;‡;T¥;µ;P =)=RU=q=Pq=‚=P±=Í=TÒ=Õ>ZÕ> ?_ ?Q?ZQ?Y?_Y?i?Zi?¹?_ç?÷?ZÄ> ?]f?¹?]K=›=[K=N=Pj=n=QK=›=[K=N=PK=›=[K=N=PK=›=[U=q=PK=›=[q=‚=PÒ=¸>Zç?÷?ZÒ=:>^å=>Pï=ò=T÷=þ=S„>¸>^å=>Pï=ò=Tå=>Pï=ò=Tå=>Pï=ò=T >W>U]>x>Uç?÷?U@>T>^]>t>^ç?ò?^x>x>^.>2>Q.>2>Q >W>U >W>UÒ>ü>[Ò=]>ZÄ> ?]f?x?]Ä>ü>]Ä>Ò>]Ò=]>Zü> ?TÄ>Ò>]?(?P??C?P?(?P??C?PÄ>Ò>]Ò=]>ZØ?ç?T@@U@›@\´@Ã@\@@T@¡@^´@)A^@@Q@z@]@@R@h@_h@z@Q@$@X@z@^@z@]@z@_@$@X$@=@X@z@]@$@X)@-@P@z@]@$@X@z@]@$@X@z@]@$@X@z@]$@=@X@›@\´@Ã@\@¡@^´@A^}@›@\´@Ã@\‚@™@PÆ@A^È@A^ñ@A^AAT,AOQ3O>OP“ O-OP#O&OR O-OP#O&OR O-OP#O&OR3OIOP“3OIOP“IOIOQ OOP#O&OR+O>OQPPQ+O>OQPPQ!P(PQáJþJ[þJKSK K[áJ K\YEeEPVEeERËFÒF[ÒF°HvH°H°H[ K-PvHÙFóFPYEeEPVEeERGUGRQG—GTUGxGRaGHYhGïGXuGÇGQëGHTQG—GTVEeERQG—GTZGnGQVEeERQG—GTZGnGQVEeERVEeERVEeERVEeERVEeERGœGPVEeERQG—GTVEeERQG—GTVEeERQG—GTVEeERQG—GTVEeERQG—GTGUGRGUGR§GªGU´GúGUVEeERxGâGRVEeERxGâGRVEeERxGâGRVEeERxGâGRVEeERxGâGR HH^ÊGÍG^×GH^VEeERxGâGRVEeERÙFóFP.H°H\“TK•K\“?NwN\“RHH_“ HH\ KTK\ÿM-N\HH\ KTK\ÿM-N\*N?NQ7N:N\“:N?N\“K$KPK:KQbNwNQoNrN_“rNwN_“dKmKPhK{KQ°HåHUIIU°HÈHSÓHòHSIISIPISuJ”JS¿JÏJSÊHåHUIIUÎHãHPÈHÓHSÈHÓHSÈHÓHS‹J”JT¯J¿JP0PRPURP\vH0PNPTNP¤Vv¸¤V°VTZW\v¸0PJPQJP]RS]ReRXeRhRShRmRPmRíRSíR÷RXúR#SX#S8SS8S€SX€S¬SS¬SÆSYÏSTYT@T_XTyTYyTÿTSÿTUY-UvUYvU1VS1VoVXoVVSV˜VX˜VªVSªVÄVXÄVåV]åVWXWWSW7WX7WEW^EWZWXZWÄWSÄWÏWXæW>XY>XIXSIXNXYNXsX_sX€XX€X‘X^‘X–XX–X¨XY·X YS YÇYXÇYÕY^ÕYÚYXÚYEZSEZQZXQZcZScZuZXuZƒZ]ƒZZXZÅZYÅZÕZXÕZæZ]æZïZXïZ2[Y2[p[Sp[[Y[Œ[SŒ[Ž[YŽ[³[S³[º[Xº[È[]È[Ü[XÜ[\S0PGPRGPÈPZÈPìPv@ìPNRYNRZR^ZReRYmRñRv@ñR÷RYúRSYS>S^>StSYtSµS^µSÆSSÏSßSSyTëTZ-UvUSvU5Vv@5VoVYoV“Vv@“V˜VY˜V®Vv@®VÇVYÇVâVSâVWYW"W]"W:WY:WBWSBWžWYžWÊW^ÊWÏWYæW'XSsXƒXYƒX‹XS‹X–XY·XÉXYÉXÛXZÛXYYYmYv@mY•YX•YY^YÊYYÊYÒYSÒYÚYYÚY+Z]+ZLZv@LZxZYxZ€ZS€ZZYZµZSÅZØZYØZàZSàZïZYïZ/[Sp[[S³[½[Y½[Å[SÅ[î[Yî[õ[Xõ[ý[]ý[\X0PžPXyT¾TXÉXÛXX0PDPYDPNR^yTëT^ZWžW^·XY^QZcZ^Ü[î[^0P³PQ“úRSR“yTØTQ“ÉXÛXQ“•P’Rv@’R ST S;S];S_SR_S¹Sv@¹SÆSTÏS@TTKTXTT¾T-Uv@-UvUTvUUv@UVTVHV^HVVVRVVjV\jVoVv@oVvVTvV„VY„V˜Vv@˜V VT VþVv@þVWTW4WR4W4Wv@4WZWTZWžWv@žWÇW]ÇWÏWRÏW*XT*XFX_FXZXTjXsXTsXzXRzXŽX\ŽX–XR·XÉXv@ÛXYv@YdYTdYÄY\ÄYÄYv@ÄYÚYT+Z7ZT7ZHZ^HZQZRQZcZv@cZŠZ^ŠZZRZÅZTÅZËZRËZãZ^ãZïZRïZs[Ts[‰[^‰[Ž[T­[³[T³[î[v@î[\\ŠPeR_mR÷R_úRqS_¾TëT_vUÏW_sX–X_·XÉX_ÛXZ_ÅZïZ_³[\_aSÆS]ÏS@T]KTST]STXTPXTtT]tTyTPëTúT]úTÿTPÿTU]UUP-UvU]ÏWáW]áWæWPæWsX]–X¨X]¨X¨XPZÅZ]ïZ³[]UPŠPXyT¾TXÉXÛXXŠPŠP_lPŠPXŠPŠP_yT¾TXÉXÛXX•T³TP®T¶T_¹T¾T_‰TTPT•TPqS–S_*ReRQØPîP^;QNR^·XÉX^ÛXY^Ü[î[^BYXYQPYSY^“SYXY^“ŠU“UPŽU¡UQÁVòVT¨R S SDSZ˜VþVþV'WZNWsXsX–XZÚYZZZ&Zv@&Z+ZZ³[\ÍR˜V˜VNWNW³[³[\åVòVPÎ[Ü[]ÍR˜V˜VNWNW\àR÷RQNWZWQÚUãU^“ SSZêYZQZ\v¨DS_SR'W4WR4W4Wv@4WNWTËVâVy˜V¤Vv¸¤V°VT¸VÁVTË[Ü[TèUXYXY+Z+Zî[î[\ûUVV]£Y³Y]+ZQZ]cZrZ]rZ‡Zv¸‡ZZ]ÅZÒZ]ÒZêZv¸êZïZ]èUXYXY+Z+Z\ûU V]+Z7Z] VVVNVP7ZQZPcZZPÅZïZPV$VPwY~YP~Y\v¸\ \R \\v¸VVjV\jV³Yv@³YÄY\ÄYÄYv@ÄYÚYT®Q¾QTR!RU.Q;QQ®Q¾QQRRRQQPZW“WPQZcZPQQP.Q.QQQQP.Q.QQQQPZW“WPQZcZPvWŠWQŽW–WQ™WžWQjWsWRnWvWQ}QšQP•QQQ Q QQqQuQPuQ}QPRRRRRR÷XYPYYRYYRëXïXPïX÷XPXY>XIXSIXNXYNXsX_–X¨XYZÅZY…SµS^µSÆSSÏSßSSæW'XSZµZS–S¬SS¬SÆSYÏSTYT@T_XTyTYÿTUYæW>XY>XIXSIXNXYNXsX_–X¨XYZÅZYµSÆSSÏSßSSæW'XSZµZS'U-UT¦SÆSQXTyTQ–X¨XQîSTS“ÏSßSSæW'XSZµZSÜSßSSæW'XSZµZS²ZÅZQ¾ZÀZS“ÀZÅZS“öWÿWPúW XQ0T@TTKTXTTÏWæWTbTyTX#[U[_“p[³[_“5UvUSïZ/[S[/[Q [#[_“#[/[_“EUNUPIU\UQp[[Y[Œ[SŒ[Ž[Yp[[S \*\U*\<\S<\G\S“d\o\o\q\P€\ \U™\ \U´\¿\¿\Á\PÐ\ù\Uò\ù\U]%]U%]û^]]"]T"]A^_]]Q]A^^]]R]A^S]]X]œ_v@]]Y]œ_vH]_^]Q^Q]±^R)]A^])]A^_)]A^^)]A^S)]A^]6]>]>]H]P“)]A^]Á]Ë]Ë];^R¤_«_«_­_P“´_¾_¾_À_P“Ä_Î_ ÿÿÿÿÿÿÿÿÿÎ_Ð_P“Ð_á_U“á_[`_“NaWaWa†aPëaöaöabTöabTld‰d‰ds/d@dR/d@dR/d@dRRdldPRdldPRdldPådePMnŽnP[rrPådePådePMnŽnP[rrP~r”rUŠrŒrP“Œr”rP“]nknRantnUe$eP“e$eP“$e+eP+eDePŽnÏnP”rºrP+eDeP+eAePŽnÏnP”rºrP·rÊrTÃrÅrP“ÅrÊrP“žn¬nR¢nµnT•eœeT¢eØeT“¤e¦eP“\ekeT±qÒq[“Ro(q^ZopP p"pRZoioRäoñoRäoñoRZoioRäoñoR¦oºoU¶o¸oQ“¸oºoQ“mo|oQRoZo^Ïn;oS#qqS”q›qSoqoqPÏnÖnP?qKqPÏnÖnP?qKqP$o;oT4o6oQ“6o;oQ“ÛnänPßnînT?qKqPGpqPúpqSGpVpRÔpápRGpVpRÔpápR“p§pU£p¥pQ“¥p§pQ“ZpipQÔpápRéqìqPùrûrP“*r8rR.rArT,stt%tYZsosR¬s·sRttYæs÷sTæs÷sT0tPtUPt³u_¸uWx_`x–z_0t°tT¸tÊtT0tMtQ“MtPt^“Pt,u^“,uÅz0tJtR“JtÅzvà~0tPtX“Pt\uX“Ptmt\°t³u\¸uWx\`xŒy\Žy–z\ºz½z\¥t³u]¸u—w]`xgx]Êt³u[¸u$v[$v¨vvà~¨v¯v[ w$w[Ñt³uS¸uÃuSÃu¶vvÐ~¶v¹vU wÅzvÐ~Du³uU¸uvUv wvÀ~ w_wULu³uT¸uvTvwvÈ~wvwTPt°tT¥t°t]¶t¸t[ÊtÊt[Ptmt\¥t°t]ªt°t[Ptmt\°t¸t\¥t¸t]ªt³t[ªt³t[¶t¸t[øt!u_Ñt!uS u uPútuQútuQPtmt\¥t°t]Ptmt\¥t°t]Ptmt\¥t°t]Ptmt\¥t°t]Ptmt\¥t°t]Ptmt\¥t°t]Ptmt\¥t°t]™uœuR¦u³uRPtmt\°u³uPPtmt\°u³uPPtmt\°u³uPPtmt\¥t°t]aueuRPtmt\¥t°t]euluRiu•uQsu…uRPtmt\}u€uP…u‰uRPtmt\}u€uPPtmt\}u€uPPtmt\}u€uPPtmt\}u€uP‰uŒuR³uÓuRBv w_Ptmt\¥t°t]gxx]ÑtútSšxÅzvÐ~DuWuU¸uïuU$wOwULuWuT¸uïuT$wOwT¥t°t]—wWx]ÑtútS¹vävUävxvÐ~xWxSWxÅzvÐ~¯v w[x!xR!xÅzvà~Ptmt\ÃuïuSPtmt\ÃuïuSPtmt\ÃuïuSPtmt\ÃuïuS7v¨vvà~¨v¯v[Bv¶vvÐ~¶v¹vUPtmt\ÃuÓuSav¡v_Ptmt\ÃuÓuSPtmt\ÃuÓuSPtmt\¥t°t]¯v w[Ptmt\¥t°t]Ptmt\¥t°t]¯v w[Êv wRÚvwTPtmt\¯v w[Ptmt\Ptmt\ïv wQPtmt\;wOwQFwOwSPtmt\;wOwQPtmt\;wOwQPtmt\;wOwQwxvà~xxR”wxSPtmt\;wOwQFwOwSFwOwS¹wüw_Ptmt\—wüw]”wüwSPtmt\—wüw]Ptmt\—w¹w]üwWx]x!xR!xÅzvà~Ptmt\—w¹w]üwWx]Ptmt\—w¹w]üwWx]x!xR!xÅzvà~!xWxR1xWxTPtmt\x!xR!xÅzvà~Ptmt\Ptmt\KxWxQxÏx_Ptmt\Ptmt\ìxAz_Ptmt\þx:zSz:zt6yvy_þxySþxySþxyS…y‰y^Fzxz_czxz_™z£zT£z³zPØzA{TØzA{Xýz{P {A{S){-{Pýz{P9{A{P9{D{Pu{Ð{P9{D{P9{A{Pu{Ð{PÙ{Ü{P“{{R…{•{QS{a{US{Y{P“d{k{Td{g{Xø{a|Tø{a|X|0|P-|a|SI|M|P|0|PY|a|PY|d|P•|ð|PY|d|PY|a|P•|ð|Pù|ü|P“¡|°|R¥|µ|Qs||Us|y|P“„|‹|T„|‡|X}…~U¨~Î~UÞ~ U±UÁ8€UŒ€¬€U<Uq UçìUñöU}>~Ti~q~Tµ~É~T9}>}ZŸ}¨}Z}Ÿ}Z¦}¨}^é}J~Yi~…~Yµ~Å~Yê~ó~^f}k}P“^}k}TE}k}Rl~¨~P¹ÁP8€A€P8€`€P<ZÑêQŒ€£€QÔöPöùR6€8€Zü€ T QyTªQ¼TñùT‚°‚TC‚°‚Ys‚x‚S“U‚x‚TU‚x‚QĂǂTÇ‚ ƒPƒhƒPǂ͂PƒQƒP ƒ=ƒQǂ͂PÇ‚ ƒPQƒhƒP邃[hƒŠƒPàƒþƒUþƒ~„Y~„•„]•„ׄYàƒûƒTûƒ„\àƒøƒQøƒ„Z„„S„´„Z´„»„S»„¿…v°¿…Â…Ràƒn„R“n„’„v@’„¡„R“¡„ÄR“àƒõƒX“õƒå…v¼þƒ„^Z„á…^K„u„Uu„Œ„vPŒ„¥„U¥„†…vP†…¶…T­„±„P±„¤…v@¤…Ö…S¿„Ö…]‚…»…Pþƒ„\K„Z„Uþƒ„^¡„Ä^K„Z„U¡„¥„U¥„å…vPP„T„_T„å…vHþƒ„^K„Z„U¿„Ä]f…r…Sþƒ„^þƒ„^þƒ„^þƒ„^þƒ„^‹…˜…Rþƒ„^‹…˜…Rþƒ„^‹…˜…Rþƒ„^‹…˜…Rþƒ„^‹…˜…R®…Ö…Qþƒ„^K„Z„Uþƒ„^K„Z„Uþƒ„^K„Z„Uþƒ„^K„Z„Uþƒ„^K„Z„U¶…¿…v°¿…Â…RÂ…Å…RÏ…Ö…Rð…†U†=†^=†é†Uø†¤‡U¨‡·‡Uð…†T†:†_:†é†Tø†¤‡T¨‡·‡Tð…†Q†7†S7†é†Zø†Z‡Zð… †R †A†vHA†é†^ø†Z‡^ð… †X †é†v@ø†‡v@‡‡[ð…†Y†—†vP—†é†Qø†‡Q/†é†\ø†Z‡\þ†¤‡Y†:†_:†I†T†7†S7†I†Z+†/†\†:†_:†I†T†7†S7†I†Z†:†_:†I†T†7†S7†I†Z†:†_:†I†T†7†S7†I†ZI†Œ†U/†Œ†\I†Œ†TI†Œ†ZŒ†é†UŒ†—†vP—†é†QÚ†Ú†PÓ†Ú†R‡F‡R‡Z‡Q‡Z‡Q‡Z‡Q‡Z‡T‡Z‡Q'‡Z‡T‡Z‡Q‡*‡P4‡>‡S4‡Z‡T>‡A‡S4‡Z‡T>‡A‡S4‡Z‡T>‡A‡S4‡Z‡T>‡A‡SF‡Z‡T>‡A‡S‡*‡PP‡Z‡RZ‡¤‡U‡¤‡Qþ†¤‡YZ‡¤‡T‡¤‡QÀ‡Ê‡TʇVˆY`ˆŽˆY“ˆH‰YÀ‡Ê‡Q“ʇVˆQ“`ˆ~ˆQ““ˆH‰Q“‡ˆ‹ˆRʇõ‡Y“ˆÍˆY‰‰Yõ‡õ‡Rׇõ‡Yõ‡õ‡R“ˆÍˆY‰‰Y¥ˆÍˆT½ˆÅˆRȈ͈RŸˆ£ˆP£ˆ¥ˆPRˆVˆT“õ‡ù‡RˆˆTˆˆT͈‰T‰7‰TˆˆTˆˆT͈‰T‰7‰T@‰C‰T“ÙˆíˆP݈íˆS8ˆPˆT“sˆŽˆYP‰d‰Ud‰‹^‹‰‹^‹Î‹^Ú‹ Œ^k‰€‰Sp‰€‰^k‰€‰S€‰¹‰¹‰Î‰yΉŒ‹‰‹S‹±‹SÚ‹õ‹S±‰‹^‹D‹^¹‰Î‰yµ‰Î‰tŠŠtщþ‰SÕ‰þ‰^щþ‰Sɉþ‰Sщþ‰SÕ‰þ‰Rщþ‰Sщþ‰SŠ‹Š^”Š‹^‹‹^<ŠYŠt@ŠYŠy2ŠMŠp‹‹S—ŠÌŠ\›ŠÌŠ^—ŠÌŠ\PŠYŠ\—ŠÌŠ\›ŠÌŠR—ŠÌŠ\—ŠÌŠ\Z‹]‹TZ‹]‹T]‹}‹Tu‹}‹P”‹§‹Z±‹Î‹Q”‹§‹ZÝ‹ã‹Uà‹æ‹PÝ‹ã‹UÝ‹ã‹Uà‹æ‹Pæ‹õ‹Pð‹õ‹R Œ=ŒU=ŒÁŒYÁŒÒŒSÒŒúŒY Œ:ŒT:ŒTŒ\ Œ7ŒQ7ŒîŒ^ Œ4ŒR“4Œ _“=ŒMŒ]˜Œâ]ŠŒ»ŒS»ŒÜŒvPÜŒ÷ŒS÷Œ'vP'*RêŒRîŒ×^ÿŒDDDRDè=ŒTŒ\ŠŒ˜ŒS=ŒMŒ]âŒ]ŠŒ˜ŒSâŒ÷ŒS÷ŒèvPŒ˜ŒRâŒêŒR36P“¸U=ŒMŒ]3wwËR36P“¸U:DP¤×S=ŒMŒ]/3P“U=ŒMŒ]=ŒMŒ]=ŒMŒ]ðýUýàŽ_ÍŽàŽs;ŽÂŽPÉŽÛŽT;Ž?ŽP?ŽHŽRHŽRŽQRŽ\ŽR\ŽfŽQfŽpŽRpŽzŽQzŽ}ŽR}Ž‘ŽR}Ž‘ŽRÍŽàŽQU^}^€¯^ë4^{ˆtƒ¤S†«P²ÅPøSPlsP€œP¯¾PÍÜPv}_G^ë4^G^GGPG^GGP)^ë4^ýPP %P÷ûPûýP{ˆt{ˆt{ˆthtU)^¿S _ÍëSÍ]ä \ï _«¿P¿¿SEJ])JSHJ_HJ\s}SSlPWl\¶ÍU@TUT…S@QTQ‹_@NQN‰^[‡\[‡\ P0=U=s^0:T:gS=gSY“Y“&&(P@GU@JT@JRJPTPWUPZTPZRZ`T`nTx~T„ŽT`gX“dgX“„ŒŒŽP°ÀTÀfSÃfSp…T…wSp‚Q‚}_äçPîòPùýPPPP%)P€”U”ò_÷Q_i_€‘T‘ò^÷T^i^¶éS“zS“éòPò÷P /Q²¶R¶¶S“¡¥PÃÚ\ÈÎPÚÚPÈÎPÓÚÚÚPÚäPý/\QWTQT^EQ\OQPQWT28P??P28P8???P?EPU`^p^òTùT>eTiT¿ùS“S“ùPP0>Q»¿R¿¿S“ª®P÷ùPÌã_Ñ×PããPÑ×PÜãããPãéP >_`eTT`_^`P`eTAGPNNPAGPGNNNPNTP›U›ºPºÅT›±±ÅrŸµµÅxÐÛQÛP"YÐRÐXÐYÛííq0XUX\^\ˆvÈ~ˆ–^–‘vÈ~‘¨SÌ ^ fSfS vÈ~S ¡ S¡ ž vÈ~ž ° ^0UTU.vè~.IQI° vè~0ÇQÇÌvÐ~Ì Q  vÐ~ž vÐ~ž ° Q0NRN và~ [_[° và~0XX“XÀX“ÀÌvÄ~Ì X“ ž vÄ~ž ° X“0GYGÄ]ÇÜ]Ì ]ž ° ]0¹U¹Ä\ÇÍ\Í:R:uv¸~ušRšÌv¸~Ì U ‰v¸~‰˜Q˜]ÈQ$ Ç ]Ç Ê TÊ  ]7 t ]t ‡ Tž ° U0Ä_Çñ_Ì _ž ° _ªÄSÇÓ^w…^8 A ^¬ ¬ ^ý3]u¨] …].:P:uv°~u|P|¾v°~¾Ï_ j _n}PÌÿPž ° Pn}P——Rn}P——RnzPÌÿPž ° Pâ SúR RÜàRàâRÚI^ÚI^Ú.vè~.IQI° vè~zˆtzˆtª¶SzˆtN\^\° vÈ~zˆtNˆ]zˆtª¶Szˆtzˆt¸Ät¸Ätª¶S¸Ätˆ–^–° vÈ~¸Ät¸Ätª¶S¸Ät¸ÄtÇÓ^ý ]¬ ¬ ^E › P.3PE › P.3P° Ú UÚ S ^° × T× S S° Ô QÔ S ]° Ñ RÑ S \° Î XÎ k và~° Ç YÇ ý _ý c vØ~c S _. 3 PL S PÚ é SÚ é Sö é ^ö é ^ 3 ^ 3 S 3 ] 3 \ 3 _p  U · Sp | Q| ½ Yp • Rp  X“ § X“À õ Uõ -^À ë Të  S ^ và}^ y Sy ‡và}‡“S“Kvà}À è Qè êvØ}ê\S““vØ}švØ}-SÀ á Rá R_R†S† _“ý_ýSÀ õ X“õ ø X“ø Kvì}À × Y× \ ›vø}›ãQ\kvø}ktSt“\“Kvø}ˆ“TÀ IS“I“v×}““S““Kv×}¿ Ï tÊ \€\“\‘\]-]õ y ^õ  S ^ và}^ y Sy Kvà}õ y ^õ  S ^ và}^ y Sy Kvà}ˆ Ç P¿ Ï tˆ Ï ^¿ Ï tˆ Ç P¿ Ï tq‡và}‡“S“\ˆ“Tq‡và}‡|Sq‡và}‡|S¦|^€\€\&€^€\€\€\€\Ê Ï \Ê Ï \Ê Ï \€¡\5>PPsUsýSPpTpý_PmQm–^–üvà~üý^PjRjý\PžX“°ºX“ËïX“X“PgY“gs]“s›]“s‚_s‚_‚S‚S0U0Z]-T-VS*Q*X\'R'S^S¹và~¹\^$X“$0_“0^_“0?S0?SL?]L?]pšUšÈSp—T—Î^p”Q”Ì]p‘R‘Ê\pŽXŽÓvà~p‡Y‡½_½#vØ~#Ð_š©^š©^¶©S¶©S!U!;STÃ]Èõ]Q^^^uPRP\PÈv@ÈÖ\X¾vH¾ÃSÈÑvHÑõS)i_Èå_PÃ]åõ][^^^uPÁÃSåõSf³^åõ\õõ_Š«P³Q+U+|^(T(Ä]%Q%Ä\"R"ãvØ~Xãvà~Qnn|r|ãx|S“ÄÄS“— PˆRUZÛÛåS“‰¯U¯ñS¬T¬ vH "R"<vH<tRt vH¨Q¨Qv@U v@¤R¤3\3yv y"\"5v 5´\Öê\¡¯U¯ñSx´S¼ÁRˆRÏñRš´RÛ¦¦´Q» èñ_ ´_ky]¯¹]ÿ"^ùPMM^ÙìSî"SîRçìR#U#6SFVS T 6_FZ_Q6^FX^`‡U‡a^`„T„[S`Qxv¸`}R}xv@`yXyxvH`uYuxvPP!&\ÄÊRìöRRÄÊRöR°üU U°ÎTÙùT T°ÿQ°áRõ P1U;UŒ“U~TŒªT*Q*Œ^'R'b_$X$;S!Y!G]1;UwŒQ°ÑUáU'.U°T'ET°ÊQÊ'^°ÇRÇ_°ÄXÄáS°ÁYÁæ]æíPù'PÑáU'QPqU¼UÇÎUP¹TÇåTPjQjÇ^PgRg§_PdXdSPaYa†]¬PqUµÇQð U! \ Ug n UðY Tg … Tð Q g ^ð R G _ð X ! Sð Y & ]- L P ! UU g Q ± UÁ ü U  U ù T % T ª Qª  ^ § R§ ç _ ¤ X¤ Á S ¡ Y¡ Æ ]Í ì P± Á Uõ  Q0 Q Ua œ U§ ® U0 ™ T§ Å T0 J QJ § ^0 G RG ‡ _0 D XD a S0 A YA f ]m Œ PQ a U• § QÐ ñ U < UG N UÐ 9 TG e TÐ ê Qê G ^Ð ç Rç ' _Ð ä Xä  SÐ á Yá  ] , Pñ  U5 G Qp U” ¹ Up z Qz « S ” UÐ ñ Uñ / \Ð R T] { TÐ î Qî * _* ] UÐ ë Rë 3 vH3 ; RÐ ç Xç  SÐ ä Yä ^! E P“ø  UN ] Q€ ¡ U¡ á \€  T . T€ ž Qž Ü _Ü  U€ › R› å vHå í R€ — X— ¸ S€ ” Y” ½ ^Ò ø P¨ ¸ U  Q0 Q UQ ‘ \0 µ TÀ Þ T0 N QN Œ _Œ À U0 K RK • vH• R0 G XG h S0 D YD m ^‚ ¨ PX h U± À Qà UA\à eTpŽTà þ Qþ <_<pUà û Rû EvHEMRà ÷ X÷ Sà ô Yô ^2XPUapQ±U±ñ\T >T®Q®ì_ì U«R«õvHõýR§X§ÈS¤Y¤Í^âP¸ÈU Q@aUa¡\@ÅTÐîT@^Q^œ_œÐU@[R[¥vH¥­R@WXWxS@TYT}^’¸PhxUÁÐQðUQ\ðuT€žTðQL_L€Uð R UvHU]RðX(SðY-^BhP(Uq€Q ÁUÁ\ %T0NT ¾Q¾ü_ü0U »R»vH R ·X·ØS ´Y´Ý^òPÈØU!0QPqUq±\PÕTàþTPnQn¬_¬àUPkRkµvHµ½RPgXgˆSPdYd^¢ÈPxˆUÑàQ!U!a\…T®TQ\_\URevHemRX8SY=^RxP(8UQÐñUñ?^ÐcTnŒTÐîQî:_:nUÐëRëCvHCKRÐçXçSÐäYä ]0VPøU_nQ±U±^$T/MT®Q®û_û/U«R«vH R§X§ÈS¤Y¤Í]ñP¸ÈU /QPqUq¿^PãTî TPnQnº_ºîUPkRkÃvHÃËRPgXgˆSPdYd]°ÖPxˆUßîQ1U1€^¤T¯ÍT.Q.{_{¯U+R+„vH„ŒR'X'HS$Y$M]q—P8HU ¯QðU_^ðƒTެTðQZ_ZŽUð R cvHckRðX(SðY-]PvP(UŽQ°ÑUÑ ^°DTOmT°ÎQÎ_OU°ËRË$vH$,R°ÇXÇèS°ÄYÄí]7PØèU@OQp‘U‘à^pT-TpŽQŽÛ_ÛUp‹R‹ävHäìRp‡X‡¨Sp„Y„­]Ñ÷P˜¨UQ0QUQ ^0ÄTÏíT0NQN›_›ÏU0KRK¤vH¤¬R0GXGhS0DYDm]‘·PXhUÀÏQ1U1{^ŸTªÈT.Q.v_vªU+R+vH‡R'X'HS$Y$M]l’P8HU›ªQÐñUñ;^Ð_TjˆTÐîQî6_6jUÐëRë?vH?GRÐçXçSÐäYä ],RPøU[jQ±U±û^T*HT®Q®ö_ö*U«R«ÿvHÿR§X§ÈS¤Y¤Í]ìP¸ÈU*QPqUq»^PßTêTPnQn¶_¶êUPkRk¿vH¿ÇRPgXgˆSPdYd]¬ÒPxˆUÛêQ1U1{^ŸTªÈT.Q.v_vªU+R+vH‡R'X'HS$Y$M]l’P8HU›ªQÐñUñ;^Ð_TjˆTÐîQî6_6jUÐëRë?vH?GRÐçXçSÐäYä ],RPøU[jQ±U±û^T*HT®Q®ö_ö*U«R«ÿvHÿR§X§ÈS¤Y¤Í]ìP¸ÈU*QPqUq»^PßTêTPnQn¶_¶êUPkRk¿vH¿ÇRPgXgˆSPdYd]¬ÒPxˆUÛêQ1U1{^ŸTªÈT.Q.v_vªU+R+vH‡R'X'HS$Y$M]l’P8HU›ªQÐñUñ4 \ÐX Tc TÐîQî/ _/ c UÐëRë8 vH8 @ RÐçXç SÐäYä ^% K Pø UT c Q ± U± ô \ !T#!A!T ® Q® ï _ï #!U « R« ø vHø !R § X§ È S ¤ Y¤ Í ^å !P¸ È U!#!QP!q!Uq!´!\P!Ø!Tã!"TP!n!Qn!¯!_¯!ã!UP!k!Rk!¸!vH¸!À!RP!g!Xg!ˆ!SP!d!Yd!!^¥!Ë!Px!ˆ!UÔ!ã!Q"1"U1"t"\"˜"T£"Á"T"."Q."o"_o"£"U"+"R+"x"vHx"€"R"'"X'"H"S"$"Y$"M"^e"‹"P8"H"U”"£"QÐ"ñ"Uñ"1#\Ð"U#T`#~#TÐ"î"Qî",#_,#`#UÐ"ë"Rë"5#vH5#=#RÐ"ç"Xç"#SÐ"ä"Yä" #^"#H#Pø"#UQ#`#Q€#¡#U¡#á#\€#$T$.$T€#ž#Qž#Ü#_Ü#$U€#›#R›#å#vHå#í#R€#—#X—#¸#S€#”#Y”#½#^Ò#ø#P¨#¸#U$$Q0$Q$UQ$‘$\0$µ$TÀ$Þ$T0$N$QN$Œ$_Œ$À$U0$K$RK$•$vH•$$R0$G$XG$h$S0$D$YD$m$^‚$¨$PX$h$U±$À$Qà$%U%A%\à$e%Tp%Ž%Tà$þ$Qþ$<%_<%p%Uà$û$Rû$E%vHE%M%Rà$÷$X÷$%Sà$ô$Yô$%^2%X%P%%Ua%p%Q%±%U±%ô%\%&T#&A&T%®%Q®%ï%_ï%#&U%«%R«%ø%vHø%&R%§%X§%È%S%¤%Y¤%Í%^å% &P¸%È%U&#&QP&q&Uq&´&\P&Ø&Tã&'TP&n&Qn&¯&_¯&ã&UP&k&Rk&¸&vH¸&À&RP&g&Xg&ˆ&SP&d&Yd&&^¥&Ë&Px&ˆ&UÔ&ã&Q'1'U1't'\'˜'T£'Á'T'.'Q.'o'_o'£'U'+'R+'x'vHx'€'R'''X''H'S'$'Y$'M'^e'‹'P8'H'U”'£'QÐ'ñ'Uñ'4(\Ð'X(Tc((TÐ'î'Qî'/(_/(c(UÐ'ë'Rë'8(vH8(@(RÐ'ç'Xç'(SÐ'ä'Yä' (^%(K(Pø'(UT(c(Q(±(U±(ñ(\()T )>)T(®(Q®(ì(_ì( )U(«(R«(õ(vHõ(ý(R(§(X§(È(S(¤(Y¤(Í(^â()P¸(È(U) )Q@)a)Ua)¡)\@)Å)TÐ)î)T@)^)Q^)œ)_œ)Ð)U@)[)R[)¥)vH¥)­)R@)W)XW)x)S@)T)YT)})^’)¸)Ph)x)UÁ)Ð)Q`**U‘*¿*U`*z*Qz*¸*^`*w*Rw*¯*_`*t*Xt*‘*S`*q*Yq*–*]µ*¸*P“*‘*Uà*+U+¢+U§+ê+Uà*J+TS+v+T€+‡+T‘+›+T§+×+Tã+,Tà*ú*Qú*§+^à*÷*R÷*0+\à*ô*Xô*+Sà*ñ*Yñ*+]++U,^,Un,‚,U,™,U,,T,™,T,+,Q+,K,\r,Œ,\,(,R(,G,S,%,X%,n,_,",Y",[,^p,‡,‡,™,:,K,P{,Œ,Q ,î,Uþ,-U -)-U ,-T -)-T ,»,Q»,Û,\--\ ,¸,R¸,×,S ,µ,Xµ,þ,_ ,²,Y²,ë,^---)-Ê,Û,P --Q0-}-UŽ--U0-z-TŽ--T0-€-Q0-^-Rv-Š-P-Ý-Uî-ð-U-Ú-Tî-ð-T-à-Q-¾-RÖ-ê-Pð-?.UP.R.Uð-.T.<.TP.R.Tð-B.Qð-$.R./.T8.L.P`.«.U¼.¾.U`.¨.T¼.¾.T`.®.Q`..R¤.¸.PÀ. /U//UÀ.à.Tê. /T//TÀ./QÀ.ò.Rà.ü.T“//P /l/U}//U /@/TJ/i/T}//T /o/Q /R/R@/\/T“e/y/P€/Ì/UÝ/ß/U€/ /Tª/É/TÝ/ß/T€/Ï/Q€/²/R /¼/T“Å/Ù/Pà/0U0*0U>0N0U_0x0U³0Ë0Uç0 1U141U¯1Å1UÌ1ß1Uê1ñ1Uà/f0T³0<1T¯1Ü1Tê1 2Tà/0Q0Â1^Ì1ê1^à/ý/Rý/½1_à/ú/Xú/0Sà/÷/Y÷/$0\˜1Â1P“00UÕ1ê1Q02m2U02S2Tm22T¡2£2T02“2Q02u2Rb2€2TW2h2P“W2h2P“b2m2T‰22PÐ23UÐ2ô2T3#3T7393TÐ2)3QÐ2 3Rø23Tø23T333P`3•3U`3†3T•3µ3TÉ3Ë3T`3»3Q`33RŠ3¨3T±3Å3PÐ34UÐ3ö3T4#4T7494TÐ3)4QÐ3 4Rú34T“434P@4v4U@4f4Tv4–4Tª4¬4T@4œ4Q@4~4Rk4‰4T’4¦4P°4Ç4U°4½4Q½4ö4_Ä4ô4^Ä4ô4^5 5U5%5T,5.5T05R5U05V5T[5d5Tp5¡5Up5ç5Tð506T?6¡6T¯6æ6Tp5Ž5QŽ5Ò5_Ò56v@6¯6_Í6æ6_p5‹5R‹56vH6‰6RÍ6æ6vHp5‡5X‡5É5Sp5„5Y„5À5\¡5G6G6I6P“I6d6d6d6P“d6æ6Ã5ý5\q6”6P6&6^“¡5°5U+6?6\6&6^“6&6\Ö6æ6\Í6Ö6Ö6æ6\6¯6Q¶6Í6Uð6 7Uð6W7Tj7{7TŒ7®7Tð6 7Q 7D7\n7ˆ7\—7®7\ð67R7@7]—7®7]ð67X7j7_—7®7_ð67Y7T7^—7®7^*7D7Sl7ƒ7ƒ7®77 7SŸ7®7S—7Ÿ7Ÿ7®7S27D7Pw7ˆ7Q°7à7U°78T*8;8TL8n8T°7Ê7QÊ78\.8H8\W8n8\°7Ç7RÇ78]W8n8]°7Ä7XÄ7*8_W8n8_°7Á7YÁ78^W8n8^ê78S,8C8C8n8Û7à7S_8n8SW8_8_8n8Sò78P78H8Qp8Ÿ8Up8Ò8TÛ8™9T¡9÷9Tü9#:Tp8”8Q”8™9]œ9æ9Uê9ü9U!:3:]p8‘8R‘8™9_¡9¯9_!:3:_p8Ž8XŽ8º8\º8<9Q!:3:Qp8‹8Y‹8Á8v¨~Á8î8\!:3:\˜8Û8^“.99TŸ8·8U˜8Û8^“Ò8Û8T):3:T!:):):3:T<99qó9ü9Q”9™9u:!:U@:T:U“T:í:]“@:Q:T“Q:T:^“T:í:^“ ;B;^“n;‡;^“i:~:U“:¡:sµ:·:TÇ:Ì:T­:µ:µ:·:Tß:é:UQ;V;U4;<;S˜:¡:]“;;Sv;‡;Sn;v;v;‡;S%;*;U};‡;U ;È;UÙ;ú;U< <U<1<UB<F<U\<c<Ur<~<UŒ<½<UÇ<Î<Uä<ë<U==U=!=UG=N=U\=c=Ux=}=U’=™=UÀ=Ç=UÕ=Ü=Uî=ó=U>>U,>3>UD>K>UU>\>U ;<T<N<T\<{<TŒ<º<TÇ<ï<T=,=TG=R=T\=g=Tx=¤=TÀ=Ë=TÕ=à=Tî=>T,>7>TD>f>T ;¾;Q¾;#<^#<X<SX<Ç<^ä<\=^\=Õ=SÕ=D>^ ;»;R»;—<v¨—<Ÿ<Pä<f>v¨ ;·;X·;r<]ä<D>] ;´;Y´; <\ <\<v \<w<\ä<\=\\=Õ=v Õ=D>\{<Œ<tï<=tR=\=tà=î=t7>D>tg=x=tË=Õ=tc<r<U¶<Ç<QÎ<ä<Up>™>Uª>Ä>UÒ>Ö>Uæ>÷>U? ?U"?X?Uc?u?UŠ??U¤?ª?UÑ?Ø?Uæ?í?U@@U@#@UJ@Q@U_@f@Ux@}@U‹@‘@U·@¾@UÏ@Ö@Uà@ç@Up>Þ>Tæ>?T"?K?TU?_?Tc?y?TŠ?µ?TÑ?Ü?Tæ?ñ?T@.@TJ@U@T_@j@Tx@œ@T·@Â@TÏ@ñ@Tp>Ž>QŽ>,?]n?Ï@]p>‹>R‹>ñ@v°p>‡>X‡>ê>_ê>"?v¨"?U?_n?æ?_æ?_@v¨_@Ï@_p>„>Y„>í>^í>?_?H?^n?æ?^æ?_@__@Ï@^3?K? ÿÿÿÿÿÿÿÿÿK?_?T“y?Š?tÜ?æ?tj@x@tÂ@Ï@tñ?@tU@_@tA)AU:ATAUbAfAUvA‡AU˜AœAU²AèAUóABUBBU4B:BUaBhBUvB}BU’B—BU¬B³BUÚBáBUïBöBUC CUC!CUGCNCU_CfCUpCwCUAnATvA¤AT²AÛATåAïATóA BTBEBTaBlBTvBBT’B¾BTÚBåBTïBúBTC,CTGCRCT_CCTAAQA¼A]þA_C]AARACv°AAXAzA_zA²Av¨²AåA_þAvB_vBïBv¨ïB_C_AAYA}A^}A®A_®AØA^þAvB^vBïB_ïB_C^ÃAÛA ÿÿÿÿÿÿÿÿÿÛAïAT“ BBtlBvBtúBCtRC_CtB’BtåBïBtCÄCUÏCâCUóCõCUC±CT¼CßCTóCõCTCåCQCÉCR±CÔCT“ßCïCtDODU`DbDUD!DT,DLDT`DbDTDRDQD4DR!D?DTHD\DPpD¿DUÐDÒDUpD‘DTœD¼DTÐDÒDTpDÂDQpD¤DR‘D¯DT¸DÌDPàD,EU=E?EUàDET E)ET=E?ETàD/EQàDEREET“%E9EP@E™EUªE¬EU@EgETvE–ETªE¬ET@EœEQ@E~ERkE‰ET’E¦EP°EÿEUFFU°EÑETÜEüETFFT°EFQ°EäERÑEïETøE FP FoFU€F‚FU FAFTLFlFT€F‚FT FrFQ FTFRAF_FThF|FPFÄFUÏFâFUóFõFUF±FT¼FßFTóFõFTFåFQFÉFR±FÔFT“ßFïFtGOGU`GbGUG!GT,GLGT`GbGTGRGQG4GR!G?GTHG\GPpG¤GU¯GÂGUÓGÕGUpG‘GTœG¿GTÓGÕGTpGÅGQpG©GR‘G´GT“¿GÏGtàG/HU@HBHUàGHT H,HT@HBHTàG2HQàGHRHHT(HPS>P÷Pv ÷PQUaQxQU•QRSRdSv PPRPþPv˜þPQP•QdSv˜PPXPÙPv¨ÙPóPP•QdSv¨PPYPðP\•Q£R\ÒRBS\ÒP=QT“ÒPóPT“óPóP^“óP=QT“ÜP]Q_£RÒR_ Q±QtRRtÝRîRt8SBSt7RHRt™R£Rt¶P¿P_R,R_ÊPáPUjQxQQRQ]Q\QQ^“4Q=Q\¬R±R\¼R¼R\£R¬R¬R±R\MQ]QUQ„QUpS©SUºSÜSUñSõSUT7TUETWTUlTqTU†TŒTU³TºTUÈTÏTUäTéTUúTUU+U2UU@UGUUQUXUUpSÜSTñSýSTTTT"T4TTET[TTlT—TT³T¾TTÈTÓTTäT UT+U6UT@UbUTpS‡SQ‡SÜS_ñSAT_PT@U_pS„SR„SÜS^ñS"T^PT@U^ T'TR[TlTt¾TÈTtÓTäTt6U@Ut0TATQpU©UUºUÜUUñUõUUV7VUEVWVUlVqVU†VŒVU³VºVUÈVÏVUäVéVUúVWU+W2WU@WGWUQWXWUpUÜUTñUýUTV4VTEV[VTlV—VT³V¾VTÈVÓVTäV WT+W6WT@WbWTpU‡UQ‡UÜU_ñUAV_PV@W_pU„UR„UÜU^ñU"V^PV@W^ V'VS[VlVt¾VÈVtÓVäVt6W@Wt0VAVQpW©WUºWÜWUñWõWUX7XUEXWXUlXqXU†XŒXU³XºXUÈXÏXUäXéXUúXYU+Y2YU@YGYUQYXYUpWÜWTñWýWTXXT"X4XTEX[XTlX—XT³X¾XTÈXÓXTäX YT+Y6YT@YbYTpW‡WQ‡WÜW_ñWAX_PX@Y_pW„WR„WÜW^ñW"X^PX@Y^ X'XR[XlXt¾XÈXtÓXäXt6Y@Yt0XAXQpY©YUºYÜYUñYõYUZ7ZUEZWZUlZqZU†ZŒZU³ZºZUÈZÏZUäZéZUúZ[U+[2[U@[G[UQ[X[UpYÜYTñYýYTZ4ZTEZ[ZTlZ—ZT³Z¾ZTÈZÓZTäZ [T+[6[T@[b[TpY‡YQ‡YÜY_ñYAZ_PZ@[_pY„YR„YÜY^ñY"Z^PZ@[^ Z'ZS[ZlZt¾ZÈZtÓZäZt6[@[t0ZAZQ[·[UÈ[í[Uû[ÿ[U\'\U8\<\UR\™\Uª\Ì\Uá\å\Uô\]U ]=]UK]]]Ur]w]UŒ]’]U¿]Æ]UÔ]Û]Uð]õ]U ^^U>^E^US^Z^Uo^t^U‰^^U¶^½^UË^Ò^Uç^ì^U__U/_6_UD_K_U]_b_Us_y_U¦_­_U¿_Æ_UÐ_×_U[\T\D\TR\Ì\Tá\í\Tô\:]TK]a]Tr]]T¿]Ê]TÔ]ß]Tð]^T>^I^TS^^^To^š^T¶^Á^TË^Ö^Tç^_T/_:_TD_O_T]_„_T¦_±_T¿_á_T[­[Q­[\_\N\\N\‰\_‰\ÿ\v ÿ\G]_V]Ô]_Ô]S^\S^D_v D_¿__[ª[Rª[Ì[^Ì[]v¨]]RV]Ô]^Ô]á_v¨[§[X§[•\]V]S^]D_¿_][¤[Y¤[\\\R\v R\…\\V]Ô]\Ô]D_v D_¿_\:]G]tU\Z\P“a]r]tÊ]Ô]tO_]_t±_¿_tß]ð]tI^S^t^^o^tÁ^Ë^tÖ^ç^t:_D_tð_ `U-`K`U_`c`Ur`u`U€`Ž`UŸ`¤`U¹`¿`Uå`ì`Uú`aUaaU,a3aUUa\aUjaqaU{a‚aUð_K`T_`k`Tr`|`T€`’`TŸ`Ê`Tå`ð`Tú`aTa>aTUa`aTjaŒaTð_`R’`Ÿ`tð`ú`taat`ajatÊaAc3cucucycR“§hµhS“µhsi\cbcR“Tc\cQicncQLcTcTc\cQ–c!eR!esivð~c’cS“–c!eR!esivð~$f+f[¹hiu½hþhtÁhßhq#U4R¦´R#PÁUó%UT‰U„‰R“ššR“YUÁóU4IUY`R8ER8ERY`R8ERåèQîñQ“ñóQ“ewRiyQPXQ“PXQ“TiUÁQó%QXmQ”R\iR”R\iRS #S“#%S“™«R­S\iRÀ¥Tü¥Y)iT]“^Åú^2i^]“]Åú]#X]SXP“iiP“)]S“ÅSS)0PPP)0PP·ºPÀÃP“ÃÅP“59P9IP'P“'P“#8]]“PÅúP'<P]dR+8R]dR+8RìïSõøS“øúS“i|Rm~\+8R´·S·ThT·½TTT"<P·½T·TThTÚPhŒTðqTœ¥TßóT(YÎ×YÌÎ^Õ×^}Zœ¹ZßïZ^BT'‘Tv¬PÞPZ‹Pv¬]Þ]K€]{€R“‘‘R“BvS¬ÞS+@SBIR/<R/<RBIR/<RÐÓQÙÜQ“ÜÞQ“N`RRbQGOQ“GOQ“K`]v¬QÞQOdQv}RS`Rv}RS`RSS“S“‚•R†—\S`R ÑRìôRÓ â Ro x Po – PO z R  QÄ Ü Q * P* - Qm o R7 J RJ O Sž ³ RÁÝS³ Ó R1 < RP ] U † UP ] T Š Tˆ Š PŠ › Q› › P‚ Š R˜ › R× Û T“à î Uà ò Tç ô R  R$ $ R0 7 U0 E T7 E U„ Ž U9 > P  1 TÔ 1 Yý  S“D G TG ‹ P è PG M P Ô P¢ ¿ QG M PG ‹ PÔ è Pj [è P`ÙUü#U4\UeU&¡U÷U‚­UâU]bUhmU`‘T¼ÅT T‰ŽZíöZëíZôö^:Y¼ÙY Y@I^³¸Q“ÀüP&P¡ªP¡ÉP‚­Z6PQ÷Q:\P\_RŸ¡Zj}T}‚QêÿTòQÿ0ThqTR“R“XY CUCNv@NbSbjv@j«S¾‚v@‚˜S˜õ v@ ?T?cvHchSyöSÛ%S%µ\¾‚vH‚˜\˜q vHq … \… õ vH ;Q;ö]Ûw]¾‚]˜þ]… Å ]2 D ]u ‡ ] 8R8—_¾‚_˜þ_… Å _2 D _u ‡ _ 5X“5õ v¼ ËYËÓSÓHXH3v°3ÛY¾MXMZv°ZqXq˜v°˜éYéWv°WY Y(<YP}Y}…S…ŸYŸ§^§¯Y¯Ev°EJYJVv°VY´E v°E J YJ V v°V q Y… J YJ R SR h Yh p ^p — Y¦ õ Y¡¤R}—rŽö^Û¾^‚˜^q … ^C\]ªÀ]/¡]… Å ]u ‡ ]/T‘˜UªR/RˆSsƒT˜ÌT2 D TsƒTRsƒTRs€T˜ÌT2 D T¯×UÇÏRÒ×R¨¯R¬¯UÖ]×é]î TRRçîRëîTQ|]… Å ]u ‡ ]||S^|]||S… Å ]u ‡ ] ± Sµ ½ SÀ Å S– Rš SÖh\¾‚\Ö\¾I\Zm\Ö\¾I\Zm\òRÖß\Öß\^mRQ“,IUZmUÔêPß\¾ê\ÂÆRÔøPäêTöøTäêTïøRïööøT 5P9?RGIR9?R?GGIR0P!+R8SR“SSPUZP}‚P0P!+R0DP8DR“0P!+R0P!+R0P!+R8SR“8SR“SSPP!+R0DPmtP0DPmtPw}PSScSSYPY\PYcvHchSpySõþSÖß\Öß\RÖß\Öß\NVRòõQ“9UJVUÅÛPß\³·RÅéPÕÛTçéTÕÛTàéRàççéTû%P)/R79R)/R/779R#EP6@RMhR“hhPAJPlqP#EP6@RE]PM]R“#EP6@R#EP6@R#EP6@RMhR“MhR“hhP#,P6@RE]PVYPE]PVYPflP,^hƒ^hkPkqPkqPz²Q<PQq´Q²X<PXŸ¶^qy^z©Q©Xz©Q©Xz©Q©Xºï^“iŸ^“^ºÊ^“õY YPiYzƒQ©XŸ©^Ÿ©^õ  ^“T h ^“TÅ é T‡ — T¦ õ TTTí ð ^““ — P— ¦ QŽÌ^žÌ]ŽÌ^Öß\Öß\íöRÖß\Öß\N V RòõQ“ 9 UJ V UÊàPß\¸¼RÊîPÚàTìîTÚàTåîRåììîTû% P) / R7 9 R) / R/ 7 7 9 Rÿ!PR)DR“DDPA J Pl q Pÿ!PR!9P)9R“ÿ!PRÿ!PRÿ!PR)DR“)DR“DDPÿPR!9PV Y P!9PV Y Pf l Pù^D_^DGPGMPGMPVµQi…X{‘^V…Qi…XV…Qi…XV…Qi…XV_Qi…X{…^{…^¥ÛT¥µTÒÛPw«S‚˜S„«S‚˜Sˆ¥P E UE svà~s³Uº và~ àUç£và~£ÑUñûUvà~QUUÿvà~ T l]ºÉ]Ð%]+Ä]Ê™]çœ]Uf]m~]…±]¸ø]  Q í _ Í_ºÉ_Ð%_+¥_ºÄ_Ê_çó_…§_¸ç_  R í ^ ò ^  X í \ x \ Í\É\Ð\ºÄ\Ê\–§\Øç\ > Y“> x Y“x › S“› Ô Y“Ô Ü S“Ü í Y“ Æ Y“Æ ÿvØ~Íl]m~]€ŠPïP“"%P“NlQëïRïïP“ÚÞPüXTTT R T+XX\bRjlR\bRbjjlRlsvà~s³Ulƒ^³^ÑÝ^†³UŠŸPí ]çø]&0P 5 P“B E P“n Q  R  P“ú þ P 5 X! ' T3 5 T! ' T, 5 R, 3 3 5 TK | X€ † RŽ R€ † R† Ž Ž Rvà~QU)^5Q^,QU0EP # _ò d \v x \ # ^¾ËPËEvÐ~EtP¸ÿvÐ~È^+.^.t\¸Ø^t R# * R R  ^ R  ^ R# * R5 U UM P ^P U SS U ^/ 3 R3 5 R ]ºÔ]…–]¾ËPËÿvÐ~£ É P“Ò Õ P“þ UºÔUŸ £ R£ £ P“Ž ’ P° É Xµ » TÇ É Tµ » TÀ É RÀ Ç Ç É TÛ XR RR RàY¸ØY¾ËPËEvÐ~EtPx S¾ËPËEvÐ~EtPþœ]Uf]°ºP FP“RUP“~œQ R  P“ P-FX28TDFT28T=FR=DDFT[ˆXŒ’RšœRŒ’R’ššœRœ£và~£ÑUñûUœ³^¿Ñ^ñû^¶ÑUñûUºÏP É_Ð_Ê_ É\Ð\Ê\'P-çvÐ~çP$µ^µÅvØ~ÅÉ^Ð^ÊØ^ØÿvØ~ t)Í]¢]–§]'P-ÿvÐ~KqP“‚…P“¬ÍT7TGKRKKP“6:PXqS]cQoqQ]cQhqRhooqQ‹¹S½ÃRËÍR½ÃRÃËËÍR'P-ÿvÐ~à\'P-ÿvÐ~™]§±]™]§±]­·P,KP“RUP“|™T(,S,,P“"P2KS7=QIKQ7=QBKRBIIKQ[…S‰R—™R‰R——™R™ và~ àU™°^¼à^ÿ^³àU·ÌPU[^p¶^Õæ^UTU[vH[bTbvHQXvHXpPpxvHx­SÕæTYQY[v@[fQf v@ A_A^\p¹\ÕæQR“QR“Q[v¼[^R“^öv¼öFS“ÕæR“ÐA\Ô _ýxN^[^Õæ^Ð\6NP“[uP“‚…P“®ÞU26U66P“!%PCNX[uXHNYsuYHNYkuRkssuY‹¸X¼ÂRÊÌR¼ÂRÂÊÊÌRÐA\'A_AC\“P=P“BEP“n•QRP“P#=X(.Y;=Y(.Y3=R3;;=YKxX|‚RŠŒR|‚R‚ŠŠŒR°ÙUÙYvP°ÑTÑ]"]°ÎQÎ^P"^4§^§\4^FÄ^Ýä^äí\`\`t^‡ª\ªY^°ßRß4vH4ªSeÄSÝíSS‡šSªêS&/S°ÇXÇ\"\4F\°ÄYÄ_°Y"Y(ˆ_ˆYYTe_eíY.Y.6S6PYPX^X`Y‡/Y/7S7MYMU\UYY6]4]77PFí]t]‡Y]Fe\ò_"]"\"YF§^§\4^F{^Ýä^äí\`\`t^‡ª\TªSe{SÝíSS‡šSe§^§\4^T{^Ýä^äí\`\`t^‡ª\…ªSe{SÝíSS‡šSu{Yu—Q4Qe{Q`tQ¹ÌS“—ªSÝíSS‡šS¤ªSÝíSS‡šS—ªQ£¥S“¥ªS“ðùPôQ÷YYÄÝY%4XÞ \“&M\“ƒÄSªêSÍêQÛÞ\“Þê\““œP—ªQ`U·vH·ÝSú S U½vH½ÐSÐ+vH+;SY`vH`pSp~vH~ŽSŽÒ vH`!T T`tQtŸ\¬·\ $\pÒ \Ÿ^;^Yp^ŽÒ ^<S<Ò vPt!T TA^–½P“ÂÅP“îAQ’–R––P“…P£½_¨®X»½X¨®X³½R³»»½XËø_üR  RüR   R!TA^®·RÔÝR6UP“beP“ެTÐÝT16_66P“š·^'+P<U_AGQSUQAGQLURLSSUQk˜_œ¢Rª¬Rœ¢R¢ªª¬RÀâPÓÝRêR“P´¹PóøPÀâPÓÝRâöPêöR“ÀâPÓÝRÀâPÓÝRÀâPÓÝRêR“êR“PÀÉPÓÝRâöPÝàPâöPÝàPíóPºÉSSP P PLQø;QYpQ'LXYpX9P]ø]CQ'CXCQ'CXCQ'CXT‰]“ŽÈ]“Td]“z~vH~ŽSŸ\¬·\pŽ\ $]ÈØ]< n ]– À ]Q'CX9C]9C] $]ô ]“{ – ]“$TÈèT< n T– Ò T$T$TÊ Í ]“H Q PL [ Q·ÝSú S<S<Ò vPÂÝSú SÆÛPà |!U¤!µ!U€!”!^”!¢!^ç |!U¤!µ!U€!”!^ !/!P“2!5!P“^!…!S! !R ! !P“ô ø P!/!X!!!T-!/!T!!!T&!/!R&!-!-!/!T;!h!Xl!r!Rz!|!Rl!r!Rr!z!z!|!R˜TÐÞUÞ$^Þ$^$^UOSTb_?ZPœŸPŸ¡^¡¤P¤¤^?EPOb_ÐóUÐóTPmUmÔ^PjTj×SPgQgÜ\PdRdâ_ßòSÆ^Æ\âò_ßòSUA_SW_fœ_¢__"8_>_+A]SW]f˜]¢ü]]>]MYR_Pr|R‰ R“  P†P¸½P_Pr|R•P‰•R“_Pr|R_Pr|R_Pr|R‰ R“‰ R“  P_hPr|R•P¢¥P•P¢¥P²¸P ¼\ £Pª¼P³îQ½"QÆîX"XØò\½Å\³âQÆâX³âQÆâX³âQÆâXö+\“>†\“ö\“/8_:V^³¼QÆâXØâ\Øâ\²×\“-T\“ÚêT†¦Tñ#TTTÚêTÚêTˆ‹\“ýPQSW_+6]SW]§U§ôZôüSü•Z¥tZ€©Z©±^±ØZØß^ßôZúZ^vZBeZem^mZ‰]‰ÎZÎÕ^ÕÞZÞã^æñZñùSù Z¤T¤ _  vH €_€øvHøú_ú$vH$û_ {_{vHã_ë _·]¥÷]$v]Üû]ûûS·Ø]¥ç]$]]·Ø]·Ä]¥ç]$]]G]QUX^“X]^“¶¿PºÍQØôZôüSüZÜá\ÿ\îôZôüSüZÿ\–ºTT{ /•S€ºSÂßSúS{SB€€úú{{ ±ºP]/eS€–SúSB€€úú Ue]ú]éôZ\šºy–TŒTú^“TX{TBB··ëë 'g]p{]·ã]BB·· '7]·Ã]7BBbQÃãQBRQOXTü T§·Z˜Rž¾P­·RÄÖP“ÖÖP(*P@BPž¾P­·R¼ËRÄËP“ž¾P­·Rž¾P­·Rž¾P­·RÄÖP“ÄÖP“ÖÖPž£P­·R¼ËR*-R¼ËR*-R:@PÖû^ÖÜPÜûP'U'ê\ó# \# „ vH„ « \« Ï vHÏ \ vH a \Ì ù \  \C Ü \å [ vH[ …\$T$ª]ªñvHñà ]Ë ÷ ] c ]m ½ ]Ì û ]  ] 9 ]C Ü ]å 9 ]F …]‡ê^óà ^Ë î ^C Ü ^å / ^[ É ^Ó >^I…^ÃPÃêvPê P „ vP„ P Ÿ vPŸ « P« û vPû  Pm ½ P C PC F vPF [ P[ …vPAcPT^Rk‚Q“‚‚PÔ Ù På ê PAcPT^RcwPkwQ“AcPT^RAcPT^RAcPT^Rk‚Q“k‚Q“‚‚PAJPT^RcwPÙ Ü PcwPÙ Ü Pß å P& m Q  Q9 m X& T Q9 T X& T Q9 T X& T Q9 T X¶¿SÖæ\‡^¶¿S # \# vH « \« Ï vHÏ \ vH  \C Ü \å [ vH[ …\‡^ P PP z Sz « v¸« ² P² v¸  ^C …v¸J m \M ~ _ç ÷ R 6 T  R* A R“A A P_ d P‹ P 6 T  R" 6 P* 6 R“ 6 T  R 6 T  R 6 T  R* A R“* A R“A A P T  R" 6 Pu x P" 6 Pu x P… ‹ PA \ _A D PJ \ PS Q Ü Qf XÎ Ü Xx “ Y š YS ‚ Qf ‚ XS ‚ Qf ‚ XS ‚ Qf ‚ X— Ì _“å / _“— § _“Ô ð _S \ Qf ‚ Xx ‚ Yx ‚ Y‡ ­ Y“>Y“9 F \Ô ð _® ¾ T[ { TÓ TI…T® ¾ T® ¾ T}€Y“ß è Pã ò Q  \  PŒ Q¡U¡Õ^àí^ü^¥ÕSü›S®S¯»^¥¯S»ÁSàìRòPR3R“33PPCHPòPR(P(R“òPRòPRòPR3R“3R“33PòûPR(P-0P(P-0P=CP3P\36P=PPG‚QH›QZ‚Xˆ›Xl†\HP\GvQZvXGvQZvXGvQZvXŠ¿\“®ö\“Šš\“¡®^Ìé_GPQZvXlv\lv\"H\“žÅ\“euTöTb”TÅTeuTeuTùü\“nwPrQåí^T‹S¢S7bQ›¢QFbX7]QF]X7]QF]X7]QF]XsQsRËX“msZ“UQQ)T“QQ)T“JZRZ\P59P“$9SQWRWZP€ŒUŒ½T€‰T‰ßS¶ÆRÆÈP›ŸP“ŒŸS½ÃRÃÆPU™\™^7C\CKUKW\WZ^Š ^ ¼ ]¼ ^º\ºÈ^Èi\i²_²À\À^Tr^rS7F^FZSŠ S ¹ ^¹  S ] _] c Tc Sº_ºÈSÈW_W‹S‹¨T¨ËSËæ]æSQÝ]+ÄÄÆÆa+ÉÉËËa+ºº¼¼a+¶¶¸¸a+ÎÎÎÎa+¿¿ÁÁa3FF`q`aX`P“&P“Š––¤q¤‡‡•q•;;IqI‚‚qÉÉ×q×qWWeqežž¬q¬(q(™™§q§¹¹ÇqÇq11?q?¾¾ÌqÌ: : H qH  q È È Ö qÖ . . @ q a’JJXqXašÝÝëqëqö ö  q a¢ÆÆÔqÔææôqô++9q9KKYqYååóq󉉗q—   q aª#q#‚‚qÑÑßqßddrqra+t’¤tƒ•t7It~tÅ×t tSetš¬t(t•§t tºÌt6 H t} tÄ Ö t* @ tÙ ò tµÒÒäqÇaü+q×aµÇt-?t : : L qa| ™ ™ « qçaà à à ò q÷a - - ? qa‚ Ÿ Ÿ ± qaK h h z q7a  ½ ½ Ï qGa - - ? q'ah ˆ ˆ š qUaš º º Ì qhaÌ ì ì þ q{aþ 0qŽa0PPbq¡ab‚‚”q´aãêê R 22Dq[ŽsyŽqÈëëýqKs6Kq×Ü_“ ÐUÐ_ZSZ*"_7" (_ (>(vèw>(K(_K(f(vèwf(v(_v(‘(vèw‘(§(_§(Ñ)vèwÑ)»*_»*-vèw-i-Si- -vèw -×-_×-¹0vèw¹0&1S&1S5vèw ÍTÍ*"]7"w"]w"*vØw*¾*]¾*ÿ,Sÿ,o-]o-™-S™-.].²0S²0,1],1m1S ÊQ“Ê~S“ ÈR“ÈS5vôw ÂX“ÂS5vÔw »Y“»S5vÐwÄ-×-_×-¹0vèw¹0&1S&1S5vèwÄ-.].²0S²0,1],1m1S71G1\“ß-ù-ù- .q .(.(.:.q:.T.T.f.q95S5}.–.´.´.ç1S5‹.Í.ç1S5î./"/"/ú1S5ù.8/ú1S5\/r/// 2S5g/¦/ 2S5Ú/ð/00ñ2S5å/0ñ2S5=0S0q0q03S5H0‡03S5Þþþq=3S588EqES5kk~rŠ1S5›ÃÃÐqÐS5¦ôôrv3S5"JJWqWS5-~~‘r‰3S5ÞqS5é77Qrœ3S5޶¶ÃqÃS5™ççúr¯3S5ú""/q/S5SSfrÂ3S5fŽŽ›q›S5q¿¿ÒrÕ3S5ÒúúqS5Ý++>rè3S5>ffsqsS5I——ªrû3S5ò'q'S5ýKK^r4S5^††“q“S5i··Êr!4S5ÊòòÿqÿS5Õ##6r44S56^^kqkS5A¢rG4S5Öþþ q S5á//BrZ4S5BjjwqwS5M››®rm4S5®ÖÖãqãS5¹r€4S5BBOqOS5%ss†r“4S5ºââïqïS5Å&r¦4S5&NN[q[S51’r¹4S5’ººÇqÇS5ëëþrÉ4S5þ&&3q3S5 WWjrÙ4S5- U U b qb S58 † † ™ ré4S5´ Ü Ü é qé S5¿ ! ! !rù4S5 !H!H!U!qU!S5+!y!y!Œ!r 5S5"#"_"#"]û!"t÷)*\“¼!Ó!Ó!å!qå!ÿ!ÿ!"q)5S57"Q"Q"c"qP3S5‡"¬"Ê"Ê"›1S5¡"ã"›1S5÷'(RC#Y#w#w# 2S5N#‚# 2S5¦#¼#Ú#Ú#32S5±#å#32S5 $$=$=$F2S5$H$F2S5l$‚$ $ $Y2S5w$¶$Y2S5Ú$ð$%%l2S5å$$%l2S5H%^%|%|%2S5S%’%2S5¶%Ì%ê%ê%’2S5Á%&’2S51&G&e&e&3S5<&{&3S5Ÿ&µ&Ó&Ó&*3S5ª&é&*3S5 '#'A'A'¥2S5'W'¥2S5{'‘'¯'¯'¸2S5†'Å'¸2S5;*»*_»*-vèw-i-Si- -vèw -¶-_;*¾*]¾*ÿ,Sÿ,o-]o-™-S™-¶-]z-Š-_“O*i*i*{*q{*•*•*§*q5S5È*æ*++®1S5Û*+®1S5>+T+r+r+Á1S5I+ˆ+Á1S5©+¿+Ý+Ý+Ô1S5´+ó+Ô1S5',=,[,[,Ë2S52,f,Ë2S5Š, ,¾,¾,Þ2S5•,Ô,Þ2S5T½S/[Tr|TÐíUí2S8_S_Pv°P‘S$SÐ2T88T=RT_óTþLT]‘T #T.ÙTT$TÐêQê2_8‘_ _$_ÐçR“ç^“’v¤’«^“$^“ÐäX“ä\“Žv¨Ž\“$\“í––½½ÒÒùù$ 2]“8   ]“ ;;=]“=$8šv@š±R±$v@é1QaQõüPü$v@8_\{\¸iSx–RùþT 1TµÒR).T=aT{–\¸ÒS8KS“HS“8KSLPv°PwSTqPH]S“wS“$PJTP)1RYaRùþT 1T).T=aT$PJTP0¦U°°U°mv¸m¹U;IU0KTK,S;IS0DQ“DÛv ÛÞQ“;Iv 0DR“Dk^“kvœ,^“;I^“KÞÞIq‰]“‰åv@åíRñIv@‰KKM]“MI)XQSZPZIv@‰°^Ë®^ÈÞR9>TMXT‰¦Uimv¸m°UËÞ^‰œ_“y®_“‰œU|£U€Py‰_“£®_“PfQu€Q–¯QP`R`–S›¯SP]X“]hP“hpR“PZYZ–^›ª^–›P`–S›¯S‹–Pª¯P°ÀUÀùS°½Q½ ^ÀùSÅ ^ 7U7Ã\Ë- \ 4T4 _ Pš vP  ± U± y _  ® T® Î ^± á á Z $Z c U“c × $à ô Uô 0 ^E – ^& 3 ^} Š T] b P“1 B t” ž tÄ Õ t) 3 t> O t¡ « t¶ Ç ttþ  T  Pt } T© ¹ T@ÊUìøU4U@RTR=vP=ZSZ›QìvPp­^ËÚ^ì^pz^zyP¨ÊQ4P9Ú_”ÖÖÚR“zâ@â9€ 9‚@‚‰T4@´ÁQ1QtyRŠšT4hTŠšT´´QŠšT´´QŠ—T4hT@TQX`QchQ9CR=@Qz‚Pz‚PûQQQôþRøûQz‚Pz‚PrrRz‚PrrRz‚Pt’Q•RmwRqtQŸ¨TóøT«Ê_ìøPìóóøT«Ê_Áb]ø4]Áí]ø ]Áí]ø ]áíRóPR3P“33PP/4PóPR(R(P“óPRóPRóPR3P“3P“33PóüPR(RR(RR)/P3=S39P9WP9 _9=vP=ZSZ›Q ©U©ÂS­ÂTÐçUçf^fÿvPÿŒSšª^ª½vP½òS SÐäTäû\ÿŽ\šô\ \ø S ³vH³¾Q¾vHQQÑ$ÑÜS“Ü$ëôS¥ªSŒÏ_ïûR)P"R/EP“EEPÅÊPàåP)P"R':R/:P“)P"R)P"R)P"R/EP“/EP“EEPP"R':RÊÍR':RÊÍRÚàPE`_EHPHNPHNPåçQWšQQjšXWQjXWQjXWQjX0AUA›_åî_0>T>Ø^åî^–ØP¢¸R‰ŽTìîTåììîTðT“ :T“6aS6KSÒÒ$R“AAU3AQ?AU“AAU“©²P­¼Q 2U2_À_`qp1\\q\*1Pü5p|p=W^x^PWPLp7DT0Apí_,A_PÎp×èp˜²\Óè\«²Pu§pN_p)\J_\")PêpP a p $ ^L a ^ $ Pï ( pù pº Ô _õ _Í Ô P— É po € p0 J _k € _C J P > p0DUDÂ^0ATA³\L›][ˆPˆˆRàðUð_)0_àíTí)SPYUY…S¤¬S«¬S U "S%DS%DSP\UPYTYxS¡U¡*_/2_;„_žTž2^;„^ôQ“[Q“gjQ“;pQ“|„Q“›¡U¡Ã_ÃÃ\Ã_\E_EbSgÝ_ÝåTù*_/2_;f_fwT|„_›¡U¡¥_&7\ÿj ÿÿÿÿÿÿÿÿÿjÖÖÙRãåQðù ÿÿÿÿÿÿÿÿÿùÿÿP„ ÿÿÿÿÿÿÿÿÿQjjf f„™žU°µUÇÍTÍÏUù Q¼U¼ÖvÐ~Öí]íÆvÐ~Æú_úcvÐ~c ] ÇvÐ~Çû_ûF]F|vÐ~|›_›ÒvÐ~Ò _  vÐ~ ß _ß  vÐ~ ˜ _˜  vÐ~ Y ]Y ˆ vÐ~ˆ ´ _´ † vÐ~† ‹ U‹ ¤ vÐ~¤ ¹ ]¹ è vÐ~è ],vÐ~,Ï]ÏävÐ~ä_!V]V`vÐ~`ŸUŸBvÐ~BDQDNvÐ~N‹Q‹´vÐ~´×]×ßvÐ~ßï_ï]vÐ~[_[”vÐ~”¾_¾ÊvÐ~Ê _ *vÐ~*Ö]ÖâvÐ~ââ]âîvÐ~î3]3ÂvÐ~ÂsSsþvÐ~®T®æZï-Z-Jvà~J|Z?Z?rvà~rúZúvà~/Z/cvà~cNZNi^iå Zå  ^ ¢ Zª Ï ZÛ 6Z6X_XZ8æZæ^=Z=_^_eZe†^††Z†«và~«tZ¢ÃZÐÕZÝZ1Z!ÙZÙî^î¹ZÇÔZÖQ«R«ÈvÈ~ÈíQíTvÈ~TrTrÍvÈ~ÍúQúvÈ~*T*/vÈ~/;T;cvÈ~cŽQ•¨Qª¹QÇÖQÛQQÎvÈ~ÎûUû^vÈ~^›U›§T§½vÈ~½ U ± vÈ~± Ï UÏ Ö vÈ~Ö ô Tô " vÈ~" Y QY f vÈ~f ´ Q´ F UF ‹ X‹ ¹ T¹ Æ vÈ~Æ Ï QÛ Q,U,,T,NvÈ~NÏTÏQ8VQV±X±¸U¸´vÈ~´TßvÈ~ßCQCvÈ~dQdvÈ~ÃQÐÕQÝQ1Q!QQQ…vÈ~…´Q¤ÖQùQáøRu|RQ*Q.?Rú RAcQ®¸Q¸½R¥´QÖããæ^æ^tt P ûû PILRLQPQ½ ½  P  ^   Z P¢ ¥ ^¥ ª Pª ©©®P®±^±WS˜›^››S´ûûP^jj£Pß99>P>>^>˜˜×P\\aPaa^a¶¶üPE­­²P²²^²øøv^}…^…þäõ^“ÎÕ\“=VP“09_“ª½_“ï++-P<<P<þŠ’T× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_cjP× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_˜®SÊÜS.QWzQqƒP“t“SûS8`Q + + 4 P` b Pq s P‚ ‰ P‰ þð T× á ]  ]ø  _  Sz|X’X©¯Y¹Ä_òö_Å Ì P× Ù ]á  ]ø  _  Sz|X’X©¯Y¹Ä_òö_ª Ì U : SJ _ S¡ ² QÛ þ QÃ Ó RÃ Ó R  T× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_Ã Ó Rè ï R× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_œ Ÿ TŸ þv°~0\D\\†—QÑÿQô LLNR]]R]þw™Q™›R× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_¶ÄS@QQz›Qi  X9;XJJXJ¨¨´XdÒX¹Í-ÍÐY“æöY“ïöT× Ù ]á ]ø  _  Sz†Uz|X’X©¯Y¹Ò_æò_nwUŠ«Q«­U× Ù ]á ]ø  _  Sz|X’X©¯Y¹Ä_òö_ø ]‘¢QËèQjˆS•¨SßðQ OQÎÕ\09_SVP“`xUx S`uTu ^É S"%S%%^pƒUƒNZN`Q5SSSUUâ`ZC`Rgimli-0.19.0/fixtures/self/debug_pubnames010066400017500001750000004164741343337721300166600ustar0000000000000000ëÙ>_ZN5gimli6parser22test_compilation_units15__STATIC_FMTSTRE>__STATIC_FMTSTRW_ZN5gimli6parser22test_compilation_units10_FILE_LINEEW_FILE_LINEp_ZN5gimli6parser22test_compilation_units15__STATIC_FMTSTREp__STATIC_FMTSTRŠ_ZN5gimli6parser22test_compilation_units10_FILE_LINEEŠ_FILE_LINE£_ZN5gimli6parser22test_compilation_units15__STATIC_FMTSTRE£__STATIC_FMTSTR¼_ZN5gimli6parser22test_compilation_units10_FILE_LINEE¼_FILE_LINEÕ_ZN5gimli6parser22test_compilation_units15__STATIC_FMTSTREÕ__STATIC_FMTSTRï_ZN5gimli6parser22test_compilation_units10_FILE_LINEEï_FILE_LINE_ZN5gimli6parser22test_compilation_units10_FILE_LINEE_FILE_LINE2_ZN5gimli6parser8{{impl}}3new10_FILE_LINEE2_FILE_LINEU_ZN5gimli6parser28test_parse_unit_length_32_ok15__STATIC_FMTSTREU__STATIC_FMTSTRn_ZN5gimli6parser28test_parse_unit_length_32_ok10_FILE_LINEEn_FILE_LINE‡_ZN5gimli6parser28test_parse_unit_length_32_ok15__STATIC_FMTSTRE‡__STATIC_FMTSTR _ZN5gimli6parser28test_parse_unit_length_32_ok10_FILE_LINEE _FILE_LINE¹_ZN5gimli6parser28test_parse_unit_length_32_ok15__STATIC_FMTSTRE¹__STATIC_FMTSTRÒ_ZN5gimli6parser28test_parse_unit_length_32_ok10_FILE_LINEEÒ_FILE_LINEë_ZN5gimli6parser28test_parse_unit_length_32_ok15__STATIC_FMTSTREë__STATIC_FMTSTR_ZN5gimli6parser28test_parse_unit_length_32_ok10_FILE_LINEE_FILE_LINE'_ZN5gimli6parser28test_parse_unit_length_64_ok15__STATIC_FMTSTRE'__STATIC_FMTSTR@_ZN5gimli6parser28test_parse_unit_length_64_ok10_FILE_LINEE@_FILE_LINEY_ZN5gimli6parser28test_parse_unit_length_64_ok15__STATIC_FMTSTREY__STATIC_FMTSTRr_ZN5gimli6parser28test_parse_unit_length_64_ok10_FILE_LINEEr_FILE_LINE‹_ZN5gimli6parser28test_parse_unit_length_64_ok15__STATIC_FMTSTRE‹__STATIC_FMTSTR¤_ZN5gimli6parser28test_parse_unit_length_64_ok10_FILE_LINEE¤_FILE_LINE½_ZN5gimli6parser28test_parse_unit_length_64_ok15__STATIC_FMTSTRE½__STATIC_FMTSTR×_ZN5gimli6parser28test_parse_unit_length_64_ok10_FILE_LINEE×_FILE_LINEù_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_value15__STATIC_FMTSTREù__STATIC_FMTSTR_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_value10_FILE_LINEE_FILE_LINE5_ZN5gimli6parser33test_parse_unit_length_incomplete15__STATIC_FMTSTRE5__STATIC_FMTSTRO_ZN5gimli6parser33test_parse_unit_length_incomplete10_FILE_LINEEO_FILE_LINEq_ZN5gimli6parser36test_parse_unit_length_64_incomplete15__STATIC_FMTSTREq__STATIC_FMTSTR‹_ZN5gimli6parser36test_parse_unit_length_64_incomplete10_FILE_LINEE‹_FILE_LINE­_ZN5gimli6parser32test_compilation_unit_version_ok15__STATIC_FMTSTRE­__STATIC_FMTSTRÆ_ZN5gimli6parser32test_compilation_unit_version_ok10_FILE_LINEEÆ_FILE_LINEß_ZN5gimli6parser32test_compilation_unit_version_ok15__STATIC_FMTSTREß__STATIC_FMTSTRø_ZN5gimli6parser32test_compilation_unit_version_ok10_FILE_LINEEø_FILE_LINE_ZN5gimli6parser32test_compilation_unit_version_ok15__STATIC_FMTSTRE__STATIC_FMTSTR+_ZN5gimli6parser32test_compilation_unit_version_ok10_FILE_LINEE+_FILE_LINEM_ZN5gimli6parser45test_compilation_unit_version_unknown_version15__STATIC_FMTSTREM__STATIC_FMTSTRg_ZN5gimli6parser45test_compilation_unit_version_unknown_version10_FILE_LINEEg_FILE_LINE€_ZN5gimli6parser45test_compilation_unit_version_unknown_version15__STATIC_FMTSTRE€__STATIC_FMTSTRš_ZN5gimli6parser45test_compilation_unit_version_unknown_version10_FILE_LINEEš_FILE_LINE¼_ZN5gimli6parser40test_compilation_unit_version_incomplete15__STATIC_FMTSTRE¼__STATIC_FMTSTRÖ_ZN5gimli6parser40test_compilation_unit_version_incomplete10_FILE_LINEEÖ_FILE_LINEø_ZN5gimli6parser33test_parse_debug_abbrev_offset_3215__STATIC_FMTSTREø__STATIC_FMTSTR_ZN5gimli6parser33test_parse_debug_abbrev_offset_3210_FILE_LINEE_FILE_LINE*_ZN5gimli6parser33test_parse_debug_abbrev_offset_3215__STATIC_FMTSTRE*__STATIC_FMTSTRD_ZN5gimli6parser33test_parse_debug_abbrev_offset_3210_FILE_LINEED_FILE_LINEf_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incomplete15__STATIC_FMTSTREf__STATIC_FMTSTR€_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incomplete10_FILE_LINEE€_FILE_LINE¢_ZN5gimli6parser33test_parse_debug_abbrev_offset_6415__STATIC_FMTSTRE¢__STATIC_FMTSTR»_ZN5gimli6parser33test_parse_debug_abbrev_offset_6410_FILE_LINEE»_FILE_LINEÔ_ZN5gimli6parser33test_parse_debug_abbrev_offset_6415__STATIC_FMTSTREÔ__STATIC_FMTSTRî_ZN5gimli6parser33test_parse_debug_abbrev_offset_6410_FILE_LINEEî_FILE_LINE_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incomplete15__STATIC_FMTSTRE__STATIC_FMTSTR*_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incomplete10_FILE_LINEE*_FILE_LINEL_ZN5gimli6parser26test_parse_address_size_ok15__STATIC_FMTSTREL__STATIC_FMTSTRe_ZN5gimli6parser26test_parse_address_size_ok10_FILE_LINEEe_FILE_LINE~_ZN5gimli6parser26test_parse_address_size_ok15__STATIC_FMTSTRE~__STATIC_FMTSTR˜_ZN5gimli6parser26test_parse_address_size_ok10_FILE_LINEE˜_FILE_LINEÂ_ZN5gimli6parser8{{impl}}10range_from10_FILE_LINEEÂ_FILE_LINEæ_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok15__STATIC_FMTSTREæ__STATIC_FMTSTRÿ_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok10_FILE_LINEEÿ_FILE_LINE_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok15__STATIC_FMTSTRE__STATIC_FMTSTR2_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok10_FILE_LINEE2_FILE_LINET_ZN5gimli6parser40test_parse_compilation_unit_header_64_ok15__STATIC_FMTSTRET__STATIC_FMTSTRm_ZN5gimli6parser40test_parse_compilation_unit_header_64_ok10_FILE_LINEEm_FILE_LINE†_ZN5gimli6parser40test_parse_compilation_unit_header_64_ok15__STATIC_FMTSTRE†__STATIC_FMTSTR _ZN5gimli6parser40test_parse_compilation_unit_header_64_ok10_FILE_LINEE _FILE_LINEÂ_ZN5gimli6parser25test_parse_attribute_addr15__STATIC_FMTSTREÂ__STATIC_FMTSTRÛ_ZN5gimli6parser25test_parse_attribute_addr10_FILE_LINEEÛ_FILE_LINEô_ZN5gimli6parser25test_parse_attribute_addr15__STATIC_FMTSTREô__STATIC_FMTSTR _ZN5gimli6parser25test_parse_attribute_addr10_FILE_LINEE _FILE_LINE&_ZN5gimli6parser25test_parse_attribute_addr15__STATIC_FMTSTRE&__STATIC_FMTSTR?_ZN5gimli6parser25test_parse_attribute_addr16__STATIC_FMTARGSE?__STATIC_FMTARGSX_ZN5gimli6parser25test_parse_attribute_addr10_FILE_LINEEX_FILE_LINEz_ZN5gimli6parser27test_parse_attribute_block115__STATIC_FMTSTREz__STATIC_FMTSTR“_ZN5gimli6parser27test_parse_attribute_block110_FILE_LINEE“_FILE_LINE¬_ZN5gimli6parser27test_parse_attribute_block115__STATIC_FMTSTRE¬__STATIC_FMTSTRÅ_ZN5gimli6parser27test_parse_attribute_block110_FILE_LINEEÅ_FILE_LINEÞ_ZN5gimli6parser27test_parse_attribute_block115__STATIC_FMTSTREÞ__STATIC_FMTSTR÷_ZN5gimli6parser27test_parse_attribute_block116__STATIC_FMTARGSE÷__STATIC_FMTARGS _ZN5gimli6parser27test_parse_attribute_block110_FILE_LINEE _FILE_LINE2 _ZN5gimli6parser27test_parse_attribute_block215__STATIC_FMTSTRE2 __STATIC_FMTSTRK _ZN5gimli6parser27test_parse_attribute_block210_FILE_LINEEK _FILE_LINEd _ZN5gimli6parser27test_parse_attribute_block215__STATIC_FMTSTREd __STATIC_FMTSTR} _ZN5gimli6parser27test_parse_attribute_block210_FILE_LINEE} _FILE_LINE– _ZN5gimli6parser27test_parse_attribute_block215__STATIC_FMTSTRE– __STATIC_FMTSTR¯ _ZN5gimli6parser27test_parse_attribute_block216__STATIC_FMTARGSE¯ __STATIC_FMTARGSÈ _ZN5gimli6parser27test_parse_attribute_block210_FILE_LINEEÈ _FILE_LINEê _ZN5gimli6parser27test_parse_attribute_block415__STATIC_FMTSTREê __STATIC_FMTSTR _ZN5gimli6parser27test_parse_attribute_block410_FILE_LINEE _FILE_LINE _ZN5gimli6parser27test_parse_attribute_block415__STATIC_FMTSTRE __STATIC_FMTSTR5 _ZN5gimli6parser27test_parse_attribute_block410_FILE_LINEE5 _FILE_LINEN _ZN5gimli6parser27test_parse_attribute_block415__STATIC_FMTSTREN __STATIC_FMTSTRg _ZN5gimli6parser27test_parse_attribute_block416__STATIC_FMTARGSEg __STATIC_FMTARGS€ _ZN5gimli6parser27test_parse_attribute_block410_FILE_LINEE€ _FILE_LINE¢ _ZN5gimli6parser26test_parse_attribute_block15__STATIC_FMTSTRE¢ __STATIC_FMTSTR» _ZN5gimli6parser26test_parse_attribute_block10_FILE_LINEE» _FILE_LINEÔ _ZN5gimli6parser26test_parse_attribute_block15__STATIC_FMTSTREÔ __STATIC_FMTSTRí _ZN5gimli6parser26test_parse_attribute_block10_FILE_LINEEí _FILE_LINE _ZN5gimli6parser26test_parse_attribute_block15__STATIC_FMTSTRE __STATIC_FMTSTR _ZN5gimli6parser26test_parse_attribute_block16__STATIC_FMTARGSE __STATIC_FMTARGS8 _ZN5gimli6parser26test_parse_attribute_block10_FILE_LINEE8 _FILE_LINEZ _ZN5gimli6parser26test_parse_attribute_data115__STATIC_FMTSTREZ __STATIC_FMTSTRs _ZN5gimli6parser26test_parse_attribute_data110_FILE_LINEEs _FILE_LINEŒ _ZN5gimli6parser26test_parse_attribute_data115__STATIC_FMTSTREŒ __STATIC_FMTSTR¥ _ZN5gimli6parser26test_parse_attribute_data116__STATIC_FMTARGSE¥ __STATIC_FMTARGS¾ _ZN5gimli6parser26test_parse_attribute_data110_FILE_LINEE¾ _FILE_LINEà _ZN5gimli6parser26test_parse_attribute_data215__STATIC_FMTSTREà __STATIC_FMTSTRù _ZN5gimli6parser26test_parse_attribute_data210_FILE_LINEEù _FILE_LINE _ZN5gimli6parser26test_parse_attribute_data215__STATIC_FMTSTRE __STATIC_FMTSTR+ _ZN5gimli6parser26test_parse_attribute_data210_FILE_LINEE+ _FILE_LINED _ZN5gimli6parser26test_parse_attribute_data215__STATIC_FMTSTRED __STATIC_FMTSTR] _ZN5gimli6parser26test_parse_attribute_data216__STATIC_FMTARGSE] __STATIC_FMTARGSv _ZN5gimli6parser26test_parse_attribute_data210_FILE_LINEEv _FILE_LINE˜ _ZN5gimli6parser26test_parse_attribute_data415__STATIC_FMTSTRE˜ __STATIC_FMTSTR± _ZN5gimli6parser26test_parse_attribute_data410_FILE_LINEE± _FILE_LINEÊ _ZN5gimli6parser26test_parse_attribute_data415__STATIC_FMTSTREÊ __STATIC_FMTSTRã _ZN5gimli6parser26test_parse_attribute_data410_FILE_LINEEã _FILE_LINEü _ZN5gimli6parser26test_parse_attribute_data415__STATIC_FMTSTREü __STATIC_FMTSTR _ZN5gimli6parser26test_parse_attribute_data416__STATIC_FMTARGSE __STATIC_FMTARGS. _ZN5gimli6parser26test_parse_attribute_data410_FILE_LINEE. _FILE_LINEP _ZN5gimli6parser26test_parse_attribute_data815__STATIC_FMTSTREP __STATIC_FMTSTRi _ZN5gimli6parser26test_parse_attribute_data810_FILE_LINEEi _FILE_LINE‚ _ZN5gimli6parser26test_parse_attribute_data815__STATIC_FMTSTRE‚ __STATIC_FMTSTR› _ZN5gimli6parser26test_parse_attribute_data810_FILE_LINEE› _FILE_LINE´ _ZN5gimli6parser26test_parse_attribute_data815__STATIC_FMTSTRE´ __STATIC_FMTSTRÍ _ZN5gimli6parser26test_parse_attribute_data816__STATIC_FMTARGSEÍ __STATIC_FMTARGSæ _ZN5gimli6parser26test_parse_attribute_data810_FILE_LINEEæ _FILE_LINE_ZN5gimli6parser26test_parse_attribute_udata15__STATIC_FMTSTRE__STATIC_FMTSTR!_ZN5gimli6parser26test_parse_attribute_udata10_FILE_LINEE!_FILE_LINE:_ZN5gimli6parser26test_parse_attribute_udata15__STATIC_FMTSTRE:__STATIC_FMTSTRS_ZN5gimli6parser26test_parse_attribute_udata10_FILE_LINEES_FILE_LINEl_ZN5gimli6parser26test_parse_attribute_udata15__STATIC_FMTSTREl__STATIC_FMTSTR…_ZN5gimli6parser26test_parse_attribute_udata16__STATIC_FMTARGSE…__STATIC_FMTARGSž_ZN5gimli6parser26test_parse_attribute_udata10_FILE_LINEEž_FILE_LINEÀ_ZN5gimli6parser26test_parse_attribute_sdata15__STATIC_FMTSTREÀ__STATIC_FMTSTRÙ_ZN5gimli6parser26test_parse_attribute_sdata10_FILE_LINEEÙ_FILE_LINEò_ZN5gimli6parser26test_parse_attribute_sdata15__STATIC_FMTSTREò__STATIC_FMTSTR _ZN5gimli6parser26test_parse_attribute_sdata10_FILE_LINEE _FILE_LINE$_ZN5gimli6parser26test_parse_attribute_sdata15__STATIC_FMTSTRE$__STATIC_FMTSTR=_ZN5gimli6parser26test_parse_attribute_sdata16__STATIC_FMTARGSE=__STATIC_FMTARGSV_ZN5gimli6parser26test_parse_attribute_sdata10_FILE_LINEEV_FILE_LINEx_ZN5gimli6parser28test_parse_attribute_exprloc15__STATIC_FMTSTREx__STATIC_FMTSTR‘_ZN5gimli6parser28test_parse_attribute_exprloc10_FILE_LINEE‘_FILE_LINEª_ZN5gimli6parser28test_parse_attribute_exprloc15__STATIC_FMTSTREª__STATIC_FMTSTRÃ_ZN5gimli6parser28test_parse_attribute_exprloc10_FILE_LINEEÃ_FILE_LINEÜ_ZN5gimli6parser28test_parse_attribute_exprloc15__STATIC_FMTSTREÜ__STATIC_FMTSTRõ_ZN5gimli6parser28test_parse_attribute_exprloc16__STATIC_FMTARGSEõ__STATIC_FMTARGS_ZN5gimli6parser28test_parse_attribute_exprloc10_FILE_LINEE_FILE_LINE0_ZN5gimli6parser30test_parse_attribute_flag_true15__STATIC_FMTSTRE0__STATIC_FMTSTRI_ZN5gimli6parser30test_parse_attribute_flag_true10_FILE_LINEEI_FILE_LINEb_ZN5gimli6parser30test_parse_attribute_flag_true15__STATIC_FMTSTREb__STATIC_FMTSTR{_ZN5gimli6parser30test_parse_attribute_flag_true16__STATIC_FMTARGSE{__STATIC_FMTARGS”_ZN5gimli6parser30test_parse_attribute_flag_true10_FILE_LINEE”_FILE_LINE¶_ZN5gimli6parser31test_parse_attribute_flag_false15__STATIC_FMTSTRE¶__STATIC_FMTSTRÏ_ZN5gimli6parser31test_parse_attribute_flag_false10_FILE_LINEEÏ_FILE_LINEè_ZN5gimli6parser31test_parse_attribute_flag_false15__STATIC_FMTSTREè__STATIC_FMTSTR_ZN5gimli6parser31test_parse_attribute_flag_false16__STATIC_FMTARGSE__STATIC_FMTARGS_ZN5gimli6parser31test_parse_attribute_flag_false10_FILE_LINEE_FILE_LINE<_ZN5gimli6parser33test_parse_attribute_flag_present15__STATIC_FMTSTRE<__STATIC_FMTSTRU_ZN5gimli6parser33test_parse_attribute_flag_present10_FILE_LINEEU_FILE_LINEn_ZN5gimli6parser33test_parse_attribute_flag_present15__STATIC_FMTSTREn__STATIC_FMTSTR‡_ZN5gimli6parser33test_parse_attribute_flag_present10_FILE_LINEE‡_FILE_LINE _ZN5gimli6parser33test_parse_attribute_flag_present15__STATIC_FMTSTRE __STATIC_FMTSTR¹_ZN5gimli6parser33test_parse_attribute_flag_present16__STATIC_FMTARGSE¹__STATIC_FMTARGSÒ_ZN5gimli6parser33test_parse_attribute_flag_present10_FILE_LINEEÒ_FILE_LINEô_ZN5gimli6parser34test_parse_attribute_sec_offset_3215__STATIC_FMTSTREô__STATIC_FMTSTR _ZN5gimli6parser34test_parse_attribute_sec_offset_3210_FILE_LINEE _FILE_LINE&_ZN5gimli6parser34test_parse_attribute_sec_offset_3215__STATIC_FMTSTRE&__STATIC_FMTSTR?_ZN5gimli6parser34test_parse_attribute_sec_offset_3210_FILE_LINEE?_FILE_LINEX_ZN5gimli6parser34test_parse_attribute_sec_offset_3215__STATIC_FMTSTREX__STATIC_FMTSTRq_ZN5gimli6parser34test_parse_attribute_sec_offset_3216__STATIC_FMTARGSEq__STATIC_FMTARGSŠ_ZN5gimli6parser34test_parse_attribute_sec_offset_3210_FILE_LINEEŠ_FILE_LINE¬_ZN5gimli6parser34test_parse_attribute_sec_offset_6415__STATIC_FMTSTRE¬__STATIC_FMTSTRÅ_ZN5gimli6parser34test_parse_attribute_sec_offset_6410_FILE_LINEEÅ_FILE_LINEÞ_ZN5gimli6parser34test_parse_attribute_sec_offset_6415__STATIC_FMTSTREÞ__STATIC_FMTSTR÷_ZN5gimli6parser34test_parse_attribute_sec_offset_6410_FILE_LINEE÷_FILE_LINE_ZN5gimli6parser34test_parse_attribute_sec_offset_6415__STATIC_FMTSTRE__STATIC_FMTSTR)_ZN5gimli6parser34test_parse_attribute_sec_offset_6416__STATIC_FMTARGSE)__STATIC_FMTARGSB_ZN5gimli6parser34test_parse_attribute_sec_offset_6410_FILE_LINEEB_FILE_LINEd_ZN5gimli6parser25test_parse_attribute_ref115__STATIC_FMTSTREd__STATIC_FMTSTR}_ZN5gimli6parser25test_parse_attribute_ref110_FILE_LINEE}_FILE_LINE–_ZN5gimli6parser25test_parse_attribute_ref115__STATIC_FMTSTRE–__STATIC_FMTSTR¯_ZN5gimli6parser25test_parse_attribute_ref116__STATIC_FMTARGSE¯__STATIC_FMTARGSÈ_ZN5gimli6parser25test_parse_attribute_ref110_FILE_LINEEÈ_FILE_LINEê_ZN5gimli6parser25test_parse_attribute_ref215__STATIC_FMTSTREê__STATIC_FMTSTR_ZN5gimli6parser25test_parse_attribute_ref210_FILE_LINEE_FILE_LINE_ZN5gimli6parser25test_parse_attribute_ref215__STATIC_FMTSTRE__STATIC_FMTSTR5_ZN5gimli6parser25test_parse_attribute_ref210_FILE_LINEE5_FILE_LINEN_ZN5gimli6parser25test_parse_attribute_ref215__STATIC_FMTSTREN__STATIC_FMTSTRg_ZN5gimli6parser25test_parse_attribute_ref216__STATIC_FMTARGSEg__STATIC_FMTARGS€_ZN5gimli6parser25test_parse_attribute_ref210_FILE_LINEE€_FILE_LINE¢_ZN5gimli6parser25test_parse_attribute_ref415__STATIC_FMTSTRE¢__STATIC_FMTSTR»_ZN5gimli6parser25test_parse_attribute_ref410_FILE_LINEE»_FILE_LINEÔ_ZN5gimli6parser25test_parse_attribute_ref415__STATIC_FMTSTREÔ__STATIC_FMTSTRí_ZN5gimli6parser25test_parse_attribute_ref410_FILE_LINEEí_FILE_LINE_ZN5gimli6parser25test_parse_attribute_ref415__STATIC_FMTSTRE__STATIC_FMTSTR_ZN5gimli6parser25test_parse_attribute_ref416__STATIC_FMTARGSE__STATIC_FMTARGS8_ZN5gimli6parser25test_parse_attribute_ref410_FILE_LINEE8_FILE_LINEZ_ZN5gimli6parser25test_parse_attribute_ref815__STATIC_FMTSTREZ__STATIC_FMTSTRs_ZN5gimli6parser25test_parse_attribute_ref810_FILE_LINEEs_FILE_LINEŒ_ZN5gimli6parser25test_parse_attribute_ref815__STATIC_FMTSTREŒ__STATIC_FMTSTR¥_ZN5gimli6parser25test_parse_attribute_ref810_FILE_LINEE¥_FILE_LINE¾_ZN5gimli6parser25test_parse_attribute_ref815__STATIC_FMTSTRE¾__STATIC_FMTSTR×_ZN5gimli6parser25test_parse_attribute_ref816__STATIC_FMTARGSE×__STATIC_FMTARGSð_ZN5gimli6parser25test_parse_attribute_ref810_FILE_LINEEð_FILE_LINE_ZN5gimli6parser29test_parse_attribute_refudata15__STATIC_FMTSTRE__STATIC_FMTSTR+_ZN5gimli6parser29test_parse_attribute_refudata10_FILE_LINEE+_FILE_LINED_ZN5gimli6parser29test_parse_attribute_refudata15__STATIC_FMTSTRED__STATIC_FMTSTR]_ZN5gimli6parser29test_parse_attribute_refudata10_FILE_LINEE]_FILE_LINEv_ZN5gimli6parser29test_parse_attribute_refudata15__STATIC_FMTSTREv__STATIC_FMTSTR_ZN5gimli6parser29test_parse_attribute_refudata16__STATIC_FMTARGSE__STATIC_FMTARGS¨_ZN5gimli6parser29test_parse_attribute_refudata10_FILE_LINEE¨_FILE_LINEÊ_ZN5gimli6parser31test_parse_attribute_refaddr_3215__STATIC_FMTSTREÊ__STATIC_FMTSTRã_ZN5gimli6parser31test_parse_attribute_refaddr_3210_FILE_LINEEã_FILE_LINEü_ZN5gimli6parser31test_parse_attribute_refaddr_3215__STATIC_FMTSTREü__STATIC_FMTSTR_ZN5gimli6parser31test_parse_attribute_refaddr_3210_FILE_LINEE_FILE_LINE._ZN5gimli6parser31test_parse_attribute_refaddr_3215__STATIC_FMTSTRE.__STATIC_FMTSTRG_ZN5gimli6parser31test_parse_attribute_refaddr_3216__STATIC_FMTARGSEG__STATIC_FMTARGS`_ZN5gimli6parser31test_parse_attribute_refaddr_3210_FILE_LINEE`_FILE_LINE‚_ZN5gimli6parser31test_parse_attribute_refaddr_6415__STATIC_FMTSTRE‚__STATIC_FMTSTR›_ZN5gimli6parser31test_parse_attribute_refaddr_6410_FILE_LINEE›_FILE_LINE´_ZN5gimli6parser31test_parse_attribute_refaddr_6415__STATIC_FMTSTRE´__STATIC_FMTSTRÍ_ZN5gimli6parser31test_parse_attribute_refaddr_6410_FILE_LINEEÍ_FILE_LINEæ_ZN5gimli6parser31test_parse_attribute_refaddr_6415__STATIC_FMTSTREæ__STATIC_FMTSTRÿ_ZN5gimli6parser31test_parse_attribute_refaddr_6416__STATIC_FMTARGSEÿ__STATIC_FMTARGS_ZN5gimli6parser31test_parse_attribute_refaddr_6410_FILE_LINEE_FILE_LINE:_ZN5gimli6parser28test_parse_attribute_refsig815__STATIC_FMTSTRE:__STATIC_FMTSTRS_ZN5gimli6parser28test_parse_attribute_refsig810_FILE_LINEES_FILE_LINEl_ZN5gimli6parser28test_parse_attribute_refsig815__STATIC_FMTSTREl__STATIC_FMTSTR…_ZN5gimli6parser28test_parse_attribute_refsig810_FILE_LINEE…_FILE_LINEž_ZN5gimli6parser28test_parse_attribute_refsig815__STATIC_FMTSTREž__STATIC_FMTSTR·_ZN5gimli6parser28test_parse_attribute_refsig816__STATIC_FMTARGSE·__STATIC_FMTARGSÐ_ZN5gimli6parser28test_parse_attribute_refsig810_FILE_LINEEÐ_FILE_LINEò_ZN5gimli6parser27test_parse_attribute_string15__STATIC_FMTSTREò__STATIC_FMTSTR _ZN5gimli6parser27test_parse_attribute_string10_FILE_LINEE _FILE_LINE$_ZN5gimli6parser27test_parse_attribute_string15__STATIC_FMTSTRE$__STATIC_FMTSTR=_ZN5gimli6parser27test_parse_attribute_string10_FILE_LINEE=_FILE_LINEV_ZN5gimli6parser27test_parse_attribute_string15__STATIC_FMTSTREV__STATIC_FMTSTRo_ZN5gimli6parser27test_parse_attribute_string16__STATIC_FMTARGSEo__STATIC_FMTARGSˆ_ZN5gimli6parser27test_parse_attribute_string10_FILE_LINEEˆ_FILE_LINEª_ZN5gimli6parser28test_parse_attribute_strp_3215__STATIC_FMTSTREª__STATIC_FMTSTRÃ_ZN5gimli6parser28test_parse_attribute_strp_3210_FILE_LINEEÃ_FILE_LINEÜ_ZN5gimli6parser28test_parse_attribute_strp_3215__STATIC_FMTSTREÜ__STATIC_FMTSTRõ_ZN5gimli6parser28test_parse_attribute_strp_3210_FILE_LINEEõ_FILE_LINE_ZN5gimli6parser28test_parse_attribute_strp_3215__STATIC_FMTSTRE__STATIC_FMTSTR'_ZN5gimli6parser28test_parse_attribute_strp_3216__STATIC_FMTARGSE'__STATIC_FMTARGS@_ZN5gimli6parser28test_parse_attribute_strp_3210_FILE_LINEE@_FILE_LINEb_ZN5gimli6parser28test_parse_attribute_strp_6415__STATIC_FMTSTREb__STATIC_FMTSTR{_ZN5gimli6parser28test_parse_attribute_strp_6410_FILE_LINEE{_FILE_LINE”_ZN5gimli6parser28test_parse_attribute_strp_6415__STATIC_FMTSTRE”__STATIC_FMTSTR­_ZN5gimli6parser28test_parse_attribute_strp_6410_FILE_LINEE­_FILE_LINEÆ_ZN5gimli6parser28test_parse_attribute_strp_6415__STATIC_FMTSTREÆ__STATIC_FMTSTRß_ZN5gimli6parser28test_parse_attribute_strp_6416__STATIC_FMTARGSEß__STATIC_FMTARGSø_ZN5gimli6parser28test_parse_attribute_strp_6410_FILE_LINEEø_FILE_LINE_ZN5gimli6parser29test_parse_attribute_indirect15__STATIC_FMTSTRE__STATIC_FMTSTR3_ZN5gimli6parser29test_parse_attribute_indirect10_FILE_LINEE3_FILE_LINEL_ZN5gimli6parser29test_parse_attribute_indirect15__STATIC_FMTSTREL__STATIC_FMTSTRe_ZN5gimli6parser29test_parse_attribute_indirect10_FILE_LINEEe_FILE_LINE~_ZN5gimli6parser29test_parse_attribute_indirect15__STATIC_FMTSTRE~__STATIC_FMTSTR—_ZN5gimli6parser29test_parse_attribute_indirect16__STATIC_FMTARGSE—__STATIC_FMTARGS°_ZN5gimli6parser29test_parse_attribute_indirect10_FILE_LINEE°_FILE_LINEÚ_ZN5gimli6parser8{{impl}}4next10_FILE_LINEEÚ_FILE_LINEõ_ZN5gimli6parser8{{impl}}33nextEõnextÖ_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTREÖ__STATIC_FMTSTRï_ZN5gimli6parser15test_attrs_iter10_FILE_LINEEï_FILE_LINE_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTRE__STATIC_FMTSTR!_ZN5gimli6parser15test_attrs_iter16__STATIC_FMTARGSE!__STATIC_FMTARGS:_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE:_FILE_LINES_ZN5gimli6parser15test_attrs_iter10_FILE_LINEES_FILE_LINEl_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTREl__STATIC_FMTSTR…_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE…_FILE_LINEž_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTREž__STATIC_FMTSTR·_ZN5gimli6parser15test_attrs_iter16__STATIC_FMTARGSE·__STATIC_FMTARGSÐ_ZN5gimli6parser15test_attrs_iter10_FILE_LINEEÐ_FILE_LINEé_ZN5gimli6parser15test_attrs_iter10_FILE_LINEEé_FILE_LINE_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTRE__STATIC_FMTSTR_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE_FILE_LINE4_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTRE4__STATIC_FMTSTRM_ZN5gimli6parser15test_attrs_iter16__STATIC_FMTARGSEM__STATIC_FMTARGSf_ZN5gimli6parser15test_attrs_iter10_FILE_LINEEf_FILE_LINE_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE_FILE_LINE˜_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE˜_FILE_LINE±_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE±_FILE_LINEÊ_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTREÊ__STATIC_FMTSTRã_ZN5gimli6parser15test_attrs_iter10_FILE_LINEEã_FILE_LINE _ZN5gimli6parser8{{impl}}7current10_FILE_LINEE _FILE_LINE'_ZN5gimli6parser8{{impl}}7current10_FILE_LINEE'_FILE_LINEJ_ZN5gimli6parser8{{impl}}12next_sibling40{{closure}}EJ{{closure}}…_ZN5gimli6parser8{{impl}}12next_sibling40{{closure}}E…{{closure}}Ê_ZN5gimli6parser22assert_entry_with_name15__STATIC_FMTSTREÊ__STATIC_FMTSTRã_ZN5gimli6parser22assert_entry_with_name10_FILE_LINEEã_FILE_LINEü_ZN5gimli6parser22assert_entry_with_name40{{closure}}Eü{{closure}}@ _ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTRE@ __STATIC_FMTSTRY _ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEEY _FILE_LINEr _ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTREr __STATIC_FMTSTR‹ _ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE‹ _FILE_LINE¤ _ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTRE¤ __STATIC_FMTSTR½ _ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE½ _FILE_LINEÖ _ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTREÖ __STATIC_FMTSTRï _ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEEï _FILE_LINE!_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTRE!__STATIC_FMTSTR!!_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE!!_FILE_LINE:!_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTRE:!__STATIC_FMTSTRS!_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEES!_FILE_LINEl!_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTREl!__STATIC_FMTSTR…!_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE…!_FILE_LINEž!_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTREž!__STATIC_FMTSTR·!_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE·!_FILE_LINEÐ!_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTREÐ!__STATIC_FMTSTRé!_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEEé!_FILE_LINE"_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE"_FILE_LINE"_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEE"_FILE_LINE="_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr15__STATIC_FMTSTRE="__STATIC_FMTSTRV"_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr10_FILE_LINEEV"_FILE_LINEo"_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr10_FILE_LINEEo"_FILE_LINEˆ"_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr10_FILE_LINEEˆ"_FILE_LINEª"_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr15__STATIC_FMTSTREª"__STATIC_FMTSTRÃ"_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr10_FILE_LINEEÃ"_FILE_LINEÜ"_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr10_FILE_LINEEÜ"_FILE_LINEõ"_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr10_FILE_LINEEõ"_FILE_LINE#_ZN5gimli6parser28test_parse_type_signature_ok15__STATIC_FMTSTRE#__STATIC_FMTSTR0#_ZN5gimli6parser28test_parse_type_signature_ok10_FILE_LINEE0#_FILE_LINEI#_ZN5gimli6parser28test_parse_type_signature_ok15__STATIC_FMTSTREI#__STATIC_FMTSTRc#_ZN5gimli6parser28test_parse_type_signature_ok10_FILE_LINEEc#_FILE_LINE…#_ZN5gimli6parser36test_parse_type_signature_incomplete15__STATIC_FMTSTRE…#__STATIC_FMTSTRŸ#_ZN5gimli6parser36test_parse_type_signature_incomplete10_FILE_LINEEŸ#_FILE_LINEÁ#_ZN5gimli6parser28test_parse_type_offset_32_ok15__STATIC_FMTSTREÁ#__STATIC_FMTSTRÚ#_ZN5gimli6parser28test_parse_type_offset_32_ok10_FILE_LINEEÚ#_FILE_LINEó#_ZN5gimli6parser28test_parse_type_offset_32_ok15__STATIC_FMTSTREó#__STATIC_FMTSTR $_ZN5gimli6parser28test_parse_type_offset_32_ok10_FILE_LINEE $_FILE_LINE%$_ZN5gimli6parser28test_parse_type_offset_32_ok15__STATIC_FMTSTRE%$__STATIC_FMTSTR>$_ZN5gimli6parser28test_parse_type_offset_32_ok10_FILE_LINEE>$_FILE_LINEW$_ZN5gimli6parser28test_parse_type_offset_32_ok15__STATIC_FMTSTREW$__STATIC_FMTSTRq$_ZN5gimli6parser28test_parse_type_offset_32_ok10_FILE_LINEEq$_FILE_LINE“$_ZN5gimli6parser28test_parse_type_offset_64_ok15__STATIC_FMTSTRE“$__STATIC_FMTSTR¬$_ZN5gimli6parser28test_parse_type_offset_64_ok10_FILE_LINEE¬$_FILE_LINEÅ$_ZN5gimli6parser28test_parse_type_offset_64_ok15__STATIC_FMTSTREÅ$__STATIC_FMTSTRÞ$_ZN5gimli6parser28test_parse_type_offset_64_ok10_FILE_LINEEÞ$_FILE_LINE÷$_ZN5gimli6parser28test_parse_type_offset_64_ok15__STATIC_FMTSTRE÷$__STATIC_FMTSTR%_ZN5gimli6parser28test_parse_type_offset_64_ok10_FILE_LINEE%_FILE_LINE)%_ZN5gimli6parser28test_parse_type_offset_64_ok15__STATIC_FMTSTRE)%__STATIC_FMTSTRC%_ZN5gimli6parser28test_parse_type_offset_64_ok10_FILE_LINEEC%_FILE_LINEe%_ZN5gimli6parser33test_parse_type_offset_incomplete15__STATIC_FMTSTREe%__STATIC_FMTSTR%_ZN5gimli6parser33test_parse_type_offset_incomplete10_FILE_LINEE%_FILE_LINE¡%_ZN5gimli6parser33test_parse_type_unit_header_32_ok15__STATIC_FMTSTRE¡%__STATIC_FMTSTRº%_ZN5gimli6parser33test_parse_type_unit_header_32_ok16__STATIC_FMTARGSEº%__STATIC_FMTARGSÓ%_ZN5gimli6parser33test_parse_type_unit_header_32_ok15__STATIC_FMTSTREÓ%__STATIC_FMTSTRì%_ZN5gimli6parser33test_parse_type_unit_header_32_ok10_FILE_LINEEì%_FILE_LINE&_ZN5gimli6parser33test_parse_type_unit_header_32_ok15__STATIC_FMTSTRE&__STATIC_FMTSTR&_ZN5gimli6parser33test_parse_type_unit_header_32_ok10_FILE_LINEE&_FILE_LINE7,_ZN5gimli6parser8{{impl}}32newE7,newr,_ZN5gimli6parser8{{impl}}46compilation_unitsEr,compilation_unitsÌ,_ZN5gimli6parser8{{impl}}39range_fromEÌ,range_from-_ZN5gimli6parser8{{impl}}32newE-newM-_ZN5gimli6parser8{{impl}}37range_toEM-range_to÷-_ZN5gimli6parser8{{impl}}48size_of_unit_lengthE÷-size_of_unit_length2._ZN5gimli6parser8{{impl}}43size_of_headerE2.size_of_header¯._ZN5gimli6parser8{{impl}}32newE¯.new6/_ZN5gimli6parser8{{impl}}50length_including_selfE6/length_including_selfr/_ZN5gimli6parser8{{impl}}41address_sizeEr/address_size®/_ZN5gimli6parser8{{impl}}35formatE®/formatê/_ZN5gimli6parser8{{impl}}36entriesEê/entries40_ZN5gimli6parser8{{impl}}44is_valid_offsetE40is_valid_offset£0_ZN5gimli6parser8{{impl}}39range_fromE£0range_from#1_ZN5gimli6parser8{{impl}}34mergeE#1merge1_ZN5gimli6parser8{{impl}}3newE1newI2_ZN5gimli6parser8{{impl}}3newEI2newì2_ZN5gimli6parser8{{impl}}12has_childrenEì2has_childrenT3_ZN5gimli6parser8{{impl}}5emptyET3emptyv3_ZN5gimli6parser8{{impl}}6insertEv3insertÚ3_ZN5gimli6parser8{{impl}}3getEÚ3get=6_ZN5gimli6parser8{{impl}}4nameE=6namep6_ZN5gimli6parser8{{impl}}5valueEp6valueÎ6_ZN5gimli6parser8{{impl}}40mergeEÎ6mergeC7_ZN5gimli6parser8{{impl}}88merge>EC7merge>¸7_ZN5gimli6parser8{{impl}}39range_fromE¸7range_fromF8_ZN5gimli6parser8{{impl}}34attrsEF8attrsÀ8_ZN5gimli6parser8{{impl}}32newEÀ8newû8_ZN5gimli6parser8{{impl}}42abbreviationsEû8abbreviationsm9_ZN5gimli6parser8{{impl}}36currentEm9current|:_ZN5gimli6parser8{{impl}}37next_dfsE|:next_dfs[;_ZN5gimli6parser8{{impl}}41next_siblingE[;next_siblingX<_ZN5gimli6parser8{{impl}}32newEX<new¹<_ZN5gimli6parser8{{impl}}8read_u16E¹<read_u16é<_ZN5gimli6parser8{{impl}}8read_u32Eé<read_u32=_ZN5gimli6parser8{{impl}}8read_u64E=read_u64Q=_ZN5gimli6parser8{{impl}}5cloneEQ=clone=_ZN5gimli6parser8{{impl}}3fmtE=fmtŽ?_ZN5gimli6parser8parse_u8EŽ?parse_u8Ç?_ZN5gimli6parser8{{impl}}2eqEÇ?eqJ@_ZN5gimli6parser8{{impl}}3fmtEJ@fmtÕ@_ZN5gimli6parser8{{impl}}2eqEÕ@eqXA_ZN5gimli6parser8{{impl}}3fmtEXAfmtãA_ZN5gimli6parser8{{impl}}2eqEãAeqfB_ZN5gimli6parser8{{impl}}3fmtEfBfmtñB_ZN5gimli6parser8{{impl}}2eqEñBeqtC_ZN5gimli6parser8{{impl}}3fmtEtCfmtÿC_ZN5gimli6parser8{{impl}}2eqEÿCeq‚D_ZN5gimli6parser8{{impl}}3fmtE‚DfmtE_ZN5gimli6parser22test_compilation_unitsEEtest_compilation_unitsôF_ZN5gimli6parser8{{impl}}33nextEôFnext…G_ZN5gimli6parser8{{impl}}34derefE…Gderef¿G_ZN5gimli6parser58parse_compilation_unit_headerE¿Gparse_compilation_unit_headerJ_ZN5gimli6parser46parse_unit_lengthEJparse_unit_lengthOK_ZN5gimli6parser45parse_u32_as_u64EOKparse_u32_as_u64ŠK_ZN5gimli6parser38parse_u64EŠKparse_u64ÃK_ZN5gimli6parser42parse_versionEÃKparse_versionrL_ZN5gimli6parser38parse_u16ErLparse_u16«L_ZN5gimli6parser54parse_debug_abbrev_offsetE«Lparse_debug_abbrev_offsetM_ZN5gimli6parser25parse_debug_abbrev_offset40{{closure}}EM{{closure}}nM_ZN5gimli6parser18parse_address_sizeEnMparse_address_size©M_ZN5gimli6parser8{{impl}}33intoE©MintoìM_ZN5gimli6parser8{{impl}}33intoEìMinto.N_ZN5gimli6parser8{{impl}}31eqE.NeqVO_ZN5gimli6parser8{{impl}}32fmtEVOfmtE8QeqÛQ_ZN5gimli6parser8{{impl}}32fmtEÛQfmtrR_ZN5gimli6parser18parse_unsigned_lebErRparse_unsigned_lebìR_ZN5gimli6parser16parse_signed_lebEìRparse_signed_lebfS_ZN5gimli6parser23parse_abbreviation_codeEfSparse_abbreviation_code T_ZN5gimli6parser22parse_abbreviation_tagE Tparse_abbreviation_tag²T_ZN5gimli6parser31parse_abbreviation_has_childrenE²Tparse_abbreviation_has_children`U_ZN5gimli6parser8{{impl}}2eqE`UeqÑU_ZN5gimli6parser8{{impl}}3fmtEÑUfmt1b_ZN5gimli6parser20parse_attribute_nameE1bparse_attribute_nameßb_ZN5gimli6parser8{{impl}}3fmtEßbfmtZf_ZN5gimli6parser20parse_attribute_formEZfparse_attribute_form g_ZN5gimli6parser8{{impl}}3fmtE gfmt›g_ZN5gimli6parser29parse_attribute_specificationE›gparse_attribute_specificationÅh_ZN5gimli6parser34parse_null_attribute_specificationEÅhparse_null_attribute_specificationßi_ZN5gimli6parser30parse_attribute_specificationsEßiparse_attribute_specificationsÞj_ZN5gimli6parser30parse_attribute_specifications11{{closure}}EÞj{{closure}}k_ZN5gimli6parser30parse_attribute_specifications11{{closure}}Ek{{closure}}Nk_ZN5gimli6parser30parse_attribute_specifications11{{closure}}11{{closure}}ENk{{closure}}‘k_ZN5gimli6parser18parse_abbreviationE‘kparse_abbreviationŒm_ZN5gimli6parser23parse_null_abbreviationEŒmparse_null_abbreviation2n_ZN5gimli6parser19parse_abbreviationsE2nparse_abbreviations(o_ZN5gimli6parser19parse_abbreviations11{{closure}}E(o{{closure}}Zo_ZN5gimli6parser19parse_abbreviations11{{closure}}EZo{{closure}}˜o_ZN5gimli6parser19parse_abbreviations11{{closure}}11{{closure}}E˜o{{closure}}Ýo_ZN5gimli6parser28test_parse_unit_length_32_okEÝotest_parse_unit_length_32_okªq_ZN5gimli6parser28test_parse_unit_length_64_okEªqtest_parse_unit_length_64_okws_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_valueEwstest_parse_unit_length_unknown_reserved_valueús_ZN5gimli6parser33test_parse_unit_length_incompleteEústest_parse_unit_length_incomplete}t_ZN5gimli6parser36test_parse_unit_length_64_incompleteE}ttest_parse_unit_length_64_incompleteu_ZN5gimli6parser32test_compilation_unit_version_okEutest_compilation_unit_version_ok]v_ZN5gimli6parser45test_compilation_unit_version_unknown_versionE]vtest_compilation_unit_version_unknown_versionEw_ZN5gimli6parser40test_compilation_unit_version_incompleteEEwtest_compilation_unit_version_incompleteÈw_ZN5gimli6parser33test_parse_debug_abbrev_offset_32EÈwtest_parse_debug_abbrev_offset_32½x_ZN5gimli6parser8{{impl}}32fmtE½xfmtYy_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incompleteEYytest_parse_debug_abbrev_offset_32_incompleteÜy_ZN5gimli6parser33test_parse_debug_abbrev_offset_64EÜytest_parse_debug_abbrev_offset_64Éz_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incompleteEÉztest_parse_debug_abbrev_offset_64_incompleteL{_ZN5gimli6parser26test_parse_address_size_okEL{test_parse_address_size_ok9|_ZN5gimli6parser40test_parse_compilation_unit_header_32_okE9|test_parse_compilation_unit_header_32_ok&}_ZN5gimli6parser40test_parse_compilation_unit_header_64_okE&}test_parse_compilation_unit_header_64_ok1~_ZN5gimli6parser8{{impl}}2eqE1~eq,_ZN5gimli6parser8{{impl}}3fmtE,fmtÚ„_ZN5gimli6parser8{{impl}}2eqEÚ„eq{…_ZN5gimli6parser8{{impl}}3fmtE{…fmt †_ZN5gimli6parser4takeE †takeO†_ZN5gimli6parser15length_u8_valueEO†length_u8_valueö†_ZN5gimli6parser16length_leb_valueEö†length_leb_value‡_ZN5gimli6parser25test_parse_attribute_addrE‡test_parse_attribute_addr)‰_ZN5gimli6parser44parse_attributeE)‰parse_attribute+Š_ZN5gimli6parser8{{impl}}33intoE+ŠintooŠ_ZN5gimli6parser15parse_attribute40{{closure}}EoŠ{{closure}}ðŠ_ZN5gimli6parser15parse_attribute40{{closure}}EðŠ{{closure}}q‹_ZN5gimli6parser15parse_attribute40{{closure}}Eq‹{{closure}}ò‹_ZN5gimli6parser15parse_attribute40{{closure}}Eò‹{{closure}}sŒ_ZN5gimli6parser15parse_attribute40{{closure}}EsŒ{{closure}}ôŒ_ZN5gimli6parser15parse_attribute40{{closure}}EôŒ{{closure}}u_ZN5gimli6parser15parse_attribute40{{closure}}Eu{{closure}}ö_ZN5gimli6parser15parse_attribute40{{closure}}Eö{{closure}}wŽ_ZN5gimli6parser15parse_attribute40{{closure}}EwŽ{{closure}}øŽ_ZN5gimli6parser15parse_attribute40{{closure}}EøŽ{{closure}}x_ZN5gimli6parser15parse_attribute40{{closure}}Ex{{closure}}ø_ZN5gimli6parser15parse_attribute40{{closure}}Eø{{closure}}y_ZN5gimli6parser15parse_attribute40{{closure}}Ey{{closure}}ù_ZN5gimli6parser15parse_attribute40{{closure}}Eù{{closure}}y‘_ZN5gimli6parser15parse_attribute40{{closure}}Ey‘{{closure}}ù‘_ZN5gimli6parser15parse_attribute40{{closure}}Eù‘{{closure}}y’_ZN5gimli6parser15parse_attribute40{{closure}}Ey’{{closure}}ù’_ZN5gimli6parser15parse_attribute40{{closure}}Eù’{{closure}}y“_ZN5gimli6parser15parse_attribute40{{closure}}Ey“{{closure}}ù“_ZN5gimli6parser15parse_attribute40{{closure}}Eù“{{closure}}y”_ZN5gimli6parser15parse_attribute40{{closure}}Ey”{{closure}} •_ZN5gimli6parser15parse_attribute40{{closure}}E •{{closure}}™•_ZN5gimli6parser15parse_attribute40{{closure}}E™•{{closure}})–_ZN5gimli6parser15parse_attribute40{{closure}}E)–{{closure}}d–_ZN5gimli6parser15parse_attribute40{{closure}}Ed–{{closure}}ô–_ZN5gimli6parser15parse_attribute40{{closure}}Eô–{{closure}}…—_ZN5gimli6parser45length_u16_valueE…—length_u16_value<˜_ZN5gimli6parser16length_u16_value40{{closure}}E<˜{{closure}}˜_ZN5gimli6parser8{{impl}}33intoE˜into̘_ZN5gimli6parser45length_u32_valueE̘length_u32_value{™_ZN5gimli6parser38parse_u32E{™parse_u32¼™_ZN5gimli6parser16length_u32_value40{{closure}}E¼™{{closure}}š_ZN5gimli6parser8{{impl}}34derefEšderefTš_ZN5gimli6parser8{{impl}}32fmtETšfmtÿš_ZN5gimli6parser27test_parse_attribute_block1Eÿštest_parse_attribute_block1‹œ_ZN5gimli6parser27test_parse_attribute_block2E‹œtest_parse_attribute_block2ž_ZN5gimli6parser27test_parse_attribute_block4Ežtest_parse_attribute_block4£Ÿ_ZN5gimli6parser26test_parse_attribute_blockE£Ÿtest_parse_attribute_block/¡_ZN5gimli6parser26test_parse_attribute_data1E/¡test_parse_attribute_data1K¢_ZN5gimli6parser26test_parse_attribute_data2EK¢test_parse_attribute_data2×£_ZN5gimli6parser26test_parse_attribute_data4E×£test_parse_attribute_data4c¥_ZN5gimli6parser26test_parse_attribute_data8Ec¥test_parse_attribute_data8ï¦_ZN5gimli6parser26test_parse_attribute_udataEï¦test_parse_attribute_udata¬¨_ZN5gimli6parser26test_parse_attribute_sdataE¬¨test_parse_attribute_sdataiª_ZN5gimli6parser28test_parse_attribute_exprlocEiªtest_parse_attribute_exprlocõ«_ZN5gimli6parser30test_parse_attribute_flag_trueEõ«test_parse_attribute_flag_true­_ZN5gimli6parser31test_parse_attribute_flag_falseE­test_parse_attribute_flag_false-®_ZN5gimli6parser33test_parse_attribute_flag_presentE-®test_parse_attribute_flag_present¹¯_ZN5gimli6parser34test_parse_attribute_sec_offset_32E¹¯test_parse_attribute_sec_offset_32E±_ZN5gimli6parser34test_parse_attribute_sec_offset_64EE±test_parse_attribute_sec_offset_64Ѳ_ZN5gimli6parser25test_parse_attribute_ref1EѲtest_parse_attribute_ref1í³_ZN5gimli6parser25test_parse_attribute_ref2Eí³test_parse_attribute_ref2yµ_ZN5gimli6parser25test_parse_attribute_ref4Eyµtest_parse_attribute_ref4·_ZN5gimli6parser25test_parse_attribute_ref8E·test_parse_attribute_ref8‘¸_ZN5gimli6parser29test_parse_attribute_refudataE‘¸test_parse_attribute_refudataNº_ZN5gimli6parser31test_parse_attribute_refaddr_32ENºtest_parse_attribute_refaddr_32Ú»_ZN5gimli6parser31test_parse_attribute_refaddr_64EÚ»test_parse_attribute_refaddr_64f½_ZN5gimli6parser28test_parse_attribute_refsig8Ef½test_parse_attribute_refsig8ò¾_ZN5gimli6parser27test_parse_attribute_stringEò¾test_parse_attribute_string~À_ZN5gimli6parser28test_parse_attribute_strp_32E~Àtest_parse_attribute_strp_32 Â_ZN5gimli6parser28test_parse_attribute_strp_64E Âtest_parse_attribute_strp_64–Ã_ZN5gimli6parser29test_parse_attribute_indirectE–Ãtest_parse_attribute_indirectJÅ_ZN5gimli6parser15test_attrs_iterEJÅtest_attrs_iter1È_ZN5gimli6parser20test_cursor_next_dfsE1Ètest_cursor_next_dfs‚Í_ZN5gimli6parser8{{impl}}13abbreviations40{{closure}}E‚Í{{closure}}ÈÍ_ZN5gimli6parser8{{impl}}34cloneEÈÍcloneaÎ_ZN5gimli6parser51assert_entry_with_nameEaÎassert_entry_with_name\Ï_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptrE\Ïtest_cursor_next_sibling_no_sibling_ptróÐ_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptrEóÐtest_cursor_next_sibling_with_sibling_ptrVÒ_ZN5gimli6parser28test_parse_type_signature_okEVÒtest_parse_type_signature_okCÓ_ZN5gimli6parser49parse_type_signatureECÓparse_type_signature~Ó_ZN5gimli6parser36test_parse_type_signature_incompleteE~Ótest_parse_type_signature_incompleteÔ_ZN5gimli6parser28test_parse_type_offset_32_okEÔtest_parse_type_offset_32_ok¾Õ_ZN5gimli6parser46parse_type_offsetE¾Õparse_type_offset"Ö_ZN5gimli6parser8{{impl}}33intoE"ÖintofÖ_ZN5gimli6parser17parse_type_offset40{{closure}}EfÖ{{closure}}ÅÖ_ZN5gimli6parser28test_parse_type_offset_64_okEÅÖtest_parse_type_offset_64_ok‚Ø_ZN5gimli6parser33test_parse_type_offset_incompleteE‚Øtest_parse_type_offset_incompleteÙ_ZN5gimli6parser33test_parse_type_unit_header_32_okEÙtest_parse_type_unit_header_32_ok#Ú_ZN5gimli6parser51parse_type_unit_headerE#Úparse_type_unit_headerÂÛ_ZN5gimli6parser8{{impl}}32fmtEÂÛfmtlÜ_ZN5gimli6parser8{{impl}}31eqElÜeq;Ý_ZN5gimli6__test4mainE;ÝmainªÝ_ZN4core3ptr8{{impl}}10offsetEªÝoffsetõÝ_ZN4core3ptr8{{impl}}11is_nullEõÝis_null@Þ_ZN4core3num8{{impl}}11checked_mulE@Þchecked_mul²Þ_ZN4core3num8{{impl}}15overflowing_mulE²Þoverflowing_mul$ß_ZN4core3num8{{impl}}12wrapping_subE$ßwrapping_subfß_ZN4core3num8{{impl}}11checked_addEfßchecked_addØß_ZN4core3num8{{impl}}15overflowing_addEØßoverflowing_addJà_ZN4core3num8{{impl}}15is_power_of_twoEJàis_power_of_two}à_ZN4core3num8{{impl}}17next_power_of_twoE}ànext_power_of_twoÔà_ZN4core3num8{{impl}}13leading_zerosEÔàleading_zeros.á_ZN4core3num8{{impl}}5to_leE.áto_leèã_ZN4core3fmt8{{impl}}11debug_tupleEèãdebug_tuple*ä_ZN4core3fmt8{{impl}}12debug_structE*ädebug_structlä_ZN4core3fmt8{{impl}}10debug_listElädebug_listçä_ZN4core3fmt8{{impl}}65new<&gimli::parser::CompilationUnit>Eçänew<&gimli::parser::CompilationUnit>/å_ZN4core3fmt8{{impl}}130new, gimli::parser::Error>>>E/ånew, gimli::parser::Error>>>wå_ZN4core3fmt8{{impl}}11new<&usize>Ewånew<&usize>¿å_ZN4core3fmt8{{impl}}27new<&gimli::parser::Format>E¿ånew<&gimli::parser::Format>æ_ZN4core3fmt8{{impl}}9new<&u64>Eænew<&u64>Oæ_ZN4core3fmt8{{impl}}134new, (u64, gimli::parser::Format)), gimli::parser::Error>>EOænew, (u64, gimli::parser::Format)), gimli::parser::Error>>—æ_ZN4core3fmt8{{impl}}9new<&u16>E—ænew<&u16>ßæ_ZN4core3fmt8{{impl}}59new<&gimli::parser::EndianBuf>Eßænew<&gimli::parser::EndianBuf>'ç_ZN4core3fmt8{{impl}}109new, u16), gimli::parser::Error>>E'çnew, u16), gimli::parser::Error>>oç_ZN4core3fmt8{{impl}}38new<&gimli::parser::DebugAbbrevOffset>Eoçnew<&gimli::parser::DebugAbbrevOffset>·ç_ZN4core3fmt8{{impl}}140new, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>>E·çnew, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>>ÿç_ZN4core3fmt8{{impl}}8new<&u8>Eÿçnew<&u8>Gè_ZN4core3fmt8{{impl}}60new>EGènew>è_ZN4core3fmt8{{impl}}165new, gimli::parser::CompilationUnit), gimli::parser::Error>>Eènew, gimli::parser::CompilationUnit), gimli::parser::Error>>×è_ZN4core3fmt8{{impl}}30new<&gimli::parser::Attribute>E×ènew<&gimli::parser::Attribute>é_ZN4core3fmt8{{impl}}135new, gimli::parser::Attribute), gimli::parser::Error>>Eénew, gimli::parser::Attribute), gimli::parser::Error>>gé_ZN4core3fmt8{{impl}}9new<&str>Egénew<&str>¯é_ZN4core3fmt8{{impl}}26newE¯énew÷é_ZN4core3fmt8{{impl}}95new>>E÷énew>>?ê_ZN4core3fmt8{{impl}}11new<&&[u8]>E?ênew<&&[u8]>‡ê_ZN4core3fmt8{{impl}}25newE‡ênewÏê_ZN4core3fmt8{{impl}}35new<&gimli::parser::AttributeValue>EÏênew<&gimli::parser::AttributeValue>ë_ZN4core3fmt8{{impl}}11new<&isize>Eënew<&isize>_ë_ZN4core3fmt8{{impl}}109new, u64), gimli::parser::Error>>E_ënew, u64), gimli::parser::Error>>§ë_ZN4core3fmt8{{impl}}37new<&gimli::parser::DebugTypesOffset>E§ënew<&gimli::parser::DebugTypesOffset>ïë_ZN4core3fmt8{{impl}}139new, gimli::parser::DebugTypesOffset), gimli::parser::Error>>Eïënew, gimli::parser::DebugTypesOffset), gimli::parser::Error>>7ì_ZN4core3fmt8{{impl}}158new, gimli::parser::TypeUnit), gimli::parser::Error>>E7ìnew, gimli::parser::TypeUnit), gimli::parser::Error>>ì_ZN4core3fmt8{{impl}}58new<&gimli::parser::TypeUnit>Eìnew<&gimli::parser::TypeUnit>Gí_ZN4core3fmt8builders8{{impl}}34entries<&u8,core::slice::Iter>EGíentries<&u8,core::slice::Iter>ï_ZN4core3fmt8{{impl}}6new_v1Eïnew_v1Ïï_ZN4core3fmt8{{impl}}16new_v1_formattedEÏïnew_v1_formatted&ð_ZN4core3fmt8{{impl}}8fmtE&ðfmtqð_ZN4core3fmt8{{impl}}64fmt>Eqðfmt>¼ð_ZN4core3fmt8{{impl}}8fmtE¼ðfmtñ_ZN4core3fmt8{{impl}}37fmtEñfmtRñ_ZN4core3fmt8{{impl}}7fmtERñfmtñ_ZN4core3fmt8{{impl}}26fmtEñfmtèñ_ZN4core3fmt8{{impl}}58fmt>Eèñfmt>3ò_ZN4core3fmt8{{impl}}10fmt<&[u8]>E3òfmt<&[u8]>~ò_ZN4core3fmt8{{impl}}9fmt<[u8]>E~òfmt<[u8]>Éò_ZN4core3fmt8{{impl}}7fmtEÉòfmtó_ZN4core3fmt8{{impl}}59fmt>Eófmt>_ó_ZN4core3fmt8{{impl}}32fmtE_ófmtªó_ZN4core3fmt8{{impl}}108fmt, gimli::parser::Error>>Eªófmt, gimli::parser::Error>>õó_ZN4core3fmt8{{impl}}25fmtEõófmt@ô_ZN4core3fmt8{{impl}}33fmtE@ôfmt‹ô_ZN4core3fmt8{{impl}}33fmtE‹ôfmtÖô_ZN4core3fmt8{{impl}}42fmtEÖôfmt!õ_ZN4core3fmt8{{impl}}10fmtE!õfmtlõ_ZN4core3fmt8{{impl}}90fmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format))>Elõfmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format))>·õ_ZN4core3fmt8{{impl}}87fmt,(u64, gimli::parser::Format)>E·õfmt,(u64, gimli::parser::Format)>Kö_ZN4core3fmt8{{impl}}30fmtEKöfmtßö_ZN4core3fmt8{{impl}}65fmt<(gimli::parser::EndianBuf, u16)>Eßöfmt<(gimli::parser::EndianBuf, u16)>*÷_ZN4core3fmt8{{impl}}62fmt,u16>E*÷fmt,u16>¾÷_ZN4core3fmt8{{impl}}96fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)>E¾÷fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)> ø_ZN4core3fmt8{{impl}}93fmt,gimli::parser::DebugAbbrevOffset>E øfmt,gimli::parser::DebugAbbrevOffset>ø_ZN4core3fmt8{{impl}}16fmt<(&[u8], u8)>Eøfmt<(&[u8], u8)>èø_ZN4core3fmt8{{impl}}13fmt<&[u8],u8>Eèøfmt<&[u8],u8>|ù_ZN4core3fmt8{{impl}}121fmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)>E|ùfmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)>Çù_ZN4core3fmt8{{impl}}118fmt,gimli::parser::CompilationUnit>EÇùfmt,gimli::parser::CompilationUnit>[ú_ZN4core3fmt8{{impl}}8fmtE[úfmt¦ú_ZN4core3fmt8{{impl}}9fmtE¦úfmtñú_ZN4core3fmt8{{impl}}30fmtEñúfmt<û_ZN4core3fmt8{{impl}}35fmtE<ûfmt‡û_ZN4core3fmt8{{impl}}36fmtE‡ûfmtÒû_ZN4core3fmt8{{impl}}34fmtEÒûfmtü_ZN4core3fmt8{{impl}}34fmtEüfmthü_ZN4core3fmt8{{impl}}29fmtEhüfmt³ü_ZN4core3fmt8{{impl}}91fmt<(gimli::parser::AttributeInput, gimli::parser::Attribute)>E³üfmt<(gimli::parser::AttributeInput, gimli::parser::Attribute)>þü_ZN4core3fmt8{{impl}}88fmt,gimli::parser::Attribute>Eþüfmt,gimli::parser::Attribute>’ý_ZN4core3fmt8{{impl}}65fmt<&gimli::parser::CompilationUnit>E’ýfmt<&gimli::parser::CompilationUnit>Ýý_ZN4core3fmt8{{impl}}8fmtEÝýfmt(þ_ZN4core3fmt8{{impl}}73fmt>E(þfmt>sþ_ZN4core3fmt8{{impl}}10fmtEsþfmt¾þ_ZN4core3fmt8{{impl}}65fmt<(gimli::parser::EndianBuf, u64)>E¾þfmt<(gimli::parser::EndianBuf, u64)> ÿ_ZN4core3fmt8{{impl}}62fmt,u64>E ÿfmt,u64>ÿ_ZN4core3fmt8{{impl}}95fmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)>Eÿfmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)>èÿ_ZN4core3fmt8{{impl}}92fmt,gimli::parser::DebugTypesOffset>Eèÿfmt,gimli::parser::DebugTypesOffset>|_ZN4core3fmt8{{impl}}114fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit)>E|fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit)>Ç_ZN4core3fmt8{{impl}}111fmt,gimli::parser::TypeUnit>EÇfmt,gimli::parser::TypeUnit>[_ZN4core3fmt8{{impl}}57fmt>E[fmt>H_ZN4core6result8{{impl}}132map<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>EHmap<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>ò_ZN4core6result8{{impl}}132map<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Eòmap<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>ñ_ZN4core6result8{{impl}}88expect,gimli::parser::Error>Eñexpect,gimli::parser::Error>‰_ZN4core6result8{{impl}}186map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),closure>E‰map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),closure>3_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E3map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Ý_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>EÝmap<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>‡_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E‡map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>1_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E1map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Û_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>EÛmap<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>… _ZN4core6result8{{impl}}185map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),closure>E… map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),closure>„ _ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u16),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E„ map<(gimli::parser::EndianBuf, u16),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Ø _ZN4core6result8{{impl}}133map<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>EØ map<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>‚ _ZN4core6result8{{impl}}133map<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E‚ map<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>+_ZN4core6result8{{impl}}133map<(&[u8], i64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E+map<(&[u8], i64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Ó_ZN4core6result8{{impl}}149map<(&[u8], gimli::parser::AttributeSpecification),gimli::parser::Error,(&[u8], core::option::Option),closure>EÓmap<(&[u8], gimli::parser::AttributeSpecification),gimli::parser::Error,(&[u8], core::option::Option),closure>Ò_ZN4core6result8{{impl}}114map<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>EÒmap<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>{_ZN4core6result8{{impl}}104map<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>E{map<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>Î_ZN4core6result8{{impl}}127or_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>EÎor_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>Í_ZN4core6result8{{impl}}129map<(&[u8], gimli::parser::Abbreviation),gimli::parser::Error,(&[u8], core::option::Option),closure>EÍmap<(&[u8], gimli::parser::Abbreviation),gimli::parser::Error,(&[u8], core::option::Option),closure>_ZN4core6result8{{impl}}100map<(&[u8], gimli::parser::Abbreviations),gimli::parser::Error,gimli::parser::Abbreviations,closure>Emap<(&[u8], gimli::parser::Abbreviations),gimli::parser::Error,gimli::parser::Abbreviations,closure> _ZN4core6result8{{impl}}117or_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>E or_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure> _ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>·_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E·map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>a_ZN4core6result8{{impl}}111map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure>Eamap<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure> _ZN4core6result8{{impl}}111map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure>E map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure>µ_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Eµmap<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>__ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E_map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure> _ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>³_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E³map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>]_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E]map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>[_ZN4core6result8{{impl}}183map<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E[map<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure> _ZN4core6result8{{impl}}183map<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E map<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>!_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E!map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>®!_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E®!map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>X"_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>EX"map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>#_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>E#map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>$_ZN4core6result8{{impl}}35expectE$expectí$_ZN4core6result8{{impl}}53expectEí$expect…%_ZN4core6result8{{impl}}52is_okE…%is_okÊ%_ZN4core6result8{{impl}}53unwrapEÊ%unwrap¨&_ZN4core6result8{{impl}}57expectE¨&expect–'_ZN4core6result8{{impl}}98expect,gimli::parser::Error>E–'expect,gimli::parser::Error>0(_ZN4core6result8{{impl}}97is_ok,gimli::parser::Error>E0(is_ok,gimli::parser::Error>c)_ZN4core6result8{{impl}}85fmt,gimli::parser::Error>Ec)fmt,gimli::parser::Error>8*_ZN4core6result8{{impl}}111fmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)),gimli::parser::Error>E8*fmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)),gimli::parser::Error> +_ZN4core6result8{{impl}}86fmt<(gimli::parser::EndianBuf, u16),gimli::parser::Error>E +fmt<(gimli::parser::EndianBuf, u16),gimli::parser::Error>â+_ZN4core6result8{{impl}}117fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),gimli::parser::Error>Eâ+fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),gimli::parser::Error>·,_ZN4core6result8{{impl}}37fmt<(&[u8], u8),gimli::parser::Error>E·,fmt<(&[u8], u8),gimli::parser::Error>Œ-_ZN4core6result8{{impl}}142fmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit),gimli::parser::Error>EŒ-fmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit),gimli::parser::Error>a._ZN4core6result8{{impl}}112fmt<(gimli::parser::AttributeInput, gimli::parser::Attribute),gimli::parser::Error>Ea.fmt<(gimli::parser::AttributeInput, gimli::parser::Attribute),gimli::parser::Error>6/_ZN4core6result8{{impl}}50fmtE6/fmt 0_ZN4core6result8{{impl}}97clone,gimli::parser::Error>E 0clone,gimli::parser::Error>0_ZN4core6result8{{impl}}86fmt<(gimli::parser::EndianBuf, u64),gimli::parser::Error>E0fmt<(gimli::parser::EndianBuf, u64),gimli::parser::Error>e1_ZN4core6result8{{impl}}116fmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),gimli::parser::Error>Ee1fmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),gimli::parser::Error>:2_ZN4core6result8{{impl}}135fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit),gimli::parser::Error>E:2fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit),gimli::parser::Error>3_ZN4core6result36unwrap_failedE3unwrap_failed‹3_ZN4core6result35unwrap_failedE‹3unwrap_failedj4_ZN4core6option8{{impl}}13expectEj4expectÖ4_ZN4core6option8{{impl}}13unwrapEÖ4unwrap|5_ZN4core6option8{{impl}}112is_none, gimli::parser::Error>>E|5is_none, gimli::parser::Error>>¶5_ZN4core6option8{{impl}}112is_some, gimli::parser::Error>>E¶5is_some, gimli::parser::Error>>ð5_ZN4core6option8{{impl}}111expect, gimli::parser::Error>>Eð5expect, gimli::parser::Error>>É6_ZN4core6option8{{impl}}29map<&u8,(usize, &u8),closure>EÉ6map<&u8,(usize, &u8),closure>Ü7_ZN4core6option8{{impl}}65expect<&core::cell::UnsafeCell>>EÜ7expect<&core::cell::UnsafeCell>>r8_ZN4core6option8{{impl}}18as_ref<(u64, u64)>Er8as_ref<(u64, u64)>9_ZN4core6option8{{impl}}19unwrap<&(u64, u64)>E9unwrap<&(u64, u64)>á9_ZN4core6option8{{impl}}76expect>Eá9expect>¼:_ZN4core6option8{{impl}}193map>,&gimli::parser::Abbreviation,closure>E¼:map>,&gimli::parser::Abbreviation,closure>­;_ZN4core6option8{{impl}}14is_none<&[u8]>E­;is_none<&[u8]>ç;_ZN4core6option8{{impl}}14is_some<&[u8]>Eç;is_some<&[u8]>!<_ZN4core6option8{{impl}}13expect<&[u8]>E!<expect<&[u8]>¸<_ZN4core6option8{{impl}}77is_none>E¸<is_none>ò<_ZN4core6option8{{impl}}77is_some>Eò<is_some>,=_ZN4core6option8{{impl}}76expect>E,=expect>™=_ZN4core6option8{{impl}}155and_then,core::result::Result,closure>E™=and_then,core::result::Result,closure>a>_ZN4core6option8{{impl}}121expect, gimli::parser::Error>>Ea>expect, gimli::parser::Error>>Ñ>_ZN4core6option8{{impl}}122is_none, gimli::parser::Error>>EÑ>is_none, gimli::parser::Error>> ?_ZN4core6option8{{impl}}122is_some, gimli::parser::Error>>E ?is_some, gimli::parser::Error>>Ú?_ZN4core6option8{{impl}}13expectEÚ?expectF@_ZN4core6option8{{impl}}14is_noneEF@is_none€@_ZN4core6option8{{impl}}14is_someE€@is_someA_ZN4core6option8{{impl}}10expect<()>EAexpect<()>JA_ZN4core6option8{{impl}}11is_none<()>EJAis_none<()>„A_ZN4core6option8{{impl}}11is_some<()>E„Ais_some<()>öA_ZN4core6option8{{impl}}108fmt, gimli::parser::Error>>EöAfmt, gimli::parser::Error>> B_ZN4core6option8{{impl}}73fmt>E Bfmt>JC_ZN4core6option8{{impl}}120clone, gimli::parser::Error>>EJCclone, gimli::parser::Error>>µC_ZN4core3cmp5impls8{{impl}}13eq<[u8],[u8]>EµCeq<[u8],[u8]> D_ZN4core3cmp5impls8{{impl}}2ltE DltKD_ZN4core3cmp5impls8{{impl}}2geEKDgeD_ZN4core3cmp5impls8{{impl}}2eqEDeqÏD_ZN4core3cmp5impls8{{impl}}2leEÏDleE_ZN4core3cmp10maxEEmax^E_ZN4core3cmp10minE^Emin5F_ZN4core5slice8{{impl}}7lenE5FlenqF_ZN4core5slice8{{impl}}10as_ptrEqFas_ptr­F_ZN4core5slice8{{impl}}14as_mut_ptrE­Fas_mut_ptréF_ZN4core5slice8{{impl}}9indexEéFindex4G_ZN4core5slice8{{impl}}9indexE4GindexG_ZN4core5slice8{{impl}}9indexEGindexÊG_ZN4core5slice8{{impl}}9eqEÊGeqH_ZN4core5slice8{{impl}}9equalEHequal‹H_ZN4core5slice8{{impl}}8nextE‹HnextXI_ZN4core5slice8{{impl}}8iterEXIiter J_ZN4core5slice8{{impl}}12split_atE Jsplit_atQJ_ZN4core5slice8{{impl}}19copy_from_sliceEQJcopy_from_slice˜J_ZN4core5slice8{{impl}}49as_mut_ptrE˜Jas_mut_ptrÔJ_ZN4core5slice8{{impl}}42lenEÔJlenK_ZN4core5slice8{{impl}}45as_ptrEKas_ptrLK_ZN4core5slice8{{impl}}9indexELKindex—K_ZN4core5slice8{{impl}}17get_uncheckedE—Kget_uncheckedâK_ZN4core5slice8{{impl}}9indexEâKindex-L_ZN4core5slice8{{impl}}13index_mutE-Lindex_mutxL_ZN4core5slice8{{impl}}16split_at_mutExLsplit_at_mutçL_ZN4core5slice8{{impl}}44indexEçLindex2M_ZN4core5slice8{{impl}}44indexE2Mindex}M_ZN4core5slice8{{impl}}21get_unchecked_mutE}Mget_unchecked_mutÉM_ZN4core5slice18from_raw_partsEÉMfrom_raw_partsN_ZN4core5slice8SliceExt14is_empty<[u8]>ENis_empty<[u8]>pN_ZN4core5slice57from_raw_parts_mutEpNfrom_raw_parts_mut»N_ZN4core5slice53from_raw_partsE»Nfrom_raw_partsO_ZN4core5slice22from_raw_parts_mutEOfrom_raw_parts_mut˜O_ZN4core6marker8{{impl}}31eqE˜OeqùO_ZN4core3any8{{impl}}8of<&str>EùOof<&str>+P_ZN4core3any8{{impl}}17get_type_id<&str>E+Pget_type_id<&str>ÏP_ZN4core3ops8{{impl}}80deref>EÏPderef> Q_ZN4core3ops8{{impl}}80deref>E Qderef>lQ_ZN4core3ptr8{{impl}}42newElQnewèQ_ZN4core3ptr8{{impl}}8newEèQnewdR_ZN4core3ptr8{{impl}}7newEdRnewÇR_ZN4core3ptr8{{impl}}44derefEÇRderefS_ZN4core3ptr8{{impl}}10derefESderef?S_ZN4core3ptr8{{impl}}9derefE?Sderef|S_ZN4core3ptr44writeE|Swrite&T_ZN4core3ptr10writeE&TwritejT_ZN4core3ptr34writeEjTwrite®T_ZN4core3ptr48replaceE®TreplaceöT_ZN4core3ptr12replaceEöTreplace>U_ZN4core3ptr36replaceE>Ureplace†U_ZN4core3ptr9writeE†Uwrite€V_ZN4core7nonzero8{{impl}}51deref<*const gimli::parser::AttributeSpecification>E€Vderef<*const gimli::parser::AttributeSpecification>ÚV_ZN4core7nonzero8{{impl}}17deref<*const u64>EÚVderef<*const u64>4W_ZN4core7nonzero8{{impl}}16deref<*const u8>E4Wderef<*const u8>§W_ZN4core4cell8{{impl}}37get>E§Wget>öW_ZN4core4cell8{{impl}}32get>EöWget>0X_ZN4core4cell8{{impl}}32set>E0Xset>tX_ZN4core4cell8{{impl}}32new>EtXnew>ÁX_ZN4core4cell8{{impl}}32get>EÁXget>ýX_ZN4core4cell8{{impl}}32new>EýXnew>XY_ZN4core4cell8{{impl}}143borrow, gimli::parser::Error>>>EXYborrow, gimli::parser::Error>>>ªY_ZN4core4cell8{{impl}}147borrow_mut, gimli::parser::Error>>>EªYborrow_mut, gimli::parser::Error>>>Z_ZN4core4cell8{{impl}}10getEZgetIZ_ZN4core4cell8{{impl}}10setEIZset Z_ZN4core4cell8{{impl}}10getE ZgetïZ_ZN4core4cell8{{impl}}140get, gimli::parser::Error>>>EïZget, gimli::parser::Error>>>][_ZN4core4cell8{{impl}}3newE][newã[_ZN4core4cell8{{impl}}3newEã[new\_ZN4core4cell8{{impl}}4dropE\drop`\_ZN4core4cell8{{impl}}142deref, gimli::parser::Error>>>E`\deref, gimli::parser::Error>>>œ\_ZN4core4cell8{{impl}}34clone>Eœ\clone>Ø\_ZN4core4cell8{{impl}}4dropEØ\drop(]_ZN4core4cell8{{impl}}142deref, gimli::parser::Error>>>E(]deref, gimli::parser::Error>>>d]_ZN4core4cell8{{impl}}146deref_mut, gimli::parser::Error>>>Ed]deref_mut, gimli::parser::Error>>>¾]_ZN4core4hash3sip8{{impl}}13new_with_keysE¾]new_with_keysX^_ZN4core4hash3sip8{{impl}}43new_with_keysEX^new_with_keysÁ^_ZN4core4hash3sip8{{impl}}35resetEÁ^reset:__ZN4core4hash3sip8{{impl}}5writeE:_writeu__ZN4core4hash3sip8{{impl}}35writeEu_write²`_ZN4core4hash3sip8{{impl}}8c_roundsE²`c_roundsá`_ZN4core4hash3sip8{{impl}}6finishEá`finisha_ZN4core4hash3sip8{{impl}}36finishEafinish~a_ZN4core4hash3sip8{{impl}}8d_roundsE~ad_rounds®a_ZN4core4hash3sip11load_u64_leE®aload_u64_leb_ZN4core4hash5impls8{{impl}}48hashEbhashfb_ZN4core4hash6Hasher53write_u64Efbwrite_u64c_ZN4core4iter6traits8{{impl}}32into_iter>Ecinto_iter>Ac_ZN4core4iter6traits8{{impl}}34into_iter>EAcinto_iter>}c_ZN4core4iter6traits8{{impl}}90into_iter>E}cinto_iter>¹c_ZN4core4iter6traits8{{impl}}60into_iter>>E¹cinto_iter>>õc_ZN4core4iter6traits8{{impl}}69into_iter<&mut gimli::parser::AttrsIter>Eõcinto_iter<&mut gimli::parser::AttrsIter>1d_ZN4core4iter6traits8{{impl}}64into_iter>E1dinto_iter>md_ZN4core4iter6traits8{{impl}}101into_iter<&mut core::iter::TakeWhile, closure>>Emdinto_iter<&mut core::iter::TakeWhile, closure>>µd_ZN4core4iter5range8{{impl}}11nextEµdnexte_ZN4core4iter5range8{{impl}}7add_oneEeadd_oneOe_ZN4core4iter8iterator8Iterator39position,closure>EOeposition,closure> f_ZN4core4iter8iterator8Iterator37enumerate<&mut core::slice::Iter>E fenumerate<&mut core::slice::Iter>Hf_ZN4core4iter8iterator8Iterator67find,closure>EHffind,closure>õf_ZN4core4iter8iterator8Iterator99find, closure>,closure>Eõffind, closure>,closure>¢g_ZN4core4iter8iterator8Iterator73take_while,closure>E¢gtake_while,closure>üg_ZN4core4iter8iterator8{{impl}}27next>Eügnext>8h_ZN4core4iter8iterator8{{impl}}59next>E8hnext>th_ZN4core4iter8iterator8{{impl}}91next, closure>>Ethnext, closure>>·h_ZN4core4iter8{{impl}}32next<&mut core::slice::Iter>E·hnext<&mut core::slice::Iter>óh_ZN4core4iter8{{impl}}67next,closure>Eóhnext,closure>?i_ZN4core3mem12size_ofE?isize_ofki_ZN4core3mem12size_ofEkisize_of—i_ZN4core3mem12size_ofE—isize_ofÃi_ZN4core3mem17size_of_val<[u8]>EÃisize_of_val<[u8]>ýi_ZN4core3mem11size_ofEýisize_of)j_ZN4core3mem46size_ofE)jsize_ofUj_ZN4core3mem47align_ofEUjalign_ofj_ZN4core3mem14size_ofEjsize_of­j_ZN4core3mem11swapE­jswapk_ZN4core3mem20uninitializedEkuninitializedBk_ZN4core3mem13forgetEBkforgetxk_ZN4core3mem36size_ofExksize_of¤k_ZN4core3mem13align_ofE¤kalign_ofÐk_ZN4core3mem37align_ofEÐkalign_ofük_ZN4core3mem18uninitializedEükuninitialized)l_ZN4core3mem42uninitializedE)luninitializedVl_ZN4core3mem41replace>EVlreplace>¡l_ZN4core3mem38swap>E¡lswap> m_ZN4core3mem47uninitialized>E muninitialized>6m_ZN4core3mem40forget>E6mforget>lm_ZN4core3mem82replace>Elmreplace>·m_ZN4core3mem79swap>E·mswap>n_ZN4core3mem88uninitialized>Enuninitialized>@n_ZN4core3mem81forget>E@nforget>vn_ZN4core3mem45swapEvnswapÞn_ZN4core3mem54uninitializedEÞnuninitialized o_ZN4core3mem47forgetE oforgetAo_ZN4core3mem9swapEAoswap©o_ZN4core3mem11forgetE©oforgetßo_ZN4core3mem33swapEßoswap;p_ZN4core3mem35forgetE;pforgetqp_ZN4core3mem18replace<&mut [u8]>Eqpreplace<&mut [u8]>¼p_ZN4core3mem15swap<&mut [u8]>E¼pswap<&mut [u8]>$q_ZN4core3mem24uninitialized<&mut [u8]>E$quninitialized<&mut [u8]>Qq_ZN4core3mem17forget<&mut [u8]>EQqforget<&mut [u8]>‡q_ZN4core3mem52forget>E‡qforget>½q_ZN4core3mem144replace, gimli::parser::Error>>>E½qreplace, gimli::parser::Error>>> r_ZN4core3mem141swap, gimli::parser::Error>>>E rswap, gimli::parser::Error>>>rr_ZN4core3mem150uninitialized, gimli::parser::Error>>>Erruninitialized, gimli::parser::Error>>>Ÿr_ZN4core3mem143forget, gimli::parser::Error>>>EŸrforget, gimli::parser::Error>>>Ör_ZN4core3mem12align_ofEÖralign_of s_ZN4core5clone8{{impl}}5cloneE sclone>s_ZN4core5clone8{{impl}}11clone<[u8]>E>sclone<[u8]>xs_ZN4core5clone8{{impl}}34cloneExsclone²s_ZN4core5clone8{{impl}}66clone>E²sclone>ìs_ZN4core5clone8{{impl}}5cloneEìsclone)t_ZN4core7convert8{{impl}}26fromE)tfromct_ZN4core7convert8{{impl}}21into<&str,Box>Ectinto<&str,Box>¦t_ZN4core7convert8{{impl}}17into<&[u8],&[u8]>E¦tinto<&[u8],&[u8]>ét_ZN4core7convert8{{impl}}11from<&[u8]>Eétfrom<&[u8]>#u_ZN4core7convert8{{impl}}27fromE#ufrom]u_ZN4core7convert8{{impl}}37into<&[u8],collections::vec::Vec>E]uinto<&[u8],collections::vec::Vec>¬u_ZN4core6borrow8{{impl}}11borrowE¬uborrowòu_ZN4core3str8{{impl}}8as_bytesEòuas_bytes/v_ZN4core3num8{{impl}}5to_leE/vto_le¨v_ZN4core3num8{{impl}}12wrapping_addE¨vwrapping_adddw_ZN6leb1284read15unsigned<&[u8]>Edwunsigned<&[u8]>x_ZN6leb1284read13signed<&[u8]>Exsigned<&[u8]>çx_ZN6leb12816low_bits_of_byteEçxlow_bits_of_bytey_ZN6leb1285write19unsigned<&mut [u8]>Eyunsigned<&mut [u8]>Éy_ZN6leb1285write17signed<&mut [u8]>EÉysigned<&mut [u8]>„z_ZN6leb12815low_bits_of_u64E„zlow_bits_of_u64{_ZN3std2io5error8{{impl}}9new<&str>E{new<&str>O|_ZN3std2io5error8{{impl}}2eqEO|eqÈ|_ZN3std2io5impls8{{impl}}10read_exactEÈ|read_exact7}_ZN3std2io5impls8{{impl}}9write_allE7}write_all­}_ZN3std2io5impls8{{impl}}5writeE­}writeŠ~_ZN3std11collections4hash5table8{{impl}}50new_uninitializedEŠ~new_uninitialized~_ZN3std11collections4hash5table8{{impl}}41capacityE~capacityÃ_ZN3std11collections4hash5table8{{impl}}49rev_move_bucketsEÃrev_move_buckets)€_ZN3std11collections4hash5table8{{impl}}49first_bucket_rawE)€first_bucket_rawÑ€_ZN3std11collections4hash5table8{{impl}}37sizeEÑ€size_ZN3std11collections4hash5table8{{impl}}36newEnewH‚_ZN3std11collections4hash5table8{{impl}}39offsetEH‚offsetÄ‚_ZN3std11collections4hash5table8{{impl}}117first>EÄ‚first>ƒ_ZN3std11collections4hash5table8{{impl}}116next>Eƒnext>Œƒ_ZN3std11collections4hash5table8{{impl}}116peek>EŒƒpeek>Úƒ_ZN3std11collections4hash5table8{{impl}}115new>EÚƒnew>X„_ZN3std11collections4hash5table8{{impl}}120at_index>EX„at_index>Ê„_ZN3std11collections4hash5table8{{impl}}117index>EÊ„index>…_ZN3std11collections4hash5table8{{impl}}113index>E…index>Ë…_ZN3std11collections4hash5table8{{impl}}112peek>EË…peek>†_ZN3std11collections4hash5table8{{impl}}112next>E†next>“†_ZN3std11collections4hash5table8{{impl}}111new>E“†new>‡_ZN3std11collections4hash5table8{{impl}}116at_index>E‡at_index>.ˆ_ZN3std11collections4hash5table8{{impl}}112read>E.ˆread>|ˆ_ZN3std11collections4hash5table8{{impl}}112hash>E|ˆhash>ʈ_ZN3std11collections4hash5table8{{impl}}113index>Eʈindex>‰_ZN3std11collections4hash5table8{{impl}}120displacement>E‰displacement>…‰_ZN3std11collections4hash5table8{{impl}}112next>E…‰next>õ‰_ZN3std11collections4hash5table8{{impl}}119into_bucket>Eõ‰into_bucket>CŠ_ZN3std11collections4hash5table8{{impl}}117into_refs>ECŠinto_refs>6‹_ZN3std11collections4hash5table8{{impl}}124displacement>E6‹displacement>¥‹_ZN3std11collections4hash5table8{{impl}}116hash>E¥‹hash>ó‹_ZN3std11collections4hash5table8{{impl}}123into_bucket>Eó‹into_bucket>AŒ_ZN3std11collections4hash5table8{{impl}}37takeEAŒtakeåŒ_ZN3std11collections4hash5table8{{impl}}117index>EåŒindex>1_ZN3std11collections4hash5table8{{impl}}116read>E1read>_ZN3std11collections4hash5table8{{impl}}116next>Enext>ï_ZN3std11collections4hash5table8{{impl}}117table>Eïtable>;Ž_ZN3std11collections4hash5table8{{impl}}117stash>E;Žstash>‰Ž_ZN3std11collections4hash5table8{{impl}}125into_mut_refs>E‰Žinto_mut_refs>_ZN3std11collections4hash5table8{{impl}}123into_bucket>Einto_bucket>P_ZN3std11collections4hash5table8{{impl}}115put>EPput>ð_ZN3std11collections4hash5table8{{impl}}117table>Eðtable>¼_ZN3std11collections4hash5table8{{impl}}201displacement>>E¼displacement>>+‘_ZN3std11collections4hash5table8{{impl}}193hash>>E+‘hash>>y‘_ZN3std11collections4hash5table8{{impl}}196replace>>Ey‘replace>>+’_ZN3std11collections4hash5table8{{impl}}193next>>E+’next>>œ’_ZN3std11collections4hash5table8{{impl}}200into_bucket>>Eœ’into_bucket>>ë’_ZN3std11collections4hash5table8{{impl}}199into_table>>Eë’into_table>>8“_ZN3std11collections4hash5table8{{impl}}194index>>E8“index>>¯“_ZN3std11collections4hash5table8{{impl}}193next>>E¯“next>>)”_ZN3std11collections4hash5table8{{impl}}193peek>>E)”peek>>Ù”_ZN3std11collections4hash5table8{{impl}}192put>>EÙ”put>>ž•_ZN3std11collections4hash5table8{{impl}}37dropEž•drop‰–_ZN3std11collections4hash5table8{{impl}}37nextE‰–next-—_ZN3std11collections4hash5table8{{impl}}49borrow_table_mutE-—borrow_table_mutp—_ZN3std11collections4hash5table8{{impl}}2eqEp—eqï—_ZN3std11collections4hash5table8{{impl}}117deref>Eï—deref>;˜_ZN3std11collections4hash5table8{{impl}}128borrow_table_mut>E;˜borrow_table_mut>ˆ˜_ZN3std11collections4hash5table17calculate_offsetsEˆ˜calculate_offsets8™_ZN3std11collections4hash5table16round_up_to_nextE8™round_up_to_nextz™_ZN3std11collections4hash5table55make_hashEz™make_hashjš_ZN3std11collections4hash3map8{{impl}}85with_hasherEjšwith_hasheröš_ZN3std11collections4hash3map8{{impl}}36newEöšnew,›_ZN3std11collections4hash3map8{{impl}}79entryE,›entry‰›_ZN3std11collections4hash3map8{{impl}}81reserveE‰›reserve4œ_ZN3std11collections4hash3map8{{impl}}77lenE4œlen‚œ_ZN3std11collections4hash3map8{{impl}}80resizeE‚œresize7ž_ZN3std11collections4hash3map8{{impl}}95insert_hashed_orderedE7žinsert_hashed_orderedŸ_ZN3std11collections4hash3map8{{impl}}88search_mutEŸsearch_mut¦Ÿ_ZN3std11collections4hash3map8{{impl}}87make_hashE¦Ÿmake_hash  _ZN3std11collections4hash3map8{{impl}}81getE  getr _ZN3std11collections4hash3map8{{impl}}84searchEr search¡_ZN3std11collections4hash3map8{{impl}}3newE¡newB¡_ZN3std11collections4hash3map8{{impl}}12min_capacityEB¡min_capacity3¢_ZN3std11collections4hash3map8{{impl}}39insertE3¢insertS£_ZN3std11collections4hash3map8{{impl}}43into_entryES£into_entryޤ_ZN3std11collections4hash3map8{{impl}}128into_occupied_bucket>Eޤinto_occupied_bucket>Ä¥_ZN3std11collections4hash3map8{{impl}}81defaultEÄ¥default¦_ZN3std11collections4hash3map8{{impl}}7defaultE¦default&¦_ZN3std11collections4hash3map8{{impl}}12build_hasherE&¦build_hasherY¦_ZN3std11collections4hash3map8{{impl}}5writeEY¦write—¦_ZN3std11collections4hash3map8{{impl}}6finishE—¦finish˦_ZN3std11collections4hash3map133search_hashed,closure>E˦search_hashed,closure>î§_ZN3std11collections4hash3map43robin_hoodEî§robin_hoody©_ZN3std11collections4hash3map129search_hashed,closure>Ey©search_hashed,closure>Óª_ZN3std6thread5local8{{impl}}65with<(u64, u64),closure,std::collections::hash::map::RandomState>EÓªwith<(u64, u64),closure,std::collections::hash::map::RandomState>«_ZN3std6thread5local8{{impl}}16init<(u64, u64)>E«init<(u64, u64)> ¬_ZN3std9panicking17begin_panic<&str>E ¬begin_panic<&str>¬_ZN4core3num8{{impl}}5to_leE¬to_le¾®_ZN4core3num8{{impl}}12wrapping_subE¾®wrapping_subP°_ZN11collections3vec8{{impl}}42newEP°new}°_ZN11collections3vec8{{impl}}43pushE}°push3²_ZN11collections3vec8{{impl}}53from_raw_partsE3²from_raw_parts¬²_ZN11collections3vec8{{impl}}17with_capacityE¬²with_capacityè²_ZN11collections3vec8{{impl}}21extend_from_sliceEè²extend_from_sliceŸ³_ZN11collections3vec8{{impl}}11reserveEŸ³reserveæ³_ZN11collections3vec8{{impl}}7lenEæ³len"´_ZN11collections3vec8{{impl}}11set_lenE"´set_leni´_ZN11collections3vec8{{impl}}8pushEi´pushà´_ZN11collections3vec8{{impl}}43dropEà´dropµ_ZN11collections3vec8{{impl}}48index_mutEµindex_mutcµ_ZN11collections3vec8{{impl}}48deref_mutEcµderef_mutÀµ_ZN11collections3vec8{{impl}}44indexEÀµindex ¶_ZN11collections3vec8{{impl}}44derefE ¶derefh¶_ZN11collections3vec8{{impl}}8fromEh¶from¤¶_ZN11collections3vec8{{impl}}13deref_mutE¤¶deref_mut·_ZN11collections3vec8{{impl}}8dropE·drop9·_ZN11collections3vec8{{impl}}13index_mutE9·index_mut„·_ZN11collections3vec8{{impl}}9derefE„·derefí·_ZN11collections5slice4hack47into_vecEí·into_vec;¸_ZN11collections5slice4hack10to_vecE;¸to_vec´¸_ZN5alloc7raw_vec8{{impl}}42newE´¸new¹_ZN5alloc7raw_vec8{{impl}}69unsafe_no_drop_flag_needs_dropE¹unsafe_no_drop_flag_needs_drop<¹_ZN5alloc7raw_vec8{{impl}}42ptrE<¹ptr¬¹_ZN5alloc7raw_vec8{{impl}}45doubleE¬¹doubleW¼_ZN5alloc7raw_vec8{{impl}}53from_raw_partsEW¼from_raw_parts¾¼_ZN5alloc7raw_vec8{{impl}}17with_capacityE¾¼with_capacityš½_ZN5alloc7raw_vec8{{impl}}11reserveEš½reservee¾_ZN5alloc7raw_vec8{{impl}}22amortized_new_sizeEe¾amortized_new_size¿_ZN5alloc7raw_vec8{{impl}}7ptrE¿ptrL¿_ZN5alloc7raw_vec8{{impl}}34unsafe_no_drop_flag_needs_dropEL¿unsafe_no_drop_flag_needs_dropˆ¿_ZN5alloc7raw_vec8{{impl}}10doubleEˆ¿double”À_ZN5alloc7raw_vec8{{impl}}43dropE”ÀdropÁ_ZN5alloc7raw_vec8{{impl}}8dropEÁdrop§Á_ZN5alloc7raw_vec11alloc_guardE§Áalloc_guardÜÁ_ZN5alloc4heap15exchange_mallocEÜÁexchange_malloc;Â_ZN5alloc4heap8allocateE;ÂallocatezÂ_ZN5alloc4heap13exchange_freeEzÂexchange_freeÃÂ_ZN5alloc4heap10deallocateEÃÂdeallocate Ã_ZN5alloc4heap10reallocateE ÃreallocaterÃ_ZN4core3ptr8{{impl}}45offsetErÃoffsetØÄ_ZN4core3ptr8{{impl}}11offsetEØÄoffset-Å_ZN4core3ptr8{{impl}}11offsetE-Åoffset‚Å_ZN4core3ptr8{{impl}}35offsetE‚Åoffset7É_ZN9byteorder8{{impl}}8read_u16E7Éread_u16ŒÉ_ZN9byteorder8{{impl}}8read_u32EŒÉread_u32áÉ_ZN9byteorder8{{impl}}8read_u64EáÉread_u64qÊ_ZN4core3ptr8{{impl}}11is_nullEqÊis_null­Ê_ZN4core3ptr8{{impl}}10offsetE­ÊoffsetË_ZN11collections5slice8{{impl}}7lenEËlen>Ë_ZN11collections5slice8{{impl}}10as_ptrE>Ëas_ptrzË_ZN11collections5slice8{{impl}}14as_mut_ptrEzËas_mut_ptr¶Ë_ZN11collections5slice8{{impl}}12is_emptyE¶Ëis_emptyðË_ZN11collections5slice8{{impl}}12split_atEðËsplit_at;Ì_ZN11collections5slice8{{impl}}19copy_from_sliceE;Ìcopy_from_slice‚Ì_ZN11collections5slice8{{impl}}8iterE‚Ìiter¾Ì_ZN11collections5slice8{{impl}}16split_at_mutE¾Ìsplit_at_mut Í_ZN11collections5slice8{{impl}}10to_vecE Íto_vecEÍ_ZN11collections5slice8{{impl}}21get_unchecked_mutEEÍget_unchecked_mutÍ_ZN11collections5slice8{{impl}}17get_uncheckedEÍget_uncheckedìÍ_ZN4core3ptr8{{impl}}46is_nullEìÍis_null(Î_ZN4core3ptr8{{impl}}45offsetE(Îoffset‚Î_ZN11collections5slice8{{impl}}49as_mut_ptrE‚Îas_mut_ptr¾Î_ZN11collections5slice8{{impl}}42lenE¾ÎlenøÎ_ZN11collections5slice8{{impl}}47into_vecEøÎinto_vecžÙÚž_ZN6leb1284read8{{impl}}4fromEžfrom<_ZN5alloc4heap13exchange_freeE<exchange_free…_ZN5alloc4heap10deallocateE…deallocateŽàÛú?_ZN9byteorder8{{impl}}8read_u1610_FILE_LINEE?_FILE_LINEY_ZN9byteorder8{{impl}}8read_u1610_FILE_LINEEY_FILE_LINE|_ZN9byteorder8{{impl}}8read_u3210_FILE_LINEE|_FILE_LINE–_ZN9byteorder8{{impl}}8read_u3210_FILE_LINEE–_FILE_LINE¹_ZN9byteorder8{{impl}}8read_u6410_FILE_LINEE¹_FILE_LINEÓ_ZN9byteorder8{{impl}}8read_u6410_FILE_LINEEÓ_FILE_LINE ÚÝM’/je_opt_abortLje_opt_junksje_opt_junk_alloc‰je_opt_junk_freeŸje_opt_quarantineÒje_opt_redzoneèje_opt_utraceþje_opt_xmallocje_opt_zero*je_opt_narenasGje_index2size_tabuje_size2index_tab¯config_profÀje_malloc_confÖje_ncpusìarenas_lockAje_arenasqnarenas_total†narenas_auto›large_pad©tsd_initializerŒmalloc_slow_flags¡a0¶malloc_init_stateóinit_lockconfig_xmallocmalloc_slow)je_a0malloc`a0iallocEje_a0dallocz a0idallocÎ$je_narenas_total_getÇ%je_arena_init(je_arena_migrateg*je_arena_tdata_get_hardQ-je_arena_choose_hard5je_thread_allocated_cleanup15je_thread_deallocated_cleanup‹5je_arena_cleanup{6je_arenas_tdata_cleanup 7je_narenas_tdata_cleanupK7je_arenas_tdata_bypass_cleanup²Bje_mallocxq[je_rallocx¼kje_sdallocx[sje_mallctlËwje_mallctlnametomib?|je_mallctlbymib¿€jemalloc_constructorw‡malloc_init_hard_a0_lockednstats_print_atexit'p‚ù+je_opt_purgecje_purge_mode_namesje_opt_lg_dirty_multÐje_opt_decay_timeælarge_padlg_dirty_mult_default+decay_time_default@je_arena_bin_infoje_map_bias1je_map_misc_offsetGje_arena_maxrun]je_large_maxclasssje_run_quantize_max‰nlclassesŸnhclassesµruns_avail_biasÕruns_avail_nclassesêsmall_run_tab small_maxrun run_quantize_ceil_tab:run_quantize_floor_tabOconfig_prof6je_arena_chunk_cache_maybe_insert"je_arena_chunk_cache_maybe_removeñje_arena_node_alloc¨je_arena_node_dallocñje_arena_chunk_alloc_hugewje_arena_chunk_dalloc_huge¸ je_arena_chunk_ralloc_huge_similarÚ"arena_huge_ralloc_stats_update®$je_arena_chunk_ralloc_huge_shrink'je_arena_chunk_ralloc_huge_expand˜+je_arena_lg_dirty_mult_geta,je_arena_lg_dirty_mult_setw-je_arena_maybe_purgeç-je_arena_decay_time_get–.je_arena_decay_time_set¿0arena_maybe_purge_decayÏ1je_arena_purge#8arena_purge_to_limit‘Cje_arena_tcache_fill_small-Jarena_bin_malloc_hardœRje_arena_alloc_junk_smallÑSje_arena_dalloc_junk_smallUje_arena_quarantine_junk_small¼Wje_arena_malloc_largeb\je_arena_malloc_hardfje_arena_palloc5zje_arena_dalloc_bin_junked_locked`|arena_dalloc_bin_locked_implÊje_arena_dalloc_smallú„je_arena_dalloc_junk_large"…je_arena_dalloc_large_junked_locked…arena_dalloc_large_locked_impl¾‡je_arena_dalloc_largeŠje_arena_ralloc_no_movee§je_arena_ralloc÷²je_arena_dss_prec_geth³je_arena_dss_prec_set§³je_arena_lg_dirty_mult_default_getI´je_arena_lg_dirty_mult_default_set¥´je_arena_decay_time_default_getµje_arena_decay_time_default_setd¶je_arena_stats_mergeð¸je_arena_nthreads_getV¹je_arena_nthreads_incï¹je_arena_nthreads_decºje_arena_newF¿je_arena_bootuÆbin_info_run_size_calcÊarena_run_dallocÔØarena_avail_insert·Úarena_avail_removeßÜarena_run_tree_removecßarena_run_tree_insert‡áarena_run_split_large_helperÒåarena_run_split_removeçêarena_run_alloc_large_helperðarena_chunk_alloc öarena_run_split_smalldøarena_decay_deadline_init¬©i8/base_mtx„base_avail_szadçbase_nodesübase_allocatedbase_resident&base_mappedje_base_allocje_base_stats_getje_base_boot9á‚a/je_bitmap_info_initåje_bitmap_init¬B„â=/je_opt_dssVje_opt_lg_chunk‰je_chunk_hooks_defaultTje_chunks_rtreewje_chunksizeje_chunksize_mask£je_chunk_npagesÝchunk_alloc_default chunk_dalloc_defaulthchunk_commit_defaultÖchunk_decommit_default„chunk_purge_defaultžchunk_split_defaultchunk_merge_defaultÑje_chunk_hooks_get‰je_chunk_hooks_setSje_chunk_registerp"je_chunk_deregister¥%je_chunk_alloc_base&je_chunk_alloc_cacheX)chunk_recycle1je_chunk_alloc_wrapperÎ2je_chunk_dalloc_cacheÃ3chunk_recordœ9je_chunk_dalloc_arenaö:je_chunk_dalloc_wrapper@<je_chunk_purge_wrapperk=je_chunk_boot‹=chunks_rtree_node_allocX$Âï+je_dss_prec_names‚je_chunk_dss_prec_get­je_chunk_dss_prec_setQÃû/config_munmapÒje_chunk_alloc_mmapÀje_chunk_dalloc_mmap Åʾ/ctl_mtx‹super_root_node®root_nodeÐstats_nodeòstats_arenas_nodeisuper_stats_arenas_i_nodestats_arenas_i_node¡stats_arenas_i_hchunks_node·super_stats_arenas_i_hchunks_j_nodeÍstats_arenas_i_hchunks_j_nodeïstats_arenas_i_lruns_nodesuper_stats_arenas_i_lruns_j_nodestats_arenas_i_lruns_j_node1stats_arenas_i_bins_nodeGsuper_stats_arenas_i_bins_j_node]stats_arenas_i_bins_j_nodestats_arenas_i_huge_node•stats_arenas_i_large_node«stats_arenas_i_small_nodeÁstats_arenas_i_metadata_nodeprof_node3arenas_nodeUarenas_hchunk_nodeksuper_arenas_hchunk_i_nodearenas_hchunk_i_node—arenas_lrun_node­super_arenas_lrun_i_nodeÃarenas_lrun_i_nodeÙarenas_bin_nodeïsuper_arenas_bin_i_nodearenas_bin_i_node'arena_node=super_arena_i_nodeSarena_i_nodeutcache_node‹tsd_initializerBopt_nodedconfig_nodeyconfig_xmallocŠconfig_valgrind–config_utrace¢config_tls®config_tcacheºconfig_statsÆconfig_prof_libunwindÒconfig_prof_libgccÞconfig_profêconfig_munmapöconfig_lazy_lockconfig_fillconfig_debugconfig_cache_oblivious&thread_node;thread_prof_nodePthread_tcache_nodeectl_epoch“je_ctl_byname»ctl_initóctl_lookupje_ctl_nametomibúje_ctl_bymibwje_ctl_boot—version_ctlŠ epoch_ctlÃ!stats_cactive_ctl#stats_allocated_ctl=$stats_active_ctlz%stats_metadata_ctl·&stats_resident_ctlô'stats_mapped_ctl1)stats_arenas_i_indexÍ)stats_arenas_i_nthreads_ctl +stats_arenas_i_dss_ctlG,stats_arenas_i_lg_dirty_mult_ctl„-stats_arenas_i_decay_time_ctlÁ.stats_arenas_i_pactive_ctlþ/stats_arenas_i_pdirty_ctl;1stats_arenas_i_mapped_ctlx2stats_arenas_i_npurge_ctlµ3stats_arenas_i_nmadvise_ctlò4stats_arenas_i_purged_ctl/6stats_arenas_i_hchunks_j_indexy6stats_arenas_i_hchunks_j_nmalloc_ctl¶7stats_arenas_i_hchunks_j_ndalloc_ctló8stats_arenas_i_hchunks_j_nrequests_ctl0:stats_arenas_i_hchunks_j_curhchunks_ctlm;stats_arenas_i_lruns_j_index·;stats_arenas_i_lruns_j_nmalloc_ctlô<stats_arenas_i_lruns_j_ndalloc_ctl1>stats_arenas_i_lruns_j_nrequests_ctln?stats_arenas_i_lruns_j_curruns_ctl«@stats_arenas_i_bins_j_indexõ@stats_arenas_i_bins_j_nmalloc_ctl2Bstats_arenas_i_bins_j_ndalloc_ctloCstats_arenas_i_bins_j_nrequests_ctl¬Dstats_arenas_i_bins_j_curregs_ctléEstats_arenas_i_bins_j_nfills_ctl&Gstats_arenas_i_bins_j_nflushes_ctlcHstats_arenas_i_bins_j_nruns_ctl Istats_arenas_i_bins_j_nreruns_ctlÝJstats_arenas_i_bins_j_curruns_ctlLstats_arenas_i_huge_allocated_ctlWMstats_arenas_i_huge_nmalloc_ctl”Nstats_arenas_i_huge_ndalloc_ctlÑOstats_arenas_i_huge_nrequests_ctlQstats_arenas_i_large_allocated_ctlKRstats_arenas_i_large_nmalloc_ctlˆSstats_arenas_i_large_ndalloc_ctlÅTstats_arenas_i_large_nrequests_ctlVstats_arenas_i_small_allocated_ctl?Wstats_arenas_i_small_nmalloc_ctl|Xstats_arenas_i_small_ndalloc_ctl¹Ystats_arenas_i_small_nrequests_ctlöZstats_arenas_i_metadata_mapped_ctl3\stats_arenas_i_metadata_allocated_ctlp]prof_thread_active_init_ctlü]prof_active_ctlˆ^prof_dump_ctl_prof_gdump_ctl _prof_reset_ctl8`prof_interval_ctlÄ`lg_prof_sample_ctlPaarenas_narenas_ctl,barenas_initialized_ctlcarenas_lg_dirty_mult_ctlúcarenas_decay_time_ctlàdarenas_quantum_ctlÔearenas_page_ctlÉfarenas_tcache_max_ctlÀgarenas_nbins_ctl´harenas_nhbins_ctl«iarenas_nlruns_ctl¢jarenas_nhchunks_ctlÂkarenas_extend_ctl marenas_hchunk_i_index˜marenas_hchunk_i_size_ctlÜnarenas_lrun_i_index&oarenas_lrun_i_size_ctlXparenas_bin_i_index¢parenas_bin_i_size_ctl™qarenas_bin_i_nregs_ctlrarenas_bin_i_run_size_ctl‡sarena_i_index%tarena_i_purge_ctlªtarena_i_decay_ctl½uarena_i_dss_ctlÿwarena_i_lg_dirty_mult_ctlvyarena_i_decay_time_ctlízarena_i_chunk_hooks_ctl÷|arena_i_purgeÄ€tcache_create_ctl!ƒtcache_flush_ctlÜ„tcache_destroy_ctl—†opt_abort_ctlЇopt_dss_ctlˆopt_lg_chunk_ctlx‰opt_narenas_ctloŠopt_purge_ctlf‹opt_lg_dirty_mult_ctl]Œopt_decay_time_ctlTopt_stats_print_ctlGŽopt_junk_ctl>opt_zero_ctl1opt_quarantine_ctl(‘opt_redzone_ctl’opt_utrace_ctl§’opt_xmalloc_ctl3“opt_tcache_ctl&”opt_lg_tcache_max_ctl•opt_prof_ctl©•opt_prof_prefix_ctl5–opt_prof_active_ctlÁ–opt_prof_thread_active_init_ctlM—opt_lg_prof_sample_ctlÙ—opt_lg_prof_interval_ctle˜opt_prof_gdump_ctlñ˜opt_prof_final_ctl}™opt_prof_leak_ctl šopt_prof_accum_ctl•šconfig_cache_oblivious_ctlˆ›config_debug_ctl{œconfig_fill_ctlnconfig_lazy_lock_ctlažconfig_malloc_conf_ctlTŸconfig_munmap_ctlG config_prof_ctl:¡config_prof_libgcc_ctl-¢config_prof_libunwind_ctl £config_stats_ctl¤config_tcache_ctl¥config_tls_ctlù¥config_utrace_ctlì¦config_valgrind_ctlß§config_xmalloc_ctl©thread_arena_ctlK¬thread_allocated_ctlo®thread_allocatedp_ctl°thread_deallocated_ctl´²thread_deallocatedp_ctlÕ´thread_prof_name_ctlUµthread_prof_active_ctlS¶thread_tcache_enabled_ctlºthread_tcache_flush_ctlW¼ctl_refresh2؃-#ije_extent_tree_szad_newªje_extent_tree_szad_nsearchÖje_extent_tree_szad_insertjje_extent_tree_szad_remove‹je_extent_tree_ad_newîje_extent_tree_ad_prev›je_extent_tree_ad_search je_extent_tree_ad_nsearchŽje_extent_tree_ad_insertq je_extent_tree_ad_removeا-g/config_profGlarge_padåje_huge_malloc% je_huge_pallocÒ:je_huge_ralloc_no_moveNhuge_ralloc_no_move_expandmQje_huge_aallocWUje_huge_rallocYje_huge_dallocRdje_huge_salloc92Ô/je_malloc_mutex_init´je_mutex_bootð·/je_nstime_initeje_nstime_init2¨je_nstime_nsÕje_nstime_copyûje_nstime_compare!je_nstime_addWje_nstime_subtractje_nstime_imultiplyÅje_nstime_idivideûje_nstime_divideÆje_nstime_update½Æ­je_pages_mapVje_pages_unmap¬je_pages_trimøje_pages_commit2je_pages_decommitlje_pages_purgeFƒâconfig_prof’large_padªje_prof_tdata_cleanup§e)Š9/config_profGlarge_pad°je_quarantine_alloc_hook_work€!quarantine_initõ(je_quarantine†2je_quarantine_cleanupl8quarantine_drain_one[ïb”je_rtree_newOje_rtree_subtree_read_hard¶je_rtree_child_read_hardc zé/je_opt_stats_printLje_stats_cactiveje_stats_printa stats_arena_print~ó‘ö9/je_opt_tcacheLje_opt_lg_tcache_maxje_tcache_bin_infoÃstack_nelmsØje_nhbinsîje_tcache_maxclass!je_tcachesïtcaches_pasttcaches_availconfig_prof*large_pad=tsd_initializeržje_tcache_event_hard?je_tcache_bin_flush_small’je_tcache_bin_flush_largeäje_tcache_alloc_small_hard©je_tcache_arena_reassociateàje_tcache_arena_dissociateØje_tcache_stats_merge "je_tcache_get_hardÌ(je_tcache_create40je_tcache_cleanup°1tcache_destroy6je_tcache_enabled_cleanup¸6je_tcaches_create¾7je_tcaches_flush8je_tcaches_destroy&9je_tcache_boot)éËr"+je_tsd_init_headëtsd_boot_wrapper1je_tsd_bootedGncleanups\je_tsd_tsdˆtsd_initializer£je_malloc_tsd_malloc×je_tsd_cleanup­je_malloc_tsd_boot0Þje_malloc_tsd_boot1!je_tsd_init_check_recursion¨!je_tsd_init_finish"je_tsd_cleanup_wrapperÉ[î%/je_malloc_message›je_malloc_writeùwrtmessage(je_buferrorje_malloc_strtoumax™je_malloc_vsnprintf je_malloc_snprintf¨je_malloc_cprintf9je_malloc_printfgimli-0.19.0/fixtures/self/debug_pubtypes010066400017500001750000001473701343337721300167150ustar0000000000000000ÊxÙ9&Error™&Format±&AbbreviationTag9(AbbreviationHasChildrenQ(AttributeNameÄ*AttributeFormf+AttributeValueÀ+LittleEndianÆ+DebugTypesOffsetÙ+DebugStrOffsetì+DebugAbbrevOffsetÿ+DebugInfoOffset,UnitOffset%,DebugInfo®,EndianBuf–-CompilationUnitsIter©-CompilationUnit1FormatInputo1AttributeSpecification2AbbreviationB3Abbreviations4AttributeValueŒ4Addr«4BlockÊ4Dataé4Sdata5Udata'5ExprlocF5Flage5SecOffset„5UnitRef£5DebugInfoRefÂ5DebugTypesRefá5DebugStrRef6String6Attribute¤6AttributeInput8DebuggingInformationEntryƒ8AttrsIter®8DebugAbbrev79EntriesCursor.<TypeUnitZÝ&[&str]yÝ*const &str‚Ý&str¡Ý*const u82Þu89Þusizeá(&str, u32)'áu32¨á&[core::fmt::rt::v1::Argument]Çá*const core::fmt::rt::v1::ArgumentäáArgumentâPositionâNext-âPositionEâAtdâFormatSpec§âAlignmentËâCountòâIsãCount5ãParamTãNextParamgãImplied|ãError‚ãFormatterÃä&mut WriteÉäArgumentV1ÈìVoidÓìDebugTuple íDebugStruct5íDebugList|îDebugInner§îDebugMapfïArguments­ResultÅResultÝResult<(), core::fmt::Error>ôOkErr2Result<(&[u8], u8), gimli::parser::Error>Ok¼ErrÛResult, gimli::parser::Error>‹OkªErrÉResult<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>àOkÿErrResult<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>5OkTErrsResult<(gimli::parser::EndianBuf, u64), gimli::parser::Error>0 OkO Errn Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>/ OkN Errm Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>„ Ok£ Err Result<(&[u8], u64), gimli::parser::Error>- OkL Errk Result‚ Ok¡ ErrÀ Result<(), std::io::error::Error>× Okö ErrResult<(&[u8], i64), gimli::parser::Error>ÖOkõErrResult+OkJErriResult<(&[u8], gimli::parser::AbbreviationTag), gimli::parser::Error>€OkŸErr¾Result<(&[u8], gimli::parser::AbbreviationHasChildren), gimli::parser::Error>ÕOkôErrResult<(&[u8], gimli::parser::AttributeName), gimli::parser::Error>*OkIErrhResult<(&[u8], gimli::parser::AttributeForm), gimli::parser::Error>OkžErr½Result<(&[u8], gimli::parser::AttributeSpecification), gimli::parser::Error>~OkErr¼Result<(&[u8], ()), gimli::parser::Error>%OkDErrcResult<(&[u8], collections::vec::Vec), gimli::parser::Error>zOk™Err¸Result<(&[u8], core::option::Option), gimli::parser::Error>yOk˜Err·Result<(&[u8], gimli::parser::Abbreviation), gimli::parser::Error>nOkErr¬Result<(), ()>ÃOkâErrResult<(&[u8], gimli::parser::Abbreviations), gimli::parser::Error>¸Ok×ErröResult<(&[u8], core::option::Option), gimli::parser::Error>¹OkØErr÷Result<(&[u8], &[u8]), gimli::parser::Error>²OkÑErrðResult<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>Ok&ErrEResult<(gimli::parser::EndianBuf, &[u8]), gimli::parser::Error>° OkÏ Errî Result<(gimli::parser::EndianBuf, u32), gimli::parser::Error>­#OkÌ#Errë#Result™$Ok¸$Err×$ResultT&Oks&Err’&ResultB'Oka'Err€'Result, gimli::parser::Error>v(Ok•(Err´(Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>Ë(Okê(Err )Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error> )Ok?)Err 4Option$4Option<4OptionT4Option45NoneG5Somef5Option, gimli::parser::Error>>_6Noner6Some‘6Option<&[core::fmt::rt::v1::Argument]>¤6Some·6Option<&u8>H7Some[7Optionr7None…7Some¤7Option<(u64, gimli::parser::Abbreviation)>·7SomeÊ7Option<&core::cell::UnsafeCell>>I8Some\8Option<(u64, u64)>Í8Noneà8Someÿ8Option<&(u64, u64)>o9Some‚9Option™9None¬9SomeË9Option>R:Nonee:Some„:Option<&gimli::parser::Abbreviation>—:Someª:Option>><;SomeO;Optionb;Someu;Option<(usize, &u8)>ˆ;Some›;Option<&[u8]><Some¢<Option>>None,>SomeK>Option, gimli::parser::Error>>F?NoneY?Somex?Option‹?Somež?Option±?SomeÄ?Option»@NoneÎ@Someí@Option<()>¿ANoneÒASome¯EIterÚEIterFIterWOPhantomData<&core::fmt::ArgumentV1>]OPhantomDatacOPhantomData<&u8>iOPhantomDataoOPhantomData<&gimli::parser::AttributeSpecification>uOPhantomData{OPhantomData<(u64, gimli::parser::Abbreviation)>OPhantomData<&()>‡OPhantomDataOPhantomDataçOTypeIdlPRangeFromPRangežPRangeTo±PRangeFull·PRangeFromNQUniqueÊQUniqueFRUniqueÐUNonZero<*const gimli::parser::AttributeSpecification> VNonZero<*const u64>BVNonZero<*const u8>•WUnsafeCell>äWCell>¯XUnsafeCell>:YRefCell, gimli::parser::Error>>>ýYCellŽZUnsafeCellÝZUnsafeCell, gimli::parser::Error>>>,[Ref, gimli::parser::Error>>>K[BorrowRef²[RefMut, gimli::parser::Error>>>Ñ[BorrowRefMut¬]SipHasher13þ]Hasherø^State/_Sip13Rounds±bEnumerate<&mut core::slice::Iter>ÐbTakeWhile, closure>(vu64ëvcharòvi8wErrorwError2wIoErrorQwOverflowåzReprýzErrorKind{{ErrorÖ{Reprí{Os |Custom+|Custom<~BucketStateT~RawTableÛRevMoveBuckets‚RawBucketš‚Bucket>…Bucket>„‡BucketState>›‡Emptyº‡EmptyBucket>å‡FullˆFullBucket>’ŠSafeHashŠIteráŠRawBuckets ‹FullBucket>ØŽEmptyBucket>=BucketState>TEmptysFull’FullBucket>>…“Bucket>>y”BucketState>>”Empty¯”EmptyBucket>>z•Fullò™Entry šVacantEntryState"šInternalEntry@šHashMapú RandomState<¡DefaultResizePolicy‚¡Iter•¡Entry¬¡OccupiedË¡OccupiedEntryê¡Vacant ¢VacantEntryÔ¢VacantEntryState>ë¢NeqElem£NoElem5£InternalEntry>¤Occupied¤VacantJ¤TableIsEmpty]¤DefaultHasherp¤InternalEntry>¥Occupied ¥VacantK¥VacantEntryState>b¥NeqElem¥NoElem¬¥TableIsEmpty¤ªBoxµªLocalKey<(u64, u64)>z¬u16û¬()­*const core::fmt::ArgumentV1 ­&core::fmt::Void­fn(&core::fmt::Void, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>-­&mut core::fmt::Formatter6­&[core::fmt::ArgumentV1]U­&[u8]t­&mut [u8]“­boolš­(&[u8], u8)¹­(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)Ø­(gimli::parser::EndianBuf, (u64, gimli::parser::Format))÷­(u64, gimli::parser::Format)®(gimli::parser::EndianBuf, u64)5®(gimli::parser::EndianBuf, u16)T®(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)s®closure†®&gimli::parser::FormatInput®&u8˜®(&[u8], u64)·®i32¯Box ¯(&[u8], &[u8]))¯(&[u8], i64)H¯i64O¯(&[u8], gimli::parser::AbbreviationTag)n¯(&[u8], gimli::parser::AbbreviationHasChildren)¯(&[u8], gimli::parser::AttributeName)¬¯(&[u8], gimli::parser::AttributeForm)˯(&[u8], gimli::parser::AttributeSpecification)ê¯(&[u8], ()) °(&[u8], collections::vec::Vec)2°Vec޲Vec–¸RawVec ¼RawVeciÃ*const gimli::parser::AttributeSpecificationêÃ(&[u8], core::option::Option) ÄclosureÄ&mut [gimli::parser::AttributeSpecification].ÄclosureAÄ&&[u8]JÄ&[gimli::parser::AttributeSpecification]iÄ(usize, bool)ˆÄ(usize, usize)§Ä&gimli::parser::AttributeSpecification°Ä(&[u8], gimli::parser::Abbreviation)ÏÄ*const u64$Å*mut u64yÅ*const gimli::parser::AbbreviationÎÅ(usize, usize, bool)ùÅ(u64, gimli::parser::Abbreviation)Æ&mut std::collections::hash::table::RawTable!Æ&std::collections::hash::table::RawTable*Æ(&u64, &gimli::parser::Abbreviation)IÆ&u64RÆ&gimli::parser::Abbreviation[Æfn() -> core::option::Option<&core::cell::UnsafeCell>>iÆ&core::cell::UnsafeCell>rÆ(u64, u64)‘Æfn() -> (u64, u64)ŸÆ&(u64, u64)¨Æ(std::collections::hash::table::EmptyBucket>, u64, gimli::parser::Abbreviation)ÓÆclosureæÆ&&u64ïÆ(std::collections::hash::table::SafeHash, u64, gimli::parser::Abbreviation)Ç(&mut u64, &mut gimli::parser::Abbreviation)9Ç&mut u64BÇ&mut gimli::parser::AbbreviationKÇ(&[u8], gimli::parser::Abbreviations)jÇ(&[u8], core::option::Option)‰Ç&gimli::parser::CompilationUnit’Ç(gimli::parser::AttributeInput, gimli::parser::Attribute)±ÇclosureÄÇ&gimli::parser::AttributeInputÍÇ(gimli::parser::EndianBuf, &[u8])ìÇ(gimli::parser::EndianBuf, u32) È&mut core::slice::IterÈ(usize, &u8)3ÈclosureFÈ&mut &mut core::iter::Enumerate<&mut core::slice::Iter>OÈ&mut core::iter::Enumerate<&mut core::slice::Iter>XÈ(&mut [u8], &mut [u8])wÈBox<[gimli::parser::AttributeSpecification]>–È&gimli::parser::DebuggingInformationEntryŸÈ&gimli::parser::Abbreviations¨È&core::option::Option, gimli::parser::Error>>±È&core::cell::CellºÈ&mut core::option::Option, gimli::parser::Error>>ÃÈisizeÊÈclosureÝÈ&mut &mut core::iter::TakeWhile, closure>æÈ&mut core::iter::TakeWhile, closure>ïÈ(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)É(gimli::parser::EndianBuf, gimli::parser::TypeUnit)8ÊBox<&str>hÊ*mut u8ÜÍsizetypeãÍ*mut gimli::parser::AttributeSpecificationtÎ&alloc::raw_vec::RawVec5Ï&std::collections::hash::table::SafeHashcÏ&alloc::raw_vec::RawVeclÏ!sÏ&mut core::fmt::builders::DebugList|Ï&*mut gimli::parser::AttributeSpecification…Ï&*const gimli::parser::AttributeSpecificationŽÏ&*mut u64—Ï&*const u64 Ï*mut core::option::Option<(u64, u64)>©Ï&mut core::fmt::builders::DebugMap²Ï&&mut std::collections::hash::table::RawTable»Ï&usizeÄÏ&gimli::parser::FormatÍÏ&u16ÖÏ&gimli::parser::EndianBufßÏ&gimli::parser::DebugAbbrevOffsetèÏ&gimli::parser::AttributeñÏ*mut core::option::Option<&[u8]>úÏ*mut usizeÐ*mut core::option::Option, gimli::parser::Error>> Ð&mut gimli::parser::AttrsIterÐ&*mut u8Ð&*const u8'Ð&mut u80Ð&gimli::parser::AttributeValue9Ð&isizeBÐ&gimli::parser::DebugTypesOffsetKÐ&gimli::parser::TypeUnitTÐ&(&str, u32)]Ð&&strÐ&gimli::parser::Error–Ð&gimli::parser::DebugStrOffsetŸÐ&gimli::parser::DebugInfoOffset¨Ð&gimli::parser::UnitOffset¾Ð&&gimli::parser::CompilationUnitÇÐ&core::option::Option, gimli::parser::Error>>ÐÐ&gimli::parser::DebugInfoÙÐ&mut gimli::parser::CompilationUnitsIterâÐ&core::marker::PhantomDataëÐfn(&&gimli::parser::CompilationUnit, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>Ñ&&u16 Ñ&&gimli::parser::DebugAbbrevOffsetÑ&&u8Ñ&&gimli::parser::Format(Ñ&&gimli::parser::EndianBuf1Ñ&&&[u8]:Ñ&&core::marker::PhantomDataCÑfn(&core::option::Option, gimli::parser::Error>>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>\Ñ&core::result::Result, gimli::parser::Error>eÑ&&core::result::Result, gimli::parser::Error>nÑ&&gimli::parser::ErrorwÑ&std::io::error::Error€Ñ&mut &[u8]–Ñ&std::io::error::ErrorKindŸÑ&gimli::parser::AttributeName¨Ñ&gimli::parser::AttributeForm±Ñ&&gimli::parser::AttributeNameºÑ&&gimli::parser::AttributeFormÃÑ&mut collections::vec::VecÌÑ&core::ptr::UniqueÕÑ&core::nonzero::NonZero<*const gimli::parser::AttributeSpecification>ÞÑ&mut alloc::raw_vec::RawVecçÑ&collections::vec::VecðÑ&mut core::ops::RangeùÑ&mut usizeÒ&&gimli::parser::AttributeSpecification Ò&std::collections::hash::map::HashMapÒ&std::collections::hash::map::DefaultResizePolicyÒ&std::collections::hash::map::RandomState&Ò&core::ptr::Unique/Ò&core::nonzero::NonZero<*const u64>8Ò&mut std::collections::hash::table::RevMoveBucketsAÒ&&std::collections::hash::table::RawTableJÒ&std::collections::hash::table::Bucket>SÒ&std::collections::hash::table::FullBucket>\Ò*mut gimli::parser::AbbreviationeÒ&mut std::collections::hash::table::Bucket>nÒ&mut std::collections::hash::table::Bucket>wÒ&std::thread::local::LocalKey<(u64, u64)>€Ò&mut core::option::Option<(u64, u64)>‰Ò&core::option::Option<(u64, u64)>’Ò&&gimli::parser::Abbreviation›Ò&mut gimli::parser::Abbreviations¤Ò&mut std::collections::hash::map::HashMap­Ò&&usize¶Ò&std::collections::hash::table::FullBucket>¿Ò&std::collections::hash::table::Bucket>ÈÒ&mut &mut std::collections::hash::table::RawTableÑÒ&std::collections::hash::table::EmptyBucket>ÚÒfn(&&usize, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>óÒ&mut core::hash::sip::HasherüÒ&mut std::collections::hash::map::DefaultHasherÓ&mut core::hash::sip::SipHasher13Ó&mut core::hash::sip::StateÓ&std::collections::hash::map::DefaultHasher Ó&core::hash::sip::SipHasher13)Ó&core::hash::sip::Hasher2Ó&std::collections::hash::table::FullBucket>>;Ó&mut std::collections::hash::table::FullBucket>>DÓ*mut std::collections::hash::table::SafeHashMÓ&mut std::collections::hash::table::SafeHashVÓ&mut std::collections::hash::table::Bucket>>_Ó&mut std::collections::hash::table::FullBucket>hÓ&core::result::Result<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>qÓfn(&&gimli::parser::Format, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ŠÓfn(&&u64, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>£Ófn(&core::result::Result<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>¼Ó&(gimli::parser::EndianBuf, (u64, gimli::parser::Format))ÅÓ&&(gimli::parser::EndianBuf, (u64, gimli::parser::Format))ÎÓ&(u64, gimli::parser::Format)ñÓ&core::result::Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>úÓfn(&&u16, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>Ôfn(&&gimli::parser::EndianBuf, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>,Ôfn(&core::result::Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>EÔ&(gimli::parser::EndianBuf, u16)NÔ&&(gimli::parser::EndianBuf, u16)WÔ&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>`Ôfn(&&gimli::parser::DebugAbbrevOffset, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>yÔfn(&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>’Ô&(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)›Ô&&(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)¤Ô&core::result::Result<(&[u8], u8), gimli::parser::Error>­Ôfn(&&u8, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÆÔfn(&core::result::Result<(&[u8], u8), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ßÔ&(&[u8], u8)èÔ&&(&[u8], u8)þÔ&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>Õfn(&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> Õ&(gimli::parser::EndianBuf, gimli::parser::CompilationUnit))Õ&&(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)?Õ&i64HÕ&boolQÕ&&i64ZÕ&&boolcÕ&&gimli::parser::UnitOffsetlÕ&&gimli::parser::DebugInfoOffsetuÕ&&gimli::parser::DebugTypesOffset~Õ&&gimli::parser::DebugStrOffset‡Õ&&gimli::parser::AttributeValueÕ&&gimli::parser::Attribute™Õ&core::result::Result<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>¢Õ&mut &mut core::slice::Iter«Õfn(&&gimli::parser::Attribute, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÄÕfn(&core::result::Result<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÝÕ&(gimli::parser::AttributeInput, gimli::parser::Attribute)æÕ&&(gimli::parser::AttributeInput, gimli::parser::Attribute)ïÕ&&&gimli::parser::CompilationUnitÖfn(&&str, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>+Öfn(&std::io::error::Error, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>DÖ&mut &mut [u8]gÖ&core::option::Option>pÖ&core::cell::Cell>yÖ&core::cell::UnsafeCell>‚Öfn(&core::option::Option>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>›Ö&core::result::Result¤Ö&&core::result::Result­Ö&core::option::Option<&[u8]>¶Öfn(&&&[u8], &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÏÖ&[u8; 8]ØÖ&[u8; 71]îÖ&&isize÷Öfn(&gimli::parser::Error, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>×&gimli::parser::DebugAbbrev×&mut gimli::parser::EntriesCursor"×&core::result::Result, gimli::parser::Error>+×&core::cell::RefCell, gimli::parser::Error>>>4×&core::cell::UnsafeCell=×&core::cell::UnsafeCell, gimli::parser::Error>>>F×&mut core::cell::BorrowRefO×&core::cell::Ref, gimli::parser::Error>>>X×&mut core::cell::BorrowRefMuta×&core::cell::RefMut, gimli::parser::Error>>>j×&mut core::cell::RefMut, gimli::parser::Error>>>s×&mut &mut gimli::parser::AttrsIter|×&mut collections::vec::Vec…×&mut alloc::raw_vec::RawVecŽ×&core::ptr::Unique—×&core::nonzero::NonZero<*const u8> ×&collections::vec::Vec©×fn(&&gimli::parser::AttributeValue, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>Â×fn(&&isize, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>Û×&core::option::Optionä×&core::option::Option<()>ú×&core::result::Result<(gimli::parser::EndianBuf, u64), gimli::parser::Error>Øfn(&core::result::Result<(gimli::parser::EndianBuf, u64), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>Ø&(gimli::parser::EndianBuf, u64)%Ø&&(gimli::parser::EndianBuf, u64)HØ&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>QØfn(&&gimli::parser::DebugTypesOffset, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>jØfn(&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ƒØ&(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)ŒØ&&(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)¯Ø&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error>¸Ø&&gimli::parser::TypeUnitÁØfn(&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÚØ&(gimli::parser::EndianBuf, gimli::parser::TypeUnit)ãØ&&(gimli::parser::EndianBuf, gimli::parser::TypeUnit)ìØfn(&&gimli::parser::TypeUnit, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>ÞÙÚ6ErrorNErroreIoError„OverflowÒu8Ùusizeàu64öReprErrorKindŒErrorŸRepr¶OsÕCustomôCustomBox"i32)BoxÐ*mut u8XàÛúð(&str, u32)&str.*const u8su8zusizeu32òisizesÚÝM’E_Boollcharµsize_tÀ__darwin_size_tËlong unsigned int@unsigned intnsizetypeuint8_t¨unsigned charmalloc_mutex_t malloc_mutex_s#OSSpinLock/int32_t:intaarena_tlarena_sâarena_stats_tíarena_stats_sÈuint64_tÓlong long unsigned intßmalloc_large_stats_têmalloc_large_stats_s0malloc_huge_stats_t;malloc_huge_stats_sstcache_t~tcache_sîticker_tùticker_sszind_t5tcache_bin_t@tcache_bin_stcache_bin_stats_tštcache_bin_stats_s·dss_prec_täarena_chunk_tïarena_chunk_sextent_node_textent_node_sh prof_tctx_ts prof_tctx_s. prof_tdata_t9 prof_tdata_sq ckh_t| ckh_sì ckh_hash_t ckh_keycomp_t5 ckhc_t@ ckhc_se prof_cnt_tp prof_cnt_s prof_gctx_tÍ prof_gctx_sY prof_tctx_tree_tw prof_bt_t‚ prof_bt_s³ prof_tctx_state_tÛ arena_runs_dirty_link_tæ arena_runs_dirty_link_s4arena_chunk_map_bits_t?arena_chunk_map_bits_sVssize_ta__darwin_ssize_tllong intsnstime_t~nstime_s¡extent_tree_t¿chunk_hooks_t?chunk_alloc_tzchunk_dalloc_t¦chunk_commit_t×chunk_decommit_tèchunk_purge_tùchunk_split_t/chunk_merge_tlarena_bin_twarena_bin_sÂarena_run_tÍarena_run_s bitmap_tarena_run_tree_t:arena_chunk_map_misc_tEarena_chunk_map_misc_sÓmalloc_bin_stats_tÞmalloc_bin_stats_sÄtsd_tÏtsd_s~tsd_state_t«arena_tdata_t¶arena_tdata_sÏtcache_enabled_töquarantine_tquarantine_s\quarantine_obj_tgquarantine_obj_sËmalloc_init_t’$uint32_t¦7tsd_wrapper_tÖ7tsd_init_block_tá7tsd_init_block_sA8pthread_tL8__darwin_pthread_t\8_opaque_pthread_t•8__darwin_pthread_handler_rec'?tcache_bin_info_t2?tcache_bin_info_sû@tcaches_tAtcaches_s”†uintmax_t 'p‚ùApurge_mode_tchar–sizetype³ssize_t¾__darwin_ssize_tÉlong intùsize_t__darwin_size_tlong unsigned intbarena_bin_info_tmarena_bin_info_sÙuint32_täunsigned intëbitmap_info_töbitmap_info_sÊszind_t_Bool`uint64_tklong long unsigned intúextent_node_textent_node_sNarena_tYarena_sÏmalloc_mutex_tÚmalloc_mutex_sñOSSpinLockýint32_tintarena_stats_tarena_stats_súmalloc_large_stats_t malloc_large_stats_sK malloc_huge_stats_tV malloc_huge_stats_sŽ tcache_t™ tcache_s ticker_t ticker_sE tcache_bin_tP tcache_bin_sŸ tcache_bin_stats_tª tcache_bin_stats_sÇ dss_prec_t× arena_chunk_tâ arena_chunk_s arena_chunk_map_bits_t arena_chunk_map_bits_s5 arena_runs_dirty_link_t@ arena_runs_dirty_link_s} nstime_tˆ nstime_s« extent_tree_tÉ chunk_hooks_tI chunk_alloc_t chunk_dalloc_t« chunk_commit_tÜ chunk_decommit_tí chunk_purge_tþ chunk_split_t4 chunk_merge_tq arena_bin_t| arena_bin_sÇ arena_run_tÒ arena_run_sbitmap_tarena_run_tree_t?arena_chunk_map_misc_tJarena_chunk_map_misc_sÝprof_tctx_tèprof_tctx_s£prof_tdata_t®prof_tdata_sæckh_tñckh_sackh_hash_t„ckh_keycomp_t¥ckhc_t°ckhc_sÕprof_cnt_tàprof_cnt_s2prof_gctx_t=prof_gctx_sÉprof_tctx_tree_tçprof_bt_tòprof_bt_s#prof_tctx_state_t.malloc_bin_stats_t9malloc_bin_stats_sAtsd_tAtsd_sÉAtsd_state_tÙAarena_tdata_täAarena_tdata_sýAtcache_enabled_t Bquarantine_tBquarantine_ssBquarantine_obj_t~Bquarantine_obj_sxSuint8_tƒSunsigned charئtcache_bin_info_tã¦tcache_bin_info_sÔÜuintptr_tŸ©i8Dmalloc_mutex_tOmalloc_mutex_sfOSSpinLockrint32_t}int™extent_tree_t¼extent_node_tÇextent_node_sarena_tarena_s‘unsigned int˜arena_stats_t£arena_stats_s~size_t‰__darwin_size_t”long unsigned int›uint64_t¦long long unsigned int²malloc_large_stats_t½malloc_large_stats_smalloc_huge_stats_tmalloc_huge_stats_sFtcache_tQtcache_sÁticker_tÌticker_sñszind_ttcache_bin_ttcache_bin_sbtcache_bin_stats_tmtcache_bin_stats_sŠsizetype‘dss_prec_t¾arena_chunk_tÉarena_chunk_súarena_chunk_map_bits_tarena_chunk_map_bits_sssize_t'__darwin_ssize_t2long int9_Bool@arena_runs_dirty_link_tKarena_runs_dirty_link_sˆnstime_t“nstime_s¶chunk_hooks_t6 chunk_alloc_tq chunk_dalloc_t chunk_commit_tÎ chunk_decommit_tß chunk_purge_tð chunk_split_t& chunk_merge_tc arena_bin_tn arena_bin_s¹ arena_run_tÄ arena_run_s bitmap_t arena_run_tree_t1 arena_chunk_map_misc_t< arena_chunk_map_misc_sÏ prof_tctx_tÚ prof_tctx_s• prof_tdata_t  prof_tdata_sØ charß ckh_tê ckh_sZckh_hash_t‚ckh_keycomp_t£ckhc_t®ckhc_sÓprof_cnt_tÞprof_cnt_s0prof_gctx_t;prof_gctx_sÇprof_tctx_tree_tåprof_bt_tðprof_bt_s!prof_tctx_state_tImalloc_bin_stats_tTmalloc_bin_stats_stá‚aŽsize_t™__darwin_size_t¤long unsigned intµbitmap_info_tÀbitmap_info_sUbitmap_tBB„â=Ocharlsize_tw__darwin_size_t‚long unsigned int¤chunk_hooks_t$chunk_alloc_t[_Boolbunsigned intnchunk_dalloc_tšchunk_commit_tËchunk_decommit_tÜchunk_purge_tíchunk_split_t#chunk_merge_tjrtree_turtree_sÉrtree_node_alloc_tårtree_node_elm_tðrtree_node_elm_s7extent_node_tBextent_node_s‹arena_t–arena_s malloc_mutex_tmalloc_mutex_s.OSSpinLock:int32_tEintLarena_stats_tWarena_stats_s2uint64_t=long long unsigned intImalloc_large_stats_tTmalloc_large_stats_sšmalloc_huge_stats_t¥malloc_huge_stats_sÝtcache_tètcache_sX ticker_tc ticker_sˆ szind_tŸ tcache_bin_tª tcache_bin_sù tcache_bin_stats_t tcache_bin_stats_s sizetype' dss_prec_tT arena_chunk_t_ arena_chunk_s arena_chunk_map_bits_t› arena_chunk_map_bits_s² ssize_t½ __darwin_ssize_tÈ long intÏ arena_runs_dirty_link_tÚ arena_runs_dirty_link_s nstime_t" nstime_sE extent_tree_to arena_bin_tz arena_bin_sÅ arena_run_tÐ arena_run_s bitmap_t arena_run_tree_t= arena_chunk_map_misc_tH arena_chunk_map_misc_sÛ prof_tctx_tæ prof_tctx_s¡ prof_tdata_t¬ prof_tdata_säckh_tïckh_s_ckh_hash_t‡ckh_keycomp_t¨ckhc_t³ckhc_sØprof_cnt_tãprof_cnt_s5prof_gctx_t@prof_gctx_sÌprof_tctx_tree_têprof_bt_tõprof_bt_s&prof_tctx_state_tNmalloc_bin_stats_tYmalloc_bin_stats_sñrtree_node_dalloc_trtree_level_t'rtree_level_s|uintptr_t=$ÂïWchar^sizetypeÜdss_prec_tç_BoolMÃû@_Bool°size_t»__darwin_size_tÆlong unsigned intÅʾDmalloc_mutex_tOmalloc_mutex_sfOSSpinLockrint32_t}int„_Bool²ctl_named_node_t½ctl_named_node_s ctl_node_s-char4unsigned intEctl_node_t„size_t__darwin_size_tšlong unsigned int§sizetypectl_indexed_node_t$ctl_indexed_node_sèctl_arena_stats_tóctl_arena_stats_sÖssize_tá__darwin_ssize_tìlong intóarena_stats_tþarena_stats_sÙuint64_tälong long unsigned intðmalloc_large_stats_tûmalloc_large_stats_sAmalloc_huge_stats_tLmalloc_huge_stats_s‹malloc_bin_stats_t–malloc_bin_stats_s¦tsd_t±tsd_s` tsd_state_t tcache_t˜ tcache_s ticker_t ticker_s8 szind_tO tcache_bin_tZ tcache_bin_s© tcache_bin_stats_t´ tcache_bin_stats_sÕ prof_tdata_tà prof_tdata_s ckh_t# ckh_s“ ckh_hash_t¶ ckh_keycomp_t× ckhc_tâ ckhc_s prof_cnt_t prof_cnt_sd arena_to arena_sådss_prec_tarena_chunk_tarena_chunk_sBextent_node_tMextent_node_s–prof_tctx_t¡prof_tctx_s\prof_gctx_tgprof_gctx_sóprof_tctx_tree_tprof_bt_tprof_bt_sMprof_tctx_state_tuarena_runs_dirty_link_t€arena_runs_dirty_link_sÎarena_chunk_map_bits_tÙarena_chunk_map_bits_sðnstime_tûnstime_sextent_tree_t<chunk_hooks_t¼chunk_alloc_t÷chunk_dalloc_t#chunk_commit_tTchunk_decommit_techunk_purge_tvchunk_split_t¬chunk_merge_téarena_bin_tôarena_bin_s?arena_run_tJarena_run_s‰bitmap_t”arena_run_tree_t·arena_chunk_map_misc_tÂarena_chunk_map_misc_saarena_tdata_tlarena_tdata_s…tcache_enabled_t¬quarantine_t·quarantine_squarantine_obj_tquarantine_obj_stsd_wrapper_tCtsd_init_block_tNtsd_init_block_s®pthread_t¹__darwin_pthread_tÉ_opaque_pthread_t€__darwin_pthread_handler_rec§¾uintmax_t²¾uint32_t­؃-#»szind_tÆunsigned intÍsize_tØ__darwin_size_tãlong unsigned int}intŽextent_node_t™extent_node_sâarena_tíarena_scmalloc_mutex_tnmalloc_mutex_s…OSSpinLock‘int32_tœarena_stats_t§arena_stats_s‚uint64_tlong long unsigned int™malloc_large_stats_t¤malloc_large_stats_sêmalloc_huge_stats_tõmalloc_huge_stats_s-tcache_t8tcache_s¨ticker_t³ticker_sätcache_bin_tïtcache_bin_s>tcache_bin_stats_tItcache_bin_stats_sfsizetypemdss_prec_t}arena_chunk_tˆarena_chunk_s¹arena_chunk_map_bits_tÄarena_chunk_map_bits_sÛssize_tæ__darwin_ssize_tñlong intø_Boolÿarena_runs_dirty_link_t arena_runs_dirty_link_sG nstime_tR nstime_sz extent_tree_t˜ chunk_hooks_t chunk_alloc_tS chunk_dalloc_t chunk_commit_t° chunk_decommit_tÁ chunk_purge_tÒ chunk_split_t chunk_merge_tE arena_bin_tP arena_bin_s› arena_run_t¦ arena_run_så bitmap_tð arena_run_tree_t arena_chunk_map_misc_t arena_chunk_map_misc_s± prof_tctx_t¼ prof_tctx_sw prof_tdata_t‚ prof_tdata_sºcharÁckh_tÌckh_s<ckh_hash_tdckh_keycomp_t…ckhc_tckhc_sµprof_cnt_tÀprof_cnt_sprof_gctx_tprof_gctx_s©prof_tctx_tree_tÇprof_bt_tÒprof_bt_sprof_tctx_state_tmalloc_bin_stats_tmalloc_bin_stats_s¬uintptr_t§-g@_BoolZsize_te__darwin_size_tplong unsigned int›szind_t¦unsigned int tsd_ttsd_sÃtsd_state_tÓtcache_tÞtcache_sNuint64_tYlong long unsigned int`ticker_tkticker_sint32_t›int®tcache_bin_t¹tcache_bin_stcache_bin_stats_ttcache_bin_stats_s/sizetype;prof_tdata_tFprof_tdata_symalloc_mutex_t„malloc_mutex_s›OSSpinLock¬char³ckh_t¾ckh_s.ckh_hash_tVckh_keycomp_twckhc_t‚ckhc_s§prof_cnt_t²prof_cnt_sarena_tarena_s… arena_stats_t arena_stats_sp malloc_large_stats_t{ malloc_large_stats_sÁ malloc_huge_stats_tÌ malloc_huge_stats_sÿ dss_prec_t arena_chunk_t arena_chunk_s? extent_node_tJ extent_node_s“ prof_tctx_tž prof_tctx_sYprof_gctx_tdprof_gctx_sðprof_tctx_tree_tprof_bt_tprof_bt_sJprof_tctx_state_tUarena_runs_dirty_link_t`arena_runs_dirty_link_s®arena_chunk_map_bits_t¹arena_chunk_map_bits_sÐssize_tÛ__darwin_ssize_tælong intínstime_tønstime_sextent_tree_t9chunk_hooks_t¹chunk_alloc_tôchunk_dalloc_t chunk_commit_tQchunk_decommit_tbchunk_purge_tschunk_split_t©chunk_merge_tæarena_bin_tñarena_bin_s<arena_run_tGarena_run_s†bitmap_t‘arena_run_tree_t´arena_chunk_map_misc_t¿arena_chunk_map_misc_sMmalloc_bin_stats_tXmalloc_bin_stats_sðarena_tdata_tûarena_tdata_stcache_enabled_t$quarantine_t/quarantine_sŠquarantine_obj_t•quarantine_obj_s/tcache_bin_info_t:tcache_bin_info_sArtree_tLrtree_s rtree_node_alloc_t¼rtree_node_elm_tÇrtree_node_elm_srtree_node_dalloc_t9rtree_level_tDrtree_level_s”uintptr_ta2ÔSmalloc_mutex_t^malloc_mutex_suOSSpinLockint32_tŒint­_Bool¶·\nstime_tgnstime_s~uint64_t‰long long unsigned int¿intb_BoolitimevalŽ__darwin_time_t™long int __darwin_suseconds_t«__int32_tk½Æasize_tl__darwin_size_twlong unsigned intŠchar‘sizetype¦int¾_BoolHƒâ+_Bool2size_t=__darwin_size_tHlong unsigned intOssize_tZ__darwin_ssize_telong intluint64_twlong long unsigned int~char…sizetypeŒmalloc_mutex_t—malloc_mutex_s®OSSpinLockºint32_tÅintÑckh_tÜckh_sGunsigned intSckh_hash_t{ckh_keycomp_tœckhc_t§ckhc_sÑprof_tdata_tÜprof_tdata_sprof_cnt_tprof_cnt_shtsd_tstsd_s"tsd_state_tOtcache_tZtcache_sÊticker_tÕticker_súszind_ttcache_bin_ttcache_bin_sktcache_bin_stats_tvtcache_bin_stats_s—arena_t¢arena_sarena_stats_t#arena_stats_s malloc_large_stats_t malloc_large_stats_sT malloc_huge_stats_t_ malloc_huge_stats_s’ dss_prec_t¿ arena_chunk_tÊ arena_chunk_sï extent_node_tú extent_node_sC prof_tctx_tN prof_tctx_s prof_gctx_t prof_gctx_s  prof_tctx_tree_t¾ prof_bt_tÉ prof_bt_sú prof_tctx_state_t" arena_runs_dirty_link_t- arena_runs_dirty_link_s{ arena_chunk_map_bits_t† arena_chunk_map_bits_s nstime_t¨ nstime_sË extent_tree_té chunk_hooks_tichunk_alloc_t¤chunk_dalloc_tÐchunk_commit_tchunk_decommit_tchunk_purge_t#chunk_split_tYchunk_merge_t–arena_bin_t¡arena_bin_sìarena_run_t÷arena_run_s6bitmap_tAarena_run_tree_tdarena_chunk_map_misc_toarena_chunk_map_misc_sýmalloc_bin_stats_tmalloc_bin_stats_s arena_tdata_t«arena_tdata_sÄtcache_enabled_tëquarantine_töquarantine_sQquarantine_obj_t\quarantine_obj_ste)Š9@_BoolZsize_te__darwin_size_tplong unsigned intarena_tarena_s’unsigned int™malloc_mutex_t¤malloc_mutex_s»OSSpinLockÇint32_tÒintÙarena_stats_täarena_stats_s¿uint64_tÊlong long unsigned intÖmalloc_large_stats_támalloc_large_stats_s'malloc_huge_stats_t2malloc_huge_stats_sjtcache_tutcache_såticker_tðticker_sszind_t,tcache_bin_t7tcache_bin_s†tcache_bin_stats_t‘tcache_bin_stats_s®sizetypeµdss_prec_tÅarena_chunk_tÐarena_chunk_sõextent_node_textent_node_sIprof_tctx_tTprof_tctx_s prof_tdata_t prof_tdata_sR charY ckh_td ckh_sÔ ckh_hash_tü ckh_keycomp_t ckhc_t( ckhc_sM prof_cnt_tX prof_cnt_sª prof_gctx_tµ prof_gctx_sA prof_tctx_tree_t_ prof_bt_tj prof_bt_s› prof_tctx_state_t¦ arena_runs_dirty_link_t± arena_runs_dirty_link_sÿ arena_chunk_map_bits_t arena_chunk_map_bits_s! ssize_t, __darwin_ssize_t7 long int> nstime_tI nstime_sl extent_tree_tŠ chunk_hooks_t chunk_alloc_tEchunk_dalloc_tqchunk_commit_t¢chunk_decommit_t³chunk_purge_tÄchunk_split_túchunk_merge_t7arena_bin_tBarena_bin_sarena_run_t˜arena_run_s×bitmap_tâarena_run_tree_tarena_chunk_map_misc_tarena_chunk_map_misc_sžmalloc_bin_stats_t©malloc_bin_stats_s£tsd_t®tsd_s]tsd_state_tmarena_tdata_txarena_tdata_s‘tcache_enabled_t¡quarantine_t¬quarantine_squarantine_obj_tquarantine_obj_sOtcache_bin_info_tZtcache_bin_info_sRïbunsigned intˆ_Bool”uint64_tŸlong long unsigned int¦uint8_t±unsigned char0rtree_node_elm_t;rtree_node_elm_s‚extent_node_textent_node_sÖarena_táarena_sWmalloc_mutex_tbmalloc_mutex_syOSSpinLock…int32_tint—arena_stats_t¢arena_stats_s}size_tˆ__darwin_size_t“long unsigned intŸmalloc_large_stats_tªmalloc_large_stats_sðmalloc_huge_stats_tûmalloc_huge_stats_s3tcache_t>tcache_s®ticker_t¹ticker_sÞszind_tõtcache_bin_t tcache_bin_sO tcache_bin_stats_tZ tcache_bin_stats_sq sizetypex dss_prec_tˆ arena_chunk_t“ arena_chunk_sÄ arena_chunk_map_bits_tÏ arena_chunk_map_bits_sæ ssize_tñ __darwin_ssize_tü long int arena_runs_dirty_link_t arena_runs_dirty_link_sK nstime_tV nstime_sy extent_tree_t— chunk_hooks_t chunk_alloc_tR chunk_dalloc_t~ chunk_commit_t¯ chunk_decommit_tÀ chunk_purge_tÑ chunk_split_t chunk_merge_tD arena_bin_tO arena_bin_sš arena_run_t¥ arena_run_sä bitmap_tï arena_run_tree_t arena_chunk_map_misc_t arena_chunk_map_misc_s° prof_tctx_t» prof_tctx_svprof_tdata_tprof_tdata_s¹charÀckh_tËckh_s;ckh_hash_tcckh_keycomp_t„ckhc_tckhc_s´prof_cnt_t¿prof_cnt_sprof_gctx_tprof_gctx_s¨prof_tctx_tree_tÆprof_bt_tÑprof_bt_sprof_tctx_state_t malloc_bin_stats_tmalloc_bin_stats_s°rtree_t»rtree_srtree_node_alloc_t+rtree_node_dalloc_tVrtree_level_tartree_level_sß zéE_Boolbsize_tm__darwin_size_txlong unsigned int‰char¿uint64_tÊlong long unsigned intZ unsigned intm sizetype€ uint32_t¸intËssize_tÖ__darwin_ssize_tálong int(ó‘ö9E_Boolbssize_tm__darwin_ssize_txlong intštcache_bin_info_t¥tcache_bin_info_s¼unsigned intsize_t__darwin_size_tlong unsigned int<tcaches_tGtcaches_s€tcache_t‹tcache_sûuint64_tlong long unsigned int ticker_tticker_s=int32_tHintOszind_tftcache_bin_tqtcache_bin_sÀtcache_bin_stats_tËtcache_bin_stats_sèsizetypeXtsd_tctsd_stsd_state_t?prof_tdata_tJprof_tdata_s}malloc_mutex_tˆmalloc_mutex_sŸOSSpinLock°char·ckh_tÂckh_s2ckh_hash_tZckh_keycomp_t{ckhc_t†ckhc_s«prof_cnt_t¶prof_cnt_sarena_tarena_s‰ arena_stats_t” arena_stats_st malloc_large_stats_t malloc_large_stats_sÅ malloc_huge_stats_tÐ malloc_huge_stats_s dss_prec_t0 arena_chunk_t; arena_chunk_s` extent_node_tk extent_node_s´ prof_tctx_t¿ prof_tctx_sz prof_gctx_t… prof_gctx_sprof_tctx_tree_t/prof_bt_t:prof_bt_skprof_tctx_state_t“arena_runs_dirty_link_tžarena_runs_dirty_link_sìarena_chunk_map_bits_t÷arena_chunk_map_bits_snstime_tnstime_s<extent_tree_tZchunk_hooks_tÚchunk_alloc_tchunk_dalloc_tAchunk_commit_trchunk_decommit_tƒchunk_purge_t”chunk_split_tÊchunk_merge_tarena_bin_tarena_bin_s]arena_run_tharena_run_s§bitmap_t²arena_run_tree_tÕarena_chunk_map_misc_tàarena_chunk_map_misc_snmalloc_bin_stats_tymalloc_bin_stats_sarena_tdata_tarena_tdata_s5tcache_enabled_t\quarantine_tgquarantine_sÂquarantine_obj_tÍquarantine_obj_s»tsd_wrapper_tëtsd_init_block_tötsd_init_block_sV pthread_ta __darwin_pthread_tq _opaque_pthread_tª __darwin_pthread_handler_rec5éËr"Atsd_init_head_tLtsd_init_head_sŽtsd_init_block_t™tsd_init_block_sôpthread_tÿ__darwin_pthread_t_opaque_pthread_tClong intO__darwin_pthread_handler_recchar¤sizetype«malloc_mutex_t¶malloc_mutex_sÍOSSpinLockÙint32_täinttsd_wrapper_t1_Bool8tsd_tCtsd_sòtsd_state_ttcache_t*tcache_sšuint64_t¥long long unsigned int¬ticker_t·ticker_sÜszind_tçunsigned intútcache_bin_ttcache_bin_sTtcache_bin_stats_t_tcache_bin_stats_s€prof_tdata_t‹prof_tdata_sÃckh_tÎckh_s9size_tD__darwin_size_tOlong unsigned int[ckh_hash_tƒckh_keycomp_t¤ckhc_t¯ckhc_sÔprof_cnt_tßprof_cnt_s1arena_t<arena_s² arena_stats_t½ arena_stats_s malloc_large_stats_t¨ malloc_large_stats_sî malloc_huge_stats_tù malloc_huge_stats_s, dss_prec_tY arena_chunk_td arena_chunk_s‰ extent_node_t” extent_node_sÝ prof_tctx_tè prof_tctx_s£ prof_gctx_t® prof_gctx_s:prof_tctx_tree_tXprof_bt_tcprof_bt_s”prof_tctx_state_t¼arena_runs_dirty_link_tÇarena_runs_dirty_link_sarena_chunk_map_bits_t arena_chunk_map_bits_s7ssize_tB__darwin_ssize_tMnstime_tXnstime_s{extent_tree_t™chunk_hooks_tchunk_alloc_tTchunk_dalloc_t€chunk_commit_t±chunk_decommit_tÂchunk_purge_tÓchunk_split_t chunk_merge_tFarena_bin_tQarena_bin_sœarena_run_t§arena_run_sæbitmap_tñarena_run_tree_tarena_chunk_map_misc_tarena_chunk_map_misc_s­malloc_bin_stats_t¸malloc_bin_stats_sParena_tdata_t[arena_tdata_sttcache_enabled_t›quarantine_t¦quarantine_squarantine_obj_t quarantine_obj_srpthread_key_t}__darwin_pthread_key_t[î%bchar”long intˆint~uintmax_t‰long unsigned intunsigned int—_Bool£size_t®__darwin_size_tŽintmax_tH__va_list_tagS__va_list_tag¡sizetypeïunsigned charöva_list__darwin_va_list __builtin_va_listgimli-0.19.0/fixtures/self/debug_ranges010066400017500001750000005532401343337721300163160ustar0000000000000000Ý6ö6T7a7n9 :1:6:¨µ-¶B¶G¶g¶6·F·K·_pqLq‰r_pqLq‰rR™s™Ù™oR™s™Ù™o¯ª «ï«¯¯ª «ï«¯e®€®›®¯mšÀ6mšÀ6ÿX\ÊBÃñx BÃñx (ž !Ù"6#Ó#‹$Ù"6#Ó#‹$^T’TþT=UeUnUaRa¾aýa%b.bÎËJÌZÌÅÎŻÌâÌýÍEÎÅÎâÌýÍEÎÅÎãoé•éŸé@æ¢çcèWéq·qÇqwÇqr·rDtYtw·rÏr=s3tuÅuJvv¦vòv¦uÅu~vvm€å€Ê…D€€ð…^†»ŠQ‹9Œ‘•‹î‹D‘²‘È—ý—Ø œ0˜‰˜/œœ«¥Ó¥š¦¨¦g¦6¨¤¨«¯Ó¯š°²°g°6²¤²µ"µÕµA·Lµ¢µg·Õ·©»1¼Ö¼L¾Q¼£¼r¾à¾ªÂÃÀÃ6ŪÂÃÀÃ6Å8ÊÃ\ÅÊÅÚáÓâŽã8çóâEã^ç)èéé éÿ‡é»éø ùÍö4÷üÆýütü¯üÆýütü¯üÆýIHUIJºMuIÇIàM«NP%QàQŠUEQ—Q°U{VéWâXYG]YTYm]8^¦_Ÿ`Zae¿`a*eõeWg hºh0j)h{hVj!k¶l¯mjnrÏm!n:rsitbuvÇy‚uÔuíy¸z0|)}ä}ŽI}›}´‚¡„û„¶…d‰…m…ЉUŠ™Û™–šDžû™Mšjž5Ÿó¢ÿ£º¤d¨¤q¤ЍU©·ªߪ«­ÿªQ«,­÷­W¯¯0°¦±Ÿ¯ñ¯̱—²ú³T´µ¨¸t´Æ´θ™¹»q»,¼Ö¿‘»ã»ü¿ÇÀ4ÂŽÂIÃóÆ®ÂÃÇäÇGÉoÉ Ê–ËÉáɼˇÌíÍGÎϬÒgιÎÒÒÓÕjÕ%ÖÏÙŠÕÜÕõÙÀÚ7Ü‘ÜLÝöà±ÜÝáçáä[äåÄè{äÍäêèµé'ëë<ìæï¡ëóë ð×ðDòžòYó÷¾òó)÷ô÷dù¾ùyú#þÞù0úIþÿwp+ÕâûÆ7‘L ö ±  ç T®iÎ 9²«°÷Q ºqÃà«÷ !/"²#n!Ç!Ê#¨$¨%Ð%à&c(&x&{(Y)Y**‘+-Ð*)+,- .ÇÂï¢ÃÅÃoÃ6ŤÅ'˾˘̉ÑÌ[̯ÑÒÊØaÙ>Ú/ߥÙþÙUßÃßäéä‘åç å[å-ç›çL + < A /|G|„|Ž|_fwf´f¾f'•ß•ð•õ•õrsDsksŽs™s•y³yäy z.z9z v@vMvRv‡,è2ñ2"4L-t-ª-».y/š/Ð/á0Å1à1¿2Ô2ñ2"42|2 2¿2S9t99¢9,†R†}†˜†œ°°í°±ä£ª—\z]¡]¨]¢UÁUÑUP>é>ð>(?0?j?p?r@€@™@ @µ@À@AAbApAF€F¶FÀFòFG2G@GrG€G²GÀGvH€H²HÀH_J`J’J JÖJàJAKPKzL€L§L°L´MÀMËMÐMéMðMN N*O0ObOpO©O°OQ QRQ`QSSBSPS|S€SÇSÐSŽUU@np‚ÆÐ$0 .0U`vÀÎЦ°GPY`• ùZ`~€ž * 0 Á Ð Ê Ð ï ð ; @ A P { €  ÏЪ°¹À"0þ¤°ÌÐ+0‹0ì!ð!9"@"ï"ð"##¸%À%Ñ%à%õ%&R&`&((÷()3)@)–) )Ñ)à)**±*À*H+P+v+€+,,;,@,k,p,"404•4 4½8À8Ù8à8ô89K9P9k9p9‹99uF€FèJðJKKaKÀKäKðKÖLàLîLðLÜOàO‚VV¥V°V%W0WÔWàWüWXOXPX2Z@ZzZ€ZØZàZêZðZ[[:[@[Œ[[š[ [v\€\¨]°]__”_ _Î`Ð`ÞaàaØdàdÿdeCePe±eÀeÒeàeffVf`füf g"h0h—h hmmYm`mnn"n0nÔn0oKpPp“p pw wäwðwWx€x*z€zÝz0{*}0}s~à~g†p†~ˆ€ˆ²ˆÀˆo‰p‰Š Š»‘À‘‰““\•`•¦œ°œ¾žÀžòžŸ¯Ÿ°ŸK£P£¥¥­¨°¨žª ªÒªàª««/­0­ ¯¯­²°²‚´´Þ·à·ιйºº¿ºÀºé¾ð¾¾ÀÀÀòÀÁ¯Á°ÁÓÅàŃÎÀÎØÀØòØÙ2Ù@ÙrـٲÙÀÙòÙÚ2Ú@ÚaÚpÚ ÛÛÅÜÐÜÝÝ)Ý0ÝXÝ`Ý;Þ@Þ^ß`ß~à€à2è@èÿ ÿæÿðÿap²ÀV`†z€) 0 Y ` å ð ' 0 ³ À   ú ¨°Ÿ ÉÐU`¦°Öà6@fpop,0O P  !!V"`"_$`$$%0%G%P%o&p&9'@'_(`(&)0)O*P*/,0,ü,-. .é.ð.00Ö0à0ÿ12¼2À2ß3à3·4À4ß5à5´6À6ß7à7´8À8ß9à9::,:0:y:€:;À;Þ;à;ÿ;<.<0<Q<`<¿<À<ß=à=·>À>ß?à?´@À@A AtA€ANCPC‚CC?D@D¬F°FâFðF´NÀN„VVA^P^þef*k0kRk`kssÁzÐzˆ‚‚^Š`Š‚ŠŠ¦‹°‹ v€ ð Å’Ð’N”P”š” ”Æ”Д••õ•–%–0–o–p–Ü–à–î–ð–þ–—f—p—>Ÿ@Ÿ¡ ¡^©`©¢¹°¹íÇðǦӰÓÉÚÐÚ¾éÀéý÷øÿ ÿÏÐ ´À 33Œ3355R5`5¨56^6`6w:€:Ž::Ñ:à::;@;< <==Â=Ð=~?€?¬?°?ò?@,@0@w@€@AAÌaÐalcpc’d dÀdeZg`gwhàhjjk k¬k°k‹ll4m@m¬r°rñstÁtÐtötuuu>u@uNuvRvpvv vävðv—w wIxPxŽxxÔxàxyy!y0yAyPy‘z z&{à{|0|\|`|§|°|Á|à|L}P}~ ~)~0~ª~°~Á~Ð~|€Xƒ`ƒX„`„F…P…܆à†î†ð†‡ ‡ü‡ˆgˆpˆ´ˆÀˆª‰°‰Þ‰à‰ŠŠ>Š@Š‹‹F‹P‹Œ Œ+Œ0Œ^Œ`ŒŽ ŽKŽPŽÓàÈÐö‘#‘0‘F‘P‘b‘p‘‰‘‘»‘À‘7’@’{’€’š’ð’7“@“h“p“§“”Ԕ𔕠• ––˜ ˜W˜`˜ú˜™€Òà2ž@žlžpž·žÀžå©ð©JªPª²¯À¯L±P±^±`±‰±±²²Y³0´V´`´"µ0µеµG¶P¶K·P·|·€·Ä·з+Â0­ŰÅôÅÆÎÇÐÇÈÈ¿ÈÀÈ‹ÊÊ&Ò0ÒfÓpÓŸÓ Ó¿ÔÀÔLÕPÕ>×@×r×€×/Ø0ØÌßÐß­á°á¤ç°çÊìÐìaípí>ï@ïrï€ï/ð0ðÃòÐò¡ó°óôô)ôzÐû+7DE7D:7D:DeEw¾öEw¾ÔÞöEw¾ÔÞöe{yƒr{yƒ{ƒ¾‘ƒ¾œƒ¾œ»ƒŽœ¸ƒŽ»Ž¾»Ž¾Á–¾Ê£¾ë£¾?"?"A">A‡?A‡?G‡?P‡$?q‡$?¼¿ ¼¿¥¼¿Úòl¦Àã¦ÀÆ¡¦ÀÆú28 288G?G7„ˆ¥7„ˆ¥<Su™<Su™„™¥„™¥ßô:Lß:-LÿCLñCLñCL‡»Î‡ÉÎŒ¬ÎñŒ¬Îñ¤¬Ö夬àå¬"/:""œ¬/:œ¬/:£¬/:¯Ó$,¯¾$,¹¾$,LôL\ôùY\ôù\ùm”¥r”¥r‡¥‚‡¥ 2 Þ ü dûæfîÍ…§ 2 Þ ü dûæfîÍ…§ $ Þ  ¬ƒîÍÞ  ¬ƒîͬ¾¹Í¾ìùÝìƒî¯ƒî£$ 2  ü d¬ƒûæf…§$ 2  ü d¬ƒûæf…§ ü d¬ƒûæf…§ ü d”ƒûæf…§ > Æ Í ƒû7>…§ : Æ Í ƒû7>…§1 : ƒû…§ƒû…§Òæ–§> Æ Í ü d”æ7>fR Æ Í ü d”æ7>fR Æ Í ü d”æ7>fR Æ Í ü Y Æ Í ü Y Æ Í ü e Æ Í ü n Æ Í ü d”æ7>fd”æ7>fk”æ7>fk€æ7>fw€æ7>fæ7>f2 Ò ü u ædoæ2 Q ü u 5<2 M ü u 5<D M ü u Q Ò æ5<doæ^ Ò æ5<doæ^ Ò æ5<doæ^ “ oæe “ oæe | oæs | oæ™ Ò æ5<d™ Ò æ5<d  Ò æ5<d  · æ5<d® · æ5<dæ5<dÒ Þ … æû 0ofîÍ…Ò Þ … æû 0ofîÍ…Ò Þ í Cû5òâ!7Ce‰˜“µÛ Þ í Cû5òâ!7Ce‰˜“µÛ ý í .û5í .û5í .û5 Þ .Cúâ!7Ce‰˜“µM Þ .Cúâ!7Ce‰˜“µM Þ .Cúâ!7Ce‰˜“µM Þ .Câ!7Ce‰˜“µV Þ .Câ!7Ce‰˜“µV Þ ¬C¾âg Þ ¬C¾âg Þ ¬éñC¾âs § ¬´(4Å Þ Å Þ Å Þ Å Þ ´é¾â´é¾â¼Å¾Ô.¬¾!7Ce‰˜“µ>¬¾!7Ce‰˜“µ>¬¾!7Ce‰˜“µ>xŠCOx—оTe‰˜“µx—Te‰˜Š¾“µŽ—“§—¬!7—¬!7—¬!'—¬!'… í K¢ofîÍ  .X§… í K¢ofîÍ  .X§… í Ky-of¥ÜîÍ  .n€— í f¥ÜîÍ .n€š ô û þ  í f¥ÜîÍ .n€š í f¥.¨ í f¥.¶ à f¥.f¥.f¥.í ô û þ  u Üî u Üî S Üî S Üî S Üî Ï Í n€— Ï Í n€— à Í n€Í n€Í n€Ky-o Ky-o -o -o ï­ÜXnÒï­ÜXnÒï­ÜXnØï­ÜXnâï­ÜXn±ºXnñ¢-‚§ú¢-‚§¢‚§¢‚§¢‚§¨‚§¼‚§Êû‚§ëû‚ˆòû‚ˆæ;ò 0â7Ce‰ “µÿ.X§…&;V*GYš BYš ",BYš ",BGP£\BL§5]…£\BL§5]…£\BL§5]…£\BL§5]…£\BL§5]…£\BL§5]…£\ÑL 5°\ÑL 5°\Ñ&L 5¿ùÑÚ=LD\&=D\&=D\&,D\&,Ú 5Ú 5Úßãì 'BƧ ]…NƧ ]…NƧ ]…P“§° “±°ñ]…°ñ]…°µ¹Â]w±Æñ±Æñ±Æñ÷±Æñ÷Yæ\ò 0â7Ce‰L“µÿ.X5]Yæ\ò 0â7Ce‰L“µÿ.X5]Yæ\ò 0â7Ce‰L“µÿ.X5]Yæ\å0â7Ce‰L“µÿ.X5]Yæ\å0â7Ce‰L“µÿ.X5]Yæ0â7Ce‰.Xfæ0â7Ce‰.Xfæ0yâ7Ce‰.Xu«097CÎæÎæÎæÎæ9y.X9y.X9>BK.J\åL“µÿ5]håL“µÿ5]håL“µÿ5]j§LUÍÙ§ÑU“Þÿ5]§ÑÞÿU“5]UZ^g5OÑåµÍÑåµÍÑåµ½Ñåµ½×åÇ"w#¾%&±')( (#)q*“*×åÇ"w#¾%&±')( (#)q*“*Ç"w#¾%&±')( (#)q*“*Ç"w#¾%í%±')( (#)q*“*Ç"æ"e#l#±')(ì(ó(q*“*Ç"â"e#l#±')(ì(ó(q*“*Ù"â"±')(q*“*±')(q*“*((‚*“*æ"e#l#w#¾%í% (ì(ó(#)û"e#l#w#¾%í% (ì(ó(#)û"e#l#w#¾%í% (ì(ó(#)û"e#l#w#ý( )#e#l#w#ý( )#e#l#w#ý( ) #e#l#w#ý( )#e#l#w#ý( )l#w#ý( )¾%í% (ì(ó(ý( )#)¾%í% (ì(ó(ý( )#)Ä%í% (ì(ó(ý( )#)Ä%Ø% (ì(ó(ý( )#)Ï%Ø% (ì(ó(ý( )#) (ì(ó(ý( )#)å†w#î#@%¾%)( (åw#î#%–%åw#î#%–%÷w#î#†@%%–%¾%)( (!†@%%–%¾%)( (!†@%%–%¾%)( (!S)( ((S)( ((<)( (3<)( (S†@%%–%¾%S†@%%–%¾%Z†@%%–%¾%Zq@%%–%¾%hq@%%–%¾%@%%–%¾%ˆ™î#$K*q*î#$K*q*ø#{$K*q*${$K*q*${$K*q*${$K*q*$${$K*q*2$e$K*q*U$e$K*Q*\$e$K*Q*œØö$@%3*I*ö$@%3*I*ö$@%3*I*þ$@%3*I*%@%3*I*%&%3*I*Ø+O V $!+!*"1"$Á$Ø+O V $!+!*"1"$Á$ë+$Á$ô+¥$Á$+¥$Á$+O V $!+!*"1"{"°"Ç"Á$é$&±'#)3*+O V $!+!*"1"{"°"Ç"Á$é$&±'#)3*+O V $!+!#"°"Ç"&±'#)3*+O V $!+!õ!°"Ç"&±'#)3*]O V $!+!õ!°"Ç"&±'#)3*]O V $!+!õ!°"Ç"&±'#)3*]ºÁÄÖO V ³ &T&Ë&Ý&r'±'#)5)!*3*]³&T&#)5)o³&T&#)5)}¦&T&#)5)&T&#)5)&T&#)5)³ºÁÄÖ= Ë&Ý&Ö= Ë&Ý&ß Ë&Ý&ß Ë&Ý&ß Ë&Ý&Y — r'±'!*3*a — r'±'!*3*a Œ r'±'!*3*r'±'!*3*r'±'!*3*!$!+!õ!°"Ç"&&W&Ë&Ý&r'9)!*!$!+!õ!°"Ç"&&W&Ë&Ý&r'9)!*+!õ!°"Ç"W&Ë&Ý&r'9)!*+!õ!°"º"½"Ç"W&j&q&Ë&Ý&b'e'r'9)!*4!õ!°"º"½"Ç"W&j&q&Ë&Ý&b'e'r'9)!*C!õ!°"º"½"Ç"d&j&q&Ë&Ý&b'e'r'9)!*C!õ!°"º"½"Ç"d&j&q&Ë&Ý&b'e'r'9)!*P!õ!°"º"½"Ç"Ý&b'9)p)P!õ!°"º"½"Ç"Ý&b'9)p)Y!õ!Ý&b'9)p)Y!€!ö&<'9)p)ö&<'9)O)Y)p)ö&<'9)O)Y)p)€!õ!Ý&ö&<'b'á!õ!Ý&ö&á!õ!Ý&ö&á!õ!Ý&å&á!õ!Ý&å&°"º"½"Ç"d&j&q&Ë&e'r't)!*d&j&q&Ë&e'r't)!*‚&Ë&t)!*‚&Ë&t)!*‚&Ë&t)«)‚&Ë&t)Š)”)«)‚&Ë&t)Š)”)«)1"{"Á$é$1"{"Á$é$1"{"Á$é$:"{"Á$é$C"{"Î$é$d"{"Î$é$¹*ó*ª,..Ð. 0²0ê0+1G2§2¸2Ç2¹*ó*ª,..Ð. 0²0ê0+1G2§2¸2Ç2Å*ó*.Ð. 0²0.Ð. 0²0.Ð. 0²0­,--.ê0+1G2§2¸2Ç2­,-ê0+1”2§2»,-ê0+1”2§2É,ó,ê0+1”2§2ê0+1”2§2ê0+1”2§2---ƒ-G2Y2-ƒ-G2Y2'-b-G2Y2'-b-G2Y2'-b-G2Y2£-â-Y2”2¸2Ç2«-â-Y2”2¸2Ç2«-Ö-Y2”2¸2Ç2Y2”2¸2Ç2Y2”2¸2Ç2ó*„+.z."0 0Ð1G2Ç2é2ó*+.z.q0x0Ç2é2ó*+.z.q0x0Ç2é2++.z.Ç2é2.z.Ç2é2R.e.Ø2é2+„+"0q0x0 0Ð1G2!+„+"0q0x0 0Ð1G2!+„+"0q0x0 0Ð1G2!+R+Ð1G2'+R+Ð1G2'+;+Ð1G22+;+Ð1G2R+„+"0q0x0 0R+„+"0q0x0 0X+„+"0q0x0 0X+o+"0q0x0 0f+o+"0q0x0 0"0q0x0 0‹++Ì/0§2¸2Ì/0§2¸2Ì/0§2¸2Ô/0§2¸2Þ/0§2¸2ð/ù/§2¸2+’,z.Œ.Ð.¿/0"0²0ê0+1Ð1¢+’,z.Œ.Ð.¿/0"0²0ê0+1Ð1¢+’,z.Œ.Ð.¿/0"0²0ê0+1Ð1°+’,Ð.¿/0"0²0ê0+1Ð1°+ƒ,†,’,Ð.ê.ñ.¿/0"0²0ê0+1Ð1Ä+ƒ,†,’,Ð.ê.ñ.¿/0"0²0ê0+1Ð1Í+ƒ,†,’,ä.ê.ñ.¿/0"0²0ê0+1Ð1Í+ƒ,†,’,ä.ê.ñ.¿/0"0²0ê0+1Ð1Ú+ƒ,†,’,D/¿/²0ê0Ú+ƒ,†,’,D/¿/²0ê0ã+y,D/¿/²0ê0ã+,]/Ÿ/²0ê0]/Ÿ/²0È0Ò0ê0]/Ÿ/²0È0Ò0ê0,y,D/]/Ÿ/¿/e,y,D/]/e,y,D/]/e,y,D/L/e,y,D/L/y,ƒ,†,’,ä.ê.ñ.D/0"0+1Ð1ä.ê.ñ.D/0"0+1Ð1/D/+1Ð1/D/+1Ð1/D/+1_1/D/+1A1K1_1/D/+1A1K1_13#3F3s73#3F3s733F3ƒ34m5p6Q7F3ƒ34m5p6Q74¡4;7Q7¡455 5¡4Ï4Ü455 5À4Ï4ö4555 5m5p61755 5m5p6%73#3ƒ34m5p6Q7s73#3ƒ34m5p6Q7s7ƒ34m5p6Q7s7ƒ3w4m5p6Q7s7ƒ3Ÿ3­3º3%4,4A4H4m5í596@6Q7s7ƒ3›3­3º3%4,4A4H4m5í596@6Q7s7’3›3m5¶5½5í5Q7s7m5¶5½5í5Q7s7½5Ô5b7s7Ÿ3«3¾3%4,4A4H4w4í596@6p6¾3%4,4A4H4w4í596@6p6¾3%4,4A4H4w4í596@6p6¾3%4,474J6W6Ä3%4,474J6W6Ä3%4,474J6W6Ð3%4,474J6W6Ù3%4,474J6W6,474J6W6;4A4H4w4í596@6J6W6p6;4A4H4w4í596@6J6W6p6H4w4í596@6J6W6p6H4]4í596@6J6W6p6T4]4í596@6J6W6p6í596@6J6W6p6š7­7Ê7<š7­7Ê7<š7£7Ê78¶8‘9Ž:o;Ê78¶8‘9Ž:o;¶8È8Y;o;È8ö89+9ç8ö89+9+9‘9Ž:O;+9‘9Ž:C;£7­78¶8‘9Ž:o;<£7­78¶8‘9Ž:o;<8¶8‘9Ž:o;<88‘9Ž:o;<8(8‘9 :W:^:ß;<8#8‘9 :W:^:ß;<8#8‘9 :ß;<‘9 :ß;<â9ö9ð;<(88 :W:^:Ž:o;ß;688 :W:^:Ž:o;ß;688 :W:^:Ž:o;ß;68m8o;ß;<8m8o;ß;<8R8o;ß;I8R8o;ß;m88 :W:^:Ž:m88 :W:^:Ž:s88 :W:^:Ž:s8ˆ8 :W:^:Ž:8ˆ8 :W:^:Ž: :W:^:Ž:0<C<j<§@0<C<j<§@0<9<j<¥<Ã=¡>¤?…@j<¥<Ã=¡>¤?…@Ã=Õ=o@…@Õ=6>M>T>Õ=>>6>M>T>ô=>*>6>6>M>T>¡>¤?e@6>M>T>¡>¤?Y@9<C<¯<Ã=¡>¤?…@§@9<C<¯<Ã=¡>¤?…@§@¯<Ã=¡>¤?…@§@¯<£=¡>¤?…@§@¯<Ë<Ù<æ<Q=X=m=t=¡>!?m?t?…@§@¯<Ç<Ù<æ<Q=X=m=t=¡>!?m?t?…@§@¾<Ç<¡>ê>ñ>!?…@§@¡>ê>ñ>!?…@§@ñ>?–@§@Ë<×<ê<Q=X=m=t=£=!?m?t?¤?ê<Q=X=m=t=£=!?m?t?¤?ê<Q=X=m=t=£=!?m?t?¤?ê<Q=X=c=~?‹?ð<Q=X=c=~?‹?ð<Q=X=c=~?‹?ü<Q=X=c=~?‹?=Q=X=c=~?‹?X=c=~?‹?g=m=t=£=!?m?t?~?‹?¤?g=m=t=£=!?m?t?~?‹?¤?t=£=!?m?t?~?‹?¤?t=‰=!?m?t?~?‹?¤?€=‰=!?m?t?~?‹?¤?!?m?t?~?‹?¤?´@Ò@ß@eD´@È@ß@A˜AoB`CCDß@A˜AoB`CCD˜AªA+DCDªAØAåA BÉAØAÿA B BoB`C!D BoB`CDÈ@Ò@A˜AoB`CCDeDÈ@Ò@A˜AoB`CCDeDA˜AoB`CCDeDA€AoB`CCDeDAx>„>­>ç?÷?¿=Ã=ï=ò=¿=Ã=ï=ò=¿=Ã=ï=ò=Ê=Í= >x>ç?÷?Ê=Í=>2>7>:>Ê=Í=>.>­>¸>Ä>¹?Ø?ç?Ä> ?i?¹?Ä> ?i?x?Ä> ?i?x? ?f?Ø?ç?(?1?9?f?Ø?ç?(?1?9?f?Ø?ç?u@¥@´@RAu@¥@´@RAz@›@´@¼@z@}@‚@›@´@¼@›@¥@Ã@RA›@¥@Ã@È@ÒABB`BvBäBÒABB`BvBäBB`BvBäBB`BvBäBB8BvBäBvB¾BÈBäBvB¾BÈBäB.C[CjCD.C[CjCD3CQCjCrC3C6C:CQCjCrCQC[CyCDQC[CyC~CFDpDFIFsDžDIF‰FÏJáJIF‰FÏJáJIF‰FÏJáJžDF‰FòHIÏJéJ-PºDF­FòHIÏJéJ-PºDF­F°HPIuJéJ-PÃDEPIåIÅMÿMÃDEPIåIÅMÿMÌDìDPI¢IìD E¢IåIÅMÿM¢IåIÅMÜMæMÿM¢IåIÅMÜMæMÿM,EF­F°HåIuJéJÅMÿM-P9EF­F°HåIuJéJÅMÿM-P9EVEYEF­F°HåIuJéJÅMÿM-PYEFåIuJ™KiMpMÅMwNýNO-PiEFåIuJ™KiMpMÅMwNýNO-PiEFåIuJ™K2MwNùNeOÕO§EÔEÛKâKºEÌEÛKâKºEÇEÛKâKºEÇEÛKâKºEÇEÛKâKäEFåIuJ™KÛKâKæKúK2MwNùNeOÕOôEFåIuJ™KÛKâKæKúK2MwNùNeOÕOýEFåIdJýEFOJdJýEFXJdJåI0J:JOJåI0J:JOJFFgJkJFFgJkJ½KÛKâKæK+L2L7L?L+L2L7L:L+L2L7L:L+L2L7L:LL)MwNùNeOÕOL)MwNùNeOÕOL®LwN¸NeOOwN¸NeO{O…OOwN¸NeO{O…OO±LÑL¸NùNOÕO¸NùNO³O½OÕO¸NùNO³O½OÕO2MiMpMÅMùNýNOYOÕO-PEMiMpMÅMùNýNOYOÕO-PEMiMpMÅMùNýNOYOÕO-PUMiMpMÅMåOPeMiMpMÅMåOPpMµMåOPpMµMåOPyMµMåOP…MµMõOPŸMµMõOPùNýNOYOÕOåOP-POIOÕOåOP-POIOÕOåOP-P OIOÕOåOP-POIOP-P3OIOP-P­F½FéJ KÅFGG°H K•KÿMwNÅFËFG"G)GCGJGHG"G)GCGJGQGÙFóF"G)GCGJGH£H K•KÿMwNH£H K•KÿMwNH*H KTKÿM?N KTKÿMN'N?N KTKÿMN'N?N.HNHTK•K?NwNTK•K?NUN_NwNTK•K?NUN_NwN°HµHÈHòHIPIuJÏJ°HµHÈHòHIPIuJÏJÈHåHI IÈHÊHÎHåHI IåHòHIPIuJÏJåHòHIIIPIuJÏJ)IPIuJ¿J)IPIuJ¿J6IPIuJ¿J_PŠPyT¾TÉXÛXyT¾TÉXÛXyT¾TÉXÛXžPyTÂT¨X·XÉXÛX\¯PyTëT¨X·XÉXÛX\ØP_SvUÏWsX–X·XÉXÛXZÅZïZ³[\ØPáPmR_SvUZWžWÏWsX–XYQZhZZÅZïZ³[Ü[î[\mR’RvU»UYXYvU»UY5Y?YXYvU»UY5Y?YXY’R_S»UZWžWÏWsX–XXYQZhZZÅZïZ³[Ü[î[\’R_S»UoV˜VZWžWÏWsX–XXYQZhZZÅZïZ³[Ü[î[\›R_S»UoV˜VZWžWÏWsX–XXYQZhZZÅZïZ³[Ü[î[\›R_S˜VZWžWÏWsX–XÚY+Z³[Ü[¨R_S˜VZWžWÏWsX–XÚY+Z³[Ü[¨R_S˜VòV WZWžWÏWsX–XÚY+Z³[Ü[·R÷R˜V¤VNWZW SDS W'WžWÏWsX–XÚY+Z SS W'WÚY+Z SSÚY+Z+SDSžWÏWsX–X+SDSžWÏWsX–X+SDSžWÏWsX–X+SDSžWÏWsX–XKS_S'WNWKS_S'WNWKS_S'W-WKS_S'W-W¤VòV³[Ü[¤VòV³[Ü[¤V°V¸VÁV³[Î[»UoVXYÚY+ZQZhZZÅZïZî[\ËUoVXYÚY+ZQZhZZÅZïZî[\ËUoVXYÚY+ZQZhZZÅZïZî[\ÎU VXYdY+Z7ZVVVdY³Y7ZQZhZZÅZïZî[\VVV7ZQZhZZÅZïZdY³Yî[\dYoYwY„Yî[\VVoV³YÚYVVoV³YÚYVVoV³Y½YVVoV³Y½YáP;QBQFQXQ*RZWžW·XÉXÛXYQZcZÜ[î[áP;QZWžWQZcZ÷P;QZWžWQZcZQ.QZWžWQZcZZWžWQZcZZWžWQZcZBQFQXQ¾Q·XÉXXQ¾Q·XÉXaQ Q·XÉXaQ Q·XÉXaQ Q·XÉXÓQRÛXYÜ[î[ÛQRÛXYÜ[î[ÛQRÛXYÜ[î[ÛXYÜ[î[ÛXYÜ[î[…SyTëTvUÏWsX–X¨XZÅZïZ³[…SyTëTvUÏWsX–X¨XZÅZïZ³[–SyTÿTvUÏWsX–X¨XZÅZïZ³[–SbTeTyTÿTU$UvUÏWsX™X¨XZÅZïZ³[¦SbTeTyTÿTU$UvUÏWsX™X¨XZÅZïZ³[¹SbTeTyTUU$UvUÏWsX™X¨XZÅZïZ³[¹SbTeTyTUU$UvUÏWsX™X¨XZÅZïZ³[ÆSbTeTyTÏWsXZÅZÆSbTeTyTÏWsXZÅZÏSXTÏWsXZÅZÏSîSæW'XZÅZæW'XZ¥Z¯ZÅZæW'XZ¥Z¯ZÅZîSXTÏWæW*XsX@TXTÏWæW@TXTÏWæW@TXTÏWÕW@TXTÏWÕWXTbTeTyTUU$UvU™X¨XïZ³[UU$UvU™X¨XïZ³[5UvUïZ³[5UvUïZ³[5UvUïZ#[5UvUïZ[[#[5UvUïZ[[#[#[/[x[Ž[d(d9d@d@dKdedldùdeMnŽn[rŒrMnŽn[rqr{rŒrMnŽn[rqr{rŒr5eSeŽnÏn”rÊrŽnÏn”rªr´rÊrŽnÏn”rªr´rÊrµmn;nMnÏnÒqµmn;nMnÏnÒq nn;nMnÏn±q¸qÒq;nMnÏn®q;nMn_o"p;nMn_oºoäop;nMnäop;nMnñopÏn;oBpqÏn;o#qqÏn;o/qqÏn;o/qqÏn;o/qoqÏn;o8qoqÏn;o?q[qÏno!o;oÏno!o;oLp§pÔpñpn$nÒqÛqn$nÒqÛqn$nÒqÛqáqûqr[rÊrûrr[rÊràrêrûrr[rÊràrêrûrs,sãs%ttt¥tPvWvavkv­wÃwxx‹x6y=yLuRu\u¸uLuRu•u³uLuRu•u«u\u•u³u¸u‰u•u³u¸u¸uïu$vPvWvavkvOw}w­wÃwPxOyVy™z z¸uïu$vPvWvavkv wOyVy™z z$vPvWvavkv wWvavkv¡v$wOw}w­wÃwPx}w­wÃwPx¥w­wÃwüwuxxx‹xÏxÏx6y=yOyVyAzæx6y=yOyVyAzæx6y=yOyVyAz÷x6y=yOyVyAzy6y=yOyVy:z,y6y=yOyVyvy=yOyVyvy=yOyVyvyAz™z z³zFz™z z³zPz™z z³zcz™z z³zoz™z z³z9{S{u{Ü{u{À{Ê{Ü{u{À{Ê{Ü{a{n{Ü{ç{Y|s|•|ü|•|à|ê|ü|•|à|ê|ü||Ž|ü|}S}‡}¨}â}é}Å~¹Íò}i~¨~µ~i~¨~¼~Å~¹Íæ~ªÍùó~¡Íùó~¡Íùó~ `ÍÀyçñó~5`ÍÀyçñó~B`A€Œ€K_qçñó~R`Kçñó~R`KçñKçñDMA€Œ€_qA€Œ€_qÍ8€Œ€Ã€K_qyÔ8€Œ€£€`¡Ì€yçñùf¡Ì€yçñùjqÌ€¼çu¡y¼ñùƒ¡y¼ñùy¼ñùĂǂƒQƒÍ‚ƒQƒŠƒÜ‚ƒQƒŠƒæ‚ƒQƒŠƒé‚ƒQƒŠƒ„K„D…K…‹…•…K„P„¥„´„å„D…K…r…ð„D…K…r…ð„D…K…r…ð„D…K…r……D…K…r……D…K…r……D…K…c……D…K…c…?…D…K…N…?…D…K…N…?…D…K…N…ä†é†‡·‡Ê‡õ‡“ˆÍˆ‰‰“ˆÍˆ‰‰“ˆÍˆ‰‰õ‡CˆKˆoˆÍˆ‰‰H‰ˆ$ˆÍˆ‰‰H‰Íˆ‰‰'‰1‰H‰Íˆ‰‰'‰1‰H‰$ˆCˆKˆoˆ6ˆCˆKˆPˆ`ˆoˆKˆPˆcˆkˆÉ‰ЋДŠÎ‰ЋДŠЋДŠ‹ЋДŠ‹ЋДŠÇŠÌŠ‹”ŠÇŠÌŠ‹{‹}‹‹Ú‹§‹«‹±‹Ë‹§‹«‹Æ‹Ë‹TŒŠŒŠŒŒâŒêŒÿŒ'×'DwÇ3D“©µÇ:D¤©ÂÇ'3w“©µ'*wŠ©¬'*wŠ©¬}ކމޑŽ}ކމޑކމޑŽÍކމޑ޽ŽÂŽÍŽfpÄÐlpÔà?@ïðíð €  ‡½À NPýÛàop%%Ë&Ð&a+p+>/@/= =/=0=÷?@RA`A„AAŸA AäBðBDD-P0P\ \K\P\[\`\q\€\¤\°\Á\Ð\ý\]œ_ _­_°_ddss%t0tÅzÐzç{ð{}}݃àƒå…ð…·‡À‡H‰P‰Œ ŒèðëŽGë4ƒEÕë¤EÕë¤EÕëïøÕë ( ( (dx†Ždx†Žqx†Ž”Wi”Wi”¶iz¶äzÈÎÕÚÚäzéò÷W /QW'+QWep¿pÑ×Þãùe0>be6:ben—Ì ž ° Ì ž ° Ì ž ° Çܨ·‰¬  7 ¤¬  7 ¤  7 Ï  7 Ê €\€\“&\“‘\-ê\-?ÃåõPÃåõ^Ãåõ\Ûáål\Ûáål\Ûáål\Ùl\Ùl\cyÙÝ´Öêõ£Öê ¹"_ ¹"U$hy¬"U$/"5Þçñ YbsŒþ'ž§±Ç> G Q g Þ ç ñ  ~ ‡ ‘ §  ' 1 G 8 A J ] ê ó ý  š £ ­ À JS]pú  ª³½ÐZcm€ 0ºÃÍàjs}HQ[n /ÈÑÛœ¯hq{Ž)2<Oéòü©²¼Ï„—ªDMWj *ÄÍ×ê„—ªDMWj *ÄÍ×ê„—ª= F P c ý !!#!½!Æ!Ð!ã!}"†""£":#C#M#`#ê#ó#ý#$š$£$­$À$J%S%]%p%ý%&&#&½&Æ&Ð&ã&}'†''£'=(F(P(c(ú() ) )ª)³)½)Ð)+,K,w,Œ,5,K,w,Œ,>,K,w,Œ,>,K,w,Œ,>,K,w,Œ,>,G,w,Œ,»,Û,--Å,Û,--Î,Û,--Î,Û,--Î,Û,--Î,×,--[-d-r-Š-»-Ä-Ò-ê-!.*.4.L.Š.“. .¸.ï.ø.//O/X/a/y/¯/¸/Á/Ù/$0¡1Â1Ì1$0¡1Â1Ì1™01Â1Ì1ª1Â1Ñ1ê1ª1Â1Ñ1ê1´1Â1Ñ1ê1´1½1Ñ1ê1r2{2…2233333š3£3­3Å3 44434{4„4Ž4¦46d6Ð6æ6 6I6Ð6æ6 6&6Ð6Ü66&6Ð6Ü6†66™6¯6 7 7™7¤77 7™7¤7 7D7s7ˆ7*7D7s7ˆ767D7s7ˆ767D7s7ˆ767D7s7ˆ767@7s7ˆ7Í7à7Y8d8Û7à7Y8d8à7838H8ê7838H8ö7838H8ö7838H8ö7838H8ö7838H8¤8ü9#:3:Á8Û8#:):Ò8Û8#:):ä89œ9¯9ï9ü9œ9¯9ï9ü9œ9¯9ï9ü9¦9¯9ï9ü9¦9¯9ï9ü9”9™9¯9æ9n:_;p;‡;n:_;p;‡;n:q:~: ;J;_;¯:·:Ç:Ì:Ø:é:J;V; ;J;p;‡; ;;p;v;;;p;v;;*;v;‚;¾;\<ä<f>¾;Ù;à;ä;ä<\=D>f>¾;Ù;ä<\=D>f>Ð;Ù;ä<\=D>f>ä<\=D>f>4=G=U>f>Ü;à;ä;\<\=D>í;\<\=D>í;\<\=D>í;<Õ=D>÷;<Õ=D>÷;<Õ=D>ÿ;<Õ=D>#<\<\=Õ=#<\<\=Õ=-<\<\=Õ=-<B<\=Õ=9<B<\=Õ=œ<¥<²<Ç<Ž>"?n?ñ@Ž>ª>­>±>n?æ?Ï@ñ@Ž>ª>n?æ?Ï@ñ@¡>ª>n?æ?Ï@ñ@n?æ?Ï@ñ@½?Ñ?à@ñ@ª>­>±>"?æ?Ï@º>"?æ?Ï@º>"?æ?Ï@º>æ>_@Ï@À>æ>_@Ï@À>Ò>_@Ï@É>Ò>_@Ï@í>"?æ?_@í>"?æ?_@ó>"?æ?_@ó>?æ?_@ÿ>?æ?_@A²AþACA:A=AAAþAvB_CCA:AþAvB_CC1A:AþAvB_CCþAvB_CCMBaBpCC:A=AAA²AvB_CJA²AvB_CJA²AvB_CJAvAïB_CPAvAïB_CPAbAïB_CYAbAïB_C}A²AvBïB}A²AvBïBƒA²AvBïBƒA˜AvBïBA˜AvBïBÁCÏCßCïC1D:DDD\D¡DªD´DÌDEE!E9E{E„EŽE¦EáEêEôE FQFZFdF|FÁFÏFßFïF1G:GDG\G¡G¯G¿GÏGHH$HAS"9AS"(AS"(Âêí†Òê톆¦ñ#Tñ#Tjtñ#Tjt·Ø¥ç$]¥ç$:D]¥ç$:D]¥çeÜ  ¥çevB ¥çB ¥çB ¥€{ ¥€{ ¥€ºÂ{/e€‰úˆ¥ßôˆ¥ßôˆ¥ß鈥ß鉺{‰º{–{ç€B{ ÷€B{ ÷€B{ ú7BK·Ã7gK{È 7gÈãK{ë OXëþg€·g€·g€§g€§xÜ B}Ü B}˜ }• ˜ÖB˜ÖBžÖ B£Ö*BÄÖ*B1‚Ô Û û  Ì ê 1‚Ô Û û  Ì ê A‚Ì ê J‚Ù ê k‚Ù ê ‡ m ì   m ì   m ì   F I m ì  & F I m ì  / F I m   æ„ Ÿ «  ó„ Ÿ « Ô Û ÷  G F [ … „ Ÿ « Ô Û ÷  G F [ …* „ « Ï G „ Ã Ï Û ÷ G F [ …Û J G d u Û J G d u Û ÷ G O Û ð G O ú A O d u ú A O d u A W d u A u * A u J ÷ d u — ¾ Á Î Ñ F [ …S ÷ d u — ¾ Á Î Ñ F [ …\ ÷ — ¾ Á Î Ñ F [ …x ÷ — ¾ Á Î Ñ F [ …‰ ÷ Ñ 9 ‰ ÷ Ñ 9 ÷ è 9 — ÷ è 9 ã ÷ / 9 ã ÷ / 9 ã ÷ / 9 ã ÷ / 9 — ¾ Á Î 9 F [ …§ ¾ Á Î 9 F [ …9 F [ …9 F [ …9 F Â Ó >I9 F Â Ó >IÂ Ó >IÂ Ó >I[ { Ó I…Ó I_i…Ó I_i…  m ½  C K [ m ½  C K [ ¥íü¯íüÌåüÌ=ü-HÌ=ü-HÌìüÌéüì3-Hì3-Hò3-Hû3-H3-H=å-Muxˆ‹Gå-Muxˆ‹PåMuxˆ‹låMuxˆ‹|å‹ö|å‹ö‚å›öŠå›öÕå›®Õå›®Õ囡Õ囡Muxˆö]uxˆööb”Åb”ÅÛåb”ÅÛå'b‘¢'SVb‘¢7SVb‘¢<SVb›¢Ëéôø+W\o+W\o“ÃÈß“ÃÈß„h 1ÇaŠh 1ÇaµäÇ×Waü+×ç L 1| « ç÷à ò ÷ ? ‚ ± '  7UK  7UK z 7G  Ï GU ? '7h æBÇh æBÇh š Uhš Ì h{Ì þ {Žþ 0Ž¡0b¡´b”´Çþ²öÀBU²öÀBUD²öÀBUÀÈÀæÐÞ**Œ-¢-¶-m1ç1 2ñ2395G5Ä-1141>1G1I1U1m1ç1 2ñ2395G5:.f.95G5f.1141>1ç1 2ñ23}.11ç1 2ñ23}.î.ç1ú1î.\/ú1 2\/Ê/ 2 2Ì/11ñ23Ú/11ñ23Ú/=0ñ23=0«033Þ=3P3I5S5~Š1›1c3v3›v3‰3"‘‰3œ3ÞQœ3¯3Žú¯3Â3úfÂ3Õ3fÒÕ3è3Ò>è3û3>ªû34ò^4!4^Ê!444Ê644G46¢G4Z4ÖBZ4m4B®m4€4®€4“4†“4¦4º&¦4¹4&’¹4É4’þÉ4Ù4þjÙ4é4- ™ é4ù4´ !ù4 5 !Œ! 55®!**-*›1®1 2Ë23=3P3c3)595¼!p""ê)ô)**-*›1®1 2Ë23=3P3c3)595å!")5957"c"P3c3c"p""ê)ô)*›1®1 2Ë23=3"ê)›1®1 2Ë23=3"#›1®1 #ê) 2Ë23=3#ê) 2Ë23=3C#¦# 232¦# $32F2 $l$F2Y2l$Ú$Y2l2Ú$H%l22H%¶%2’2¶%$&’2¥2$& '3=31& '3=31&Ÿ&3*3Ÿ& '*3=3 '{'¥2¸2{'é'¸2Ë2-*Œ-¢-¶-®1ç1Ë2ñ25)5;*t-w--Š-Œ-¢-¶-®1ç1Ë2ñ25)5{*§*5)5§*t-w--®1ç1Ë2ñ2È*t-®1ç1Ë2ñ2È*>+®1Á1>+©+Á1Ô1©+,Ô1ç1,t-Ë2ñ2',t-Ë2ñ2',Š,Ë2Þ2Š,ø,Þ2ñ2õ$ƒ r}…!2{¸Ì8_Hƒ8=Hw8=HPTwK_wƒKRwƒÀéð9ù iÇéð1 aù1)a 1=a)JY9Eir}…S`;I‰°mvy°‰Žy£‰Žy|€£œ°£°œ££°m–›¯•÷ B™»„ c v º Ê Î ô p Œ  & ž ¹ >ô Z ] l & ž ¹ 3 >ô Z & ž ¹ 3 >ô  & ž >ô  & ž >  & ž >& ž >u ‰ -> Z ¹ 3 Z ¹ 3 Z ¹ 3 ) 0 E ¹  0 E ¹  0 E ¹  < E ¹  ) 0 E Z  3 ) 0 E Z  3 E Z  3 Œ  3 Œ  3 –  3 – ó 3 – ¯ 3 « – « 3 « ¢ « 3 « ¯ ó « » ó « » ó « » Ä Ë à « Ë à « Ë à « × à « Ä Ë à ó Ä Ë à ó à ó t } ž « zÈ×’4zÁ4h‚Á4hŠ´4hÁÈ×119CyhHyhHrh’¨îøŸ¨îø¹=ø4ÁÊÍ=ø4Í=ø4ÍíøÍêøí34í34ó3 4ü3434=]b=]b=]bëôšªrœÏr¤Ïr¤¬ÜšªÜNªåÜNªåÜûªµÜøªµÿEµåÿEµåE½åEÊå/EÊåNwzšçWwzšç`wzš|Žççî¦ÏêA¦Ï&0A¦Ï&0A:âAs5L†A\5L†S\5L†5L†16PTY`ŸL\#16PTYL\6JL\6JL\å5j†Ó5L†âÓï5L†âæï5L†â5L†â5W\lpu|»†–IW\lpu†–\f†–\f†–ïÑâL¤À Káò Káò-DáòKÏåáò KcåVò K_åVò V_åVò åVò å $)0o,ù $),,,·:VcÏVápÏVápÏVáp¢áw¢áw‹á‚‹á²·ÇËÐ×§·¤²·ÇËЧ··Á§··Á§·^§Åá¢ÏV¢ÏV©ÏV©½V´½VV).>BGNVf).>BGVf.8Vf.8VfÓt& f %K f %f í  f €  ( > x f {  ( > x r {  ( > x  ( > x  $ 0 @ D I P > N  $ 0 @ D I > N 0 : > N 0 : > N Ø ( \ x € í ( > x Ž í ( > x Ž í ( > x Ž ¿ ² • ¿ ² • ª ² ¡ ª ² ² Ô Ù é í ò ù 8 É Ù Æ Ô Ù é í ò É Ù Ù ã É Ù Ù ã É Ù € É ç ¿ í ( > x ² ¿ í ( > x ² Æ í ( > x ² Æ Û ( > x ² Ò Û ( > x ² ( > x ² ( J O _ c h o ® x ˆ < J O _ c h x ˆ O Y x ˆ O Y x ˆ õ > – ² X…ÂÎgvÂÎgvÂÎ âð  %0ÝàBP·¡¥ôÖæï´Öæïe´Öæïe´ÖæïÈíŸúc›Ò´ïŸúˆ ´ äßïÍÚˆ ‘ äñCx…’ÍÚˆ ‘ äñCxËàô>˜¦Èíc“ûQ~“ûQˆ•˜t“ûQt}Š“ûQ û‚›Ò¢ Ì Ó ÎÛ‰›Òß+ H ‚ ‰ ˜ Õ Ý  Ì Ó ÎÛ‰›Òß+ H ‚ ‰ ˜ Õ  Ì Ó ÎÛ‰›Òß+ H ‚ ‰ œ Ì  Ì Ó ÎÛ‰›Òß+ H ‚ ‰ œ Ì  Ì Ó N c w   % 2 ¢ ± Ï ´ Ì Ó s ,V´Ã Ì Ó Ã Ì Ó ü s ,V›( s ,V±h s V±'›ô  9 Y 8Vï4=Ed–™©éþa¶»îE, 9 ò û +84=o}…´, 9 ò û +84=Ž¢í1Xadö, 9 ò û +84=Ž¢í1Xan¨«Ä×á3H]²ø#v[Ï´ßsÏ´˜±´js€ßŸÎTr/[0/›½gimli-0.19.0/fixtures/self/debug_str010066400017500001750000004346021343337721300156470ustar0000000000000000rustc version 1.11.0-nightly (696b703b5 2016-07-03)./src/lib.rs/Users/fitzgen/src/gimligimliparsertest_compilation_units__STATIC_FMTSTR_ZN5gimli6parser22test_compilation_units15__STATIC_FMTSTRE_FILE_LINE_ZN5gimli6parser22test_compilation_units10_FILE_LINEE{{impl}}new_ZN5gimli6parser8{{impl}}3new10_FILE_LINEEtest_parse_unit_length_32_ok_ZN5gimli6parser28test_parse_unit_length_32_ok15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_unit_length_32_ok10_FILE_LINEEtest_parse_unit_length_64_ok_ZN5gimli6parser28test_parse_unit_length_64_ok15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_unit_length_64_ok10_FILE_LINEEtest_parse_unit_length_unknown_reserved_value_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_value15__STATIC_FMTSTRE_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_value10_FILE_LINEEtest_parse_unit_length_incomplete_ZN5gimli6parser33test_parse_unit_length_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_unit_length_incomplete10_FILE_LINEEtest_parse_unit_length_64_incomplete_ZN5gimli6parser36test_parse_unit_length_64_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser36test_parse_unit_length_64_incomplete10_FILE_LINEEtest_compilation_unit_version_ok_ZN5gimli6parser32test_compilation_unit_version_ok15__STATIC_FMTSTRE_ZN5gimli6parser32test_compilation_unit_version_ok10_FILE_LINEEtest_compilation_unit_version_unknown_version_ZN5gimli6parser45test_compilation_unit_version_unknown_version15__STATIC_FMTSTRE_ZN5gimli6parser45test_compilation_unit_version_unknown_version10_FILE_LINEEtest_compilation_unit_version_incomplete_ZN5gimli6parser40test_compilation_unit_version_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser40test_compilation_unit_version_incomplete10_FILE_LINEEtest_parse_debug_abbrev_offset_32_ZN5gimli6parser33test_parse_debug_abbrev_offset_3215__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_debug_abbrev_offset_3210_FILE_LINEEtest_parse_debug_abbrev_offset_32_incomplete_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incomplete10_FILE_LINEEtest_parse_debug_abbrev_offset_64_ZN5gimli6parser33test_parse_debug_abbrev_offset_6415__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_debug_abbrev_offset_6410_FILE_LINEEtest_parse_debug_abbrev_offset_64_incomplete_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incomplete10_FILE_LINEEtest_parse_address_size_ok_ZN5gimli6parser26test_parse_address_size_ok15__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_address_size_ok10_FILE_LINEErange_from_ZN5gimli6parser8{{impl}}10range_from10_FILE_LINEEtest_parse_compilation_unit_header_32_ok_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok15__STATIC_FMTSTRE_ZN5gimli6parser40test_parse_compilation_unit_header_32_ok10_FILE_LINEEtest_parse_compilation_unit_header_64_ok_ZN5gimli6parser40test_parse_compilation_unit_header_64_ok15__STATIC_FMTSTRE_ZN5gimli6parser40test_parse_compilation_unit_header_64_ok10_FILE_LINEEtest_parse_attribute_addr_ZN5gimli6parser25test_parse_attribute_addr15__STATIC_FMTSTRE_ZN5gimli6parser25test_parse_attribute_addr10_FILE_LINEE__STATIC_FMTARGS_ZN5gimli6parser25test_parse_attribute_addr16__STATIC_FMTARGSEtest_parse_attribute_block1_ZN5gimli6parser27test_parse_attribute_block115__STATIC_FMTSTRE_ZN5gimli6parser27test_parse_attribute_block110_FILE_LINEE_ZN5gimli6parser27test_parse_attribute_block116__STATIC_FMTARGSEtest_parse_attribute_block2_ZN5gimli6parser27test_parse_attribute_block215__STATIC_FMTSTRE_ZN5gimli6parser27test_parse_attribute_block210_FILE_LINEE_ZN5gimli6parser27test_parse_attribute_block216__STATIC_FMTARGSEtest_parse_attribute_block4_ZN5gimli6parser27test_parse_attribute_block415__STATIC_FMTSTRE_ZN5gimli6parser27test_parse_attribute_block410_FILE_LINEE_ZN5gimli6parser27test_parse_attribute_block416__STATIC_FMTARGSEtest_parse_attribute_block_ZN5gimli6parser26test_parse_attribute_block15__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_block10_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_block16__STATIC_FMTARGSEtest_parse_attribute_data1_ZN5gimli6parser26test_parse_attribute_data115__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_data110_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_data116__STATIC_FMTARGSEtest_parse_attribute_data2_ZN5gimli6parser26test_parse_attribute_data215__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_data210_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_data216__STATIC_FMTARGSEtest_parse_attribute_data4_ZN5gimli6parser26test_parse_attribute_data415__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_data410_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_data416__STATIC_FMTARGSEtest_parse_attribute_data8_ZN5gimli6parser26test_parse_attribute_data815__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_data810_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_data816__STATIC_FMTARGSEtest_parse_attribute_udata_ZN5gimli6parser26test_parse_attribute_udata15__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_udata10_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_udata16__STATIC_FMTARGSEtest_parse_attribute_sdata_ZN5gimli6parser26test_parse_attribute_sdata15__STATIC_FMTSTRE_ZN5gimli6parser26test_parse_attribute_sdata10_FILE_LINEE_ZN5gimli6parser26test_parse_attribute_sdata16__STATIC_FMTARGSEtest_parse_attribute_exprloc_ZN5gimli6parser28test_parse_attribute_exprloc15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_attribute_exprloc10_FILE_LINEE_ZN5gimli6parser28test_parse_attribute_exprloc16__STATIC_FMTARGSEtest_parse_attribute_flag_true_ZN5gimli6parser30test_parse_attribute_flag_true15__STATIC_FMTSTRE_ZN5gimli6parser30test_parse_attribute_flag_true10_FILE_LINEE_ZN5gimli6parser30test_parse_attribute_flag_true16__STATIC_FMTARGSEtest_parse_attribute_flag_false_ZN5gimli6parser31test_parse_attribute_flag_false15__STATIC_FMTSTRE_ZN5gimli6parser31test_parse_attribute_flag_false10_FILE_LINEE_ZN5gimli6parser31test_parse_attribute_flag_false16__STATIC_FMTARGSEtest_parse_attribute_flag_present_ZN5gimli6parser33test_parse_attribute_flag_present15__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_attribute_flag_present10_FILE_LINEE_ZN5gimli6parser33test_parse_attribute_flag_present16__STATIC_FMTARGSEtest_parse_attribute_sec_offset_32_ZN5gimli6parser34test_parse_attribute_sec_offset_3215__STATIC_FMTSTRE_ZN5gimli6parser34test_parse_attribute_sec_offset_3210_FILE_LINEE_ZN5gimli6parser34test_parse_attribute_sec_offset_3216__STATIC_FMTARGSEtest_parse_attribute_sec_offset_64_ZN5gimli6parser34test_parse_attribute_sec_offset_6415__STATIC_FMTSTRE_ZN5gimli6parser34test_parse_attribute_sec_offset_6410_FILE_LINEE_ZN5gimli6parser34test_parse_attribute_sec_offset_6416__STATIC_FMTARGSEtest_parse_attribute_ref1_ZN5gimli6parser25test_parse_attribute_ref115__STATIC_FMTSTRE_ZN5gimli6parser25test_parse_attribute_ref110_FILE_LINEE_ZN5gimli6parser25test_parse_attribute_ref116__STATIC_FMTARGSEtest_parse_attribute_ref2_ZN5gimli6parser25test_parse_attribute_ref215__STATIC_FMTSTRE_ZN5gimli6parser25test_parse_attribute_ref210_FILE_LINEE_ZN5gimli6parser25test_parse_attribute_ref216__STATIC_FMTARGSEtest_parse_attribute_ref4_ZN5gimli6parser25test_parse_attribute_ref415__STATIC_FMTSTRE_ZN5gimli6parser25test_parse_attribute_ref410_FILE_LINEE_ZN5gimli6parser25test_parse_attribute_ref416__STATIC_FMTARGSEtest_parse_attribute_ref8_ZN5gimli6parser25test_parse_attribute_ref815__STATIC_FMTSTRE_ZN5gimli6parser25test_parse_attribute_ref810_FILE_LINEE_ZN5gimli6parser25test_parse_attribute_ref816__STATIC_FMTARGSEtest_parse_attribute_refudata_ZN5gimli6parser29test_parse_attribute_refudata15__STATIC_FMTSTRE_ZN5gimli6parser29test_parse_attribute_refudata10_FILE_LINEE_ZN5gimli6parser29test_parse_attribute_refudata16__STATIC_FMTARGSEtest_parse_attribute_refaddr_32_ZN5gimli6parser31test_parse_attribute_refaddr_3215__STATIC_FMTSTRE_ZN5gimli6parser31test_parse_attribute_refaddr_3210_FILE_LINEE_ZN5gimli6parser31test_parse_attribute_refaddr_3216__STATIC_FMTARGSEtest_parse_attribute_refaddr_64_ZN5gimli6parser31test_parse_attribute_refaddr_6415__STATIC_FMTSTRE_ZN5gimli6parser31test_parse_attribute_refaddr_6410_FILE_LINEE_ZN5gimli6parser31test_parse_attribute_refaddr_6416__STATIC_FMTARGSEtest_parse_attribute_refsig8_ZN5gimli6parser28test_parse_attribute_refsig815__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_attribute_refsig810_FILE_LINEE_ZN5gimli6parser28test_parse_attribute_refsig816__STATIC_FMTARGSEtest_parse_attribute_string_ZN5gimli6parser27test_parse_attribute_string15__STATIC_FMTSTRE_ZN5gimli6parser27test_parse_attribute_string10_FILE_LINEE_ZN5gimli6parser27test_parse_attribute_string16__STATIC_FMTARGSEtest_parse_attribute_strp_32_ZN5gimli6parser28test_parse_attribute_strp_3215__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_attribute_strp_3210_FILE_LINEE_ZN5gimli6parser28test_parse_attribute_strp_3216__STATIC_FMTARGSEtest_parse_attribute_strp_64_ZN5gimli6parser28test_parse_attribute_strp_6415__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_attribute_strp_6410_FILE_LINEE_ZN5gimli6parser28test_parse_attribute_strp_6416__STATIC_FMTARGSEtest_parse_attribute_indirect_ZN5gimli6parser29test_parse_attribute_indirect15__STATIC_FMTSTRE_ZN5gimli6parser29test_parse_attribute_indirect10_FILE_LINEE_ZN5gimli6parser29test_parse_attribute_indirect16__STATIC_FMTARGSEnext_ZN5gimli6parser8{{impl}}4next10_FILE_LINEE_ZN5gimli6parser8{{impl}}33nextEnextselfattrendresteEndiantest_attrs_iter_ZN5gimli6parser15test_attrs_iter15__STATIC_FMTSTRE_ZN5gimli6parser15test_attrs_iter10_FILE_LINEE_ZN5gimli6parser15test_attrs_iter16__STATIC_FMTARGSEcurrent_ZN5gimli6parser8{{impl}}7current10_FILE_LINEEnext_sibling_ZN5gimli6parser8{{impl}}12next_sibling40{{closure}}E{{closure}}{{closure}}resassert_entry_with_name_ZN5gimli6parser22assert_entry_with_name15__STATIC_FMTSTRE_ZN5gimli6parser22assert_entry_with_name10_FILE_LINEE_ZN5gimli6parser22assert_entry_with_name40{{closure}}Etest_cursor_next_dfs_ZN5gimli6parser20test_cursor_next_dfs15__STATIC_FMTSTRE_ZN5gimli6parser20test_cursor_next_dfs10_FILE_LINEEtest_cursor_next_sibling_no_sibling_ptr_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr15__STATIC_FMTSTRE_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptr10_FILE_LINEEtest_cursor_next_sibling_with_sibling_ptr_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr15__STATIC_FMTSTRE_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptr10_FILE_LINEEtest_parse_type_signature_ok_ZN5gimli6parser28test_parse_type_signature_ok15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_type_signature_ok10_FILE_LINEEtest_parse_type_signature_incomplete_ZN5gimli6parser36test_parse_type_signature_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser36test_parse_type_signature_incomplete10_FILE_LINEEtest_parse_type_offset_32_ok_ZN5gimli6parser28test_parse_type_offset_32_ok15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_type_offset_32_ok10_FILE_LINEEtest_parse_type_offset_64_ok_ZN5gimli6parser28test_parse_type_offset_64_ok15__STATIC_FMTSTRE_ZN5gimli6parser28test_parse_type_offset_64_ok10_FILE_LINEEtest_parse_type_offset_incomplete_ZN5gimli6parser33test_parse_type_offset_incomplete15__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_type_offset_incomplete10_FILE_LINEEtest_parse_type_unit_header_32_ok_ZN5gimli6parser33test_parse_type_unit_header_32_ok15__STATIC_FMTSTRE_ZN5gimli6parser33test_parse_type_unit_header_32_ok16__STATIC_FMTARGSE_ZN5gimli6parser33test_parse_type_unit_header_32_ok10_FILE_LINEEErrorBadUnsignedLeb128BadSignedLeb128AbbreviationCodeZeroUnknownTagBadHasChildrenUnknownNameUnknownFormExpectedZeroDuplicateAbbreviationCodeUnknownReservedLengthUnknownVersionUnitHeaderLengthTooShortUnknownAbbreviationUnexpectedEofFormatDwarf64Dwarf32AbbreviationTagArrayTypeClassTypeEntryPointEnumerationTypeFormalParameterImportedDeclarationLabelLexicalBlockMemberPointerTypeReferenceTypeCompileUnitStringTypeStructureTypeSubroutineTypeTypedefUnionTypeUnspecifiedParametersVariantCommonBlockCommonInclusionInheritanceInlinedSubroutineModulePtrToMemberTypeSetTypeSubrangeTypeWithStmtAccessDeclarationBaseTypeCatchBlockConstTypeConstantEnumeratorFileTypeFriendNamelistNamelistItemPackedTypeSubprogramTemplateTypeParameterTemplateValueParameterThrownTypeTryBlockVariantPartVariableVolatileTypeDwarfProcedureRestrictTypeInterfaceTypeNamespaceImportedModuleUnspecifiedTypePartialUnitImportedUnitConditionSharedTypeTypeUnitRvalueReferenceTypeTemplateAliasLoUserHiUserAbbreviationHasChildrenNoYesAttributeNameSiblingLocationNameOrderingByteSizeBitOffsetBitSizeStmtListLowPcHighPcLanguageDiscrDiscrValueVisibilityImportStringLengthCommonReferenceCompDirConstValueContainingTypeDefaultValueInlineIsOptionalLowerBoundProducerPrototypedReturnAddrStartScopeBitStrideUpperBoundAbstractOriginAccessibilityAddressClassArtificialBaseTypesCallingConventionCountDataMemberLocationDeclColumnDeclFileDeclLineDeclarationDiscrListEncodingExternalFrameBaseIdentifierCaseMacroInfoPrioritySegmentSpecificationStaticLinkTypeUseLocationVariableParameterVirtualityVtableElemLocationAllocatedAssociatedDataLocationByteStrideEntryPcUseUtf8ExtensionRangesTrampolineCallColumnCallFileCallLineDescriptionBinaryScaleDecimalScaleSmallDecimalSignDigitCountPictureStringMutableThreadsScaledExplicitObjectPointerEndianityElementalPureRecursiveSignatureMainSubprogramDataBitOffsetConstExprEnumClassLinkageNameAttributeFormAddrBlock2Block4Data2Data4Data8StringBlockBlock1Data1FlagSdataStrpUdataRefAddrRef1Ref2Ref4Ref8RefUdataIndirectSecOffsetExprlocFlagPresentRefSig8AttributeValueDataUnitRefDebugInfoRefDebugTypesRefDebugStrRefLittleEndianDebugTypesOffset__0DebugStrOffsetDebugAbbrevOffsetDebugInfoOffsetUnitOffsetDebugInfodebug_info_section_ZN5gimli6parser8{{impl}}32newEnew_ZN5gimli6parser8{{impl}}46compilation_unitsEcompilation_unitscompilation_unitsEndianBuf__1_ZN5gimli6parser8{{impl}}39range_fromErange_fromidxbuf_ZN5gimli6parser8{{impl}}37range_toErange_torange_toCompilationUnitsIterinputCompilationUnitunit_lengthversiondebug_abbrev_offsetaddress_sizeformatentries_buf_ZN5gimli6parser8{{impl}}48size_of_unit_lengthEsize_of_unit_lengthsize_of_unit_length_ZN5gimli6parser8{{impl}}43size_of_headerEsize_of_headersize_of_headerunit_length_sizeversion_sizedebug_abbrev_offset_sizeaddress_size_size_ZN5gimli6parser8{{impl}}50length_including_selfElength_including_selflength_including_self_ZN5gimli6parser8{{impl}}41address_sizeEaddress_size_ZN5gimli6parser8{{impl}}35formatEformat_ZN5gimli6parser8{{impl}}36entriesEentriesentriesabbreviations_ZN5gimli6parser8{{impl}}44is_valid_offsetEis_valid_offsetis_valid_offsetoffsetrelative_to_entries_bufstartFormatInput_ZN5gimli6parser8{{impl}}34mergeEmergemergeAttributeSpecificationnameform_ZN5gimli6parser8{{impl}}3newE_ZN5gimli6parser8{{impl}}4nameE_ZN5gimli6parser8{{impl}}4formEAbbreviationcodetaghas_childrenattributes_ZN5gimli6parser8{{impl}}4codeE_ZN5gimli6parser8{{impl}}3tagE_ZN5gimli6parser8{{impl}}12has_childrenE_ZN5gimli6parser8{{impl}}10attributesEAbbreviationsabbrevs_ZN5gimli6parser8{{impl}}5emptyEempty_ZN5gimli6parser8{{impl}}6insertEinsertabbreventry_ZN5gimli6parser8{{impl}}3getEgetRUST$ENUM$DISRAttributevalue_ZN5gimli6parser8{{impl}}5valueEAttributeInput__2_ZN5gimli6parser8{{impl}}40mergeEmergeT_ZN5gimli6parser8{{impl}}88merge>Emerge>rangeDebuggingInformationEntryattrs_sliceafter_attrsunit_ZN5gimli6parser8{{impl}}34attrsEattrsattrsAttrsIterDebugAbbrevdebug_abbrev_section_ZN5gimli6parser8{{impl}}42abbreviationsEabbreviationsEntriesCursorcached_current_ZN5gimli6parser8{{impl}}36currentEcurrentcachedresult_ZN5gimli6parser8{{impl}}37next_dfsEnext_dfsnext_dfsdelta_depth_resultiter_ZN5gimli6parser8{{impl}}41next_siblingEnext_siblingsibling_ptrdepthTypeUnitheadertype_signaturetype_offset_ZN5gimli6parser8{{impl}}8read_u16Eread_u16_ZN5gimli6parser8{{impl}}8read_u32Eread_u32_ZN5gimli6parser8{{impl}}8read_u64Eread_u64_ZN5gimli6parser8{{impl}}5cloneEclone_ZN5gimli6parser8{{impl}}3fmtEfmt__arg_0builder_ZN5gimli6parser8parse_u8Eparse_u8_ZN5gimli6parser8{{impl}}2eqEeq__self_1_0__self_0_0_ZN5gimli6parser22test_compilation_unitsEdebug_infounitsexpectedright_valleft_val__arg1__arg0otherwiseunit_len_ZN5gimli6parser8{{impl}}34derefEderefderef_ZN5gimli6parser58parse_compilation_unit_headerEparse_compilation_unit_headerparse_compilation_unit_headervalerr_ZN5gimli6parser46parse_unit_lengthEparse_unit_lengthparse_unit_length_ZN5gimli6parser45parse_u32_as_u64Eparse_u32_as_u64parse_u32_as_u64_ZN5gimli6parser38parse_u64Eparse_u64parse_u64_ZN5gimli6parser42parse_versionEparse_versionparse_version_ZN5gimli6parser38parse_u16Eparse_u16parse_u16_ZN5gimli6parser54parse_debug_abbrev_offsetEparse_debug_abbrev_offsetparse_debug_abbrev_offset_ZN5gimli6parser25parse_debug_abbrev_offset40{{closure}}E_ZN5gimli6parser18parse_address_sizeEparse_address_size_ZN5gimli6parser8{{impl}}33intoEintointo_ZN5gimli6parser8{{impl}}31eqEeq__self_1_3__self_1_1__self_1_4__self_1_2__self_1_5__self_0_4__self_0_2__self_0_3__self_0_1__self_0_5_ZN5gimli6parser8{{impl}}32fmtEfmt__self_vi__arg_1_vi_ZN5gimli6parser18parse_unsigned_lebEparse_unsigned_leb_ZN5gimli6parser16parse_signed_lebEparse_signed_leb_ZN5gimli6parser23parse_abbreviation_codeEparse_abbreviation_code_ZN5gimli6parser22parse_abbreviation_tagEparse_abbreviation_tag_ZN5gimli6parser31parse_abbreviation_has_childrenEparse_abbreviation_has_children_ZN5gimli6parser20parse_attribute_nameEparse_attribute_name_ZN5gimli6parser20parse_attribute_formEparse_attribute_form_ZN5gimli6parser29parse_attribute_specificationEparse_attribute_specificationspec_ZN5gimli6parser34parse_null_attribute_specificationEparse_null_attribute_specification_ZN5gimli6parser30parse_attribute_specificationsEparse_attribute_specifications_ZN5gimli6parser30parse_attribute_specifications11{{closure}}E_ZN5gimli6parser30parse_attribute_specifications11{{closure}}11{{closure}}Ea_ZN5gimli6parser18parse_abbreviationEparse_abbreviation_ZN5gimli6parser23parse_null_abbreviationEparse_null_abbreviation_ZN5gimli6parser19parse_abbreviationsEparse_abbreviations_ZN5gimli6parser19parse_abbreviations11{{closure}}E_ZN5gimli6parser19parse_abbreviations11{{closure}}11{{closure}}E_ZN5gimli6parser28test_parse_unit_length_32_okElength_ZN5gimli6parser28test_parse_unit_length_64_okE_ZN5gimli6parser45test_parse_unit_length_unknown_reserved_valueE_ZN5gimli6parser33test_parse_unit_length_incompleteE_ZN5gimli6parser36test_parse_unit_length_64_incompleteE_ZN5gimli6parser32test_compilation_unit_version_okE_ZN5gimli6parser45test_compilation_unit_version_unknown_versionE_ZN5gimli6parser40test_compilation_unit_version_incompleteE_ZN5gimli6parser33test_parse_debug_abbrev_offset_32E_ZN5gimli6parser44test_parse_debug_abbrev_offset_32_incompleteE_ZN5gimli6parser33test_parse_debug_abbrev_offset_64E_ZN5gimli6parser44test_parse_debug_abbrev_offset_64_incompleteE_ZN5gimli6parser26test_parse_address_size_okE_ZN5gimli6parser40test_parse_compilation_unit_header_32_okE_ZN5gimli6parser40test_parse_compilation_unit_header_64_okE__self_0__arg_1_0_ZN5gimli6parser4takeEtakebytes_ZN5gimli6parser15length_u8_valueElength_u8_valuelen_ZN5gimli6parser16length_leb_valueElength_leb_value_ZN5gimli6parser25test_parse_attribute_addrE_ZN5gimli6parser44parse_attributeEparse_attributeparse_attributedynamic_formnull_idx_ZN5gimli6parser15parse_attribute40{{closure}}Eaddrblockdatapresentreferencech_ZN5gimli6parser45length_u16_valueElength_u16_valuelength_u16_value_ZN5gimli6parser16length_u16_value40{{closure}}E_ZN5gimli6parser45length_u32_valueElength_u32_valuelength_u32_value_ZN5gimli6parser38parse_u32Eparse_u32parse_u32_ZN5gimli6parser16length_u32_value40{{closure}}E_ZN5gimli6parser27test_parse_attribute_block1E_ZN5gimli6parser27test_parse_attribute_block2E_ZN5gimli6parser27test_parse_attribute_block4E_ZN5gimli6parser26test_parse_attribute_blockE_ZN5gimli6parser26test_parse_attribute_data1E_ZN5gimli6parser26test_parse_attribute_data2E_ZN5gimli6parser26test_parse_attribute_data4E_ZN5gimli6parser26test_parse_attribute_data8E_ZN5gimli6parser26test_parse_attribute_udataEbytes_writtenwritable_ZN5gimli6parser26test_parse_attribute_sdataE_ZN5gimli6parser28test_parse_attribute_exprlocE_ZN5gimli6parser30test_parse_attribute_flag_trueE_ZN5gimli6parser31test_parse_attribute_flag_falseE_ZN5gimli6parser33test_parse_attribute_flag_presentE_ZN5gimli6parser34test_parse_attribute_sec_offset_32E_ZN5gimli6parser34test_parse_attribute_sec_offset_64E_ZN5gimli6parser25test_parse_attribute_ref1E_ZN5gimli6parser25test_parse_attribute_ref2E_ZN5gimli6parser25test_parse_attribute_ref4E_ZN5gimli6parser25test_parse_attribute_ref8E_ZN5gimli6parser29test_parse_attribute_refudataE_ZN5gimli6parser31test_parse_attribute_refaddr_32E_ZN5gimli6parser31test_parse_attribute_refaddr_64E_ZN5gimli6parser28test_parse_attribute_refsig8E_ZN5gimli6parser27test_parse_attribute_stringE_ZN5gimli6parser28test_parse_attribute_strp_32E_ZN5gimli6parser28test_parse_attribute_strp_64E_ZN5gimli6parser29test_parse_attribute_indirectE_ZN5gimli6parser15test_attrs_iterE_ZN5gimli6parser20test_cursor_next_dfsEabbrevs_bufdebug_abbrevinfo_bufcursor_ZN5gimli6parser8{{impl}}13abbreviations40{{closure}}E_ZN5gimli6parser8{{impl}}34cloneEclone_ZN5gimli6parser51assert_entry_with_nameEassert_entry_with_namewith_null_ZN11collections3str8{{impl}}8as_bytesEas_bytes_ZN5gimli6parser39test_cursor_next_sibling_no_sibling_ptrE_ZN5gimli6parser41test_cursor_next_sibling_with_sibling_ptrEabbrev_bufroot_ZN5gimli6parser28test_parse_type_signature_okE_ZN5gimli6parser49parse_type_signatureEparse_type_signatureparse_type_signature_ZN5gimli6parser36test_parse_type_signature_incompleteE_ZN5gimli6parser28test_parse_type_offset_32_okE_ZN5gimli6parser46parse_type_offsetEparse_type_offsetparse_type_offset_ZN5gimli6parser17parse_type_offset40{{closure}}E_ZN5gimli6parser28test_parse_type_offset_64_okE_ZN5gimli6parser33test_parse_type_offset_incompleteE_ZN5gimli6parser33test_parse_type_unit_header_32_okE_ZN5gimli6parser51parse_type_unit_headerEparse_type_unit_headerparse_type_unit_headersignature__test_ZN5gimli6__test4mainEmain&[&str]data_ptr*const &str&str*const u8_ZN4core3ptr8{{impl}}10offsetEoffsetcount_ZN4core3ptr8{{impl}}11is_nullEis_nullis_nullu8usize_ZN4core3num8{{impl}}11checked_mulEchecked_mulotherb_ZN4core3num8{{impl}}15overflowing_mulEoverflowing_mulrhs_ZN4core3num8{{impl}}12wrapping_subEwrapping_sub_ZN4core3num8{{impl}}11checked_addEchecked_add_ZN4core3num8{{impl}}15overflowing_addEoverflowing_add_ZN4core3num8{{impl}}15is_power_of_twoEis_power_of_two_ZN4core3num8{{impl}}17next_power_of_twoEnext_power_of_twobitsone_ZN4core3num8{{impl}}13leading_zerosEleading_zeros(&str, u32)u32_ZN4core3num8{{impl}}5to_leEto_le_ZN4core3num8{{impl}}5to_beEto_be_ZN4core3num8{{impl}}10swap_bytesEswap_bytes&[core::fmt::rt::v1::Argument]*const core::fmt::rt::v1::Argumentcorertv1ArgumentpositionPositionNextAtFormatSpecfillalignflagsprecisionwidthAlignmentLeftRightCenterUnknownIsParamNextParamImpliedFormattercurargargs_ZN4core3fmt8{{impl}}11debug_tupleEdebug_tuple_ZN4core3fmt8{{impl}}12debug_structEdebug_struct_ZN4core3fmt8{{impl}}10debug_listEdebug_list_ZN4core3fmt8{{impl}}9debug_mapEdebug_map&mut WriteArgumentV1formatter_ZN4core3fmt8{{impl}}65new<&gimli::parser::CompilationUnit>Enew<&gimli::parser::CompilationUnit>xf_ZN4core3fmt8{{impl}}130new, gimli::parser::Error>>>Enew, gimli::parser::Error>>>_ZN4core3fmt8{{impl}}11new<&usize>Enew<&usize>_ZN4core3fmt8{{impl}}27new<&gimli::parser::Format>Enew<&gimli::parser::Format>_ZN4core3fmt8{{impl}}9new<&u64>Enew<&u64>_ZN4core3fmt8{{impl}}134new, (u64, gimli::parser::Format)), gimli::parser::Error>>Enew, (u64, gimli::parser::Format)), gimli::parser::Error>>_ZN4core3fmt8{{impl}}9new<&u16>Enew<&u16>_ZN4core3fmt8{{impl}}59new<&gimli::parser::EndianBuf>Enew<&gimli::parser::EndianBuf>_ZN4core3fmt8{{impl}}109new, u16), gimli::parser::Error>>Enew, u16), gimli::parser::Error>>_ZN4core3fmt8{{impl}}38new<&gimli::parser::DebugAbbrevOffset>Enew<&gimli::parser::DebugAbbrevOffset>_ZN4core3fmt8{{impl}}140new, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>>Enew, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>>_ZN4core3fmt8{{impl}}8new<&u8>Enew<&u8>_ZN4core3fmt8{{impl}}60new>Enew>_ZN4core3fmt8{{impl}}165new, gimli::parser::CompilationUnit), gimli::parser::Error>>Enew, gimli::parser::CompilationUnit), gimli::parser::Error>>_ZN4core3fmt8{{impl}}30new<&gimli::parser::Attribute>Enew<&gimli::parser::Attribute>_ZN4core3fmt8{{impl}}135new, gimli::parser::Attribute), gimli::parser::Error>>Enew, gimli::parser::Attribute), gimli::parser::Error>>_ZN4core3fmt8{{impl}}9new<&str>Enew<&str>_ZN4core3fmt8{{impl}}26newEnew_ZN4core3fmt8{{impl}}95new>>Enew>>_ZN4core3fmt8{{impl}}11new<&&[u8]>Enew<&&[u8]>_ZN4core3fmt8{{impl}}25newEnew_ZN4core3fmt8{{impl}}35new<&gimli::parser::AttributeValue>Enew<&gimli::parser::AttributeValue>_ZN4core3fmt8{{impl}}11new<&isize>Enew<&isize>_ZN4core3fmt8{{impl}}109new, u64), gimli::parser::Error>>Enew, u64), gimli::parser::Error>>_ZN4core3fmt8{{impl}}37new<&gimli::parser::DebugTypesOffset>Enew<&gimli::parser::DebugTypesOffset>_ZN4core3fmt8{{impl}}139new, gimli::parser::DebugTypesOffset), gimli::parser::Error>>Enew, gimli::parser::DebugTypesOffset), gimli::parser::Error>>_ZN4core3fmt8{{impl}}158new, gimli::parser::TypeUnit), gimli::parser::Error>>Enew, gimli::parser::TypeUnit), gimli::parser::Error>>_ZN4core3fmt8{{impl}}58new<&gimli::parser::TypeUnit>Enew<&gimli::parser::TypeUnit>VoidbuildersDebugTuplefieldsempty_nameDebugStructhas_fieldsDebugListinner_ZN4core3fmt8builders8{{impl}}34entries<&u8,core::slice::Iter>Eentries<&u8,core::slice::Iter>DI_ZN4core3fmt8builders8{{impl}}104entries<&gimli::parser::AttributeSpecification,core::slice::Iter>Eentries<&gimli::parser::AttributeSpecification,core::slice::Iter>DebugInnerDebugMap_ZN4core3fmt8builders8{{impl}}110entries<&u64,&gimli::parser::Abbreviation,std::collections::hash::map::Iter>Eentries<&u64,&gimli::parser::Abbreviation,std::collections::hash::map::Iter>vkKVArgumentspieces_ZN4core3fmt8{{impl}}6new_v1Enew_v1_ZN4core3fmt8{{impl}}16new_v1_formattedEnew_v1_formatted_ZN4core3fmt8{{impl}}8fmtEfmt_ZN4core3fmt8{{impl}}64fmt>Efmt>_ZN4core3fmt8{{impl}}8fmtEfmt_ZN4core3fmt8{{impl}}37fmtEfmt_ZN4core3fmt8{{impl}}7fmtEfmt_ZN4core3fmt8{{impl}}26fmtEfmt_ZN4core3fmt8{{impl}}58fmt>Efmt>_ZN4core3fmt8{{impl}}10fmt<&[u8]>Efmt<&[u8]>_ZN4core3fmt8{{impl}}9fmt<[u8]>Efmt<[u8]>_ZN4core3fmt8{{impl}}59fmt>Efmt>_ZN4core3fmt8{{impl}}32fmtE_ZN4core3fmt8{{impl}}108fmt, gimli::parser::Error>>Efmt, gimli::parser::Error>>_ZN4core3fmt8{{impl}}25fmtEfmt_ZN4core3fmt8{{impl}}33fmtEfmt_ZN4core3fmt8{{impl}}33fmtEfmt_ZN4core3fmt8{{impl}}42fmtEfmt_ZN4core3fmt8{{impl}}10fmtEfmt_ZN4core3fmt8{{impl}}90fmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format))>Efmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format))>_ZN4core3fmt8{{impl}}87fmt,(u64, gimli::parser::Format)>Efmt,(u64, gimli::parser::Format)>T10T11_ZN4core3fmt8{{impl}}30fmtEfmt_ZN4core3fmt8{{impl}}65fmt<(gimli::parser::EndianBuf, u16)>Efmt<(gimli::parser::EndianBuf, u16)>_ZN4core3fmt8{{impl}}62fmt,u16>Efmt,u16>_ZN4core3fmt8{{impl}}96fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)>Efmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)>_ZN4core3fmt8{{impl}}93fmt,gimli::parser::DebugAbbrevOffset>Efmt,gimli::parser::DebugAbbrevOffset>_ZN4core3fmt8{{impl}}16fmt<(&[u8], u8)>Efmt<(&[u8], u8)>_ZN4core3fmt8{{impl}}13fmt<&[u8],u8>Efmt<&[u8],u8>_ZN4core3fmt8{{impl}}121fmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)>Efmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)>_ZN4core3fmt8{{impl}}118fmt,gimli::parser::CompilationUnit>Efmt,gimli::parser::CompilationUnit>_ZN4core3fmt8{{impl}}8fmtEfmt_ZN4core3fmt8{{impl}}9fmtEfmt_ZN4core3fmt8{{impl}}30fmtEfmt_ZN4core3fmt8{{impl}}35fmtEfmt_ZN4core3fmt8{{impl}}36fmtEfmt_ZN4core3fmt8{{impl}}34fmtEfmt_ZN4core3fmt8{{impl}}34fmtEfmt_ZN4core3fmt8{{impl}}29fmtEfmt_ZN4core3fmt8{{impl}}91fmt<(gimli::parser::AttributeInput, gimli::parser::Attribute)>Efmt<(gimli::parser::AttributeInput, gimli::parser::Attribute)>_ZN4core3fmt8{{impl}}88fmt,gimli::parser::Attribute>Efmt,gimli::parser::Attribute>_ZN4core3fmt8{{impl}}65fmt<&gimli::parser::CompilationUnit>Efmt<&gimli::parser::CompilationUnit>_ZN4core3fmt8{{impl}}8fmtEfmt_ZN4core3fmt8{{impl}}73fmt>Efmt>_ZN4core3fmt8{{impl}}10fmtEfmt_ZN4core3fmt8{{impl}}65fmt<(gimli::parser::EndianBuf, u64)>Efmt<(gimli::parser::EndianBuf, u64)>_ZN4core3fmt8{{impl}}62fmt,u64>Efmt,u64>_ZN4core3fmt8{{impl}}95fmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)>Efmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)>_ZN4core3fmt8{{impl}}92fmt,gimli::parser::DebugTypesOffset>Efmt,gimli::parser::DebugTypesOffset>_ZN4core3fmt8{{impl}}114fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit)>Efmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit)>_ZN4core3fmt8{{impl}}111fmt,gimli::parser::TypeUnit>Efmt,gimli::parser::TypeUnit>_ZN4core3fmt8{{impl}}57fmt>Efmt>ResultOkErrResult<(), core::fmt::Error>Result<(&[u8], u8), gimli::parser::Error>_ZN4core6result8{{impl}}132map<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(&[u8], u8),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>mapoptEUFResult, gimli::parser::Error>_ZN4core6result8{{impl}}88expect,gimli::parser::Error>Eexpect,gimli::parser::Error>expectmsgResult<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>Result<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>Result<(gimli::parser::EndianBuf, u64), gimli::parser::Error>_ZN4core6result8{{impl}}186map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),closure>Emap<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),closure>_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>_ZN4core6result8{{impl}}185map<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),closure>Emap<(gimli::parser::EndianBuf, u64),gimli::parser::Error,(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),closure>Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u16),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(gimli::parser::EndianBuf, u16),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>Result<(&[u8], u64), gimli::parser::Error>_ZN4core6result8{{impl}}133map<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(&[u8], u64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>ResultResult<(), std::io::error::Error>Result<(&[u8], i64), gimli::parser::Error>_ZN4core6result8{{impl}}133map<(&[u8], i64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(&[u8], i64),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>ResultResult<(&[u8], gimli::parser::AbbreviationTag), gimli::parser::Error>Result<(&[u8], gimli::parser::AbbreviationHasChildren), gimli::parser::Error>Result<(&[u8], gimli::parser::AttributeName), gimli::parser::Error>Result<(&[u8], gimli::parser::AttributeForm), gimli::parser::Error>Result<(&[u8], gimli::parser::AttributeSpecification), gimli::parser::Error>_ZN4core6result8{{impl}}149map<(&[u8], gimli::parser::AttributeSpecification),gimli::parser::Error,(&[u8], core::option::Option),closure>Emap<(&[u8], gimli::parser::AttributeSpecification),gimli::parser::Error,(&[u8], core::option::Option),closure>Result<(&[u8], ()), gimli::parser::Error>_ZN4core6result8{{impl}}114map<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>Emap<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>_ZN4core6result8{{impl}}104map<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>Emap<(&[u8], ()),gimli::parser::Error,(&[u8], core::option::Option),closure>Result<(&[u8], collections::vec::Vec), gimli::parser::Error>Result<(&[u8], core::option::Option), gimli::parser::Error>_ZN4core6result8{{impl}}127or_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>Eor_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>or_elseOResult<(&[u8], gimli::parser::Abbreviation), gimli::parser::Error>_ZN4core6result8{{impl}}129map<(&[u8], gimli::parser::Abbreviation),gimli::parser::Error,(&[u8], core::option::Option),closure>Emap<(&[u8], gimli::parser::Abbreviation),gimli::parser::Error,(&[u8], core::option::Option),closure>Result<(), ()>Result<(&[u8], gimli::parser::Abbreviations), gimli::parser::Error>_ZN4core6result8{{impl}}100map<(&[u8], gimli::parser::Abbreviations),gimli::parser::Error,gimli::parser::Abbreviations,closure>Emap<(&[u8], gimli::parser::Abbreviations),gimli::parser::Error,gimli::parser::Abbreviations,closure>Result<(&[u8], core::option::Option), gimli::parser::Error>_ZN4core6result8{{impl}}117or_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>Eor_else<(&[u8], core::option::Option),gimli::parser::Error,gimli::parser::Error,closure>Result<(&[u8], &[u8]), gimli::parser::Error>_ZN4core6result8{{impl}}135map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>_ZN4core6result8{{impl}}111map<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure>Emap<(&[u8], &[u8]),gimli::parser::Error,(gimli::parser::EndianBuf, &[u8]),closure>Result<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>Result<(gimli::parser::EndianBuf, &[u8]), gimli::parser::Error>_ZN4core6result8{{impl}}183map<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(gimli::parser::EndianBuf, &[u8]),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Result<(gimli::parser::EndianBuf, u32), gimli::parser::Error>_ZN4core6result8{{impl}}181map<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Emap<(gimli::parser::EndianBuf, u32),gimli::parser::Error,(gimli::parser::AttributeInput, gimli::parser::Attribute),closure>Result_ZN4core6result8{{impl}}35expectEexpectResult_ZN4core6result8{{impl}}53expectEexpect_ZN4core6result8{{impl}}52is_okEis_okis_ok_ZN4core6result8{{impl}}53unwrapEunwrapunwrapResult_ZN4core6result8{{impl}}57expectEexpectResult, gimli::parser::Error>_ZN4core6result8{{impl}}98expect,gimli::parser::Error>Eexpect,gimli::parser::Error>_ZN4core6result8{{impl}}97is_ok,gimli::parser::Error>Eis_ok,gimli::parser::Error>Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error>_ZN4core6result8{{impl}}85fmt,gimli::parser::Error>Efmt,gimli::parser::Error>_ZN4core6result8{{impl}}111fmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)),gimli::parser::Error>Efmt<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)),gimli::parser::Error>_ZN4core6result8{{impl}}86fmt<(gimli::parser::EndianBuf, u16),gimli::parser::Error>Efmt<(gimli::parser::EndianBuf, u16),gimli::parser::Error>_ZN4core6result8{{impl}}117fmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),gimli::parser::Error>Efmt<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset),gimli::parser::Error>_ZN4core6result8{{impl}}37fmt<(&[u8], u8),gimli::parser::Error>Efmt<(&[u8], u8),gimli::parser::Error>_ZN4core6result8{{impl}}142fmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit),gimli::parser::Error>Efmt<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit),gimli::parser::Error>_ZN4core6result8{{impl}}112fmt<(gimli::parser::AttributeInput, gimli::parser::Attribute),gimli::parser::Error>Efmt<(gimli::parser::AttributeInput, gimli::parser::Attribute),gimli::parser::Error>_ZN4core6result8{{impl}}50fmtEfmt_ZN4core6result8{{impl}}97clone,gimli::parser::Error>Eclone,gimli::parser::Error>_ZN4core6result8{{impl}}86fmt<(gimli::parser::EndianBuf, u64),gimli::parser::Error>Efmt<(gimli::parser::EndianBuf, u64),gimli::parser::Error>_ZN4core6result8{{impl}}116fmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),gimli::parser::Error>Efmt<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset),gimli::parser::Error>_ZN4core6result8{{impl}}135fmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit),gimli::parser::Error>Efmt<(gimli::parser::EndianBuf, gimli::parser::TypeUnit),gimli::parser::Error>_ZN4core6result36unwrap_failedEunwrap_failedunwrap_failederror_ZN4core6result35unwrap_failedEunwrap_failedoptionOptionNoneSomeOption_ZN4core6option8{{impl}}13expectEexpect_ZN4core6option8{{impl}}13unwrapEunwrapOption, gimli::parser::Error>>_ZN4core6option8{{impl}}112is_none, gimli::parser::Error>>Eis_none, gimli::parser::Error>>is_none_ZN4core6option8{{impl}}112is_some, gimli::parser::Error>>Eis_some, gimli::parser::Error>>is_some_ZN4core6option8{{impl}}111expect, gimli::parser::Error>>Eexpect, gimli::parser::Error>>Option<&[core::fmt::rt::v1::Argument]>RUST$ENCODED$ENUM$0$0$NoneOption<&u8>RUST$ENCODED$ENUM$0$None_ZN4core6option8{{impl}}29map<&u8,(usize, &u8),closure>Emap<&u8,(usize, &u8),closure>OptionOption<(u64, gimli::parser::Abbreviation)>RUST$ENCODED$ENUM$0$1$3$0$0$0$0$NoneOption<&core::cell::UnsafeCell>>_ZN4core6option8{{impl}}65expect<&core::cell::UnsafeCell>>Eexpect<&core::cell::UnsafeCell>>Option<(u64, u64)>_ZN4core6option8{{impl}}18as_ref<(u64, u64)>Eas_ref<(u64, u64)>as_refOption<&(u64, u64)>_ZN4core6option8{{impl}}19unwrap<&(u64, u64)>Eunwrap<&(u64, u64)>OptionOption>_ZN4core6option8{{impl}}76expect>Eexpect>Option<&gimli::parser::Abbreviation>Option>>RUST$ENCODED$ENUM$0$2$None_ZN4core6option8{{impl}}193map>,&gimli::parser::Abbreviation,closure>Emap>,&gimli::parser::Abbreviation,closure>OptionRUST$ENCODED$ENUM$0$3$0$0$0$0$NoneOption<(usize, &u8)>RUST$ENCODED$ENUM$0$1$NoneOption<&[u8]>_ZN4core6option8{{impl}}14is_none<&[u8]>Eis_none<&[u8]>_ZN4core6option8{{impl}}14is_some<&[u8]>Eis_some<&[u8]>_ZN4core6option8{{impl}}13expect<&[u8]>Eexpect<&[u8]>Option>_ZN4core6option8{{impl}}77is_none>Eis_none>_ZN4core6option8{{impl}}77is_some>Eis_some>_ZN4core6option8{{impl}}76expect>Eexpect>_ZN4core6option8{{impl}}155and_then,core::result::Result,closure>Eand_then,core::result::Result,closure>and_thenOption, gimli::parser::Error>>_ZN4core6option8{{impl}}121expect, gimli::parser::Error>>Eexpect, gimli::parser::Error>>_ZN4core6option8{{impl}}122is_none, gimli::parser::Error>>Eis_none, gimli::parser::Error>>_ZN4core6option8{{impl}}122is_some, gimli::parser::Error>>Eis_some, gimli::parser::Error>>OptionOptionOption_ZN4core6option8{{impl}}13expectEexpect_ZN4core6option8{{impl}}14is_noneEis_none_ZN4core6option8{{impl}}14is_someEis_someOption<()>_ZN4core6option8{{impl}}10expect<()>Eexpect<()>_ZN4core6option8{{impl}}11is_none<()>Eis_none<()>_ZN4core6option8{{impl}}11is_some<()>Eis_some<()>_ZN4core6option8{{impl}}108fmt, gimli::parser::Error>>E_ZN4core6option8{{impl}}73fmt>E_ZN4core6option8{{impl}}120clone, gimli::parser::Error>>Eclone, gimli::parser::Error>>cmpimpls_ZN4core3cmp5impls8{{impl}}13eq<[u8],[u8]>Eeq<[u8],[u8]>AB_ZN4core3cmp5impls8{{impl}}2ltElt_ZN4core3cmp5impls8{{impl}}2geEge_ZN4core3cmp5impls8{{impl}}2eqE_ZN4core3cmp5impls8{{impl}}2leEle_ZN4core3cmp10maxEmaxmaxv2_ZN4core3cmp10minEminminsliceIterptr_markerIterIter_ZN4core5slice8{{impl}}7lenElen_ZN4core5slice8{{impl}}10as_ptrEas_ptras_ptr_ZN4core5slice8{{impl}}14as_mut_ptrEas_mut_ptras_mut_ptr_ZN4core5slice8{{impl}}9indexEindexindex_ZN4core5slice8{{impl}}9eqEeq_ZN4core5slice8{{impl}}9equalEequalequalsize_ZN4core5slice8{{impl}}8nextEnextold_ZN4core5slice17size_from_ptrEsize_from_ptr_ZN4core5slice8{{impl}}8iterEiterp_ZN4core5slice8{{impl}}12split_atEsplit_atsplit_atmid_ZN4core5slice8{{impl}}19copy_from_sliceEcopy_from_slicecopy_from_slicesrc_ZN4core5slice8{{impl}}49as_mut_ptrEas_mut_ptr_ZN4core5slice8{{impl}}42lenElen_ZN4core5slice8{{impl}}45as_ptrEas_ptr_ZN4core5slice8{{impl}}17get_uncheckedEget_uncheckedget_unchecked_index_ZN4core5slice8{{impl}}13index_mutEindex_mutindex_mut_ZN4core5slice8{{impl}}16split_at_mutEsplit_at_mutsplit_at_mut_ZN4core5slice8{{impl}}44indexEindex_ZN4core5slice8{{impl}}21get_unchecked_mutEget_unchecked_mutget_unchecked_mut_ZN4core5slice18from_raw_partsEfrom_raw_partsfrom_raw_partsSliceExt_ZN4core5slice8SliceExt14is_empty<[u8]>Eis_empty<[u8]>is_emptySelf_ZN4core5slice57from_raw_parts_mutEfrom_raw_parts_mutfrom_raw_parts_mut_ZN4core5slice53from_raw_partsEfrom_raw_parts_ZN4core5slice22from_raw_parts_mutEfrom_raw_parts_mutmarkerPhantomData<&core::fmt::ArgumentV1>PhantomDataPhantomData<&u8>PhantomDataPhantomData<&gimli::parser::AttributeSpecification>PhantomDataPhantomData<(u64, gimli::parser::Abbreviation)>PhantomData<&()>PhantomDataPhantomData_ZN4core6marker8{{impl}}31eqE_otheranyTypeId_ZN4core3any8{{impl}}8of<&str>Eof<&str>of_ZN4core3any8{{impl}}17get_type_id<&str>Eget_type_id<&str>get_type_idopsRangeFromRangeRangeToRangeFullRangeFrom_ZN4core3ops8{{impl}}80deref>Ederef>Uniquepointer_ZN4core3ptr8{{impl}}42newEnew_ZN4core7nonzero8{{impl}}49new<*const gimli::parser::AttributeSpecification>Enew<*const gimli::parser::AttributeSpecification>Unique_ZN4core3ptr8{{impl}}8newEnew_ZN4core7nonzero8{{impl}}15new<*const u64>Enew<*const u64>Unique_ZN4core3ptr8{{impl}}7newEnew_ZN4core7nonzero8{{impl}}14new<*const u8>Enew<*const u8>_ZN4core3ptr8{{impl}}44derefEderef_ZN4core3ptr8{{impl}}10derefEderef_ZN4core3ptr8{{impl}}9derefEderef_ZN4core3ptr44writeEwritewritedst_ZN4core3ptr9readEreadtmp_ZN4core3ptr33readEread_ZN4core3ptr10writeEwrite_ZN4core3ptr34writeEwrite_ZN4core3ptr48replaceEreplacereplacedest_ZN4core3ptr12replaceEreplace_ZN4core3ptr36replaceEreplace_ZN4core3ptr9writeEwritenonzeroNonZero<*const gimli::parser::AttributeSpecification>NonZero<*const u64>NonZero<*const u8>_ZN4core7nonzero8{{impl}}51deref<*const gimli::parser::AttributeSpecification>Ederef<*const gimli::parser::AttributeSpecification>_ZN4core7nonzero8{{impl}}17deref<*const u64>Ederef<*const u64>_ZN4core7nonzero8{{impl}}16deref<*const u8>Ederef<*const u8>cellUnsafeCell>_ZN4core4cell8{{impl}}37get>Eget>Cell>_ZN4core4cell8{{impl}}32get>Eget>_ZN4core4cell8{{impl}}32set>Eset>set_ZN4core4cell8{{impl}}32new>Enew>UnsafeCell>RefCell, gimli::parser::Error>>>borrow_ZN4core4cell8{{impl}}143borrow, gimli::parser::Error>>>Eborrow, gimli::parser::Error>>>_ZN4core4cell8{{impl}}147borrow_mut, gimli::parser::Error>>>Eborrow_mut, gimli::parser::Error>>>borrow_mutCell_ZN4core4cell8{{impl}}10getEget_ZN4core4cell8{{impl}}10setEsetUnsafeCellUnsafeCell, gimli::parser::Error>>>_ZN4core4cell8{{impl}}140get, gimli::parser::Error>>>Eget, gimli::parser::Error>>>Ref, gimli::parser::Error>>>BorrowRef_ZN4core4cell8{{impl}}3newERefMut, gimli::parser::Error>>>BorrowRefMut_ZN4core4cell8{{impl}}4dropEdrop_ZN4core4cell8{{impl}}142deref, gimli::parser::Error>>>Ederef, gimli::parser::Error>>>_ZN4core4cell8{{impl}}34clone>Eclone>_ZN4core4cell8{{impl}}146deref_mut, gimli::parser::Error>>>Ederef_mut, gimli::parser::Error>>>deref_muthashsipSipHasher13hasher_ZN4core4hash3sip8{{impl}}13new_with_keysEnew_with_keyskey0key1Hasherk0k1statetailntail_ZN4core4hash3sip8{{impl}}43new_with_keysEnew_with_keysS_ZN4core4hash3sip8{{impl}}35resetEresetresetStatev0v3Sip13Rounds_ZN4core4hash3sip8{{impl}}5writeE_ZN4core4hash3sip8{{impl}}35writeEwriteneededleftimoutmi_ZN4core4hash3sip8{{impl}}8c_roundsEc_rounds_ZN4core4hash3sip8{{impl}}6finishEfinish_ZN4core4hash3sip8{{impl}}36finishEfinish_ZN4core4hash3sip8{{impl}}8d_roundsEd_rounds_ZN4core4hash3sip11load_u64_leEload_u64_le_ZN4core4hash5impls8{{impl}}48hashEhashHHasher_ZN4core4hash6Hasher53write_u64Ewrite_u64write_u64Enumerate<&mut core::slice::Iter>TakeWhile, closure>flagpredicatetraits_ZN4core4iter6traits8{{impl}}32into_iter>Einto_iter>into_iter_ZN4core4iter6traits8{{impl}}34into_iter>Einto_iter>_ZN4core4iter6traits8{{impl}}90into_iter>Einto_iter>_ZN4core4iter6traits8{{impl}}60into_iter>>Einto_iter>>_ZN4core4iter6traits8{{impl}}69into_iter<&mut gimli::parser::AttrsIter>Einto_iter<&mut gimli::parser::AttrsIter>_ZN4core4iter6traits8{{impl}}64into_iter>Einto_iter>_ZN4core4iter6traits8{{impl}}101into_iter<&mut core::iter::TakeWhile, closure>>Einto_iter<&mut core::iter::TakeWhile, closure>>_ZN4core4iter5range8{{impl}}11nextEnextn_ZN4core4iter5range8{{impl}}7add_oneEadd_oneiteratorIterator_ZN4core4iter8iterator8Iterator39position,closure>Eposition,closure>P_ZN4core4iter8iterator8Iterator37enumerate<&mut core::slice::Iter>Eenumerate<&mut core::slice::Iter>enumerate_ZN4core4iter8iterator8Iterator67find,closure>Efind,closure>find_ZN4core4iter8iterator8Iterator99find, closure>,closure>Efind, closure>,closure>_ZN4core4iter8iterator8Iterator73take_while,closure>Etake_while,closure>take_while_ZN4core4iter8iterator8{{impl}}27next>Enext>_ZN4core4iter8iterator8{{impl}}59next>Enext>_ZN4core4iter8iterator8{{impl}}91next, closure>>Enext, closure>>_ZN4core4iter8{{impl}}32next<&mut core::slice::Iter>Enext<&mut core::slice::Iter>_ZN4core4iter8{{impl}}67next,closure>Enext,closure>mem_ZN4core3mem12size_ofEsize_ofsize_of_ZN4core3mem12size_ofEsize_of_ZN4core3mem12size_ofEsize_of_ZN4core3mem17size_of_val<[u8]>Esize_of_val<[u8]>size_of_val_ZN4core3mem11size_ofEsize_of_ZN4core3mem46size_ofEsize_of_ZN4core3mem47align_ofEalign_ofalign_of_ZN4core3mem14size_ofEsize_of_ZN4core3mem11swapEswapswapy_ZN4core3mem20uninitializedEuninitializeduninitialized_ZN4core3mem13forgetEforgetforget_ZN4core3mem36size_ofEsize_of_ZN4core3mem13align_ofEalign_of_ZN4core3mem37align_ofEalign_of_ZN4core3mem18uninitializedEuninitialized_ZN4core3mem42uninitializedEuninitialized_ZN4core3mem41replace>Ereplace>_ZN4core3mem38swap>Eswap>_ZN4core3mem47uninitialized>Euninitialized>_ZN4core3mem40forget>Eforget>_ZN4core3mem82replace>Ereplace>_ZN4core3mem79swap>Eswap>_ZN4core3mem88uninitialized>Euninitialized>_ZN4core3mem81forget>Eforget>_ZN4core3mem45swapEswap_ZN4core3mem54uninitializedEuninitialized_ZN4core3mem47forgetEforget_ZN4core3mem9swapEswap_ZN4core3mem11forgetEforget_ZN4core3mem33swapEswap_ZN4core3mem35forgetEforget_ZN4core3mem18replace<&mut [u8]>Ereplace<&mut [u8]>_ZN4core3mem15swap<&mut [u8]>Eswap<&mut [u8]>_ZN4core3mem24uninitialized<&mut [u8]>Euninitialized<&mut [u8]>_ZN4core3mem17forget<&mut [u8]>Eforget<&mut [u8]>_ZN4core3mem52forget>Eforget>_ZN4core3mem144replace, gimli::parser::Error>>>Ereplace, gimli::parser::Error>>>_ZN4core3mem141swap, gimli::parser::Error>>>Eswap, gimli::parser::Error>>>_ZN4core3mem150uninitialized, gimli::parser::Error>>>Euninitialized, gimli::parser::Error>>>_ZN4core3mem143forget, gimli::parser::Error>>>Eforget, gimli::parser::Error>>>_ZN4core3mem12align_ofEalign_of_ZN4core5clone8{{impl}}5cloneE_ZN4core5clone8{{impl}}11clone<[u8]>Eclone<[u8]>_ZN4core5clone8{{impl}}34cloneEclone_ZN4core5clone8{{impl}}66clone>Eclone>convert_ZN4core7convert8{{impl}}26fromEfromfrom_ZN4core7convert8{{impl}}21into<&str,Box>Einto<&str,Box>_ZN4core7convert8{{impl}}17into<&[u8],&[u8]>Einto<&[u8],&[u8]>_ZN4core7convert8{{impl}}11from<&[u8]>Efrom<&[u8]>_ZN4core7convert8{{impl}}27fromEfrom_ZN4core7convert8{{impl}}37into<&[u8],collections::vec::Vec>Einto<&[u8],collections::vec::Vec>_ZN4core6borrow8{{impl}}11borrowEborrowstr_ZN4core3str8{{impl}}8as_bytesEu64_ZN4core3num8{{impl}}12wrapping_addEwrapping_addchari8leb128readIoErrorOverflow_ZN6leb1284read15unsigned<&[u8]>Eunsigned<&[u8]>unsignedrshiftlow_bitsR_ZN6leb1284read13signed<&[u8]>Esigned<&[u8]>signedbyte_ZN6leb12816low_bits_of_byteElow_bits_of_byte_ZN6leb1285write19unsigned<&mut [u8]>Eunsigned<&mut [u8]>wW_ZN6leb1285write17signed<&mut [u8]>Esigned<&mut [u8]>done_ZN6leb12815low_bits_of_u64Elow_bits_of_u64stdioReprOsCustomErrorKindNotFoundPermissionDeniedConnectionRefusedConnectionResetConnectionAbortedNotConnectedAddrInUseAddrNotAvailableBrokenPipeAlreadyExistsWouldBlockInvalidInputInvalidDataTimedOutWriteZeroInterruptedOther__Nonexhaustiverepr_ZN3std2io5error8{{impl}}9new<&str>Ekind_ZN3std2io5error8{{impl}}2eqE_ZN3std2io5impls8{{impl}}10read_exactEread_exact_ZN3std2io5impls8{{impl}}9write_allEwrite_all_ZN3std2io5impls8{{impl}}5writeEamtcollectionstableBucketStateEmptyFullRawTablecapacityhashes_ZN3std11collections4hash5table8{{impl}}50new_uninitializedEnew_uninitializednew_uninitializedhashes_sizekeys_sizevals_sizemalloc_alignmenthash_offsetoflosize_of_bucketbuffer_ZN3std11collections4hash5table8{{impl}}41capacityEcapacity_ZN3std11collections4hash5table8{{impl}}49rev_move_bucketsErev_move_bucketsrev_move_bucketsraw_bucket_ZN3std11collections4hash5table8{{impl}}49first_bucket_rawEfirst_bucket_rawfirst_bucket_rawkeys_offsetvals_offset_ZN3std11collections4hash5table8{{impl}}37sizeEsize_ZN3std11collections4hash5table8{{impl}}36newEnewret_ZN3std11collections4hash5table8{{impl}}37iterEiter_ZN3std11collections4hash5table8{{impl}}44raw_bucketsEraw_bucketsRevMoveBucketsrawhashes_endelems_leftRawBucketkey_ZN3std11collections4hash5table8{{impl}}39offsetEoffsetBucket>_ZN3std11collections4hash5table8{{impl}}117first>Efirst>firstM_ZN3std11collections4hash5table8{{impl}}116next>Enext>dist_ZN3std11collections4hash5table8{{impl}}116peek>Epeek>peek_ZN3std11collections4hash5table8{{impl}}115new>Enew>_ZN3std11collections4hash5table8{{impl}}7inspectEinspect_ZN3std11collections4hash5table8{{impl}}120at_index>Eat_index>at_indexib_index_ZN3std11collections4hash5table8{{impl}}117index>Eindex>Bucket>_ZN3std11collections4hash5table8{{impl}}113first>Efirst>_ZN3std11collections4hash5table8{{impl}}113index>Eindex>_ZN3std11collections4hash5table8{{impl}}112peek>Epeek>_ZN3std11collections4hash5table8{{impl}}112next>Enext>_ZN3std11collections4hash5table8{{impl}}111new>Enew>_ZN3std11collections4hash5table8{{impl}}116at_index>Eat_index>BucketState>EmptyBucket>FullBucket>_ZN3std11collections4hash5table8{{impl}}112read>Eread>_ZN3std11collections4hash5table8{{impl}}112hash>Ehash>_ZN3std11collections4hash5table8{{impl}}120displacement>Edisplacement>displacementbucket_ZN3std11collections4hash5table8{{impl}}119into_bucket>Einto_bucket>into_bucket_ZN3std11collections4hash5table8{{impl}}117into_refs>Einto_refs>into_refsSafeHashIterRawBucketsFullBucket>_ZN3std11collections4hash5table8{{impl}}124displacement>Edisplacement>_ZN3std11collections4hash5table8{{impl}}116hash>Ehash>_ZN3std11collections4hash5table8{{impl}}123into_bucket>Einto_bucket>_ZN3std11collections4hash5table8{{impl}}37takeEtake_ZN3std11collections4hash5table8{{impl}}116read>Eread>_ZN3std11collections4hash5table8{{impl}}117table>Etable>_ZN3std11collections4hash5table8{{impl}}117stash>Estash>stash_ZN3std11collections4hash5table8{{impl}}125into_mut_refs>Einto_mut_refs>into_mut_refsEmptyBucket>_ZN3std11collections4hash5table8{{impl}}115put>Eput>putBucketState>FullBucket>>_ZN3std11collections4hash5table8{{impl}}201displacement>>Edisplacement>>_ZN3std11collections4hash5table8{{impl}}193hash>>Ehash>>_ZN3std11collections4hash5table8{{impl}}196replace>>Ereplace>>hold_hashold_keyold_val_ZN3std11collections4hash5table8{{impl}}193next>>Enext>>_ZN3std11collections4hash5table8{{impl}}200into_bucket>>Einto_bucket>>_ZN3std11collections4hash5table8{{impl}}199into_table>>Einto_table>>into_table_ZN3std11collections4hash5table8{{impl}}194index>>Eindex>>Bucket>>_ZN3std11collections4hash5table8{{impl}}193peek>>Epeek>>BucketState>>EmptyBucket>>_ZN3std11collections4hash5table8{{impl}}192put>>Eput>>_ZN3std11collections4hash5table8{{impl}}37dropEdrop_ZN3std11collections4hash5table8{{impl}}37nextEnext_ZN3std11collections4hash5table8{{impl}}49borrow_table_mutEborrow_table_mutborrow_table_mut_ZN3std11collections4hash5table8{{impl}}2eqE_ZN3std11collections4hash5table8{{impl}}117deref>Ederef>_ZN3std11collections4hash5table8{{impl}}128borrow_table_mut>Eborrow_table_mut>_ZN3std11collections4hash5table17calculate_offsetsEcalculate_offsetskeys_alignvals_alignend_of_keys_ZN3std11collections4hash5table16round_up_to_nextEround_up_to_nextunroundedtarget_alignment_ZN3std11collections4hash5table55make_hashEmake_hashmake_hashhash_stateEntryOccupiedVacantVacantEntryStateNeqElemNoElemInternalEntryTableIsEmptyHashMaphash_builderresize_policy_ZN3std11collections4hash3map8{{impl}}85with_hasherEwith_hasherwith_hasher_ZN3std11collections4hash3map8{{impl}}78iterEiter_ZN3std11collections4hash3map8{{impl}}36newE_ZN3std11collections4hash3map8{{impl}}79entryEentry_ZN3std11collections4hash3map8{{impl}}81reserveEreservereserveadditionalnew_sizemin_capnew_capacity_ZN3std11collections4hash3map8{{impl}}77lenElen_ZN3std11collections4hash3map8{{impl}}80resizeEresizeresizeold_tableold_sizefull_ZN3std11collections4hash3map8{{impl}}95insert_hashed_orderedEinsert_hashed_orderedinsert_hashed_orderedcapbucketsib_ZN3std11collections4hash3map8{{impl}}88search_mutEsearch_mutsearch_mutqQ_ZN3std11collections4hash3map8{{impl}}87make_hashEmake_hashX_ZN3std11collections4hash3map8{{impl}}81getEget_ZN3std11collections4hash3map8{{impl}}84searchEsearchsearchRandomState_ZN3std11collections4hash3map8{{impl}}3newEDefaultResizePolicy_ZN3std11collections4hash3map8{{impl}}12min_capacityEmin_capacityusable_sizeEntryOccupiedEntryelemVacantEntry_ZN3std11collections4hash3map8{{impl}}39insertEinsertVacantEntryState>InternalEntry>_ZN3std11collections4hash3map8{{impl}}43into_entryEinto_entryinto_entryDefaultHasherInternalEntry>_ZN3std11collections4hash3map8{{impl}}128into_occupied_bucket>Einto_occupied_bucket>into_occupied_bucketVacantEntryState>_ZN3std11collections4hash3map8{{impl}}81defaultEdefaultdefault_ZN3std11collections4hash3map8{{impl}}7defaultE_ZN3std11collections4hash3map8{{impl}}12build_hasherEbuild_hasher_ZN3std11collections4hash3map8{{impl}}5writeE_ZN3std11collections4hash3map8{{impl}}6finishE_ZN3std11collections4hash3map133search_hashed,closure>Esearch_hashed,closure>search_hashedis_matchproberobin_ib_ZN3std11collections4hash3map43robin_hoodErobin_hoodrobin_hoodstarting_indexidx_endfull_bucketprobe_ib_ZN3std11collections4hash3map129search_hashed,closure>Esearch_hashed,closure>BoxthreadlocalLocalKey<(u64, u64)>init_ZN3std6thread5local8{{impl}}65with<(u64, u64),closure,std::collections::hash::map::RandomState>Ewith<(u64, u64),closure,std::collections::hash::map::RandomState>withslot_ZN3std6thread5local8{{impl}}16init<(u64, u64)>Einit<(u64, u64)>panicking_ZN3std9panicking17begin_panic<&str>Ebegin_panic<&str>begin_panicfile_line_ZN5alloc5boxed8{{impl}}9new<&str>Eu16()*const core::fmt::ArgumentV1&core::fmt::Voidfn(&core::fmt::Void, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&mut core::fmt::Formatter&[core::fmt::ArgumentV1]&[u8]&mut [u8]bool(&[u8], u8)(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)(gimli::parser::EndianBuf, (u64, gimli::parser::Format))(u64, gimli::parser::Format)(gimli::parser::EndianBuf, u64)(gimli::parser::EndianBuf, u16)(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)closure&gimli::parser::FormatInput&u8(&[u8], u64)i32Box(&[u8], &[u8])(&[u8], i64)i64(&[u8], gimli::parser::AbbreviationTag)(&[u8], gimli::parser::AbbreviationHasChildren)(&[u8], gimli::parser::AttributeName)(&[u8], gimli::parser::AttributeForm)(&[u8], gimli::parser::AttributeSpecification)(&[u8], ())(&[u8], collections::vec::Vec)vecVec_ZN11collections3vec8{{impl}}42newE_ZN11collections3vec8{{impl}}43pushEpushpush_ZN11collections3vec8{{impl}}52with_capacityEwith_capacity_ZN11collections3vec8{{impl}}56extend_from_sliceEextend_from_slice_ZN11collections3vec8{{impl}}46reserveEreserve_ZN11collections3vec8{{impl}}42lenE_ZN11collections3vec8{{impl}}46set_lenEset_len_ZN11collections3vec8{{impl}}53from_raw_partsEVec_ZN11collections3vec8{{impl}}17with_capacityEwith_capacitywith_capacity_ZN11collections3vec8{{impl}}21extend_from_sliceEextend_from_sliceextend_from_slice_ZN11collections3vec8{{impl}}11reserveEreserve_ZN11collections3vec8{{impl}}7lenE_ZN11collections3vec8{{impl}}11set_lenEset_lenset_len_ZN11collections3vec8{{impl}}8pushEpush_ZN11collections3vec8{{impl}}43dropEdrop_ZN11collections3vec8{{impl}}48index_mutEindex_mut_ZN11collections3vec8{{impl}}48deref_mutEderef_mut_ZN11collections3vec8{{impl}}44indexE_ZN11collections3vec8{{impl}}44derefE_ZN11collections3vec8{{impl}}8fromEfroms_ZN11collections3vec8{{impl}}13deref_mutEderef_mut_ZN11collections3vec8{{impl}}8dropEdrop_ZN11collections3vec8{{impl}}13index_mutE_ZN11collections3vec8{{impl}}9derefEhack_ZN11collections5slice4hack47into_vecEinto_vecinto_vecxs_ZN11collections5slice4hack10to_vecEto_vecto_vecvectorallocraw_vecRawVec_ZN5alloc7raw_vec8{{impl}}42newE_ZN5alloc7raw_vec8{{impl}}69unsafe_no_drop_flag_needs_dropEunsafe_no_drop_flag_needs_dropunsafe_no_drop_flag_needs_drop_ZN5alloc7raw_vec8{{impl}}42ptrEptr_ZN5alloc7raw_vec8{{impl}}42capEcap_ZN5alloc7raw_vec8{{impl}}45doubleEdoubledoubleelem_sizenew_capnew_alloc_size_ZN5alloc7raw_vec8{{impl}}52with_capacityEalloc_size_ZN5alloc7raw_vec8{{impl}}46reserveEused_capneeded_extra_cap_ZN5alloc7raw_vec8{{impl}}57amortized_new_sizeEamortized_new_sizerequired_capdouble_cap_ZN5alloc7raw_vec8{{impl}}53from_raw_partsERawVec_ZN5alloc7raw_vec8{{impl}}17with_capacityE_ZN5alloc7raw_vec8{{impl}}7capEcap_ZN5alloc7raw_vec8{{impl}}11reserveE_ZN5alloc7raw_vec8{{impl}}22amortized_new_sizeEamortized_new_sizeamortized_new_size_ZN5alloc7raw_vec8{{impl}}7ptrEptr_ZN5alloc7raw_vec8{{impl}}34unsafe_no_drop_flag_needs_dropEunsafe_no_drop_flag_needs_drop_ZN5alloc7raw_vec8{{impl}}10doubleEdouble_ZN5alloc7raw_vec8{{impl}}43dropEnum_bytes_ZN5alloc7raw_vec8{{impl}}8dropE_ZN5alloc7raw_vec11alloc_guardEalloc_guardheap_ZN5alloc4heap15exchange_mallocEexchange_malloc_ZN5alloc4heap8allocateEallocate_ZN5alloc4heap13exchange_freeEexchange_free_ZN5alloc4heap10deallocateEdeallocate_ZN5alloc4heap10reallocateEreallocate*const gimli::parser::AttributeSpecification_ZN4core3ptr8{{impl}}45offsetEoffset_ZN4core3ptr8{{impl}}46is_nullEis_null(&[u8], core::option::Option)&mut [gimli::parser::AttributeSpecification]&&[u8]&[gimli::parser::AttributeSpecification](usize, bool)(usize, usize)&gimli::parser::AttributeSpecification(&[u8], gimli::parser::Abbreviation)*const u64_ZN4core3ptr8{{impl}}11offsetEoffset*mut u64*const gimli::parser::Abbreviation_ZN4core3ptr8{{impl}}35offsetEoffset(usize, usize, bool)(u64, gimli::parser::Abbreviation)&mut std::collections::hash::table::RawTable&std::collections::hash::table::RawTable(&u64, &gimli::parser::Abbreviation)&u64&gimli::parser::Abbreviationfn() -> core::option::Option<&core::cell::UnsafeCell>>&core::cell::UnsafeCell>(u64, u64)fn() -> (u64, u64)&(u64, u64)(std::collections::hash::table::EmptyBucket>, u64, gimli::parser::Abbreviation)&&u64(std::collections::hash::table::SafeHash, u64, gimli::parser::Abbreviation)(&mut u64, &mut gimli::parser::Abbreviation)&mut u64&mut gimli::parser::Abbreviation(&[u8], gimli::parser::Abbreviations)(&[u8], core::option::Option)&gimli::parser::CompilationUnit(gimli::parser::AttributeInput, gimli::parser::Attribute)&gimli::parser::AttributeInput(gimli::parser::EndianBuf, &[u8])(gimli::parser::EndianBuf, u32)&mut core::slice::Iter(usize, &u8)&mut &mut core::iter::Enumerate<&mut core::slice::Iter>&mut core::iter::Enumerate<&mut core::slice::Iter>(&mut [u8], &mut [u8])Box<[gimli::parser::AttributeSpecification]>&gimli::parser::DebuggingInformationEntry&gimli::parser::Abbreviations&core::option::Option, gimli::parser::Error>>&core::cell::Cell&mut core::option::Option, gimli::parser::Error>>isize&mut &mut core::iter::TakeWhile, closure>&mut core::iter::TakeWhile, closure>(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)(gimli::parser::EndianBuf, gimli::parser::TypeUnit)byteorder_ZN9byteorder8{{impl}}8read_u16E_ZN9byteorder8{{impl}}8read_u32E_ZN9byteorder8{{impl}}8read_u64EBox<&str>*mut u8_ZN11collections5slice8{{impl}}7lenE_ZN11collections5slice8{{impl}}10as_ptrE_ZN11collections5slice8{{impl}}14as_mut_ptrE_ZN11collections5slice8{{impl}}12is_emptyEis_empty_ZN11collections5slice8{{impl}}12split_atE_ZN11collections5slice8{{impl}}19copy_from_sliceE_ZN11collections5slice8{{impl}}8iterE_ZN11collections5slice8{{impl}}16split_at_mutE_ZN11collections5slice8{{impl}}10to_vecE_ZN11collections5slice8{{impl}}21get_unchecked_mutE_ZN11collections5slice8{{impl}}17get_uncheckedEsizetype*mut gimli::parser::AttributeSpecification&alloc::raw_vec::RawVec_ZN11collections5slice8{{impl}}49as_mut_ptrE_ZN11collections5slice8{{impl}}42lenE_ZN11collections5slice8{{impl}}47into_vecE&std::collections::hash::table::SafeHash&alloc::raw_vec::RawVec!&mut core::fmt::builders::DebugList&*mut gimli::parser::AttributeSpecification&*const gimli::parser::AttributeSpecification&*mut u64&*const u64*mut core::option::Option<(u64, u64)>&mut core::fmt::builders::DebugMap&&mut std::collections::hash::table::RawTable&usize&gimli::parser::Format&u16&gimli::parser::EndianBuf&gimli::parser::DebugAbbrevOffset&gimli::parser::Attribute*mut core::option::Option<&[u8]>*mut usize*mut core::option::Option, gimli::parser::Error>>&mut gimli::parser::AttrsIter&*mut u8&*const u8&mut u8&gimli::parser::AttributeValue&isize&gimli::parser::DebugTypesOffset&gimli::parser::TypeUnit&(&str, u32)&&str&gimli::parser::Error&gimli::parser::DebugStrOffset&gimli::parser::DebugInfoOffset&gimli::parser::UnitOffset&&gimli::parser::CompilationUnit&core::option::Option, gimli::parser::Error>>&gimli::parser::DebugInfo&mut gimli::parser::CompilationUnitsIter&core::marker::PhantomDatafn(&&gimli::parser::CompilationUnit, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&&u16&&gimli::parser::DebugAbbrevOffset&&u8&&gimli::parser::Format&&gimli::parser::EndianBuf&&&[u8]&&core::marker::PhantomDatafn(&core::option::Option, gimli::parser::Error>>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&core::result::Result, gimli::parser::Error>&&core::result::Result, gimli::parser::Error>&&gimli::parser::Error&std::io::error::Error&mut &[u8]&std::io::error::ErrorKind&gimli::parser::AttributeName&gimli::parser::AttributeForm&&gimli::parser::AttributeName&&gimli::parser::AttributeForm&mut collections::vec::Vec&core::ptr::Unique&core::nonzero::NonZero<*const gimli::parser::AttributeSpecification>&mut alloc::raw_vec::RawVec&collections::vec::Vec&mut core::ops::Range&mut usize&&gimli::parser::AttributeSpecification&std::collections::hash::map::HashMap&std::collections::hash::map::DefaultResizePolicy&std::collections::hash::map::RandomState&core::ptr::Unique&core::nonzero::NonZero<*const u64>&mut std::collections::hash::table::RevMoveBuckets&&std::collections::hash::table::RawTable&std::collections::hash::table::Bucket>&std::collections::hash::table::FullBucket>*mut gimli::parser::Abbreviation&mut std::collections::hash::table::Bucket>&mut std::collections::hash::table::Bucket>&std::thread::local::LocalKey<(u64, u64)>&mut core::option::Option<(u64, u64)>&core::option::Option<(u64, u64)>&&gimli::parser::Abbreviation&mut gimli::parser::Abbreviations&mut std::collections::hash::map::HashMap&&usize&std::collections::hash::table::FullBucket>&std::collections::hash::table::Bucket>&mut &mut std::collections::hash::table::RawTable&std::collections::hash::table::EmptyBucket>fn(&&usize, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&mut core::hash::sip::Hasher&mut std::collections::hash::map::DefaultHasher&mut core::hash::sip::SipHasher13&mut core::hash::sip::State&std::collections::hash::map::DefaultHasher&core::hash::sip::SipHasher13&core::hash::sip::Hasher&std::collections::hash::table::FullBucket>>&mut std::collections::hash::table::FullBucket>>*mut std::collections::hash::table::SafeHash&mut std::collections::hash::table::SafeHash&mut std::collections::hash::table::Bucket>>&mut std::collections::hash::table::FullBucket>&core::result::Result<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>fn(&&gimli::parser::Format, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&&u64, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(gimli::parser::EndianBuf, (u64, gimli::parser::Format)), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::EndianBuf, (u64, gimli::parser::Format))&&(gimli::parser::EndianBuf, (u64, gimli::parser::Format))&(u64, gimli::parser::Format)&core::result::Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>fn(&&u16, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&&gimli::parser::EndianBuf, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(gimli::parser::EndianBuf, u16), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::EndianBuf, u16)&&(gimli::parser::EndianBuf, u16)&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>fn(&&gimli::parser::DebugAbbrevOffset, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)&&(gimli::parser::FormatInput, gimli::parser::DebugAbbrevOffset)&core::result::Result<(&[u8], u8), gimli::parser::Error>fn(&&u8, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(&[u8], u8), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(&[u8], u8)&&(&[u8], u8)&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>fn(&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::CompilationUnit), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)&&(gimli::parser::EndianBuf, gimli::parser::CompilationUnit)&i64&bool&&i64&&bool&&gimli::parser::UnitOffset&&gimli::parser::DebugInfoOffset&&gimli::parser::DebugTypesOffset&&gimli::parser::DebugStrOffset&&gimli::parser::AttributeValue&&gimli::parser::Attribute&core::result::Result<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>&mut &mut core::slice::Iterfn(&&gimli::parser::Attribute, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(gimli::parser::AttributeInput, gimli::parser::Attribute), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::AttributeInput, gimli::parser::Attribute)&&(gimli::parser::AttributeInput, gimli::parser::Attribute)&&&gimli::parser::CompilationUnitfn(&&str, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&std::io::error::Error, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&mut &mut [u8]&core::option::Option>&core::cell::Cell>&core::cell::UnsafeCell>fn(&core::option::Option>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&core::result::Result&&core::result::Result&core::option::Option<&[u8]>fn(&&&[u8], &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&[u8; 8]&[u8; 71]&&isizefn(&gimli::parser::Error, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&gimli::parser::DebugAbbrev&mut gimli::parser::EntriesCursor&core::result::Result, gimli::parser::Error>&core::cell::RefCell, gimli::parser::Error>>>&core::cell::UnsafeCell&core::cell::UnsafeCell, gimli::parser::Error>>>&mut core::cell::BorrowRef&core::cell::Ref, gimli::parser::Error>>>&mut core::cell::BorrowRefMut&core::cell::RefMut, gimli::parser::Error>>>&mut core::cell::RefMut, gimli::parser::Error>>>&mut &mut gimli::parser::AttrsIter&mut collections::vec::Vec&mut alloc::raw_vec::RawVec&core::ptr::Unique&core::nonzero::NonZero<*const u8>&collections::vec::Vecfn(&&gimli::parser::AttributeValue, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&&isize, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&core::option::Option&core::option::Option<()>&core::result::Result<(gimli::parser::EndianBuf, u64), gimli::parser::Error>fn(&core::result::Result<(gimli::parser::EndianBuf, u64), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::EndianBuf, u64)&&(gimli::parser::EndianBuf, u64)&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>fn(&&gimli::parser::DebugTypesOffset, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>fn(&core::result::Result<(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)&&(gimli::parser::FormatInput, gimli::parser::DebugTypesOffset)&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error>&&gimli::parser::TypeUnitfn(&core::result::Result<(gimli::parser::EndianBuf, gimli::parser::TypeUnit), gimli::parser::Error>, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>&(gimli::parser::EndianBuf, gimli::parser::TypeUnit)&&(gimli::parser::EndianBuf, gimli::parser::TypeUnit)fn(&&gimli::parser::TypeUnit, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>_ZN6leb1284read8{{impl}}4fromE_ZN9byteorder8{{impl}}8read_u1610_FILE_LINEE_ZN9byteorder8{{impl}}8read_u3210_FILE_LINEE_ZN9byteorder8{{impl}}8read_u6410_FILE_LINEEApple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/jemalloc.c/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/obj/x86_64-apple-darwin/rt/jemallocje_opt_abort_Boolje_opt_junkje_opt_junk_allocje_opt_junk_freeje_opt_quarantinesize_t__darwin_size_tlong unsigned intje_opt_redzoneje_opt_utraceje_opt_xmallocje_opt_zeroje_opt_narenasunsigned intje_index2size_tabje_size2index_tabuint8_tunsigned charconfig_profje_malloc_confje_ncpusarenas_lockmalloc_mutex_tmalloc_mutex_slockOSSpinLockint32_tintje_arenasarena_tarena_sindnthreadsstatstcache_qlqlh_firstprof_accumbytesoffset_statedss_precsparelg_dirty_multpurgingnactivendirtyruns_dirtychunks_cachedecay_timedecay_intervaldecay_epochdecay_jitter_statedecay_deadlinedecay_ndirtydecay_backlog_npages_limitdecay_backloghugehuge_mtxchunks_szad_cachedchunks_ad_cachedchunks_szad_retainedchunks_ad_retainedchunks_mtxnode_cachenode_cache_mtxchunk_hooksbinsruns_availarena_stats_tarena_stats_smappednpurgenmadvisepurgedmetadata_mappedmetadata_allocatedallocated_largenmalloc_largendalloc_largenrequests_largeallocated_hugenmalloc_hugendalloc_hugelstatshstatsuint64_tlong long unsigned intmalloc_large_stats_tmalloc_large_stats_snmallocndallocnrequestscurrunsmalloc_huge_stats_tmalloc_huge_stats_scurhchunkstcache_ttcache_slinkqre_nextqre_prevgc_tickernext_gc_bintbinsticker_tticker_sticknticksszind_ttcache_bin_ttcache_bin_ststatslow_waterlg_fill_divncachedavailtcache_bin_stats_ttcache_bin_stats_sdss_prec_tdss_prec_disableddss_prec_primarydss_prec_secondarydss_prec_limitarena_chunk_tarena_chunk_snodemap_bitsextent_node_textent_node_sen_arenaen_addren_sizeen_zeroeden_committeden_achunken_prof_tctxrdcc_linkszad_linkrbn_leftrbn_right_redql_linkad_linkprof_tctx_tprof_tctx_stdatathr_uidthr_discrimcntsgctxtctx_uidtctx_linkprepareddump_cntsprof_tdata_tprof_tdata_sthread_nameattachedexpiredtdata_linktctx_uid_nextbt2tctxprng_statebytes_until_sampleenqenq_idumpenq_gdumpdumpingactivecnt_summedckh_tckh_slg_minbucketslg_curbucketsje_hashkeycomptabckh_hash_tckh_keycomp_tckhc_tckhc_sprof_cnt_tprof_cnt_scurobjscurbytesaccumobjsaccumbytesprof_gctx_tprof_gctx_snlimbotctxsdump_linkbtprof_tctx_tree_trbt_rootprof_bt_tprof_bt_sprof_tctx_state_tprof_tctx_state_initializingprof_tctx_state_nominalprof_tctx_state_dumpingprof_tctx_state_purgatoryarena_runs_dirty_link_tarena_runs_dirty_link_srd_linkarena_chunk_map_bits_tarena_chunk_map_bits_sssize_t__darwin_ssize_tlong intnstime_tnstime_snsextent_tree_tchunk_hooks_tdalloccommitdecommitpurgesplitchunk_alloc_tchunk_dalloc_tchunk_commit_tchunk_decommit_tchunk_purge_tchunk_split_tchunk_merge_tarena_bin_tarena_bin_sruncurrunsarena_run_tarena_run_sbinindnfreebitmapbitmap_tarena_run_tree_tarena_chunk_map_misc_tarena_chunk_map_misc_srb_linkprof_tctx_punprof_tctxrunmalloc_bin_stats_tmalloc_bin_stats_scurregsnfillsnflushesnrunsrerunsnarenas_totalnarenas_autolarge_padtsd_initializertsd_ttsd_stcachethread_allocatedthread_deallocatedprof_tdataarenaarenas_tdatanarenas_tdataarenas_tdata_bypasstcache_enabledje_quarantinetsd_state_ttsd_state_uninitializedtsd_state_nominaltsd_state_purgatorytsd_state_reincarnatedarena_tdata_tarena_tdata_sdecay_tickertcache_enabled_ttcache_enabled_falsetcache_enabled_truetcache_enabled_defaultquarantine_tquarantine_slg_maxobjsobjsquarantine_obj_tquarantine_obj_smalloc_slow_flagsa0malloc_init_statemalloc_init_tmalloc_init_uninitializedmalloc_init_a0_initializedmalloc_init_recursiblemalloc_init_initializedinit_lockconfig_xmallocmalloc_slowje_a0mallocmalloc_init_a0je_size2indexje_size2index_lookupje_arena_getinit_if_missingje_arena_malloctsdzeroslow_pathje_iallocztmis_metadataje_arena_aallocchunkje_iaallocje_arena_sallocdemotepageindje_isallocje_arena_bitselm_getje_arena_mapbitsp_getje_arena_mapbits_getje_arena_mapbits_binind_getmapbitsje_index2size_lookupje_index2sizeje_atomic_add_uint64je_atomic_add_zje_arena_metadata_allocated_addje_malloc_mutex_lockmutexmalloc_init_hard_a0je_malloc_mutex_unlockje_size2index_computedelta_inverse_maskmodgrplg_deltalg_tminlg_ceilje_lg_floorje_atomic_add_pje_arena_mapbits_size_decodeje_arena_mapbits_large_size_geta0iallocje_a0dallocje_idalloctmje_atomic_sub_zje_arena_metadata_allocated_subje_arena_dalloca0idallocje_atomic_add_uint32uint32_tje_atomic_add_uje_narenas_total_getarena_init_lockednarenas_total_incarena_setatomic_write_uint64atomic_write_pje_arena_initje_tsd_arena_setje_arena_migrateoldindnewindoldarenanewarenatsd_arenas_tdata_settsd_narenas_tdata_setje_ticker_copytickerje_ticker_initje_arena_tdata_get_hardarenas_tdata_oldnarenas_tdata_oldnarenas_actualarenas_tdata_bypassparena_bindje_arena_choose_hardfirst_nullchooseje_thread_allocated_cleanupje_thread_deallocated_cleanuparena_unbindje_arena_cleanupje_arenas_tdata_cleanupje_narenas_tdata_cleanupje_arenas_tdata_bypass_cleanupje_tsd_wrapper_getwrappertsd_wrapper_tinitializedtsd_init_block_ttsd_init_block_spthread_t__darwin_pthread_t_opaque_pthread_t__sig__cleanup_stack__opaque__darwin_pthread_handler_rec__routine__arg__nextje_tsd_getje_tsd_fetchje_tsd_setje_imallocje_tcache_getcreateje_tsd_tcache_setje_tcache_alloc_smalltbintcache_successtcache_hard_successje_tcache_alloc_easyje_ticker_ticksje_ticker_tickje_tcache_eventmalloc_initializedmalloc_initmalloc_thread_initje_tsd_wrapper_setje_tcache_alloc_largeje_arena_choosemalloc_init_hardmalloc_init_hard_neededje_quarantine_alloc_hookmalloc_init_hard_recursiblemalloc_ncpusmalloc_init_hard_finishatomic_write_uint32atomic_write_unarenas_total_setnarenasmalloc_slow_flag_initje_set_errnoerrnumje_sa2ualignmentje_s2uje_s2u_lookupje_s2u_computedeltadelta_maskje_ipallocztmje_iralloctoldsizeje_tcache_dalloc_smalltbin_infotcache_bin_info_ttcache_bin_info_sncached_maxje_tcache_dalloc_largeimallocx_no_profimallocx_flags_decode_hardarena_indje_tcaches_getelmtcaches_ttcaches_simallocx_flagsje_imalloctje_ipalloctje_icalloctje_mallocxje_iralloct_realignextracopysizeje_isqallocje_arena_sdallocje_isdalloctje_rallocxold_rzsizeold_usizeinallocxisfreerzsizeje_sdallocxje_mallctloldpoldlenpnewpnewlenje_mallctlnametomibmibpmiblenpje_mallctlbymibmibmiblenjemalloc_constructormalloc_conf_initoptsklenvlenumlmatchlinklensaved_errnolinknameenvnameuintmax_tmalloc_conf_nextopts_pk_pklen_pv_pvlen_pacceptsecure_getenvmalloc_conf_errorje_get_errnomalloc_init_hard_a0_lockedje_malloc_stats_printwrite_cbcbopaquestats_print_atexit/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/arena.cje_opt_purgepurge_mode_tpurge_mode_ratiopurge_mode_decaypurge_mode_limitje_purge_mode_namesje_opt_lg_dirty_multje_opt_decay_timelg_dirty_mult_defaultdecay_time_defaultje_arena_bin_infoarena_bin_info_tarena_bin_info_sreg_sizeredzone_sizereg_intervalrun_sizenregsbitmap_inforeg0_offsetbitmap_info_tbitmap_info_snbitsngroupsje_map_biasje_map_misc_offsetje_arena_maxrunje_large_maxclassje_run_quantize_maxnlclassesnhclassesruns_avail_biasruns_avail_nclassessmall_run_tabsmall_maxrunrun_quantize_ceil_tabrun_quantize_floor_tabje_extent_node_dirty_linkage_initje_extent_node_dirty_insertchunks_dirtyarena_chunk_dirty_npagesje_arena_chunk_cache_maybe_insertcacheje_extent_node_dirty_removeje_arena_chunk_cache_maybe_removedirtyje_arena_node_allocje_arena_node_dallocarena_huge_malloc_stats_updatearena_nactive_addadd_pagescactive_addje_stats_cactive_addcactivearena_chunk_alloc_huge_hardcsizearena_huge_malloc_stats_update_undoarena_nactive_subsub_pagescactive_subje_stats_cactive_subje_arena_chunk_alloc_hugearena_huge_dalloc_stats_updateje_arena_chunk_dalloc_hugeje_arena_chunk_ralloc_huge_similararena_huge_ralloc_stats_updateje_arena_chunk_ralloc_huge_shrinkudiffcdiffnchunkarena_chunk_ralloc_huge_expand_hardarena_huge_dalloc_stats_update_undoarena_huge_ralloc_stats_update_undoje_arena_chunk_ralloc_huge_expandje_arena_lg_dirty_mult_getarena_lg_dirty_mult_validje_arena_maybe_purgearena_maybe_purge_ratiothresholdje_arena_lg_dirty_mult_setje_arena_decay_time_getarena_decay_time_validarena_decay_initje_arena_decay_time_setarena_decay_deadline_reachedtimearena_decay_npages_limitnpages_limitarena_decay_epoch_advancenadvancendirty_deltaarena_decay_backlog_npages_limitsumnpages_limit_backlogarena_maybe_purge_decayndirty_limitje_arena_purgearena_stash_dirtypurge_runs_sentinelpurge_chunks_sentinelnstashedrdelmrdelm_nextchunkselmnpagesmiscelmchunkselm_nextje_arena_rd_to_miscelmje_arena_miscelm_to_pageindje_arena_mapbits_unallocated_size_getarena_run_split_largearena_purge_stashednpurgedflag_unzeroeddecommittedje_arena_mapbits_large_setmapbitspje_arena_mapbitsp_writeje_arena_mapbits_size_encodeje_arena_mapbits_internal_setarena_unstash_purgedzeroedcommittedje_arena_mapbits_decommitted_getarena_purge_to_limitje_arena_alloc_junk_smallbin_infoarena_run_reg_allocregindrpagesje_bitmap_sfubinfobitgje_ffs_luje_bitmap_setgoffgpje_arena_run_to_miscelmje_arena_miscelm_to_rpagesje_arena_decay_ticksje_arena_decay_tickje_arena_tdata_getrefresh_if_missingje_decay_ticker_getallje_arena_tcache_fill_smallbinnfillje_arena_bin_indexarena_bin_nonfull_run_trygetarena_bin_nonfull_run_getarena_run_tree_firstrbtreearena_bin_runs_firstje_run_quantize_ceilarena_run_first_best_fitarena_run_alloc_small_helperarena_run_alloc_smallarena_runs_avail_getje_arena_miscelm_getarena_bin_runs_removearena_dalloc_bin_runarena_bin_lower_runarena_bin_runs_insertarena_bin_malloc_hardarena_redzones_validateje_arena_redzone_corruptionafterje_arena_dalloc_junk_smallje_arena_quarantine_junk_smallje_prng_lg_rangelg_rangearena_run_alloc_largeje_arena_malloc_largeidumprandom_offsetarena_malloc_smallje_arena_malloc_hardarena_palloc_largeleadsizetrailsizehead_miscelmhead_runrun_indje_arena_mapbits_dirty_getarena_run_trim_headnewsizehead_npagesflag_dirtyflag_decommittedflag_unzeroed_maskje_arena_mapbits_unzeroed_getarena_run_trim_tailtail_runtail_miscelmarena_run_init_largeje_arena_pallocje_arena_dalloc_bin_junked_lockedbitselmje_arena_mapbits_small_runind_getarena_run_reg_dallocje_arena_run_regindintervaldiffje_ffs_zuje_bitmap_unsetpropagatearena_dissociate_bin_runarena_dalloc_bin_locked_impljunkedrpages_indje_arena_dalloc_binje_arena_dalloc_smallje_arena_dalloc_junk_largeje_arena_dalloc_large_junked_lockedarena_dalloc_large_locked_implje_arena_dalloc_largearena_ralloc_largeusize_minusize_maxarena_ralloc_large_growfollowsizesplitsizezbasenzerozpastoldindexje_arena_mapbits_allocated_getje_arena_ralloc_junk_largearena_ralloc_large_shrinkje_arena_ralloc_no_movearena_ralloc_move_helperje_arena_rallocje_arena_dss_prec_getje_arena_dss_prec_setje_arena_lg_dirty_mult_default_getatomic_write_zje_arena_lg_dirty_mult_default_setje_arena_decay_time_default_getje_arena_decay_time_default_setje_arena_nthreads_getarena_basic_stats_merge_lockeddssje_arena_metadata_allocated_getje_arena_stats_mergeastatsbstatsje_arena_nthreads_incje_atomic_sub_uje_arena_nthreads_decarena_run_tree_newje_arena_newarena_sizebin_info_initsmall_run_size_initrun_quantize_initrun_quantize_floor_computeqsizerun_quantize_ceil_compute_hardlarge_run_size_nextrun_quantize_ceil_computeje_arena_bootheader_sizebin_info_run_size_calcpad_sizetry_run_sizeactual_run_sizeperfect_run_sizetry_nregsperfect_nregsactual_nregsalign_minje_arena_mapbits_large_getarena_run_size_getje_arena_mapbits_unallocated_setarena_run_coalescep_sizep_run_indp_run_pagesrun_pagesnrun_sizenrun_pagesprun_sizeprun_pagesarena_run_dirty_removeje_arena_mapbits_unallocated_size_setarena_run_dirty_insertarena_chunk_dallocarena_run_dalloccleanedarena_miscelm_size_getje_run_quantize_floorarena_avail_insertarena_avail_removearena_run_addr_compa_miscelmb_miscelmuintptr_tarena_run_tree_removepathnodeppathptredleftlefttnodeleftrightleftrightleftunoderightrightleftarena_run_tree_insertcnodearena_run_zeroarena_run_split_large_helperremoveneed_pagesarena_run_split_removetotal_pagesrem_pagesarena_run_alloc_large_helperarena_chunk_init_sparearena_chunk_init_hardarena_chunk_alloc_internalarena_chunk_registerje_extent_node_arena_setje_extent_node_initje_extent_node_addr_setje_extent_node_size_setje_extent_node_zeroed_setextent_node_committed_setje_extent_node_achunk_setachunkarena_chunk_alloc_internal_hardarena_chunk_allocje_arena_mapbits_small_setrunindarena_run_split_smallje_pow2_ceil_u64je_prng_rangeje_ffs_u64arena_decay_deadline_initjitter/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/base.cbase_mtxbase_avail_szadbase_nodesbase_allocatedbase_residentbase_mappedbase_node_try_allocbase_chunk_allocminsizensizebase_node_dallocje_base_allocje_base_stats_getallocatedresidentje_base_boot/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/bitmap.cje_bitmap_info_initje_bitmap_sizeje_bitmap_init/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/chunk.cje_opt_dssje_opt_lg_chunkje_chunk_hooks_defaultje_chunks_rtreertree_trtree_sheightstart_levellevelsrtree_node_alloc_trtree_node_elm_trtree_node_elm_spunchildrtree_node_dalloc_trtree_level_trtree_level_ssubtree_punsubtreecumbitsje_chunksizeje_chunksize_maskje_chunk_npageschunk_arena_getchunk_alloc_corenew_addrchunk_alloc_defaultchunk_dalloc_defaultchunk_commit_defaultchunk_decommit_defaultje_chunk_purge_arenachunk_purge_defaultchunk_split_defaultsize_asize_bchunk_merge_defaultchunk_achunk_bchunk_hooks_get_lockedje_chunk_hooks_getje_chunk_hooks_setold_chunk_hooksuje_rtree_start_levelrtreeje_rtree_setsubkeyje_rtree_subtree_tryreadlevelje_rtree_subtree_readje_rtree_node_validje_rtree_subkeyje_rtree_child_tryreadje_rtree_child_readje_rtree_val_writeje_chunk_registerje_chunk_deregisterje_chunk_alloc_baseje_chunk_alloc_cachedalloc_nodechunk_hooks_assure_initialized_impllockedchunk_hooks_assure_initialized_lockedchunk_first_best_fitchunks_szadchunks_adchunk_recyclechunk_hooks_assure_initializedchunk_alloc_retainedje_chunk_alloc_wrapperje_chunk_dalloc_cacheextent_node_committed_getje_extent_node_zeroed_getje_chunk_purge_wrapperchunk_recordprevunzeroedje_chunk_dalloc_arenaje_chunk_dalloc_wrapperje_chunk_bootchunks_rtree_node_allocnelms/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/chunk_dss.cje_dss_prec_namesje_chunk_dss_prec_getje_chunk_dss_prec_set/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/chunk_mmap.cconfig_munmapchunk_alloc_mmap_slowpagesje_chunk_alloc_mmapje_chunk_dalloc_mmap/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/ctl.cctl_mtxsuper_root_nodectl_named_node_tctl_named_node_snchildrenchildrenctlctl_node_snamedctl_node_troot_nodestats_nodestats_arenas_nodectl_indexed_node_tctl_indexed_node_ssuper_stats_arenas_i_nodestats_arenas_i_nodestats_arenas_i_hchunks_nodesuper_stats_arenas_i_hchunks_j_nodestats_arenas_i_hchunks_j_nodestats_arenas_i_lruns_nodesuper_stats_arenas_i_lruns_j_nodestats_arenas_i_lruns_j_nodestats_arenas_i_bins_nodesuper_stats_arenas_i_bins_j_nodestats_arenas_i_bins_j_nodestats_arenas_i_huge_nodestats_arenas_i_large_nodestats_arenas_i_small_nodestats_arenas_i_metadata_nodectl_arena_stats_tctl_arena_stats_spactivepdirtyallocated_smallnmalloc_smallndalloc_smallnrequests_smallprof_nodearenas_nodearenas_hchunk_nodesuper_arenas_hchunk_i_nodearenas_hchunk_i_nodearenas_lrun_nodesuper_arenas_lrun_i_nodearenas_lrun_i_nodearenas_bin_nodesuper_arenas_bin_i_nodearenas_bin_i_nodearena_nodesuper_arena_i_nodearena_i_nodetcache_nodeopt_nodeconfig_nodeconfig_valgrindconfig_utraceconfig_tlsconfig_tcacheconfig_statsconfig_prof_libunwindconfig_prof_libgccconfig_lazy_lockconfig_fillconfig_debugconfig_cache_obliviousthread_nodethread_prof_nodethread_tcache_nodectl_epochctl_named_nodeje_ctl_bynamenodesctl_arena_initctl_initjctl_named_childrenctl_indexed_nodectl_lookupnodespdepthptdotdotelenpnodeinodeje_ctl_nametomibje_ctl_bymibje_ctl_bootversion_ctloldvalcopylenepoch_ctlnewvalstats_cactive_ctlstats_allocated_ctlstats_active_ctlstats_metadata_ctlstats_resident_ctlstats_mapped_ctlstats_arenas_i_indexstats_arenas_i_nthreads_ctlstats_arenas_i_dss_ctlstats_arenas_i_lg_dirty_mult_ctlstats_arenas_i_decay_time_ctlstats_arenas_i_pactive_ctlstats_arenas_i_pdirty_ctlstats_arenas_i_mapped_ctlstats_arenas_i_npurge_ctlstats_arenas_i_nmadvise_ctlstats_arenas_i_purged_ctlstats_arenas_i_hchunks_j_indexstats_arenas_i_hchunks_j_nmalloc_ctlstats_arenas_i_hchunks_j_ndalloc_ctlstats_arenas_i_hchunks_j_nrequests_ctlstats_arenas_i_hchunks_j_curhchunks_ctlstats_arenas_i_lruns_j_indexstats_arenas_i_lruns_j_nmalloc_ctlstats_arenas_i_lruns_j_ndalloc_ctlstats_arenas_i_lruns_j_nrequests_ctlstats_arenas_i_lruns_j_curruns_ctlstats_arenas_i_bins_j_indexstats_arenas_i_bins_j_nmalloc_ctlstats_arenas_i_bins_j_ndalloc_ctlstats_arenas_i_bins_j_nrequests_ctlstats_arenas_i_bins_j_curregs_ctlstats_arenas_i_bins_j_nfills_ctlstats_arenas_i_bins_j_nflushes_ctlstats_arenas_i_bins_j_nruns_ctlstats_arenas_i_bins_j_nreruns_ctlstats_arenas_i_bins_j_curruns_ctlstats_arenas_i_huge_allocated_ctlstats_arenas_i_huge_nmalloc_ctlstats_arenas_i_huge_ndalloc_ctlstats_arenas_i_huge_nrequests_ctlstats_arenas_i_large_allocated_ctlstats_arenas_i_large_nmalloc_ctlstats_arenas_i_large_ndalloc_ctlstats_arenas_i_large_nrequests_ctlstats_arenas_i_small_allocated_ctlstats_arenas_i_small_nmalloc_ctlstats_arenas_i_small_ndalloc_ctlstats_arenas_i_small_nrequests_ctlstats_arenas_i_metadata_mapped_ctlstats_arenas_i_metadata_allocated_ctlprof_thread_active_init_ctlprof_active_ctlprof_dump_ctlfilenameprof_gdump_ctlprof_reset_ctllg_sampleprof_interval_ctllg_prof_sample_ctlarenas_narenas_ctlarenas_initialized_ctlnreadarenas_lg_dirty_mult_ctlarenas_decay_time_ctlarenas_quantum_ctlarenas_page_ctlarenas_tcache_max_ctlarenas_nbins_ctlarenas_nhbins_ctlarenas_nlruns_ctlarenas_nhchunks_ctlctl_growarenas_extend_ctlarenas_hchunk_i_indexarenas_hchunk_i_size_ctlarenas_lrun_i_indexarenas_lrun_i_size_ctlarenas_bin_i_indexarenas_bin_i_size_ctlarenas_bin_i_nregs_ctlarenas_bin_i_run_size_ctlarena_i_indexarena_i_purge_ctlarena_i_decay_ctlarena_i_dss_ctldss_prec_oldarena_i_lg_dirty_mult_ctlarena_i_decay_time_ctlarena_i_chunk_hooks_ctlnew_chunk_hooksarena_i_purgetarenastarenatcache_create_ctltcache_indtcache_flush_ctltcache_destroy_ctlopt_abort_ctlopt_dss_ctlopt_lg_chunk_ctlopt_narenas_ctlopt_purge_ctlopt_lg_dirty_mult_ctlopt_decay_time_ctlopt_stats_print_ctlopt_junk_ctlopt_zero_ctlopt_quarantine_ctlopt_redzone_ctlopt_utrace_ctlopt_xmalloc_ctlopt_tcache_ctlopt_lg_tcache_max_ctlopt_prof_ctlopt_prof_prefix_ctlopt_prof_active_ctlopt_prof_thread_active_init_ctlopt_lg_prof_sample_ctlopt_lg_prof_interval_ctlopt_prof_gdump_ctlopt_prof_final_ctlopt_prof_leak_ctlopt_prof_accum_ctlconfig_cache_oblivious_ctlconfig_debug_ctlconfig_fill_ctlconfig_lazy_lock_ctlconfig_malloc_conf_ctlconfig_munmap_ctlconfig_prof_ctlconfig_prof_libgcc_ctlconfig_prof_libunwind_ctlconfig_stats_ctlconfig_tcache_ctlconfig_tls_ctlconfig_utrace_ctlconfig_valgrind_ctlconfig_xmalloc_ctlthread_arena_ctlthread_allocated_ctltsd_thread_allocatedp_getthread_allocatedp_ctlthread_deallocated_ctltsd_thread_deallocatedp_getthread_deallocatedp_ctlthread_prof_name_ctlthread_prof_active_ctlje_tcache_enabled_getje_tsd_tcache_enabled_setje_tcache_enabled_setenabledthread_tcache_enabled_ctlje_tcache_flushthread_tcache_flush_ctlctl_arena_clearctl_arena_refreshsstatsctl_arena_stats_amergecstatsctl_arena_stats_smergectl_refresh/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/extent.cje_extent_tree_szad_newextent_quantizeextent_szad_compa_qsizeb_qsizea_addrb_addrje_extent_tree_szad_nsearchje_extent_tree_szad_insertje_extent_tree_szad_removeje_extent_tree_ad_newextent_ad_compje_extent_tree_ad_prevje_extent_tree_ad_searchje_extent_tree_ad_nsearchje_extent_tree_ad_insertje_extent_tree_ad_remove/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/huge.cje_huge_mallochuge_node_setje_rtree_getdependentje_chunk_lookuphuge_node_getje_huge_aallocje_rtree_val_readje_arena_ptr_small_binind_getje_huge_pallocausizeis_zeroedhuge_ralloc_no_move_similarusize_nextpost_zeroedpre_zeroedsdiffhuge_ralloc_no_move_shrinkje_huge_ralloc_no_movehuge_ralloc_no_move_expandis_zeroed_chunkis_zeroed_subchunkhuge_ralloc_move_helperje_huge_rallochuge_node_unsetje_huge_dallocje_huge_salloc/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/mutex.cje_malloc_mutex_initje_mutex_boot/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/nstime.cje_nstime_initje_nstime_init2secnsecje_nstime_nsje_nstime_copyje_nstime_compareje_nstime_addaddendje_nstime_subtractsubtrahendje_nstime_imultiplymultiplierje_nstime_idividedivisorje_nstime_dividesourceje_nstime_updatetvold_timetimevaltv_sectv_usec__darwin_time_t__darwin_suseconds_t__int32_t/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/pages.cje_pages_unmapje_pages_mapje_pages_trimje_pages_commitje_pages_decommitje_pages_purge/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/prof.cje_prof_tdata_cleanup/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/quarantine.cje_tsd_quarantine_setje_quarantine_alloc_hook_workquarantine_initquarantine_drainupper_boundquarantine_growncopy_ancopy_bobjje_quarantine_cleanupquarantine_drain_one/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/rtree.chminhahbje_rtree_newbits_in_leafje_atomic_cas_uint64csuccessje_atomic_cas_prtree_node_initelmpje_rtree_subtree_read_hardje_rtree_child_read_hard/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/stats.cje_opt_stats_printje_stats_cactiveje_stats_printepochlargeunmergedmergedgeneralu64szbszuszsszssszcpszbvsvcpvuvssvszssv2bv2metadataiszninitializedstats_arena_bins_printin_gappagenbinsutilavailregsmillistats_arena_lruns_printnlrunsstats_arena_hchunks_printnhchunkshchunk_sizestats_arena_printsmall_allocatedsmall_nmallocsmall_ndallocsmall_nrequestslarge_allocatedlarge_nmalloclarge_ndalloclarge_nrequestshuge_allocatedhuge_nmallochuge_ndallochuge_nrequests/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/tcache.cje_opt_tcacheje_opt_lg_tcache_maxje_tcache_bin_infostack_nelmsje_nhbinsje_tcache_maxclassje_tcachestcaches_pasttcaches_availje_tcache_event_hardje_tcache_bin_flush_smallremmerged_statsnflushndeferredbin_arenaje_tcache_bin_flush_largelocked_arenaje_tcache_alloc_small_hardje_tcache_arena_associateje_tcache_arena_reassociateje_tcache_stats_mergeje_tcache_arena_dissociateje_tcache_cleanupje_tcache_get_hardje_tcache_createstack_offsettcache_destroyje_tcache_enabled_cleanupje_tcaches_creater_indtcaches_elm_flushje_tcaches_flushje_tcaches_destroyje_tcache_boot/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/tsd.cje_tsd_init_headtsd_init_head_ttsd_init_head_sblockstsd_boot_wrapperje_tsd_bootedncleanupsje_tsd_tsdpthread_key_t__darwin_pthread_key_tje_malloc_tsd_mallocje_tsd_init_check_recursionheadje_tsd_init_finishje_tsd_cleanupargje_tsd_boot0je_malloc_tsd_boot0je_tsd_boot1je_malloc_tsd_boot1je_malloc_tsd_dallocje_tsd_cleanup_wrapper/Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/jemalloc/src/util.cje_malloc_messagewrtmessageje_malloc_writeje_buferrorbuflenje_malloc_strtoumaxnptrendptrbasedigitnegpretu2suppercaseslen_pdigitso2salt_formx2sd2ssignintmax_tje_malloc_vsnprintfapprecleft_justifyplus_spaceplus_pluspad_lencpylenuwidthuprecje_malloc_snprintfje_malloc_vcprintf__va_list_taggp_offsetfp_offsetoverflow_arg_areareg_save_areaje_malloc_cprintfje_malloc_printfva_list__darwin_va_list__builtin_va_listgimli-0.19.0/fixtures/self/eh_frame010077500017500001750000004403101343337721300154330ustar0000000000000000zRx $øÚæÿÿÿÿÿfA†C zPLRx›@ ,$ Ûæÿÿÿÿÿ7çýÿÿÿÿÿA†C $”€Ûæÿÿÿÿÿ{A†C $¼ØÛæÿÿÿÿÿ2A†C $äðÛæÿÿÿÿÿlA†C $ 8ÜæÿÿÿÿÿlA†C ,ô€Üæÿÿÿÿÿo“æýÿÿÿÿÿA†C $dÀÜæÿÿÿÿÿMA†C $ŒèÜæÿÿÿÿÿQA†C $´ ÝæÿÿÿÿÿMA†C $ÜHÝæÿÿÿÿÿlA†C $ÝæÿÿÿÿÿhA†C $,ØÝæÿÿÿÿÿhA†C $T ÞæÿÿÿÿÿhA†C $|hÞæÿÿÿÿÿhA†C $¤°Þæÿÿÿÿÿ6A†C $ÌÈÞæÿÿÿÿÿSA†C $ôßæÿÿÿÿÿ;A†C $ßæÿÿÿÿÿ;A†C $D0ßæÿÿÿÿÿ;A†C $lHßæÿÿÿÿÿ;A†C $”`ßæÿÿÿÿÿ;A†C $¼xßæÿÿÿÿÿ;A†C $äßæÿÿÿÿÿ;A†C $ ¨ßæÿÿÿÿÿ;A†C $4Àßæÿÿÿÿÿ;A†C $\Øßæÿÿÿÿÿ;A†C $„ðßæÿÿÿÿÿ;A†C $¬àæÿÿÿÿÿ;A†C $Ô àæÿÿÿÿÿ;A†C $ü8àæÿÿÿÿÿ;A†C $$PàæÿÿÿÿÿVA†C $LˆàæÿÿÿÿÿKA†C $t°àæÿÿÿÿÿKA†C $œØàæÿÿÿÿÿKA†C $ÄáæÿÿÿÿÿKA†C $ì(áæÿÿÿÿÿKA†C $PáæÿÿÿÿÿSA†C $<ˆáæÿÿÿÿÿSA†C $dÀáæÿÿÿÿÿKA†C $ŒèáæÿÿÿÿÿKA†C $´âæÿÿÿÿÿKA†C $Ü8âæÿÿÿÿÿKA†C $`âæÿÿÿÿÿ;A†C $,xâæÿÿÿÿÿ;A†C $Tâæÿÿÿÿÿ;A†C $|¨âæÿÿÿÿÿ;A†C $¤Àâæÿÿÿÿÿ;A†C $ÌØâæÿÿÿÿÿ;A†C $ôðâæÿÿÿÿÿ;A†C $ãæÿÿÿÿÿ;A†C $D ãæÿÿÿÿÿ;A†C $l8ãæÿÿÿÿÿ;A†C $”PãæÿÿÿÿÿFA†C $¼xãæÿÿÿÿÿFA†C $ä ãæÿÿÿÿÿFA†C $ ÈãæÿÿÿÿÿFA†C $4 ðãæÿÿÿÿÿFA†C $\ äæÿÿÿÿÿFA†C $„ @äæÿÿÿÿÿFA†C $¬ häæÿÿÿÿÿFA†C $Ô äæÿÿÿÿÿFA†C $ü ¸äæÿÿÿÿÿFA†C $$ àäæÿÿÿÿÿFA†C $L åæÿÿÿÿÿ;A†C $t åæÿÿÿÿÿ;A†C $œ 8åæÿÿÿÿÿ;A†C $Ä PåæÿÿÿÿÿFA†C $ì xåæÿÿÿÿÿFA†C ,Ô  åæÿÿÿÿÿaßÜýÿÿÿÿÿA†C , àåæÿÿÿÿÿaÏÜýÿÿÿÿÿA†C ,4 ææÿÿÿÿÿa¿ÜýÿÿÿÿÿA†C ,d `ææÿÿÿÿÿa¯ÜýÿÿÿÿÿA†C ,”  ææÿÿÿÿÿaŸÜýÿÿÿÿÿA†C ,Ä àææÿÿÿÿÿaÜýÿÿÿÿÿA†C ,ô çæÿÿÿÿÿaÜýÿÿÿÿÿA†C ,$ `çæÿÿÿÿÿaoÜýÿÿÿÿÿA†C $”  çæÿÿÿÿÿ>A†C $¼ ¸çæÿÿÿÿÿ;A†C $ä ÐçæÿÿÿÿÿVA†C ,Ì èæÿÿÿÿÿèçÛýÿÿÿÿÿA†C ,ü ÈèæÿÿÿÿÿèóÛýÿÿÿÿÿA†C ,, ˆéæÿÿÿÿÿLÿÛýÿÿÿÿÿA†C ,\ ¨êæÿÿÿÿÿL ÜýÿÿÿÿÿA†C ,Œ ÈëæÿÿÿÿÿLÜýÿÿÿÿÿA†C ,¼ èìæÿÿÿÿÿL#ÜýÿÿÿÿÿA†C ,ì îæÿÿÿÿÿL/ÜýÿÿÿÿÿA†C ,(ïæÿÿÿÿÿL;ÜýÿÿÿÿÿA†C ,LHðæÿÿÿÿÿLGÜýÿÿÿÿÿA†C ,|hñæÿÿÿÿÿLSÜýÿÿÿÿÿA†C $ìˆòæÿÿÿÿÿùA†C ,Ô`óæÿÿÿÿÿ¹7ÜýÿÿÿÿÿA†C $Dðöæÿÿÿÿÿ A†C $lØöæÿÿÿÿÿ A†C $”Àöæÿÿÿÿÿ A†C $¼¨öæÿÿÿÿÿ A†C $äöæÿÿÿÿÿ A†C $ xöæÿÿÿÿÿ A†C $4`öæÿÿÿÿÿ A†C $\Höæÿÿÿÿÿ A†C $„0öæÿÿÿÿÿ A†C $¬öæÿÿÿÿÿ A†C $Ôöæÿÿÿÿÿ A†C $üèõæÿÿÿÿÿ A†C $$Ðõæÿÿÿÿÿ A†C $L¸õæÿÿÿÿÿ A†C $t õæÿÿÿÿÿ A†C $œˆõæÿÿÿÿÿ A†C $Äpõæÿÿÿÿÿ A†C $ìXõæÿÿÿÿÿ A†C $@õæÿÿÿÿÿ A†C $<(õæÿÿÿÿÿ A†C $dõæÿÿÿÿÿ A†C $Œøôæÿÿÿÿÿ A†C $´àôæÿÿÿÿÿ A†C $ÜÈôæÿÿÿÿÿ A†C $°ôæÿÿÿÿÿ A†C $,˜ôæÿÿÿÿÿ A†C $T€ôæÿÿÿÿÿ A†C $|hôæÿÿÿÿÿ A†C $¤Pôæÿÿÿÿÿ A†C $Ì8ôæÿÿÿÿÿ A†C $ô ôæÿÿÿÿÿ A†C $ôæÿÿÿÿÿ A†C $Dðóæÿÿÿÿÿ A†C $lØóæÿÿÿÿÿ A†C $”Àóæÿÿÿÿÿ A†C $¼¨óæÿÿÿÿÿ A†C ,¤óæÿÿÿÿÿŒ¯ÖýÿÿÿÿÿA†C $ðóæÿÿÿÿÿ2A†C ,üôæÿÿÿÿÿMƒÖýÿÿÿÿÿA†C ,,(÷æÿÿÿÿÿVÃÖýÿÿÿÿÿA†C ,\Xúæÿÿÿÿÿ8×ýÿÿÿÿÿA†C ,Œhýæÿÿÿÿÿ2C×ýÿÿÿÿÿA†C ,¼xçÿÿÿÿÿPƒ×ýÿÿÿÿÿA†C ,ì˜çÿÿÿÿÿPÃ×ýÿÿÿÿÿA†C ,¸çÿÿÿÿÿ@ØýÿÿÿÿÿA†C ,LÈ çÿÿÿÿÿ2CØýÿÿÿÿÿA†C ,|Ø çÿÿÿÿÿ8ƒØýÿÿÿÿÿA†C ,¬èçÿÿÿÿÿPÃØýÿÿÿÿÿA†C ,ÜçÿÿÿÿÿPÙýÿÿÿÿÿA†C $L(çÿÿÿÿÿ!A†C ,40çÿÿÿÿÿ¡ÙýÿÿÿÿÿA†C $¤°çÿÿÿÿÿÿA†C Hƒ,Œˆçÿÿÿÿÿö ÙýÿÿÿÿÿA†C $üXçÿÿÿÿÿ.A†C $$`çÿÿÿÿÿ\A†C $L˜çÿÿÿÿÿlA†C $tàçÿÿÿÿÿ;A†C $œøçÿÿÿÿÿiA†C $Ä@ çÿÿÿÿÿFA†C $ìh çÿÿÿÿÿFA†C $ çÿÿÿÿÿFA†C $<¸ çÿÿÿÿÿFA†C $dà çÿÿÿÿÿFA†C $Œ!çÿÿÿÿÿFA†C $´0!çÿÿÿÿÿFA†C $ÜX!çÿÿÿÿÿFA†C $€!çÿÿÿÿÿFA†C $,¨!çÿÿÿÿÿFA†C $TÐ!çÿÿÿÿÿFA†C $|ø!çÿÿÿÿÿFA†C $¤ "çÿÿÿÿÿFA†C $ÌH"çÿÿÿÿÿFA†C $ôp"çÿÿÿÿÿFA†C $˜"çÿÿÿÿÿFA†C $DÀ"çÿÿÿÿÿFA†C $lè"çÿÿÿÿÿFA†C $”#çÿÿÿÿÿ/A†C ,|#çÿÿÿÿÿKcÕýÿÿÿÿÿA†C ,¬8$çÿÿÿÿÿKSÕýÿÿÿÿÿA†C ,ÜX%çÿÿÿÿÿ«CÕýÿÿÿÿÿA†C $LØ&çÿÿÿÿÿßA†C ,4(çÿÿÿÿÿ? ÕýÿÿÿÿÿA†C ,d )çÿÿÿÿÿ'ûÔýÿÿÿÿÿA†C ,” *çÿÿÿÿÿ'ëÔýÿÿÿÿÿA†C ,Ä +çÿÿÿÿÿ…ÛÔýÿÿÿÿÿA†C ,ô-çÿÿÿÿÿ'ËÔýÿÿÿÿÿA†C ,$.çÿÿÿÿÿ'»ÔýÿÿÿÿÿA†C ,T/çÿÿÿÿÿ?«ÔýÿÿÿÿÿA†C ,„0çÿÿÿÿÿ'›ÔýÿÿÿÿÿA†C ,´1çÿÿÿÿÿk‹ÔýÿÿÿÿÿA†C ,äP3çÿÿÿÿÿW{ÔýÿÿÿÿÿA†C ,€4çÿÿÿÿÿ'kÔýÿÿÿÿÿA†C ,D€5çÿÿÿÿÿ'[ÔýÿÿÿÿÿA†C ,t€6çÿÿÿÿÿ'KÔýÿÿÿÿÿA†C ,¤€7çÿÿÿÿÿ;ÔýÿÿÿÿÿA†C ,Ôp8çÿÿÿÿÿ'+ÔýÿÿÿÿÿA†C ,p9çÿÿÿÿÿzÔýÿÿÿÿÿA†C ,4À;çÿÿÿÿÿ' ÔýÿÿÿÿÿA†C ,dÀ<çÿÿÿÿÿ'ûÓýÿÿÿÿÿA†C ,”À=çÿÿÿÿÿ'ëÓýÿÿÿÿÿA†C ,ÄÀ>çÿÿÿÿÿ'ÛÓýÿÿÿÿÿA†C $4 À?çÿÿÿÿÿLA†C $\ è?çÿÿÿÿÿRA†C ,D @çÿÿÿÿÿ#{ÓýÿÿÿÿÿA†C ,t AçÿÿÿÿÿúkÓýÿÿÿÿÿA†C ,¤ ðBçÿÿÿÿÿ[ÓýÿÿÿÿÿA†C ,Ô àCçÿÿÿÿÿÕKÓýÿÿÿÿÿA†C ,!Dçÿÿÿÿÿ¸;ÓýÿÿÿÿÿA†C ,4! Eçÿÿÿÿÿ¸+ÓýÿÿÿÿÿA†C ,d!°EçÿÿÿÿÿíÓýÿÿÿÿÿA†C ,”!pFçÿÿÿÿÿí ÓýÿÿÿÿÿA†C ,Ä!0Gçÿÿÿÿÿ¸ûÒýÿÿÿÿÿA†C ,ô!ÀGçÿÿÿÿÿõëÒýÿÿÿÿÿA†C ,$"Hçÿÿÿÿÿ“ÛÒýÿÿÿÿÿA†C $”"Jçÿÿÿÿÿ0A†C $¼"Jçÿÿÿÿÿ0A†C $ä"Jçÿÿÿÿÿ0A†C $ #Jçÿÿÿÿÿ0A†C $4# Jçÿÿÿÿÿ0A†C $\#(Jçÿÿÿÿÿ0A†C $„#0Jçÿÿÿÿÿ@A†C $¬#HJçÿÿÿÿÿBA†C $Ô#pJçÿÿÿÿÿBA†C $ü#˜JçÿÿÿÿÿBA†C $$$ÀJçÿÿÿÿÿ?A†C $L$ØJçÿÿÿÿÿ@A†C $t$ðJçÿÿÿÿÿÁA†C $œ$˜KçÿÿÿÿÿJA†C $Ä$ÀKçÿÿÿÿÿ`A†C $ì$øKçÿÿÿÿÿ`A†C $%0Lçÿÿÿÿÿ`A†C $<%hLçÿÿÿÿÿ`A†C $d% Lçÿÿÿÿÿ|A†C $Œ%øLçÿÿÿÿÿ|A†C $´%PMçÿÿÿÿÿ|A†C $Ü%¨Mçÿÿÿÿÿ|A†C $&Nçÿÿÿÿÿ|A†C $,&XNçÿÿÿÿÿ|A†C $T&°Nçÿÿÿÿÿ|A†C $|&Oçÿÿÿÿÿ|A†C ,d&`Oçÿÿÿÿÿ[×ÎýÿÿÿÿÿA†C ,”&Qçÿÿÿÿÿ[ÓÎýÿÿÿÿÿA†C ,Ä&ÀSçÿÿÿÿÿ[ÏÎýÿÿÿÿÿA†C ,ô&ðUçÿÿÿÿÿ[ËÎýÿÿÿÿÿA†C ,$' Xçÿÿÿÿÿ[ÇÎýÿÿÿÿÿA†C ,T'PZçÿÿÿÿÿ[ÃÎýÿÿÿÿÿA†C ,„'€\çÿÿÿÿÿ[¿ÎýÿÿÿÿÿA†C ,´'°^çÿÿÿÿÿ[»ÎýÿÿÿÿÿA†C ,ä'à`çÿÿÿÿÿ[·ÎýÿÿÿÿÿA†C ,(cçÿÿÿÿÿ[³ÎýÿÿÿÿÿA†C ,D(@eçÿÿÿÿÿ[¯ÎýÿÿÿÿÿA†C ,t(pgçÿÿÿÿÿk«ÎýÿÿÿÿÿA†C ,¤(°içÿÿÿÿÿ[§ÎýÿÿÿÿÿA†C ,Ô(àkçÿÿÿÿÿ[£ÎýÿÿÿÿÿA†C ,)nçÿÿÿÿÿóŸÎýÿÿÿÿÿA†C ,4)àoçÿÿÿÿÿó›ÎýÿÿÿÿÿA†C ,d)°qçÿÿÿÿÿô—ÎýÿÿÿÿÿA†C $Ô)€sçÿÿÿÿÿ"A†C $ü)ˆsçÿÿÿÿÿ"A†C $$*sçÿÿÿÿÿ"A†C $L*˜sçÿÿÿÿÿ"A†C $t* sçÿÿÿÿÿ"A†C $œ*¨sçÿÿÿÿÿ"A†C $Ä*°sçÿÿÿÿÿ"A†C $ì*¸sçÿÿÿÿÿ"A†C $+Àsçÿÿÿÿÿ"A†C $<+ÈsçÿÿÿÿÿQA†C $d+tçÿÿÿÿÿQA†C $Œ+8tçÿÿÿÿÿQA†C $´+ptçÿÿÿÿÿQA†C $Ü+¨tçÿÿÿÿÿQA†C $,àtçÿÿÿÿÿQA†C $,,uçÿÿÿÿÿQA†C $T,PuçÿÿÿÿÿQA†C $|,ˆuçÿÿÿÿÿQA†C $¤,ÀuçÿÿÿÿÿQA†C $Ì,øuçÿÿÿÿÿQA†C ,´,0vçÿÿÿÿÿ sËýÿÿÿÿÿA†C ,ä, wçÿÿÿÿÿoËýÿÿÿÿÿA†C ,-xçÿÿÿÿÿìkËýÿÿÿÿÿA†C ,D-Pzçÿÿÿÿÿ"gËýÿÿÿÿÿA†C ,t-P|çÿÿÿÿÿMsËýÿÿÿÿÿA†C ,¤-p~çÿÿÿÿÿ†‹ËýÿÿÿÿÿA†C ,Ô-Ðçÿÿÿÿÿ¹‡ËýÿÿÿÿÿA†C ,.`çÿÿÿÿÿ݃ËýÿÿÿÿÿA†C ,4.ƒçÿÿÿÿÿçËýÿÿÿÿÿA†C ,d.Єçÿÿÿÿÿg‹ËýÿÿÿÿÿA†C ,”.†çÿÿÿÿÿ†‡ËýÿÿÿÿÿA†C ,Ä.p‡çÿÿÿÿÿNƒËýÿÿÿÿÿA†C ,ô.ˆçÿÿÿÿÿNËýÿÿÿÿÿA†C ,$/°‰çÿÿÿÿÿç{ËýÿÿÿÿÿA†C ,T/p‹çÿÿÿÿÿN‡ËýÿÿÿÿÿA†C ,„/ŒçÿÿÿÿÿçƒËýÿÿÿÿÿA†C ,´/PŽçÿÿÿÿÿðËýÿÿÿÿÿA†C $$0çÿÿÿÿÿ'A†C $L0çÿÿÿÿÿ'A†C $t0 çÿÿÿÿÿ;A†C $œ08çÿÿÿÿÿ;A†C $Ä0Pçÿÿÿÿÿ;A†C $ì0hçÿÿÿÿÿ*A†C $1pçÿÿÿÿÿ*A†C $<1xçÿÿÿÿÿ*A†C $d1€çÿÿÿÿÿWA†C $Œ1¸çÿÿÿÿÿ8A†C $´1Ðçÿÿÿÿÿ8A†C $Ü1èçÿÿÿÿÿ~A†C $2@‘çÿÿÿÿÿ…A†C ,ì1¨‘çÿÿÿÿÿòŸÉýÿÿÿÿÿA†C Hƒ$\2x™çÿÿÿÿÿ-A†C ,D2€™çÿÿÿÿÿ7·ÉýÿÿÿÿÿA†C ,t2¡çÿÿÿÿÿ7ÊýÿÿÿÿÿA†C $ä2 ©çÿÿÿÿÿ7A†C $ 3¸©çÿÿÿÿÿrA†C $43ªçÿÿÿÿÿÍA†C ,3¸ªçÿÿÿÿÿµÊýÿÿÿÿÿA†C ,L3H«çÿÿÿÿÿñ ÊýÿÿÿÿÿA†C ,|3®çÿÿÿÿÿÊýÿÿÿÿÿA†C $ì3x®çÿÿÿÿÿA†C $4à¯çÿÿÿÿÿ]A†C $<4°çÿÿÿÿÿ†A†C ,$4€±çÿÿÿÿÿe›ÉýÿÿÿÿÿA†C ,T4À³çÿÿÿÿÿ±¿ÉýÿÿÿÿÿA†C $Ä4P´çÿÿÿÿÿåA†C $ì4µçÿÿÿÿÿåA†C $5àµçÿÿÿÿÿåA†C $<5¨¶çÿÿÿÿÿåA†C $d5p·çÿÿÿÿÿ]A†C $Œ5¨·çÿÿÿÿÿ]A†C $´5à·çÿÿÿÿÿ]A†C $Ü5¸çÿÿÿÿÿ]A†C $6P¸çÿÿÿÿÿ]A†C $,6ˆ¸çÿÿÿÿÿ]A†C $T6À¸çÿÿÿÿÿ]A†C $|6ø¸çÿÿÿÿÿ]A†C $¤60¹çÿÿÿÿÿ]A†C $Ì6h¹çÿÿÿÿÿ]A†C $ô6 ¹çÿÿÿÿÿâA†C $7hºçÿÿÿÿÿâA†C $D70»çÿÿÿÿÿâA†C $l7ø»çÿÿÿÿÿmA†C $”7@¼çÿÿÿÿÿmA†C $¼7ˆ¼çÿÿÿÿÿmA†C $ä7мçÿÿÿÿÿmA†C $ 8½çÿÿÿÿÿmA†C $48`½çÿÿÿÿÿmA†C $\8¨½çÿÿÿÿÿmA†C $„8ð½çÿÿÿÿÿmA†C $¬88¾çÿÿÿÿÿmA†C $Ô8€¾çÿÿÿÿÿmA†C $ü8ȾçÿÿÿÿÿmA†C $$9¿çÿÿÿÿÿ.A†C $L9¿çÿÿÿÿÿ.A†C $t9 ¿çÿÿÿÿÿ.A†C $œ9(¿çÿÿÿÿÿ.A†C $Ä90¿çÿÿÿÿÿ.A†C $ì98¿çÿÿÿÿÿ.A†C $:@¿çÿÿÿÿÿ.A†C $<:H¿çÿÿÿÿÿ.A†C $d:P¿çÿÿÿÿÿ.A†C $Œ:X¿çÿÿÿÿÿ.A†C $´:`¿çÿÿÿÿÿ.A†C $Ü:h¿çÿÿÿÿÿ.A†C $;p¿çÿÿÿÿÿ.A†C $,;x¿çÿÿÿÿÿ.A†C $T;€¿çÿÿÿÿÿ.A†C $|;ˆ¿çÿÿÿÿÿ¢A†C $¤;Áçÿÿÿÿÿ¢A†C $Ì;˜Âçÿÿÿÿÿ¢A†C $ô; Äçÿÿÿÿÿ¢A†C $<¨Åçÿÿÿÿÿ¢A†C $D<0Ççÿÿÿÿÿ¢A†C $l<¸Èçÿÿÿÿÿ¢A†C $”<@Êçÿÿÿÿÿ¢A†C $¼<ÈËçÿÿÿÿÿ¢A†C $ä<PÍçÿÿÿÿÿ¢A†C $ =ØÎçÿÿÿÿÿ‘A†C $4=PÐçÿÿÿÿÿ¢A†C $\=ØÑçÿÿÿÿÿ¢A†C $„=`Óçÿÿÿÿÿ¢A†C $¬=èÔçÿÿÿÿÿºA†C $Ô=€ÖçÿÿÿÿÿËA†C $ü=(ØçÿÿÿÿÿËA†C $$>ÐÙçÿÿÿÿÿA†C $L>ÈÙçÿÿÿÿÿA†C $t>ÀÙçÿÿÿÿÿA†C $œ>¸ÙçÿÿÿÿÿYA†C $Ä>ðÙçÿÿÿÿÿ A†C $ì>èÙçÿÿÿÿÿA†C $?ÐÚçÿÿÿÿÿœA†C $A†C $ܧÚèÿÿÿÿÿJA†C ,ħ0ÚèÿÿÿÿÿG¯jýÿÿÿÿÿA†C ,ô§PÚèÿÿÿÿÿGŸjýÿÿÿÿÿA†C ,$¨pÚèÿÿÿÿÿGjýÿÿÿÿÿA†C ,T¨ÚèÿÿÿÿÿGjýÿÿÿÿÿA†C $Ĩ°ÚèÿÿÿÿÿJA†C $ì¨ØÚèÿÿÿÿÿ=A†C ,Ô¨ðÚèÿÿÿÿÿGjýÿÿÿÿÿA†C $D©Ûèÿÿÿÿÿ1A†C ,,©(ÛèÿÿÿÿÿGçiýÿÿÿÿÿA†C ,\©HÛèÿÿÿÿÿG×iýÿÿÿÿÿA†C ,Œ©hÛèÿÿÿÿÿGÇiýÿÿÿÿÿA†C $ü©ˆÛèÿÿÿÿÿ A†C $$ªpÛèÿÿÿÿÿ3A†C , ªˆÛèÿÿÿÿÿGgiýÿÿÿÿÿA†C ,<ª¨ÛèÿÿÿÿÿGWiýÿÿÿÿÿA†C $¬ªÈÛèÿÿÿÿÿ A†C $Ôª°Ûèÿÿÿÿÿ?A†C $üªÈÛèÿÿÿÿÿA†C ,䪰ÛèÿÿÿÿÿGÏhýÿÿÿÿÿA†C ,«ÐÛèÿÿÿÿÿG¿hýÿÿÿÿÿA†C $„«ðÛèÿÿÿÿÿ A†C ,l«ØÛèÿÿÿÿÿG‡hýÿÿÿÿÿA†C ,œ«øÛèÿÿÿÿÿGwhýÿÿÿÿÿA†C $ ¬ÜèÿÿÿÿÿA†C $4¬ÜèÿÿÿÿÿJA†C $\¬(Üèÿÿÿÿÿ$A†C ,D¬0ÜèÿÿÿÿÿGïgýÿÿÿÿÿA†C $´¬PÜèÿÿÿÿÿ A†C $ܬ8ÜèÿÿÿÿÿOA†C $­`Üèÿÿÿÿÿ A†C $,­HÜèÿÿÿÿÿ?A†C $T­`Üèÿÿÿÿÿ1A†C $|­xÜèÿÿÿÿÿJA†C ,d­ ÜèÿÿÿÿÿGïfýÿÿÿÿÿA†C ,”­ÀÜèÿÿÿÿÿGßfýÿÿÿÿÿA†C $®àÜèÿÿÿÿÿ A†C $,®ÈÜèÿÿÿÿÿJA†C $T®ðÜèÿÿÿÿÿA†C $|®ØÜèÿÿÿÿÿJA†C $¤®Ýèÿÿÿÿÿ?A†C $Ì®Ýèÿÿÿÿÿ@A†C $ô®0Ýèÿÿÿÿÿ?A†C $¯HÝèÿÿÿÿÿA†C $D¯0ÝèÿÿÿÿÿOA†C ,,¯XÝèÿÿÿÿÿGgeýÿÿÿÿÿA†C $œ¯xÝèÿÿÿÿÿ@A†C $įÝèÿÿÿÿÿ\A†C $ì¯ÈÝèÿÿÿÿÿJA†C ,Ô¯ðÝèÿÿÿÿÿGßdýÿÿÿÿÿA†C $D°Þèÿÿÿÿÿ A†C ,,°øÝèÿÿÿÿÿG§dýÿÿÿÿÿA†C $œ°Þèÿÿÿÿÿ A†C ,„°ÞèÿÿÿÿÿGodýÿÿÿÿÿA†C $ô° Þèÿÿÿÿÿ@A†C $±8Þèÿÿÿÿÿ=A†C $D±PÞèÿÿÿÿÿJA†C $l±xÞèÿÿÿÿÿ A†C ,T±`ÞèÿÿÿÿÿG¿cýÿÿÿÿÿA†C ,„±€ÞèÿÿÿÿÿG¯cýÿÿÿÿÿA†C $ô± ÞèÿÿÿÿÿA†C ,ܱˆÞèÿÿÿÿÿGwcýÿÿÿÿÿA†C $L²¨Þèÿÿÿÿÿ=A†C $t²ÀÞèÿÿÿÿÿYA†C $œ²øÞèÿÿÿÿÿYA†C $IJ0ßèÿÿÿÿÿYA†C ,¬²hßèÿÿÿÿÿ^ÇbýÿÿÿÿÿA†C ,ܲ˜ßèÿÿÿÿÿu·býÿÿÿÿÿA†C $L³èßèÿÿÿÿÿA†C $t³àßèÿÿÿÿÿBA†C $œ³àèÿÿÿÿÿBA†C $ij0àèÿÿÿÿÿBA†C $ì³XàèÿÿÿÿÿBA†C $´€àèÿÿÿÿÿBA†C $<´¨àèÿÿÿÿÿBA†C $d´ÐàèÿÿÿÿÿBA†C $Œ´øàèÿÿÿÿÿBA†C $´´ áèÿÿÿÿÿBA†C $Ü´HáèÿÿÿÿÿBA†C $µpáèÿÿÿÿÿBA†C $,µ˜áèÿÿÿÿÿBA†C $TµÀáèÿÿÿÿÿBA†C $|µèáèÿÿÿÿÿBA†C $¤µâèÿÿÿÿÿBA†C $̵8âèÿÿÿÿÿBA†C $ôµ`âèÿÿÿÿÿBA†C $¶ˆâèÿÿÿÿÿBA†C $D¶°âèÿÿÿÿÿBA†C $l¶ØâèÿÿÿÿÿBA†C $”¶ãèÿÿÿÿÿBA†C $¼¶(ãèÿÿÿÿÿBA†C $ä¶PãèÿÿÿÿÿBA†C $ ·xãèÿÿÿÿÿBA†C $4· ãèÿÿÿÿÿBA†C $\·ÈãèÿÿÿÿÿBA†C $„·ðãèÿÿÿÿÿBA†C $¬·äèÿÿÿÿÿFA†C $Ô·@äèÿÿÿÿÿBA†C $ü·häèÿÿÿÿÿBA†C $$¸äèÿÿÿÿÿBA†C $L¸¸äèÿÿÿÿÿBA†C $t¸àäèÿÿÿÿÿBA†C $œ¸åèÿÿÿÿÿBA†C $ĸ0åèÿÿÿÿÿBA†C $ì¸XåèÿÿÿÿÿBA†C $¹€åèÿÿÿÿÿBA†C $<¹¨åèÿÿÿÿÿBA†C $d¹ÐåèÿÿÿÿÿBA†C $Œ¹øåèÿÿÿÿÿBA†C $´¹ æèÿÿÿÿÿBA†C $ܹHæèÿÿÿÿÿBA†C $ºpæèÿÿÿÿÿBA†C $,º˜æèÿÿÿÿÿBA†C $TºÀæèÿÿÿÿÿBA†C $|ºèæèÿÿÿÿÿBA†C $¤ºçèÿÿÿÿÿFA†C $̺8çèÿÿÿÿÿBA†C $ôº`çèÿÿÿÿÿBA†C $»ˆçèÿÿÿÿÿBA†C $D»°çèÿÿÿÿÿBA†C $l»ØçèÿÿÿÿÿBA†C $”»èèÿÿÿÿÿBA†C $¼»(èèÿÿÿÿÿBA†C $ä»PèèÿÿÿÿÿBA†C $ ¼xèèÿÿÿÿÿBA†C $4¼ èèÿÿÿÿÿBA†C $\¼ÈèèÿÿÿÿÿBA†C $„¼ðèèÿÿÿÿÿBA†C $¬¼éèÿÿÿÿÿBA†C $Ô¼@éèÿÿÿÿÿBA†C $ü¼héèÿÿÿÿÿBA†C $$½éèÿÿÿÿÿBA†C $L½¸éèÿÿÿÿÿBA†C $t½àéèÿÿÿÿÿBA†C $œ½êèÿÿÿÿÿBA†C $Ľ0êèÿÿÿÿÿBA†C $ì½XêèÿÿÿÿÿBA†C $¾€êèÿÿÿÿÿBA†C $<¾¨êèÿÿÿÿÿBA†C $d¾ÐêèÿÿÿÿÿBA†C $Œ¾øêèÿÿÿÿÿBA†C $´¾ ëèÿÿÿÿÿBA†C $ܾHëèÿÿÿÿÿBA†C $¿pëèÿÿÿÿÿBA†C $,¿˜ëèÿÿÿÿÿBA†C $T¿ÀëèÿÿÿÿÿBA†C $|¿èëèÿÿÿÿÿBA†C $¤¿ìèÿÿÿÿÿBA†C $Ì¿8ìèÿÿÿÿÿBA†C $ô¿`ìèÿÿÿÿÿBA†C $ÀˆìèÿÿÿÿÿBA†C $DÀ°ìèÿÿÿÿÿBA†C $lÀØìèÿÿÿÿÿBA†C $”ÀíèÿÿÿÿÿFA†C $¼À(íèÿÿÿÿÿBA†C $äÀPíèÿÿÿÿÿBA†C $ ÁxíèÿÿÿÿÿBA†C $4Á íèÿÿÿÿÿBA†C $\ÁÈíèÿÿÿÿÿBA†C $„ÁðíèÿÿÿÿÿBA†C $¬ÁîèÿÿÿÿÿBA†C $ÔÁ@îèÿÿÿÿÿBA†C $üÁhîèÿÿÿÿÿBA†C $$ÂîèÿÿÿÿÿBA†C $L¸îèÿÿÿÿÿBA†C $tÂàîèÿÿÿÿÿBA†C $œÂïèÿÿÿÿÿBA†C $ÄÂ0ïèÿÿÿÿÿBA†C $ìÂXïèÿÿÿÿÿBA†C $ÀïèÿÿÿÿÿBA†C $<èïèÿÿÿÿÿBA†C $dÃÐïèÿÿÿÿÿBA†C $ŒÃøïèÿÿÿÿÿBA†C $´Ã ðèÿÿÿÿÿBA†C $ÜÃHðèÿÿÿÿÿBA†C $ÄpðèÿÿÿÿÿBA†C $,ĘðèÿÿÿÿÿBA†C $TÄÀðèÿÿÿÿÿBA†C $|ÄèðèÿÿÿÿÿBA†C $¤ÄñèÿÿÿÿÿBA†C $ÌÄ8ñèÿÿÿÿÿBA†C $ôÄ`ñèÿÿÿÿÿBA†C $ňñèÿÿÿÿÿFA†C $DŰñèÿÿÿÿÿBA†C $lÅØñèÿÿÿÿÿBA†C $”ÅòèÿÿÿÿÿBA†C $¼Å(òèÿÿÿÿÿBA†C $äÅPòèÿÿÿÿÿBA†C $ ÆxòèÿÿÿÿÿBA†C $4Æ òèÿÿÿÿÿBA†C $\ÆÈòèÿÿÿÿÿBA†C $„ÆðòèÿÿÿÿÿBA†C $¬ÆóèÿÿÿÿÿFA†C $ÔÆ@óèÿÿÿÿÿBA†C $üÆhóèÿÿÿÿÿBA†C $$ÇóèÿÿÿÿÿBA†C $LǸóèÿÿÿÿÿBA†C $tÇàóèÿÿÿÿÿBA†C $œÇôèÿÿÿÿÿBA†C $ÄÇ0ôèÿÿÿÿÿBA†C $ìÇXôèÿÿÿÿÿBA†C $È€ôèÿÿÿÿÿBA†C $<ȨôèÿÿÿÿÿBA†C $dÈÐôèÿÿÿÿÿFA†C $ŒÈøôèÿÿÿÿÿBA†C $´È õèÿÿÿÿÿBA†C $ÜÈHõèÿÿÿÿÿBA†C $ÉpõèÿÿÿÿÿBA†C $,ɘõèÿÿÿÿÿBA†C $TÉÀõèÿÿÿÿÿBA†C $|ÉèõèÿÿÿÿÿBA†C $¤ÉöèÿÿÿÿÿBA†C $ÌÉ8öèÿÿÿÿÿBA†C $ôÉ`öèÿÿÿÿÿBA†C $ʈöèÿÿÿÿÿBA†C $DʰöèÿÿÿÿÿBA†C $lÊØöèÿÿÿÿÿBA†C $”Ê÷èÿÿÿÿÿBA†C $¼Ê(÷èÿÿÿÿÿBA†C $äÊP÷èÿÿÿÿÿBA†C $ Ëx÷èÿÿÿÿÿBA†C $4Ë ÷èÿÿÿÿÿBA†C $\ËÈ÷èÿÿÿÿÿBA†C $„Ëð÷èÿÿÿÿÿBA†C $¬ËøèÿÿÿÿÿBA†C $ÔË@øèÿÿÿÿÿBA†C $üËhøèÿÿÿÿÿBA†C $$ÌøèÿÿÿÿÿBA†C $L̸øèÿÿÿÿÿBA†C $tÌàøèÿÿÿÿÿBA†C $œÌùèÿÿÿÿÿBA†C $ÄÌ0ùèÿÿÿÿÿBA†C $ìÌXùèÿÿÿÿÿBA†C $Í€ùèÿÿÿÿÿBA†C $<ͨùèÿÿÿÿÿ!A†C $dͰùèÿÿÿÿÿ*A†C $ŒÍ¸ùèÿÿÿÿÿ*A†C $´ÍÀùèÿÿÿÿÿ*A†C $ÜÍÈùèÿÿÿÿÿ*A†C $ÎÐùèÿÿÿÿÿ*A†C $,ÎØùèÿÿÿÿÿ*A†C $TÎàùèÿÿÿÿÿ*A†C $|Îèùèÿÿÿÿÿ*A†C $¤Îðùèÿÿÿÿÿ*A†C $ÌÎøùèÿÿÿÿÿ*A†C $ôÎúèÿÿÿÿÿ*A†C $Ïúèÿÿÿÿÿ*A†C $DÏúèÿÿÿÿÿ*A†C $lÏúèÿÿÿÿÿ*A†C $”Ï úèÿÿÿÿÿïA†C $¼ÏèúèÿÿÿÿÿXA†C $äÏ ûèÿÿÿÿÿXA†C $ ÐXûèÿÿÿÿÿXA†C $4ÐûèÿÿÿÿÿXA†C $\ÐÈûèÿÿÿÿÿXA†C $„ÐüèÿÿÿÿÿXA†C $¬Ð8üèÿÿÿÿÿÕA†C $ÔÐðüèÿÿÿÿÿÑA†C $üШÿèÿÿÿÿÿXA†C $$ÑàÿèÿÿÿÿÿXA†C $LÑéÿÿÿÿÿXA†C $tÑPéÿÿÿÿÿ§A†C $œÑØéÿÿÿÿÿ:A†C $ÄÑðéÿÿÿÿÿ:A†C $ìÑéÿÿÿÿÿ:A†C $Ò éÿÿÿÿÿ:A†C $<Ò8éÿÿÿÿÿ:A†C $dÒPéÿÿÿÿÿ:A†C $ŒÒhéÿÿÿÿÿ:A†C $´Ò€éÿÿÿÿÿ:A†C $ÜÒ˜éÿÿÿÿÿ:A†C $Ó°éÿÿÿÿÿ:A†C $,ÓÈéÿÿÿÿÿ:A†C $TÓàéÿÿÿÿÿ:A†C $|Óøéÿÿÿÿÿ:A†C $¤Óéÿÿÿÿÿ:A†C $ÌÓ(éÿÿÿÿÿ:A†C $ôÓ@éÿÿÿÿÿ:A†C $ÔXéÿÿÿÿÿ:A†C $DÔpéÿÿÿÿÿ:A†C $lÔˆéÿÿÿÿÿ:A†C $”Ô éÿÿÿÿÿOA†C $¼ÔÈéÿÿÿÿÿOA†C $äÔðéÿÿÿÿÿOA†C $ ÕéÿÿÿÿÿOA†C $4Õ@éÿÿÿÿÿOA†C $\ÕhéÿÿÿÿÿOA†C $„Õ éÿÿÿÿÿOA†C $¬Õ¸ éÿÿÿÿÿOA†C $ÔÕà éÿÿÿÿÿOA†C $üÕ éÿÿÿÿÿOA†C $$Ö0éÿÿÿÿÿOA†C $LÖXéÿÿÿÿÿOA†C $tÖ€éÿÿÿÿÿOA†C $œÖ¨éÿÿÿÿÿOA†C $ÄÖÐéÿÿÿÿÿOA†C $ìÖøéÿÿÿÿÿOA†C $× éÿÿÿÿÿOA†C $<×HéÿÿÿÿÿOA†C $d×péÿÿÿÿÿ˜A†C $Œ×èéÿÿÿÿÿ˜A†C $´×`éÿÿÿÿÿ*A†C $Ü×héÿÿÿÿÿ*A†C $Øpéÿÿÿÿÿ*A†C $,Øxéÿÿÿÿÿ*A†C $TØ€éÿÿÿÿÿ*A†C $|؈éÿÿÿÿÿ*A†C $¤Øéÿÿÿÿÿ*A†C $ÌØ˜éÿÿÿÿÿ*A†C $ôØ éÿÿÿÿÿ*A†C $Ù¨éÿÿÿÿÿ*A†C $DÙ°éÿÿÿÿÿ*A†C $lÙ¸éÿÿÿÿÿ*A†C $”ÙÀéÿÿÿÿÿ*A†C $¼ÙÈéÿÿÿÿÿ*A†C $äÙÐéÿÿÿÿÿ*A†C $ ÚØéÿÿÿÿÿ*A†C $4Úàéÿÿÿÿÿ*A†C $\Úèéÿÿÿÿÿ*A†C $„Úðéÿÿÿÿÿ*A†C $¬ÚøéÿÿÿÿÿtA†C $ÔÚPéÿÿÿÿÿ°A†C $üÚØéÿÿÿÿÿ;A†C $$Ûðéÿÿÿÿÿ<A†C $LÛéÿÿÿÿÿ<A†C $tÛ éÿÿÿÿÿYA†C $œÛXéÿÿÿÿÿ?A†C $ÄÛpéÿÿÿÿÿÂA†C $ìÛéÿÿÿÿÿ A†C $ÜéÿÿÿÿÿIA†C $<Ü8éÿÿÿÿÿYA†C $dÜpéÿÿÿÿÿYA†C $ŒÜ¨éÿÿÿÿÿYA†C $´Üàéÿÿÿÿÿ<A†C $ÜÜøéÿÿÿÿÿYA†C $Ý0éÿÿÿÿÿ<A†C $,ÝHéÿÿÿÿÿYA†C $TÝ€éÿÿÿÿÿYA†C $|ݸéÿÿÿÿÿYA†C $¤ÝðéÿÿÿÿÿIA†C $ÌÝéÿÿÿÿÿYA†C $ôÝPéÿÿÿÿÿYA†C $ÞˆéÿÿÿÿÿYA†C $DÞÀéÿÿÿÿÿ<A†C $lÞØéÿÿÿÿÿ<A†C $”Þðéÿÿÿÿÿ<A†C $¼Þéÿÿÿÿÿ<A†C $äÞ éÿÿÿÿÿYA†C $ ßXéÿÿÿÿÿYA†C $4ßéÿÿÿÿÿYA†C $\ßÈéÿÿÿÿÿYA†C $„ßéÿÿÿÿÿ<A†C $¬ßéÿÿÿÿÿIA†C $Ôß@éÿÿÿÿÿ<A†C $üßXéÿÿÿÿÿ<A†C $$àpéÿÿÿÿÿYA†C $Là¨éÿÿÿÿÿ<A†C $tàÀéÿÿÿÿÿ<A†C $œàØéÿÿÿÿÿ A†C $ÄàÐéÿÿÿÿÿYA†C $ìà éÿÿÿÿÿ<A†C $á éÿÿÿÿÿÂA†C $<áÈ éÿÿÿÿÿ-A†C $dáÐ éÿÿÿÿÿ-A†C $ŒáØ éÿÿÿÿÿFA†C $´á!éÿÿÿÿÿÁA†C $Üá¨!éÿÿÿÿÿÁA†C $âP"éÿÿÿÿÿ±A†C $,âè"éÿÿÿÿÿA†C $Tâ`#éÿÿÿÿÿA†C $|âØ#éÿÿÿÿÿA†C $¤âP$éÿÿÿÿÿA†C $ÌâÈ$éÿÿÿÿÿA†C $ôâ@%éÿÿÿÿÿA†C $ã¸%éÿÿÿÿÿA†C $Dã0&éÿÿÿÿÿA†C $lã¨&éÿÿÿÿÿA†C $”ã 'éÿÿÿÿÿšA†C $¼ã˜'éÿÿÿÿÿA†C $äã(éÿÿÿÿÿšA†C $ äˆ(éÿÿÿÿÿ A†C $4ä)éÿÿÿÿÿA†C $\äx)éÿÿÿÿÿA†C $„äð)éÿÿÿÿÿA†C $¬äh*éÿÿÿÿÿ A†C $Ôäà*éÿÿÿÿÿA†C $üäX+éÿÿÿÿÿA†C $$åÐ+éÿÿÿÿÿA†C $LåH,éÿÿÿÿÿA†C $tåÀ,éÿÿÿÿÿA†C $œå8-éÿÿÿÿÿA†C $Äå°-éÿÿÿÿÿ‚A†C $ìå.éÿÿÿÿÿjA†C $æ`.éÿÿÿÿÿjA†C $<æ¨.éÿÿÿÿÿjA†C $dæð.éÿÿÿÿÿ„A†C $ŒæX/éÿÿÿÿÿ„A†C $´æÀ/éÿÿÿÿÿaA†C $Üæ0éÿÿÿÿÿaA†C $çP0éÿÿÿÿÿaA†C $,ç˜0éÿÿÿÿÿZA†C $TçÐ0éÿÿÿÿÿZA†C $|ç1éÿÿÿÿÿZA†C $¤ç@1éÿÿÿÿÿvA†C $Ìç˜1éÿÿÿÿÿvA†C $ôçð1éÿÿÿÿÿvA†C $èH2éÿÿÿÿÿCA†C $Dèp2éÿÿÿÿÿ™A†C $lèè2éÿÿÿÿÿCA†C $”è3éÿÿÿÿÿqA†C $¼èh3éÿÿÿÿÿaA†C $äè°3éÿÿÿÿÿ`A†C $ éè3éÿÿÿÿÿ`A†C $4é 4éÿÿÿÿÿ`A†C $\éX4éÿÿÿÿÿ`A†C $„é4éÿÿÿÿÿ`A†C $¬éÈ4éÿÿÿÿÿ&A†C $ÔéÐ4éÿÿÿÿÿXA†C $üé5éÿÿÿÿÿCA†C $$ê05éÿÿÿÿÿ!A†C $Lê85éÿÿÿÿÿ2A†C $têP5éÿÿÿÿÿ2A†C $œêh5éÿÿÿÿÿãA†C $Äê06éÿÿÿÿÿßA†C $ìêè6éÿÿÿÿÿåA†C $ë°7éÿÿÿÿÿ½A†C $<ëH8éÿÿÿÿÿÆA†C $dëð8éÿÿÿÿÿ;A†C $Œë9éÿÿÿÿÿ;A†C $´ë 9éÿÿÿÿÿ;A†C $Üë89éÿÿÿÿÿ;A†C $ìP9éÿÿÿÿÿ;A†C $,ìh9éÿÿÿÿÿ;A†C $Tì€9éÿÿÿÿÿ;A†C $|ì˜9éÿÿÿÿÿ;A†C $¤ì°9éÿÿÿÿÿ;A†C $ÌìÈ9éÿÿÿÿÿ;A†C $ôìà9éÿÿÿÿÿ;A†C $íø9éÿÿÿÿÿ;A†C $Dí:éÿÿÿÿÿ;A†C $lí(:éÿÿÿÿÿ;A†C $”í@:éÿÿÿÿÿ;A†C $¼íX:éÿÿÿÿÿ;A†C $äíp:éÿÿÿÿÿ;A†C $ îˆ:éÿÿÿÿÿ;A†C $4î :éÿÿÿÿÿ;A†C $\î¸:éÿÿÿÿÿ;A†C $„îÐ:éÿÿÿÿÿ(A†C $¬îØ:éÿÿÿÿÿãA†C $Ôî ;éÿÿÿÿÿßA†C $üîX<éÿÿÿÿÿåA†C $$ï =éÿÿÿÿÿÉA†C $LïÈ=éÿÿÿÿÿ½A†C $tï`>éÿÿÿÿÿÆA†C $œï?éÿÿÿÿÿ>A†C $Äï ?éÿÿÿÿÿ;A†C $ìï8?éÿÿÿÿÿ;A†C $ðP?éÿÿÿÿÿ;A†C $<ðh?éÿÿÿÿÿ;A†C $dð€?éÿÿÿÿÿ;A†C $Œð˜?éÿÿÿÿÿDA†C $´ðÀ?éÿÿÿÿÿ;A†C $ÜðØ?éÿÿÿÿÿDA†C $ñ@éÿÿÿÿÿ;A†C $,ñ@éÿÿÿÿÿ;A†C $Tñ0@éÿÿÿÿÿ;A†C $|ñH@éÿÿÿÿÿ;A†C $¤ñ`@éÿÿÿÿÿDA†C $Ìñˆ@éÿÿÿÿÿ;A†C $ôñ @éÿÿÿÿÿ;A†C $ò¸@éÿÿÿÿÿA†C $Dò AéÿÿÿÿÿùA†C $lòxBéÿÿÿÿÿûA†C $”òPCéÿÿÿÿÿùA†C $¼ò(DéÿÿÿÿÿA†C $äòEéÿÿÿÿÿA†C $ óøEéÿÿÿÿÿA†C $4óàFéÿÿÿÿÿA†C $\óÈGéÿÿÿÿÿøA†C $„ó HéÿÿÿÿÿøA†C $¬óxIéÿÿÿÿÿùA†C $ÔóPJéÿÿÿÿÿùA†C $üó(KéÿÿÿÿÿA†C $$ôLéÿÿÿÿÿøA†C $LôèLéÿÿÿÿÿøA†C $tôÀMéÿÿÿÿÿøA†C $œô˜Néÿÿÿÿÿ„A†C $ÄôOéÿÿÿÿÿœA†C $ìôxPéÿÿÿÿÿ‘A†C $õðPéÿÿÿÿÿpA†C ,üô8TéÿÿÿÿÿÛ· ýÿÿÿÿÿA†C $lõèTéÿÿÿÿÿnA†C $”õ0Uéÿÿÿÿÿ"A†C $¼õ8Uéÿÿÿÿÿ!A†C $äõ@Uéÿÿÿÿÿ”A†C $ ö¸UéÿÿÿÿÿA†C $4ö VéÿÿÿÿÿA†C $\öˆVéÿÿÿÿÿA†C $„öðVéÿÿÿÿÿA†C $¬öXWéÿÿÿÿÿA†C $ÔöÀWéÿÿÿÿÿA†C $üö(XéÿÿÿÿÿA†C $$÷XéÿÿÿÿÿŒA†C $L÷øXéÿÿÿÿÿA†C $t÷`YéÿÿÿÿÿA†C $œ÷ÈYéÿÿÿÿÿA†C $Ä÷0ZéÿÿÿÿÿA†C $ì÷˜ZéÿÿÿÿÿA†C $ø[éÿÿÿÿÿA†C $<øh[éÿÿÿÿÿA†C $døÐ[éÿÿÿÿÿTA†C $Œø\éÿÿÿÿÿTA†C $´ø@\éÿÿÿÿÿTA†C $Üøx\éÿÿÿÿÿTA†C $ù°\éÿÿÿÿÿTA†C $,ùè\éÿÿÿÿÿTA†C $Tù ]éÿÿÿÿÿTA†C $|ùX]éÿÿÿÿÿTA†C $¤ù]éÿÿÿÿÿTA†C $ÌùÈ]éÿÿÿÿÿTA†C $ôù^éÿÿÿÿÿTA†C $ú8^éÿÿÿÿÿTA†C $Dúp^éÿÿÿÿÿTA†C $lú¨^éÿÿÿÿÿTA†C $”úà^éÿÿÿÿÿTA†C $¼ú_éÿÿÿÿÿTA†C $äúP_éÿÿÿÿÿTA†C $ ûˆ_éÿÿÿÿÿTA†C $4ûÀ_éÿÿÿÿÿTA†C $\ûø_éÿÿÿÿÿCA†C $„û `éÿÿÿÿÿ+A†C $¬û(`éÿÿÿÿÿ¦A†C $Ôû°`éÿÿÿÿÿ'A†C $üû¸aéÿÿÿÿÿ8A†C $$üÐbéÿÿÿÿÿCA†C $LüødéÿÿÿÿÿCA†C $tü géÿÿÿÿÿCA†C $œüHiéÿÿÿÿÿCA†C $ÄüpkéÿÿÿÿÿCA†C $ìü˜méÿÿÿÿÿ&A†C $ý méÿÿÿÿÿ&A†C $<ý¨méÿÿÿÿÿ&A†C $dý°méÿÿÿÿÿ&A†C $Œý¸méÿÿÿÿÿ&A†C $´ýÀméÿÿÿÿÿ&A†C $ÜýÈméÿÿÿÿÿ&A†C $þÐméÿÿÿÿÿ&A†C $,þØméÿÿÿÿÿ&A†C $Tþàméÿÿÿÿÿ&A†C $|þèméÿÿÿÿÿ&A†C $¤þðméÿÿÿÿÿ&A†C $Ìþøméÿÿÿÿÿ&A†C $ôþnéÿÿÿÿÿ&A†C $ÿnéÿÿÿÿÿ&A†C $Dÿnéÿÿÿÿÿ&A†C $lÿnéÿÿÿÿÿ&A†C $”ÿ néÿÿÿÿÿ&A†C $¼ÿ(néÿÿÿÿÿ…A†C $äÿnéÿÿÿÿÿôA†C $ hoéÿÿÿÿÿKA†C $4oéÿÿÿÿÿKA†C $\¸oéÿÿÿÿÿ3A†C $„Ðréÿÿÿÿÿõ A†C $¬¨|éÿÿÿÿÿ<A†C $ÔÀ|éÿÿÿÿÿA†C ,¼¸|éÿÿÿÿÿ™3ýÿÿÿÿÿA†C ,ì(€éÿÿÿÿÿù?ýÿÿÿÿÿA†C ,ø‚éÿÿÿÿÿnKýÿÿÿÿÿA†C ,L8…éÿÿÿÿÿnWýÿÿÿÿÿA†C ,|x‡éÿÿÿÿÿ:cýÿÿÿÿÿA†C ,¬ˆ‰éÿÿÿÿÿ:oýÿÿÿÿÿA†C $˜‹éÿÿÿÿÿTA†C $DЋéÿÿÿÿÿTA†C $lŒéÿÿÿÿÿTA†C $”@ŒéÿÿÿÿÿTA†C $¼xŒéÿÿÿÿÿTA†C $ä°ŒéÿÿÿÿÿTA†C $ èŒéÿÿÿÿÿTA†C $4 éÿÿÿÿÿTA†C $\XéÿÿÿÿÿTA†C $„éÿÿÿÿÿTA†C $¬ÈéÿÿÿÿÿTA†C $ÔŽéÿÿÿÿÿTA†C $ü8ŽéÿÿÿÿÿTA†C $$pŽéÿÿÿÿÿTA†C $L¨ŽéÿÿÿÿÿTA†C $tàŽéÿÿÿÿÿ=A†C $œøéÿÿÿÿÿ@A†C $Ä‘éÿÿÿÿÿ=A†C $ì(’éÿÿÿÿÿ=A†C $@“éÿÿÿÿÿDA†C $<h”éÿÿÿÿÿ@A†C $d€•éÿÿÿÿÿDA†C $Œ¨–éÿÿÿÿÿ=A†C $´À—éÿÿÿÿÿ=A†C $Üؘéÿÿÿÿÿ@A†C $ð™éÿÿÿÿÿ@A†C $,›éÿÿÿÿÿDA†C ,0œéÿÿÿÿÿCýÿÿÿÿÿA†C ,D éÿÿÿÿÿá3ýÿÿÿÿÿA†C $´àžéÿÿÿÿÿwA†C $Ü8¢éÿÿÿÿÿÄA†C $à¢éÿÿÿÿÿIA†C $,£éÿÿÿÿÿIA†C $T0£éÿÿÿÿÿ‘A†C ,<¨£éÿÿÿÿÿ¥›ýÿÿÿÿÿA†C ,l(¤éÿÿÿÿÿ‹—ýÿÿÿÿÿA†C $܈¨éÿÿÿÿÿgA†C $Шéÿÿÿÿÿ2A†C $,è¨éÿÿÿÿÿWA†C , ©éÿÿÿÿÿú7ýÿÿÿÿÿA†C ,Dð©éÿÿÿÿÿÚ 3ýÿÿÿÿÿA†C $´ ´éÿÿÿÿÿ‘A†C $ܵéÿÿÿÿÿøA†C $ ðµéÿÿÿÿÿCA†C $, ¶éÿÿÿÿÿ6A†C $T 0¶éÿÿÿÿÿ5A†C $| H¶éÿÿÿÿÿ0A†C $¤ P¶éÿÿÿÿÿ-A†C $Ì X¶éÿÿÿÿÿ(A†C $ô `¶éÿÿÿÿÿA†C $ X¶éÿÿÿÿÿA†C , P¶éÿÿÿÿÿ¯WýÿÿÿÿÿA†C ,4 жéÿÿÿÿÿ¯GýÿÿÿÿÿA†C $¤ P·éÿÿÿÿÿÈA†C $Ì ø·éÿÿÿÿÿÈA†C $ô  ¸éÿÿÿÿÿÈA†C $ H¹éÿÿÿÿÿ‡A†C $D °ºéÿÿÿÿÿ‡A†C $l ¼éÿÿÿÿÿŸA†C ,T ¾éÿÿÿÿÿ³GýÿÿÿÿÿA†C $Ä  ¿éÿÿÿÿÿ"A†C $ì (¿éÿÿÿÿÿ"A†C ,Ô 0¿éÿÿÿÿÿ0ó ýÿÿÿÿÿA†C , 0Àéÿÿÿÿÿ0ã ýÿÿÿÿÿA†C $t 0Áéÿÿÿÿÿ9A†C $œ HÁéÿÿÿÿÿ.A†C $Ä PÁéÿÿÿÿÿ9A†C $ì hÁéÿÿÿÿÿ%A†C $ pÁéÿÿÿÿÿ%A†C $< xÁéÿÿÿÿÿEA†C $d  ÂéÿÿÿÿÿEA†C $Œ ÈÃéÿÿÿÿÿ>A†C $´ àÄéÿÿÿÿÿEA†C $Ü ÆéÿÿÿÿÿEA†C $0ÇéÿÿÿÿÿEA†C $,XÈéÿÿÿÿÿEA†C $T€ÉéÿÿÿÿÿEA†C $|¨ÊéÿÿÿÿÿEA†C $¤ÐËéÿÿÿÿÿEA†C $ÌøÌéÿÿÿÿÿEA†C $ô ÎéÿÿÿÿÿEA†C $HÏéÿÿÿÿÿEA†C $DpÐéÿÿÿÿÿEA†C $l˜ÑéÿÿÿÿÿEA†C $”ÀÒéÿÿÿÿÿEA†C $¼èÓéÿÿÿÿÿEA†C $äÕéÿÿÿÿÿEA†C $ 8ÖéÿÿÿÿÿEA†C $4`×éÿÿÿÿÿEA†C $\ˆØéÿÿÿÿÿEA†C $„°ÙéÿÿÿÿÿEA†C $¬ØÚéÿÿÿÿÿEA†C $ÔÜéÿÿÿÿÿEA†C $ü(ÝéÿÿÿÿÿEA†C $$PÞéÿÿÿÿÿEA†C $LxßéÿÿÿÿÿEA†C $t àéÿÿÿÿÿEA†C $œÈáéÿÿÿÿÿEA†C $ÄðâéÿÿÿÿÿEA†C $ìäéÿÿÿÿÿEA†C $@åéÿÿÿÿÿEA†C $<hæéÿÿÿÿÿEA†C $dçéÿÿÿÿÿEA†C $Œ¸èéÿÿÿÿÿEA†C $´àééÿÿÿÿÿEA†C $ÜëéÿÿÿÿÿEA†C $0ìéÿÿÿÿÿEA†C $,XíéÿÿÿÿÿaA†C $T íéÿÿÿÿÿaA†C $|èíéÿÿÿÿÿ6A†C ,dîéÿÿÿÿÿ¾£ýÿÿÿÿÿA†C $ÔïéÿÿÿÿÿÙA†C $üHðéÿÿÿÿÿ’A†C $$Àðéÿÿÿÿÿ’A†C $L8ñéÿÿÿÿÿ:A†C $tPòéÿÿÿÿÿA†C $œÈòéÿÿÿÿÿA†C $Ä@óéÿÿÿÿÿA†C $ì¸óéÿÿÿÿÿ\A†C $ðóéÿÿÿÿÿ$A†C $<øóéÿÿÿÿÿ$A†C $dôéÿÿÿÿÿ$A†C ,Lôéÿÿÿÿÿq÷ýÿÿÿÿÿA†C ,|XõéÿÿÿÿÿbýÿÿÿÿÿA†C ,¬˜öéÿÿÿÿÿq'ýÿÿÿÿÿA†C $è÷éÿÿÿÿÿ<A†C $Døéÿÿÿÿÿ<A†C $løéÿÿÿÿÿ"A†C $” øéÿÿÿÿÿ"A†C $¼(øéÿÿÿÿÿ"A†C $ä0øéÿÿÿÿÿA†C $ (ùéÿÿÿÿÿ"A†C ,ô0ùéÿÿÿÿÿ>'ýÿÿÿÿÿA†C $d@üéÿÿÿÿÿ\A†C $Œxüéÿÿÿÿÿ@A†C $´üéÿÿÿÿÿ6A†C $ܨüéÿÿÿÿÿDA†C $Ðýéÿÿÿÿÿ’A†C ,ìHþéÿÿÿÿÿIƒýÿÿÿÿÿA†C JƒŽ,hêÿÿÿÿÿ‘ýÿÿÿÿÿA†C JƒŽ$ŒØêÿÿÿÿÿ"A†C $´àêÿÿÿÿÿ¿A†C $Üxêÿÿÿÿÿ¿A†C $êÿÿÿÿÿ¿A†C $,¨ êÿÿÿÿÿ¿A†C $T@ êÿÿÿÿÿ¿A†C $|Ø êÿÿÿÿÿ¿A†C $¤pêÿÿÿÿÿ¿A†C $Ìêÿÿÿÿÿ¿A†C $ô êÿÿÿÿÿ¿A†C $8êÿÿÿÿÿ¿A†C $DÐêÿÿÿÿÿ¿A†C $lhêÿÿÿÿÿ¿A†C $”êÿÿÿÿÿ¿A†C $¼˜êÿÿÿÿÿ®A†C $ä êÿÿÿÿÿ¿A†C $ ¸êÿÿÿÿÿvA†C $4êÿÿÿÿÿvA†C $\hêÿÿÿÿÿvA†C $„ÀêÿÿÿÿÿvA†C $¬êÿÿÿÿÿvA†C $ÔpêÿÿÿÿÿvA†C $üÈêÿÿÿÿÿPA†C ,äðêÿÿÿÿÿnãÿüÿÿÿÿÿA†C $T0êÿÿÿÿÿCA†C $|Xêÿÿÿÿÿ+A†C ,d`êÿÿÿÿÿØÿüÿÿÿÿÿA†C ,”#êÿÿÿÿÿ‡ÿüÿÿÿÿÿA†C ,Äp%êÿÿÿÿÿ‡—ÿüÿÿÿÿÿA†C $4Ð'êÿÿÿÿÿoA†C $\(êÿÿÿÿÿvA†C $„p(êÿÿÿÿÿvA†C $¬È(êÿÿÿÿÿ(A†C ,”Ð(êÿÿÿÿÿƒÿüÿÿÿÿÿA†C ,Ä0)êÿÿÿÿÿƒ ÿüÿÿÿÿÿA†C ,ô)êÿÿÿÿÿƒÿüÿÿÿÿÿA†C ,$ð)êÿÿÿÿÿƒÿüÿÿÿÿÿA†C ,TP*êÿÿÿÿÿƒÿþüÿÿÿÿÿA†C ,„°*êÿÿÿÿÿƒûþüÿÿÿÿÿA†C ,´+êÿÿÿÿÿƒ÷þüÿÿÿÿÿA†C ,äp+êÿÿÿÿÿƒóþüÿÿÿÿÿA†C ,Ð+êÿÿÿÿÿƒïþüÿÿÿÿÿA†C ,D0,êÿÿÿÿÿƒëþüÿÿÿÿÿA†C ,t,êÿÿÿÿÿƒçþüÿÿÿÿÿA†C ,¤ð,êÿÿÿÿÿƒãþüÿÿÿÿÿA†C ,ÔP-êÿÿÿÿÿƒßþüÿÿÿÿÿA†C $D °-êÿÿÿÿÿ6A†C $l È-êÿÿÿÿÿ6A†C $” à-êÿÿÿÿÿ6A†C $¼ ø-êÿÿÿÿÿ6A†C $ä .êÿÿÿÿÿ6A†C $ !(.êÿÿÿÿÿ6A†C $4!@.êÿÿÿÿÿ6A†C $\!X.êÿÿÿÿÿ6A†C $„!p.êÿÿÿÿÿ6A†C $¬!ˆ.êÿÿÿÿÿ6A†C $Ô! .êÿÿÿÿÿ6A†C $ü!¸.êÿÿÿÿÿ6A†C $$"Ð.êÿÿÿÿÿ6A†C $L"è.êÿÿÿÿÿ[A†C ,4" /êÿÿÿÿÿ«üüÿÿÿÿÿA†C ,d"1êÿÿÿÿÿY·üüÿÿÿÿÿA†C ,”"@4êÿÿÿÿÿrÏüüÿÿÿÿÿA†C $#4êÿÿÿÿÿ3A†C $,#¨4êÿÿÿÿÿ6A†C $T#À5êÿÿÿÿÿ6A†C $|#Ø6êÿÿÿÿÿ6A†C $¤#ð7êÿÿÿÿÿ6A†C $Ì#9êÿÿÿÿÿ6A†C $ô# :êÿÿÿÿÿ6A†C $$8;êÿÿÿÿÿ6A†C $D$P<êÿÿÿÿÿ6A†C $l$h=êÿÿÿÿÿ6A†C $”$€>êÿÿÿÿÿ6A†C $¼$˜?êÿÿÿÿÿ6A†C $ä$°@êÿÿÿÿÿ6A†C $ %ÈAêÿÿÿÿÿ6A†C $4%àBêÿÿÿÿÿ6A†C $\%øCêÿÿÿÿÿ6A†C $„%Eêÿÿÿÿÿ6A†C $¬%(Fêÿÿÿÿÿ6A†C $Ô%@Gêÿÿÿÿÿ6A†C $ü%XHêÿÿÿÿÿ¾A†C ,ä%ðHêÿÿÿÿÿ÷ŸùüÿÿÿÿÿA†C ,&ÀLêÿÿÿÿÿ÷ÏùüÿÿÿÿÿA†C ,D&Pêÿÿÿÿÿ÷ÿùüÿÿÿÿÿA†C ,t&`Têÿÿÿÿÿ÷/úüÿÿÿÿÿA†C ,¤&0Xêÿÿÿÿÿ÷_úüÿÿÿÿÿA†C ,Ô&\êÿÿÿÿÿ÷úüÿÿÿÿÿA†C ,'Ð_êÿÿÿÿÿ÷¿úüÿÿÿÿÿA†C ,4' cêÿÿÿÿÿ÷ïúüÿÿÿÿÿA†C ,d'pgêÿÿÿÿÿ÷ûüÿÿÿÿÿA†C ,”'@kêÿÿÿÿÿ÷OûüÿÿÿÿÿA†C ,Ä'oêÿÿÿÿÿ÷ûüÿÿÿÿÿA†C ,ô'àrêÿÿÿÿÿ÷¯ûüÿÿÿÿÿA†C ,$(°vêÿÿÿÿÿ÷ßûüÿÿÿÿÿA†C ,T(€zêÿÿÿÿÿwüüÿÿÿÿÿA†C $Ä(Ð|êÿÿÿÿÿ3A†C $ì(è|êÿÿÿÿÿ3A†C $)}êÿÿÿÿÿ3A†C $<)}êÿÿÿÿÿ3A†C $d)0}êÿÿÿÿÿ3A†C $Œ)H}êÿÿÿÿÿ3A†C $´)`}êÿÿÿÿÿ3A†C $Ü)x}êÿÿÿÿÿ3A†C $*}êÿÿÿÿÿ3A†C $,*¨}êÿÿÿÿÿ3A†C $T*À}êÿÿÿÿÿ3A†C $|*Ø}êÿÿÿÿÿ3A†C $¤*ð}êÿÿÿÿÿ3A†C $Ì*~êÿÿÿÿÿ3A†C $ô* ~êÿÿÿÿÿ3A†C $+8~êÿÿÿÿÿ3A†C $D+P~êÿÿÿÿÿ3A†C $l+h~êÿÿÿÿÿ3A†C $”+€~êÿÿÿÿÿ3A†C $¼+˜~êÿÿÿÿÿ3A†C $ä+°~êÿÿÿÿÿ3A†C $ ,È~êÿÿÿÿÿ3A†C $4,à~êÿÿÿÿÿVA†C $\,êÿÿÿÿÿ A†C $„,êÿÿÿÿÿ™A†C $¬,€êÿÿÿÿÿ™A†C $Ô,€€êÿÿÿÿÿA†C $ü,ø€êÿÿÿÿÿA†C $$-pêÿÿÿÿÿ;A†C $L-ˆêÿÿÿÿÿ9A†C $t- êÿÿÿÿÿ;A†C $œ-¸êÿÿÿÿÿA†C $Ä- ‚êÿÿÿÿÿPA†C $ì-H‚êÿÿÿÿÿPA†C $.p‚êÿÿÿÿÿPA†C $<.˜‚êÿÿÿÿÿGA†C $d.À‚êÿÿÿÿÿíA†C Hƒ$Œ.ˆ…êÿÿÿÿÿÅA†C $´.0ˆêÿÿÿÿÿHA†C $Ü.XêÿÿÿÿÿHA†C $/€’êÿÿÿÿÿaA†C $,/È’êÿÿÿÿÿEA†C $T/ð“êÿÿÿÿÿ¿A†C $|/ˆ•êÿÿÿÿÿaA†C LƒŽ$¤/Лêÿÿÿÿÿ¼A†C $Ì/hêÿÿÿÿÿ¼A†C $ô/ŸêÿÿÿÿÿA†C $0è¡êÿÿÿÿÿA†C $D0ФêÿÿÿÿÿZA†C $l0¨êÿÿÿÿÿZA†C $”0@«êÿÿÿÿÿmA†C Hƒ$¼0ˆ¯êÿÿÿÿÿmA†C Hƒ$ä0гêÿÿÿÿÿ1A†C LƒŽ$ 1èÃêÿÿÿÿÿ1A†C LƒŽ$41ÔêÿÿÿÿÿHA†C $\1(ÔêÿÿÿÿÿLA†C $„1PÕêÿÿÿÿÿ6A†C ,l1hÖêÿÿÿÿÿ´#óüÿÿÿÿÿA†C ,œ1øÖêÿÿÿÿÿ´óüÿÿÿÿÿA†C ,Ì1ˆ×êÿÿÿÿÿ´óüÿÿÿÿÿA†C $<2Øêÿÿÿÿÿ'A†C $d2 Úêÿÿÿÿÿ'A†C $Œ2(ÜêÿÿÿÿÿdA†C $´2pÞêÿÿÿÿÿdA†C ,œ2¸àêÿÿÿÿÿXSòüÿÿÿÿÿA†C Hƒ,Ì2èåêÿÿÿÿÿXkòüÿÿÿÿÿA†C Hƒ,ü2ëêÿÿÿÿÿXƒòüÿÿÿÿÿA†C Hƒ,,3Hðêÿÿÿÿÿ ›òüÿÿÿÿÿA†C Hƒ,\3¸õêÿÿÿÿÿ ³òüÿÿÿÿÿA†C Hƒ,Œ3(ûêÿÿÿÿÿXËòüÿÿÿÿÿA†C Hƒ,¼3Xëÿÿÿÿÿ ãòüÿÿÿÿÿA†C Hƒ,ì3ÈëÿÿÿÿÿçûòüÿÿÿÿÿA†C Hƒ,4ˆëÿÿÿÿÿç+óüÿÿÿÿÿA†C Hƒ,L4Hëÿÿÿÿÿ [óüÿÿÿÿÿA†C Hƒ,|4( ëÿÿÿÿÿ ‹óüÿÿÿÿÿA†C Hƒ,¬4)ëÿÿÿÿÿç»óüÿÿÿÿÿA†C Hƒ,Ü4È1ëÿÿÿÿÿ ëóüÿÿÿÿÿA†C Hƒ, 5¨:ëÿÿÿÿÿ ôüÿÿÿÿÿA†C Hƒ,<5ˆCëÿÿÿÿÿ KôüÿÿÿÿÿA†C Hƒ,l5hLëÿÿÿÿÿç{ôüÿÿÿÿÿA†C Hƒ,œ5(Uëÿÿÿÿÿ «ôüÿÿÿÿÿA†C Hƒ$ 6^ëÿÿÿÿÿ"A†C $46^ëÿÿÿÿÿKA†C $\68^ëÿÿÿÿÿ@A†C ,D6P^ëÿÿÿÿÿ côüÿÿÿÿÿA†C ,t60aëÿÿÿÿÿÚ“ôüÿÿÿÿÿA†C $ä6àaëÿÿÿÿÿ A†C $ 7ÈbëÿÿÿÿÿèA†C ,ô6cëÿÿÿÿÿOôüÿÿÿÿÿA†C ,$7ðdëÿÿÿÿÿ„gôüÿÿÿÿÿA†C ,T7Peëÿÿÿÿÿ¯côüÿÿÿÿÿA†C $Ä7ÐkëÿÿÿÿÿMA†C $ì7økëÿÿÿÿÿMA†C $8 lëÿÿÿÿÿýA†C $<8ømëÿÿÿÿÿsA†C $d8Pnëÿÿÿÿÿ.A†C $Œ8Xnëÿÿÿÿÿ>A†C $´8pnëÿÿÿÿÿÎA†C $Ü8oëÿÿÿÿÿôA†C $9ðoëÿÿÿÿÿŠA†C $,9Xpëÿÿÿÿÿ/A†C ,9`pëÿÿÿÿÿÇ÷òüÿÿÿÿÿA†C ,D9qëÿÿÿÿÿŽóòüÿÿÿÿÿA†C $´9`qëÿÿÿÿÿ’A†C $Ü9Øqëÿÿÿÿÿ]A†C $:sëÿÿÿÿÿÉA†C $,:¸vëÿÿÿÿÿû A†C $T:à‚ëÿÿÿÿÿÒA†C $|:˜ƒëÿÿÿÿÿLA†C $¤:À„ëÿÿÿÿÿ-A†C $Ì:È…ëÿÿÿÿÿrA†C $ô: †ëÿÿÿÿÿ×A†C $;؆ëÿÿÿÿÿ“A†C $D;PˆëÿÿÿÿÿúA†C $l;(Šëÿÿÿÿÿ2A†C $”;@Šëÿÿÿÿÿ¥A†C $¼;è‹ëÿÿÿÿÿÌA†C $ä;°ëÿÿÿÿÿ!A†C $ <Ø’ëÿÿÿÿÿÑA†C $4<à™ëÿÿÿÿÿ<A†C $\<H¨ëÿÿÿÿÿ<A†C $„<°¶ëÿÿÿÿÿG A†C $¬<(ÃëÿÿÿÿÿG A†C $Ô< ÏëÿÿÿÿÿCA†C $ü<øìÿÿÿÿÿCA†C $$=PVìÿÿÿÿÿžA†C $L=ÈXìÿÿÿÿÿžA†C ,4=@[ìÿÿÿÿÿN/ïüÿÿÿÿÿA†C ,d=`\ìÿÿÿÿÿEïüÿÿÿÿÿA†C ,”=€]ìÿÿÿÿÿNïüÿÿÿÿÿA†C ,Ä= ^ìÿÿÿÿÿNÿîüÿÿÿÿÿA†C ,ô=À_ìÿÿÿÿÿzïîüÿÿÿÿÿA†C ,$>bìÿÿÿÿÿz;ïüÿÿÿÿÿA†C ,T>`dìÿÿÿÿÿT ‡ïüÿÿÿÿÿA†C ,„>mìÿÿÿÿÿT cðüÿÿÿÿÿA†C ,´>ÀvìÿÿÿÿÿZ?ñüÿÿÿÿÿA†C ,ä>ð…ìÿÿÿÿÿZOòüÿÿÿÿÿA†C ,? •ìÿÿÿÿÿZ_óüÿÿÿÿÿA†C ,D?P¤ìÿÿÿÿÿôoôüÿÿÿÿÿA†C ,t? §ìÿÿÿÿÿŸôüÿÿÿÿÿA†C ,¤?ªìÿÿÿÿÿÏôüÿÿÿÿÿA†C ,Ô?­ìÿÿÿÿÿÿôüÿÿÿÿÿA†C ,@ð¯ìÿÿÿÿÿ·/õüÿÿÿÿÿA†C ,4@€³ìÿÿÿÿÿ¦ oõüÿÿÿÿÿA†C ,d@¾ìÿÿÿÿÿ‘ÿõüÿÿÿÿÿA†C ,”@pÃìÿÿÿÿÿ‘KöüÿÿÿÿÿA†C ,Ä@àÈìÿÿÿÿÿW—öüÿÿÿÿÿA†C ,ô@ÎìÿÿÿÿÿôãöüÿÿÿÿÿA†C ,$AàÐìÿÿÿÿÿ÷üÿÿÿÿÿA†C ,TAÐÓìÿÿÿÿÿC÷üÿÿÿÿÿA†C ,„AÀÖìÿÿÿÿÿs÷üÿÿÿÿÿA†C ,´A°ÙìÿÿÿÿÿÅ£÷üÿÿÿÿÿA†C ,äAPàìÿÿÿÿÿÈ øüÿÿÿÿÿA†C ,BðæìÿÿÿÿÿÅsøüÿÿÿÿÿA†C ,DBíìÿÿÿÿÿ´ÛøüÿÿÿÿÿA†C ,tB óìÿÿÿÿÿM'ùüÿÿÿÿÿA†C ,¤B@íÿÿÿÿÿ‰"ùüÿÿÿÿÿA†C ,ÔB #íÿÿÿÿÿÅûúüÿÿÿÿÿA†C ,C@*íÿÿÿÿÿ<‹ûüÿÿÿÿÿA†C ,4CP.íÿÿÿÿÿt»ûüÿÿÿÿÿA†C ,dC 2íÿÿÿÿÿ?ëûüÿÿÿÿÿA†C ,”C°6íÿÿÿÿÿ-üüÿÿÿÿÿA†C ,ÄC°:íÿÿÿÿÿeKüüÿÿÿÿÿA†C ,ôCð>íÿÿÿÿÿT{üüÿÿÿÿÿA†C ,$D CíÿÿÿÿÿV«üüÿÿÿÿÿA†C ,TDPGíÿÿÿÿÿNÛüüÿÿÿÿÿA†C ,„DpKíÿÿÿÿÿ” ýüÿÿÿÿÿA†C ,´DàOíÿÿÿÿÿb;ýüÿÿÿÿÿA†C ,äD TíÿÿÿÿÿbkýüÿÿÿÿÿA†C ,E`Xíÿÿÿÿÿb›ýüÿÿÿÿÿA†C ,DE \íÿÿÿÿÿ”ËýüÿÿÿÿÿA†C ,tEaíÿÿÿÿÿ-ûýüÿÿÿÿÿA†C ,¤Eeíÿÿÿÿÿ-+þüÿÿÿÿÿA†C ,ÔEiíÿÿÿÿÿ”[þüÿÿÿÿÿA†C ,F€míÿÿÿÿÿb‹þüÿÿÿÿÿA†C ,4FÀqíÿÿÿÿÿb»þüÿÿÿÿÿA†C ,dFvíÿÿÿÿÿ°ëþüÿÿÿÿÿA†C ,”F€|íÿÿÿÿÿê_ÿüÿÿÿÿÿA†C ,ÄF@ƒíÿÿÿÿÿ”ÓÿüÿÿÿÿÿA†C ,ôF°‡íÿÿÿÿÿ”ýÿÿÿÿÿA†C ,$G Œíÿÿÿÿÿb3ýÿÿÿÿÿA†C ,TG`íÿÿÿÿÿ”cýÿÿÿÿÿA†C ,„GДíÿÿÿÿÿ”“ýÿÿÿÿÿA†C ,´G@™íÿÿÿÿÿÚÃýÿÿÿÿÿA†C ,äGðŸíÿÿÿÿÿ’7ýÿÿÿÿÿA†C ,H`£íÿÿÿÿÿ´ gýÿÿÿÿÿA†C ,DHð­íÿÿÿÿÿÞÛýÿÿÿÿÿA†C 4tH ²íÿÿÿÿÿg ýÿÿÿÿÿA†C PƒŒŽ4¬Hعíÿÿÿÿÿ.'ýÿÿÿÿÿA†C PƒŒŽ$$IÐÀíÿÿÿÿÿ’A†C , IHÁíÿÿÿÿÿLýÿÿÿÿÿA†C ,A†C $d„à/óÿÿÿÿÿÆA†C $Œ„ˆ0óÿÿÿÿÿA†C $´„ð0óÿÿÿÿÿ?A†C $Ü„1óÿÿÿÿÿËA†C $…°1óÿÿÿÿÿƒA†C $,…3óÿÿÿÿÿÆA†C $T…À6óÿÿÿÿÿ(A†C ,<…È9óÿÿÿÿÿ¨ûóüÿÿÿÿÿA†C ,l…HJóÿÿÿÿÿÒWôüÿÿÿÿÿA†C ,œ…øZóÿÿÿÿÿC³ôüÿÿÿÿÿA†C $ †bóÿÿÿÿÿA†C $4†€bóÿÿÿÿÿPA†C $\†¨bóÿÿÿÿÿA†C $„†cóÿÿÿÿÿPA†C $¬†8cóÿÿÿÿÿA†C $Ô† cóÿÿÿÿÿPA†C $ü†ÈcóÿÿÿÿÿA†C $$‡0dóÿÿÿÿÿPA†C $L‡XdóÿÿÿÿÿA†C $t‡ÀdóÿÿÿÿÿPA†C $œ‡èdóÿÿÿÿÿPA†C $ćeóÿÿÿÿÿGA†C $ì‡8eóÿÿÿÿÿ­A†C $ˆÀgóÿÿÿÿÿ A†C $<ˆ˜róÿÿÿÿÿSA†C $dˆÐtóÿÿÿÿÿ«A†C $ŒˆXyóÿÿÿÿÿ(A†C $´ˆ`|óÿÿÿÿÿ„A†C $܈È}óÿÿÿÿÿA†C $‰0~óÿÿÿÿÿóA†C $,‰óÿÿÿÿÿA†C $T‰p‚óÿÿÿÿÿA†C $|‰X…óÿÿÿÿÿA†C $¤‰À†óÿÿÿÿÿA†C $̉(‡óÿÿÿÿÿóA†C $ô‰ŠóÿÿÿÿÿA†C $Šh‹óÿÿÿÿÿA†C $DŠPŽóÿÿÿÿÿA†C $lЏóÿÿÿÿÿA†C $”Š óÿÿÿÿÿóA†C $¼Šø’óÿÿÿÿÿA†C $äŠ`”óÿÿÿÿÿA†C $ ‹H—óÿÿÿÿÿA†C $4‹°˜óÿÿÿÿÿÞA†C $\‹hšóÿÿÿÿÿA†C $„‹`œóÿÿÿÿÿ A†C IƒŽ$¬‹Hóÿÿÿÿÿ"A†C $Ô‹PóÿÿÿÿÿA†C $ü‹Hóÿÿÿÿÿ%A†C $$ŒPóÿÿÿÿÿÁA†C $LŒø¥óÿÿÿÿÿ4A†C $tŒªóÿÿÿÿÿmA†C $œŒX®óÿÿÿÿÿUA†C $ÄŒ¿óÿÿÿÿÿnA†C $ìŒÈÎóÿÿÿÿÿÆA†C $pÏóÿÿÿÿÿªA†C $<øÏóÿÿÿÿÿA†C $dîóÿÿÿÿÿwA†C $Œèîóÿÿÿÿÿ|A†C $´@ïóÿÿÿÿÿAA†C $ÜhòóÿÿÿÿÿØA†C $Ž ôóÿÿÿÿÿÉA†C $,ŽÈôóÿÿÿÿÿXA†C $TŽùóÿÿÿÿÿàA†C $|ޏúóÿÿÿÿÿ²A†C $¤ŽPüóÿÿÿÿÿ±A†C $ÌŽèýóÿÿÿÿÿöA†C $ôŽ@ ôÿÿÿÿÿ A†C $¸ ôÿÿÿÿÿ3A†C $DÐ ôÿÿÿÿÿõA†C $l¨ôÿÿÿÿÿ²A†C $”@ôÿÿÿÿÿÅA†C $¼èôÿÿÿÿÿA†C $äàôÿÿÿÿÿA†C $ Øôÿÿÿÿÿ A†C $4ÀôÿÿÿÿÿþA†C $\˜ôÿÿÿÿÿßA†C $„PôÿÿÿÿÿñA†C $¬(ôÿÿÿÿÿýA†C $ÔôÿÿÿÿÿA†C ,¼èôÿÿÿÿÿdêüÿÿÿÿÿA†C ,ì(ôÿÿÿÿÿdÿéüÿÿÿÿÿA†C $\‘hôÿÿÿÿÿA†C $„‘P ôÿÿÿÿÿ’A†C $¬‘È ôÿÿÿÿÿ’A†C $Ô‘@!ôÿÿÿÿÿŽA†C $ü‘¨!ôÿÿÿÿÿÀA†C $$’@"ôÿÿÿÿÿÆA†C $L’è"ôÿÿÿÿÿžA†C $t’`#ôÿÿÿÿÿ™A†C $œ’Ø#ôÿÿÿÿÿ¥A†C $Ä’`$ôÿÿÿÿÿÁA†C ,¬’%ôÿÿÿÿÿrkèüÿÿÿÿÿA†C $“X&ôÿÿÿÿÿËA†C $D“'ôÿÿÿÿÿÑA†C $l“¸'ôÿÿÿÿÿÑA†C $”“p(ôÿÿÿÿÿ×A†C $¼“()ôÿÿÿÿÿÁA†C $ä“Ð)ôÿÿÿÿÿ"A†C $ ”Ø*ôÿÿÿÿÿËA†C $4”€+ôÿÿÿÿÿÑA†C ,”8,ôÿÿÿÿÿ''çüÿÿÿÿÿA†C $Œ”8.ôÿÿÿÿÿ#A†C ,t”@3ôÿÿÿÿÿ#çüÿÿÿÿÿA†C ,¤” Fôÿÿÿÿÿ» oçüÿÿÿÿÿA†C $•0QôÿÿÿÿÿýA†C $<•SôÿÿÿÿÿõA†C $d•àUôÿÿÿÿÿœA†C $Œ•XWôÿÿÿÿÿA†C $´•ÀWôÿÿÿÿÿÕA†C $Ü•x\ôÿÿÿÿÿëA†C $–@aôÿÿÿÿÿ”A†C $,–¸bôÿÿÿÿÿ A†C $T– côÿÿÿÿÿñA†C $|–xdôÿÿÿÿÿzA†C $¤–Ðeôÿÿÿÿÿ¼A†C JƒŽ$Ì–hlôÿÿÿÿÿA†C $ô–`qôÿÿÿÿÿA†C $—Xqôÿÿÿÿÿ…A†C $D—ÀqôÿÿÿÿÿA†C $l—¨qôÿÿÿÿÿA†C $”—qôÿÿÿÿÿAA†C $¼—¸qôÿÿÿÿÿ6A†C $ä—ÐqôÿÿÿÿÿyA†C $ ˜(rôÿÿÿÿÿ"A†C $4˜0rôÿÿÿÿÿÁA†C $\˜Ørôÿÿÿÿÿ6A†C $„˜ðrôÿÿÿÿÿ)A†C $¬˜ørôÿÿÿÿÿCA†C $Ô˜ sôÿÿÿÿÿTA†C $ü˜XsôÿÿÿÿÿTA†C $$™sôÿÿÿÿÿFA†C $L™¸tôÿÿÿÿÿbA†C $t™vôÿÿÿÿÿSA†C $œ™8wôÿÿÿÿÿwA†C $Ä™wôÿÿÿÿÿ†A†C $ì™øxôÿÿÿÿÿÏA†C $š yôÿÿÿÿÿFA†C $<šÈzôÿÿÿÿÿ†A†C $dš0|ôÿÿÿÿÿwA†C $Œšˆ|ôÿÿÿÿÿbA†C $´šÐ}ôÿÿÿÿÿ†A†C $Üš8ôÿÿÿÿÿtA†C $›ôÿÿÿÿÿVA†C $,›È€ôÿÿÿÿÿ†A†C $T›0‚ôÿÿÿÿÿ†A†C $|›˜ƒôÿÿÿÿÿDA†C $¤›À„ôÿÿÿÿÿRA†C $Ì›ø…ôÿÿÿÿÿbA†C $ô›@‡ôÿÿÿÿÿRA†C $œxˆôÿÿÿÿÿFA†C $Dœ ‰ôÿÿÿÿÿ†A†C $lœ‹ôÿÿÿÿÿTA†C $”œ@ŒôÿÿÿÿÿbA†C $¼œˆôÿÿÿÿÿ†A†C $äœðŽôÿÿÿÿÿwA†C $ HôÿÿÿÿÿwA†C $4 ôÿÿÿÿÿ†A†C $\‘ôÿÿÿÿÿDA†C $„0’ôÿÿÿÿÿhA†C $¬x“ôÿÿÿÿÿ†A†C $Ôà”ôÿÿÿÿÿ(A†C $üè”ôÿÿÿÿÿ(A†C $$žð”ôÿÿÿÿÿA†C $Lžè”ôÿÿÿÿÿA†C $tžà”ôÿÿÿÿÿA†C $œžØ”ôÿÿÿÿÿA†C $ÄžДôÿÿÿÿÿA†C $ìžÈ”ôÿÿÿÿÿA†C $ŸÀ”ôÿÿÿÿÿA†C $<Ÿ¸”ôÿÿÿÿÿA†C $dŸ°”ôÿÿÿÿÿA†C $ŒŸ¨”ôÿÿÿÿÿA†C $´Ÿ ”ôÿÿÿÿÿA†C $ÜŸ˜”ôÿÿÿÿÿA†C $ ”ôÿÿÿÿÿA†C $, ˆ”ôÿÿÿÿÿ+A†C $T ”ôÿÿÿÿÿ6A†C $| ¨”ôÿÿÿÿÿ6A†C $¤ À”ôÿÿÿÿÿA†C $Ì ¨–ôÿÿÿÿÿA†C $ô ˜ôÿÿÿÿÿ6A†C $¡¨˜ôÿÿÿÿÿA†C $D¡šôÿÿÿÿÿA†C $l¡xœôÿÿÿÿÿA†C $”¡`žôÿÿÿÿÿ6A†C $¼¡xžôÿÿÿÿÿA†C ä¡` ôÿÿÿÿÿ/D zRx $X ôÿÿÿÿÿ;A†C $Dp ôÿÿÿÿÿ;A†C $lˆ ôÿÿÿÿÿKA†C $”° ôÿÿÿÿÿ;A†C $¼È ôÿÿÿÿÿ;A†C $äà ôÿÿÿÿÿFA†C $ ¡ôÿÿÿÿÿ;A†C zPLRx›­ ,$¡ôÿÿÿÿÿa_ÙüÿÿÿÿÿA†C ,T@¡ôÿÿÿÿÿaOÙüÿÿÿÿÿA†C $´€¡ôÿÿÿÿÿ>A†C ,¬˜¡ôÿÿÿÿÿLÙüÿÿÿÿÿA†C ,ܸ¢ôÿÿÿÿÿL#ÙüÿÿÿÿÿA†C $<Ø£ôÿÿÿÿÿ A†C $dÀ£ôÿÿÿÿÿ A†C $Œ¨£ôÿÿÿÿÿ A†C $´£ôÿÿÿÿÿ A†C $Üx£ôÿÿÿÿÿ A†C $`£ôÿÿÿÿÿ A†C $,H£ôÿÿÿÿÿ A†C $T0£ôÿÿÿÿÿ A†C ,L£ôÿÿÿÿÿÊï×üÿÿÿÿÿA†C ,|¸¤ôÿÿÿÿÿEØüÿÿÿÿÿA†C $ÜØ¥ôÿÿÿÿÿ.A†C $à¥ôÿÿÿÿÿ;A†C $,ø¥ôÿÿÿÿÿFA†C $T ¦ôÿÿÿÿÿFA†C $|H¦ôÿÿÿÿÿFA†C $¤p¦ôÿÿÿÿÿFA†C $̘¦ôÿÿÿÿÿFA†C $ôÀ¦ôÿÿÿÿÿ/A†C ,ìȦôÿÿÿÿÿm÷ÖüÿÿÿÿÿA†C ,§ôÿÿÿÿÿ«óÖüÿÿÿÿÿA†C ,Lˆ¨ôÿÿÿÿÿ«ÿÖüÿÿÿÿÿA†C ,|ªôÿÿÿÿÿø ×üÿÿÿÿÿA†C ,¬تôÿÿÿÿÿm×üÿÿÿÿÿA†C ,Ü«ôÿÿÿÿÿK×üÿÿÿÿÿA†C , 8¬ôÿÿÿÿÿK×üÿÿÿÿÿA†C ,<X­ôÿÿÿÿÿcóÖüÿÿÿÿÿA†C ,l˜®ôÿÿÿÿÿãÖüÿÿÿÿÿA†C ,œˆ¯ôÿÿÿÿÿíÓÖüÿÿÿÿÿA†C ,ÌH°ôÿÿÿÿÿ–ÃÖüÿÿÿÿÿA†C $,¸±ôÿÿÿÿÿ`A†C $Tð±ôÿÿÿÿÿ|A†C $|H²ôÿÿÿÿÿ|A†C ,t ²ôÿÿÿÿÿ";ÖüÿÿÿÿÿA†C $Ô µôÿÿÿÿÿ"A†C $ü¨µôÿÿÿÿÿ"A†C $$°µôÿÿÿÿÿQA†C ,èµôÿÿÿÿÿæçÕüÿÿÿÿÿA†C $|¨·ôÿÿÿÿÿ;A†C $¤À·ôÿÿÿÿÿ*A†C $ÌÈ·ôÿÿÿÿÿWA†C ,ĸôÿÿÿÿÿñ{ÕüÿÿÿÿÿA†C ,ôкôÿÿÿÿÿ‡ÕüÿÿÿÿÿA†C ,$0»ôÿÿÿÿÿ±ƒÕüÿÿÿÿÿA†C $„ À»ôÿÿÿÿÿåA†C $¬ ˆ¼ôÿÿÿÿÿ]A†C $Ô À¼ôÿÿÿÿÿ]A†C $ü ø¼ôÿÿÿÿÿâA†C $$ À½ôÿÿÿÿÿmA†C $L ¾ôÿÿÿÿÿ.A†C $t ¾ôÿÿÿÿÿ.A†C $œ ¾ôÿÿÿÿÿ¢A†C $Ä  ¿ôÿÿÿÿÿËA†C $ì HÁôÿÿÿÿÿA†C $ @ÁôÿÿÿÿÿA†C $< 8Áôÿÿÿÿÿ A†C $d 0ÁôÿÿÿÿÿyA†C $Œ ˆÁôÿÿÿÿÿ‰A†C $´ ðÁôÿÿÿÿÿA†C $Ü XÂôÿÿÿÿÿA†C $ PÂôÿÿÿÿÿ!A†C $, XÂôÿÿÿÿÿ!A†C ,$ `Âôÿÿÿÿÿe¯ÒüÿÿÿÿÿA†C ,T  Ãôÿÿÿÿÿe«ÒüÿÿÿÿÿA†C ,„ àÄôÿÿÿÿÿ¥§ÒüÿÿÿÿÿA†C ,´ `Æôÿÿÿÿÿ‹³ÒüÿÿÿÿÿA†C $ ÀÇôÿÿÿÿÿ%A†C $< ÈÇôÿÿÿÿÿ(A†C ,4 ÐÇôÿÿÿÿÿÅoÒüÿÿÿÿÿA†C $” pÈôÿÿÿÿÿ:A†C $¼ ˆÈôÿÿÿÿÿ:A†C $ä  Èôÿÿÿÿÿ`A†C $ ØÈôÿÿÿÿÿ`A†C $4Éôÿÿÿÿÿ`A†C $\HÉôÿÿÿÿÿ`A†C $„€Éôÿÿÿÿÿ€A†C $¬ØÉôÿÿÿÿÿVA†C $ÔÊôÿÿÿÿÿ&A†C $üÊôÿÿÿÿÿ&A†C $$ Êôÿÿÿÿÿ&A†C $L(Êôÿÿÿÿÿ&A†C $t0ÊôÿÿÿÿÿA†C ,l(ÊôÿÿÿÿÿœWÐüÿÿÿÿÿA†C $̘ÊôÿÿÿÿÿA†C $ôÊôÿÿÿÿÿA†C $ˆÊôÿÿÿÿÿA†C $D€ÊôÿÿÿÿÿA†C $lxÊôÿÿÿÿÿA†C $”pÊôÿÿÿÿÿA†C $¼hÊôÿÿÿÿÿA†C $ä`ÊôÿÿÿÿÿA†C $ XÊôÿÿÿÿÿ-A†C $4`Êôÿÿÿÿÿ.A†C $\hÊôÿÿÿÿÿA†C $„`Êôÿÿÿÿÿ A†C $¬XÊôÿÿÿÿÿ%A†C $Ô`ÊôÿÿÿÿÿA†C $üXÊôÿÿÿÿÿ)A†C $$`Êôÿÿÿÿÿ+A†C $LhÊôÿÿÿÿÿA†C $t`Êôÿÿÿÿÿ‹A†C $œÈÊôÿÿÿÿÿ‹A†C $Ä0Ëôÿÿÿÿÿ6A†C $ìHËôÿÿÿÿÿuA†C $ ËôÿÿÿÿÿuA†C $<øËôÿÿÿÿÿuA†C $dPÌôÿÿÿÿÿA†C $ŒHÌôÿÿÿÿÿ=A†C $´`Ìôÿÿÿÿÿ?A†C $ÜxÌôÿÿÿÿÿ?A†C $Ìôÿÿÿÿÿ6A†C $,¨Ìôÿÿÿÿÿ=A†C $TÀÌôÿÿÿÿÿ?A†C $|ØÌôÿÿÿÿÿ?A†C $¤ðÌôÿÿÿÿÿ A†C $ÌØÌôÿÿÿÿÿ A†C $ôÀÌôÿÿÿÿÿ”A†C $8Íôÿÿÿÿÿ A†C $D Íôÿÿÿÿÿ A†C $lÍôÿÿÿÿÿ^A†C $”@ÍôÿÿÿÿÿqA†C ,Œ˜ÍôÿÿÿÿÿÃcÊüÿÿÿÿÿA†C ,¼8ÎôÿÿÿÿÿäoÊüÿÿÿÿÿA†C $øÒôÿÿÿÿÿYA†C ,0ÓôÿÿÿÿÿuwÊüÿÿÿÿÿA†C $t€ÓôÿÿÿÿÿVA†C $œ¸ÓôÿÿÿÿÿVA†C $ÄðÓôÿÿÿÿÿVA†C $ì(ÔôÿÿÿÿÿVA†C $`ÔôÿÿÿÿÿHA†C $<ˆÔôÿÿÿÿÿA†C $dpÕôÿÿÿÿÿ¶A†C ,\ÖôÿÿÿÿÿUOÉüÿÿÿÿÿA†C ,Œ8×ôÿÿÿÿÿU?ÉüÿÿÿÿÿA†C ,¼hØôÿÿÿÿÿƒ/ÉüÿÿÿÿÿA†C $ÈÙôÿÿÿÿÿ>A†C ,àÙôÿÿÿÿÿG÷ÈüÿÿÿÿÿA†C $tÚôÿÿÿÿÿMA†C $œ(ÚôÿÿÿÿÿOA†C ,”PÚôÿÿÿÿÿG—ÈüÿÿÿÿÿA†C $ôpÚôÿÿÿÿÿ A†C $XÚôÿÿÿÿÿA†C ,@ÚôÿÿÿÿÿG7ÈüÿÿÿÿÿA†C $t`Úôÿÿÿÿÿ A†C $œHÚôÿÿÿÿÿA†C $Ä@ÚôÿÿÿÿÿA†C $ì(Úôÿÿÿÿÿ\A†C $`ÚôÿÿÿÿÿAA†C $<ˆÚôÿÿÿÿÿCA†C $d°ÚôÿÿÿÿÿOA†C ,\ØÚôÿÿÿÿÿGÇüÿÿÿÿÿA†C $¼øÚôÿÿÿÿÿ1A†C $äÛôÿÿÿÿÿA†C $ øÚôÿÿÿÿÿ A†C $4àÚôÿÿÿÿÿJA†C ,,ÛôÿÿÿÿÿG_ÆüÿÿÿÿÿA†C $Œ(ÛôÿÿÿÿÿA†C $´Ûôÿÿÿÿÿ A†C $ÜøÚôÿÿÿÿÿ=A†C $Ûôÿÿÿÿÿ>A†C $,(Ûôÿÿÿÿÿ>A†C $T@Ûôÿÿÿÿÿ A†C $|(Ûôÿÿÿÿÿ A†C $¤Ûôÿÿÿÿÿ A†C $ÌøÚôÿÿÿÿÿ A†C ,ÄàÚôÿÿÿÿÿGçÄüÿÿÿÿÿA†C ,ôÛôÿÿÿÿÿG×ÄüÿÿÿÿÿA†C ,$ ÛôÿÿÿÿÿGÇÄüÿÿÿÿÿA†C ,T@Ûôÿÿÿÿÿ^·ÄüÿÿÿÿÿA†C $´pÛôÿÿÿÿÿ*A†C $ÜxÛôÿÿÿÿÿ*A†C $€ÛôÿÿÿÿÿXA†C $,¸Ûôÿÿÿÿÿ:A†C $TÐÛôÿÿÿÿÿ:A†C $|èÛôÿÿÿÿÿOA†C $¤Ýôÿÿÿÿÿ*A†C $ÌÝôÿÿÿÿÿ*A†C $ô Ýôÿÿÿÿÿ>A†C $8ÝôÿÿÿÿÿIA†C $D`ÝôÿÿÿÿÿYA†C $l˜ÝôÿÿÿÿÿFA†C $”ÀÝôÿÿÿÿÿÁA†C $¼hÞôÿÿÿÿÿÁA†C $äßôÿÿÿÿÿjA†C $ XßôÿÿÿÿÿjA†C $4  ßôÿÿÿÿÿ„A†C $\ àôÿÿÿÿÿ„A†C $„ pàôÿÿÿÿÿaA†C $¬ ¸àôÿÿÿÿÿaA†C $Ô áôÿÿÿÿÿZA†C $ü 8áôÿÿÿÿÿZA†C $$!páôÿÿÿÿÿvA†C $L!ÈáôÿÿÿÿÿvA†C $t! âôÿÿÿÿÿCA†C $œ!Hâôÿÿÿÿÿ™A†C $Ä!ÀâôÿÿÿÿÿCA†C $ì!èâôÿÿÿÿÿqA†C $"@ãôÿÿÿÿÿaA†C $<"ˆãôÿÿÿÿÿ`A†C $d"Àãôÿÿÿÿÿ`A†C $Œ"øãôÿÿÿÿÿ&A†C $´"äôÿÿÿÿÿ&A†C $Ü"äôÿÿÿÿÿXA†C $#@äôÿÿÿÿÿ2A†C $,#Xäôÿÿÿÿÿ2A†C $T#päôÿÿÿÿÿÉA†C $|#åôÿÿÿÿÿ½A†C $¤#°åôÿÿÿÿÿÆA†C $Ì#Xæôÿÿÿÿÿ;A†C $ô#pæôÿÿÿÿÿ;A†C $$ˆæôÿÿÿÿÿ;A†C $D$ æôÿÿÿÿÿ;A†C $l$¸æôÿÿÿÿÿÉA†C $”$`çôÿÿÿÿÿ½A†C $¼$øçôÿÿÿÿÿÆA†C $ä$ èôÿÿÿÿÿ;A†C $ %¸èôÿÿÿÿÿDA†C $4%àèôÿÿÿÿÿ‚A†C $\%Hêôÿÿÿÿÿ”A†C $„%ÀêôÿÿÿÿÿŒA†C $¬%(ëôÿÿÿÿÿA†C $Ô%ëôÿÿÿÿÿTA†C $ü%ÈëôÿÿÿÿÿTA†C $$&ìôÿÿÿÿÿ&A†C $L&ìôÿÿÿÿÿ&A†C $t&ìôÿÿÿÿÿ&A†C $œ&ìôÿÿÿÿÿ&A†C $Ä& ìôÿÿÿÿÿTA†C $ì&XìôÿÿÿÿÿTA†C $'ìôÿÿÿÿÿAA†C $<'¸ìôÿÿÿÿÿaA†C $d'íôÿÿÿÿÿ:A†C $Œ'íôÿÿÿÿÿ!A†C $´' íôÿÿÿÿÿCA†C $Ü'Híôÿÿÿÿÿ6A†C $(`íôÿÿÿÿÿ!A†C $,(híôÿÿÿÿÿVA†C $T( íôÿÿÿÿÿVA†C $|(Øíôÿÿÿÿÿ3A†C $¤(ðíôÿÿÿÿÿ6A†C $Ì(ïôÿÿÿÿÿ¾A†C ,Ä' ïôÿÿÿÿÿ‰g¹üÿÿÿÿÿA†C $$)ôôÿÿÿÿÿ3A†C $L)ôôÿÿÿÿÿ3A†C $t)0ôôÿÿÿÿÿVA†C $œ)hôôÿÿÿÿÿ A†C $Ä)àôôÿÿÿÿÿ A†C $ì)Xõôÿÿÿÿÿ™A†C $*Ðõôÿÿÿÿÿ™A†C $<*HöôÿÿÿÿÿA†C $d*ÀöôÿÿÿÿÿA†C $Œ*8÷ôÿÿÿÿÿ,A†C ,„)@÷ôÿÿÿÿÿJ#¸üÿÿÿÿÿA†C ,´)`ùôÿÿÿÿÿ„c¸üÿÿÿÿÿA†C ,ä)Àûôÿÿÿÿÿq“¸üÿÿÿÿÿA†C ,*üôÿÿÿÿÿ¸ƒ¸üÿÿÿÿÿA†C ,D* üôÿÿÿÿÿ)s¸üÿÿÿÿÿA†C ,t* ýôÿÿÿÿÿæ—¸üÿÿÿÿÿA†C ,¤*`ÿôÿÿÿÿÿÀ׸üÿÿÿÿÿA†C $,ðõÿÿÿÿÿyA†C $,,HõÿÿÿÿÿFA†C $T,põÿÿÿÿÿvA†C ,L+Èõÿÿÿÿÿ´ƒ¸üÿÿÿÿÿA†C ,|+XõÿÿÿÿÿT¸üÿÿÿÿÿA†C ,¬+ˆõÿÿÿÿÿ¡{¸üÿÿÿÿÿA†C $ -õÿÿÿÿÿCA†C $4-0õÿÿÿÿÿiA†C ,,,xõÿÿÿÿÿc7¸üÿÿÿÿÿA†C ,\,¸õÿÿÿÿÿž3¸üÿÿÿÿÿA†C $¼-(õÿÿÿÿÿCA†C $ä-PõÿÿÿÿÿbA†C $ .˜õÿÿÿÿÿ6A†C $4.°õÿÿÿÿÿ5A†C $\.Èõÿÿÿÿÿ0A†C $„.Ðõÿÿÿÿÿ-A†C ,|-Øõÿÿÿÿÿè?·üÿÿÿÿÿA†C ,¬-˜õÿÿÿÿÿ“K·üÿÿÿÿÿA†C $ /õÿÿÿÿÿ?A†C ,. õÿÿÿÿÿrc·üÿÿÿÿÿA†C $d/p õÿÿÿÿÿ:A†C $Œ/ˆ õÿÿÿÿÿPA†C ,„.° õÿÿÿÿÿØC·üÿÿÿÿÿA†C ,´.` õÿÿÿÿÿ€·üÿÿÿÿÿA†C ,ä.°õÿÿÿÿÿ §·üÿÿÿÿÿA†C ,/õÿÿÿÿÿ¾×·üÿÿÿÿÿA†C Hƒ,D/`õÿÿÿÿÿÌï·üÿÿÿÿÿA†C ,t/õÿÿÿÿÿM¸üÿÿÿÿÿA†C ,¤/ õÿÿÿÿÿâG¸üÿÿÿÿÿA†C ,Ô/àõÿÿÿÿÿâC¸üÿÿÿÿÿA†C ,0 õÿÿÿÿÿ@?¸üÿÿÿÿÿA†C ,40° õÿÿÿÿÿ@¸üÿÿÿÿÿA†C ,d0À#õÿÿÿÿÿ2¿¸üÿÿÿÿÿA†C ,”0Ð&õÿÿÿÿÿ2ÿ¸üÿÿÿÿÿA†C ,Ä0à)õÿÿÿÿÿP?¹üÿÿÿÿÿA†C ,ô0-õÿÿÿÿÿP¹üÿÿÿÿÿA†C $T2 0õÿÿÿÿÿA†C $|20õÿÿÿÿÿA†C $¤2ð/õÿÿÿÿÿ6A†C $Ì20õÿÿÿÿÿsA†C ,Ä1`0õÿÿÿÿÿq¹üÿÿÿÿÿA†C zRx ,˜2õÿÿÿÿÿ2A†C MƒŒŽ$L¨4õÿÿÿÿÿ…A†C Aƒ$t6õÿÿÿÿÿŒJ†C CƒŽ,œx7õÿÿÿÿÿ!A†C PƒŒŽzPLRx›õj 4$X?õÿÿÿÿÿïw¸üÿÿÿÿÿA†C KƒŒŽ$$@õÿÿÿÿÿÝA†C GƒŽ,„È@õÿÿÿÿÿœ7¸üÿÿÿÿÿA†C CƒŽ4´8AõÿÿÿÿÿÀ3¸üÿÿÿÿÿA†C MƒŒŽ$´ÀEõÿÿÿÿÿeA†C Bƒ$ÜFõÿÿÿÿÿ£A†C , Fõÿÿÿÿÿ1A†C MƒŒŽ,l°HõÿÿÿÿÿÀ;¸üÿÿÿÿÿA†C FƒŽ$d@IõÿÿÿÿÿlA†C FƒŽ$ŒˆIõÿÿÿÿÿA†C FƒŽ$´àIõÿÿÿÿÿGA†C CƒŽ,Jõÿÿÿÿÿu³·üÿÿÿÿÿA†C FƒŽ$ XJõÿÿÿÿÿGA†C CƒŽ4l€Jõÿÿÿÿÿ{·üÿÿÿÿÿA†C PƒŒŽ$lhLõÿÿÿÿÿqA†C CƒŽ$”ÀLõÿÿÿÿÿGA†C CƒŽ$¼èLõÿÿÿÿÿA†C ,äÐLõÿÿÿÿÿ`A†C JƒŒŽ$Nõÿÿÿÿÿ‰A†C CƒŽ$<hNõÿÿÿÿÿŒA†C CƒŽ$dÐNõÿÿÿÿÿA†C CƒŽ$Œ8OõÿÿÿÿÿŒA†C CƒŽ4ì Oõÿÿÿÿÿ0w¶üÿÿÿÿÿA†C MƒŒŽ,$˜Qõÿÿÿÿÿ‡¯¶üÿÿÿÿÿA†C IƒŽ$øRõÿÿÿÿÿEA†C FƒŽ4| Sõÿÿÿÿÿb ƒ¶üÿÿÿÿÿA†C PƒŒŽ4´X`õÿÿÿÿÿ¯'¸üÿÿÿÿÿA†C KƒŒŽ$´Ðaõÿÿÿÿÿ`A†C CƒŽ$Übõÿÿÿÿÿ\A†C CƒŽ$@bõÿÿÿÿÿhA†C CƒŽ$,ˆbõÿÿÿÿÿTA†C CƒŽ4ŒÀbõÿÿÿÿÿÖ ‹·üÿÿÿÿÿA†C PƒŒŽ4ÄhpõÿÿÿÿÿÏK¹üÿÿÿÿÿA†C PƒŒŽ,ÄtõÿÿÿÿÿÖA†C NƒŒŽ4,°tõÿÿÿÿÿGã¹üÿÿÿÿÿA†C MƒŒŽ4dÈvõÿÿÿÿÿiOºüÿÿÿÿÿA†C PƒŒŽ4œ~õÿÿÿÿÿÈs»üÿÿÿÿÿA†C NƒŒŽ4Ô˜õÿÿÿÿÿþg»üÿÿÿÿÿA†C PƒŒŽ4 `„õÿÿÿÿÿ±ï»üÿÿÿÿÿA†C PƒŒŽ4Dè‰õÿÿÿÿÿÎw¼üÿÿÿÿÿA†C PƒŒŽ,|€õÿÿÿÿÿ1W½üÿÿÿÿÿA†C JƒŽ,¬‘õÿÿÿÿÿƒ{½üÿÿÿÿÿA†C LƒŽ,Üð•õÿÿÿÿÿ"W¾üÿÿÿÿÿA†C LƒŽ$Ôð™õÿÿÿÿÿÄA†C Eƒ$ü˜šõÿÿÿÿÿUA†C $$ КõÿÿÿÿÿA†C $L (›õÿÿÿÿÿƒA†C ,¬›õÿÿÿÿÿøk¾üÿÿÿÿÿA†C Hƒ,Ü`œõÿÿÿÿÿÀg¾üÿÿÿÿÿA†C GƒŽ$Ô ðœõÿÿÿÿÿA†C ,4 HõÿÿÿÿÿÀ/¾üÿÿÿÿÿA†C GƒŽ,d ØõÿÿÿÿÿÀ¾üÿÿÿÿÿA†C GƒŽ,” hžõÿÿÿÿÿæ¾üÿÿÿÿÿA†C IƒŽ$Œ (ŸõÿÿÿÿÿýA†C FƒŽ,ì  õÿÿÿÿÿÞ×½üÿÿÿÿÿA†C FƒŽ$ä ° õÿÿÿÿÿ£A†C $ H¡õÿÿÿÿÿvA†C Bƒ,l  ¡õÿÿÿÿÿ¯w½üÿÿÿÿÿA†C GƒŽ$d ð¢õÿÿÿÿÿUN†C CƒŽ,Œ 8£õÿÿÿÿÿ¨A†C GƒŒŽ,ô ¸£õÿÿÿÿÿv½üÿÿÿÿÿA†C GƒŽ$ì ¤õÿÿÿÿÿsA†C CƒŽ$ ¤õÿÿÿÿÿÿA†C FƒŽ4t x¥õÿÿÿÿÿª»¼üÿÿÿÿÿA†C NƒŒŽ,¬ ð§õÿÿÿÿÿ©¯¼üÿÿÿÿÿA†C CƒŽ$¤ p¨õÿÿÿÿÿqA†C FƒŽ, Ȩõÿÿÿÿÿ¶ƒ¼üÿÿÿÿÿA†C LƒŽ44 XªõÿÿÿÿÿѼüÿÿÿÿÿA†C JƒŒŽ$4 ¬õÿÿÿÿÿ8A†C CƒŽ$\ ¬õÿÿÿÿÿëA†C IƒŽ4¼ à¬õÿÿÿÿÿ4¼üÿÿÿÿÿA†C JƒŒŽ,¼ è­õÿÿÿÿÿÒA†C KƒŒŽ,$ ˜®õÿÿÿÿÿÃÏ»üÿÿÿÿÿA†C JƒŽ$8¯õÿÿÿÿÿ—A†C CƒŽ$D°¯õÿÿÿÿÿŸA†C CƒŽ,¤ (°õÿÿÿÿÿÝ‹»üÿÿÿÿÿA†C GƒŽ4Ô Ø²õÿÿÿÿÿÀç»üÿÿÿÿÿA†C KƒŒŽ4 `³õÿÿÿÿÿMÛ»üÿÿÿÿÿA†C PƒŒŽ,DxµõÿÿÿÿÿB¼üÿÿÿÿÿA†C CƒŽ,t˜µõÿÿÿÿÿn¼üÿÿÿÿÿA†C GƒŽ4¤صõÿÿÿÿÿ>ó»üÿÿÿÿÿA†C PƒŒŽ4Üà·õÿÿÿÿÿ2+¼üÿÿÿÿÿA†C KƒŒŽ4è¹õÿÿÿÿÿîS¼üÿÿÿÿÿA†C KƒŒŽ,L »õÿÿÿÿÿç¼üÿÿÿÿÿA†C LƒŽ4|½õÿÿÿÿÿ›'½üÿÿÿÿÿA†C NƒŒŽ4´ø¾õÿÿÿÿÿ{½üÿÿÿÿÿA†C PƒŒŽ$´@Áõÿÿÿÿÿ A†C $Ü(Áõÿÿÿÿÿ A†C $ÁõÿÿÿÿÿA†C $,Áõÿÿÿÿÿ A†C $TðÀõÿÿÿÿÿ*A†C $|øÀõÿÿÿÿÿA†C $¤ðÀõÿÿÿÿÿA†C $ÌèÀõÿÿÿÿÿA†C ,,àÀõÿÿÿÿÿž¼üÿÿÿÿÿA†C IƒŽ4\PÁõÿÿÿÿÿ¼üÿÿÿÿÿA†C PƒŒŽ4”(ÈõÿÿÿÿÿÇã¼üÿÿÿÿÿA†C PƒŒŽ,”ÀÎõÿÿÿÿÿ„A†C MƒŒŽ,Ä ÑõÿÿÿÿÿnA†C KƒŒŽ$ô`ÓõÿÿÿÿÿA†C $XÓõÿÿÿÿÿ A†C CƒŽ$D@ÖõÿÿÿÿÿA†C $l8ÖõÿÿÿÿÿA†C $”0ÖõÿÿÿÿÿA†C 4ô(Öõÿÿÿÿÿ0w¼üÿÿÿÿÿA†C PƒŒŽ4, Ùõÿÿÿÿÿ,_¼üÿÿÿÿÿA†C PƒŒŽ4dÛõÿÿÿÿÿ S¼üÿÿÿÿÿA†C MƒŒŽ4œðÜõÿÿÿÿÿÖG¼üÿÿÿÿÿA†C PƒŒŽ,œ˜àõÿÿÿÿÿŸA†C PƒŒŽ4âõÿÿÿÿÿÞ[¼üÿÿÿÿÿA†C KƒŒŽ$°âõÿÿÿÿÿA†C $,˜âõÿÿÿÿÿ A†C $T€âõÿÿÿÿÿXA†C $|¸âõÿÿÿÿÿXA†C $¤ðâõÿÿÿÿÿ A†C $ÌØâõÿÿÿÿÿA†C ,ôÀâõÿÿÿÿÿ£A†C MƒŒŽ,$@æõÿÿÿÿÿoA†C PƒŒŽ4Œ€ëõÿÿÿÿÿ`ÿºüÿÿÿÿÿA†C MƒŒŽ$Œ¨íõÿÿÿÿÿ‰A†C GƒŽ4ìïõÿÿÿÿÿ7˺üÿÿÿÿÿA†C MƒŒŽ,$ñõÿÿÿÿÿžÛºüÿÿÿÿÿA†C IƒŽ,Tˆñõÿÿÿÿÿ×׺üÿÿÿÿÿA†C IƒŽ$L8òõÿÿÿÿÿgA†C GƒŽ4¬€óõÿÿÿÿÿP«ºüÿÿÿÿÿA†C KƒŒŽ$¬˜ôõÿÿÿÿÿ*A†C $Ô ôõÿÿÿÿÿ A†C FƒŽ44õõÿÿÿÿÿ³OºüÿÿÿÿÿA†C NƒŒŽ4l øõÿÿÿÿÿ¡ wºüÿÿÿÿÿA†C PƒŒŽ,¤öÿÿÿÿÿB»üÿÿÿÿÿA†C JƒŽ4Ô8 öÿÿÿÿÿö s»üÿÿÿÿÿA†C PƒŒŽ,Ô öÿÿÿÿÿ|A†C MƒŒŽ$pöÿÿÿÿÿàA†C GƒŽ4d(öÿÿÿÿÿ¢ã»üÿÿÿÿÿA†C PƒŒŽ4œ öÿÿÿÿÿ•×»üÿÿÿÿÿA†C NƒŒŽ4Ô!öÿÿÿÿÿeÿ»üÿÿÿÿÿA†C PƒŒŽ4 @:öÿÿÿÿÿÙW½üÿÿÿÿÿA†C PƒŒŽ4Dø@öÿÿÿÿÿdGs½üÿÿÿÿÿA†C PƒŒŽ4|0ˆöÿÿÿÿÿIÄüÿÿÿÿÿA†C PƒŒŽ4´H˜öÿÿÿÿÿÆÅüÿÿÿÿÿA†C PƒŒŽ4ìàœöÿÿÿÿÿHGÅüÿÿÿÿÿA†C PƒŒŽ4$²öÿÿÿÿÿb“ÇüÿÿÿÿÿA†C PƒŒŽ4\@·öÿÿÿÿÿûÿÇüÿÿÿÿÿA†C MƒŒŽ$\¸öÿÿÿÿÿA†C 4¼ð·öÿÿÿÿÿž ÛÇüÿÿÿÿÿA†C PƒŒŽ4ôXÂöÿÿÿÿÿZÈüÿÿÿÿÿA†C PƒŒŽ4,€Éöÿÿÿÿÿ—WÈüÿÿÿÿÿA†C PƒŒŽzPLRx›•O 4$øâöÿÿÿÿÿÀCÊüÿÿÿÿÿA†C MƒŒŽ,\€çöÿÿÿÿÿuËÊüÿÿÿÿÿA†C FƒŽzRx $¸çöÿÿÿÿÿA†C $D çöÿÿÿÿÿ{A†C CƒŽ$løçöÿÿÿÿÿhA†C LƒŽ4@éöÿÿÿÿÿ¦+ÊüÿÿÿÿÿA†C MƒŒŽ4T¸ëöÿÿÿÿÿË;ÊüÿÿÿÿÿA†C MƒŒŽ4ŒPíöÿÿÿÿÿ WÊüÿÿÿÿÿA†C MƒŒŽ$<(ðöÿÿÿÿÿA†C Bƒ,ì ðöÿÿÿÿÿ?ÊüÿÿÿÿÿA†C IƒŽ4ñöÿÿÿÿÿ@cÊüÿÿÿÿÿA†C MƒŒŽ,T˜óöÿÿÿÿÿ‡›ÊüÿÿÿÿÿA†C IƒŽ$üøôöÿÿÿÿÿ!A†C Bƒ$$õöÿÿÿÿÿ A†C Bƒ$Løôöÿÿÿÿÿ A†C Bƒ$tðôöÿÿÿÿÿ!A†C Bƒ$œøôöÿÿÿÿÿEA†C FƒŽ$Ä õöÿÿÿÿÿhA†C CƒŽ$ìhõöÿÿÿÿÿ_A†C CƒŽ$ õöÿÿÿÿÿTA†C CƒŽ4ÄØõöÿÿÿÿÿ%WÉüÿÿÿÿÿA†C MƒŒŽ$tÐ÷öÿÿÿÿÿÄA†C Eƒ$œxøöÿÿÿÿÿUA†C $Äúöÿÿÿÿÿzs†C CƒŽ$ìhúöÿÿÿÿÿUN†C CƒŽ, úöÿÿÿÿÿ$A†C MƒŒŽ$D ûöÿÿÿÿÿzs†C CƒŽ$løûöÿÿÿÿÿ2A†C Bƒ,”üöÿÿÿÿÿÉA†C KƒŒŽ$İüöÿÿÿÿÿ:A†C Bƒ,ìÈüöÿÿÿÿÿÌA†C KƒŒŽ$hýöÿÿÿÿÿ–A†C FƒŽ$Dàýöÿÿÿÿÿ A†C $lÈýöÿÿÿÿÿ A†C $”°ýöÿÿÿÿÿA†C $¼¨ýöÿÿÿÿÿA†C ,ä ýöÿÿÿÿÿ0A†C KƒŒŽ, þöÿÿÿÿÿ1A†C KƒŒŽ,D°ÿöÿÿÿÿÿ0A†C KƒŒŽ,t°÷ÿÿÿÿÿA†C MƒŒŽ,¤÷ÿÿÿÿÿñA†C MƒŒŽ4\`÷ÿÿÿÿÿúëÅüÿÿÿÿÿA†C PƒŒŽ4”( ÷ÿÿÿÿÿª?ÆüÿÿÿÿÿA†C PƒŒŽ,D ÷ÿÿÿÿÿšA†C PƒŒŽ4ü÷ÿÿÿÿÿUcÆüÿÿÿÿÿA†C MƒŒŽ$¬8÷ÿÿÿÿÿ A†C CƒŽ$Ô ÷ÿÿÿÿÿêA†C $üè÷ÿÿÿÿÿnA†C IƒŽ4¬0÷ÿÿÿÿÿÞßÅüÿÿÿÿÿA†C KƒŒŽ,\Ø÷ÿÿÿÿÿ»A†C KƒŒŽ$Œh÷ÿÿÿÿÿ A†C $´P÷ÿÿÿÿÿXA†C $܈÷ÿÿÿÿÿXA†C , À÷ÿÿÿÿÿöA†C GƒŒŽ$4 ÷ÿÿÿÿÿ A†C 4ä x÷ÿÿÿÿÿØÓÄüÿÿÿÿÿA†C NƒŒŽ, "÷ÿÿÿÿÿ×ïÄüÿÿÿÿÿA†C Eƒ4L Ð"÷ÿÿÿÿÿpëÄüÿÿÿÿÿA†C NƒŒŽ4„ %÷ÿÿÿÿÿê#ÅüÿÿÿÿÿA†C PƒŒŽ,¼ À3÷ÿÿÿÿÿÂ7ÆüÿÿÿÿÿA†C Eƒ4ì `4÷ÿÿÿÿÿ†;3ÆüÿÿÿÿÿA†C PƒŒŽ4$ ¸o÷ÿÿÿÿÿ;WËüÿÿÿÿÿA†C PƒŒŽ$Ô Àu÷ÿÿÿÿÿA†C 4„ ¨†÷ÿÿÿÿÿî.ÌüÿÿÿÿÿA†C PƒŒŽ4¼ 0»÷ÿÿÿÿÿè ÓÎüÿÿÿÿÿA†C PƒŒŽ,ô øÇ÷ÿÿÿÿÿ­ ÏüÿÿÿÿÿA†C Eƒ,$ xÈ÷ÿÿÿÿÿ­ûÎüÿÿÿÿÿA†C Eƒ$Ì øÈ÷ÿÿÿÿÿýA†C CƒŽ$ô ðÉ÷ÿÿÿÿÿ цC 4¤ øÊ÷ÿÿÿÿÿ£›ÎüÿÿÿÿÿA†C PƒŒŽ$T pÎ÷ÿÿÿÿÿ A†C $| XÎ÷ÿÿÿÿÿ A†C 4, @Î÷ÿÿÿÿÿ~gÎüÿÿÿÿÿA†C PƒŒŽ$Ü ˆÐ÷ÿÿÿÿÿA†C Bƒ$ €Ð÷ÿÿÿÿÿA†C Bƒ4´ xÐ÷ÿÿÿÿÿ:'ÎüÿÿÿÿÿA†C PƒŒŽzRx $hÕ÷ÿÿÿÿÿaA†C zPLRx›mA 4$Õ÷ÿÿÿÿÿ"?ÎüÿÿÿÿÿA†C MƒŒŽzRx $p×÷ÿÿÿÿÿÝA†C GƒŽ$D(Ø÷ÿÿÿÿÿA†C ,lØ÷ÿÿÿÿÿ`A†C JƒŒŽ$œ@Ù÷ÿÿÿÿÿA†C CƒŽ$ĨÙ÷ÿÿÿÿÿA†C CƒŽ$ìÚ÷ÿÿÿÿÿŒA†C CƒŽ$xÚ÷ÿÿÿÿÿEA†C FƒŽ$< Ú÷ÿÿÿÿÿ_A†C CƒŽ$dØÚ÷ÿÿÿÿÿhA†C CƒŽ$Œ Û÷ÿÿÿÿÿhA†C CƒŽ$´hÛ÷ÿÿÿÿÿTA†C CƒŽ,4Ü÷ÿÿÿÿÿv[ÌüÿÿÿÿÿA†C GƒŽ$ àÜ÷ÿÿÿÿÿqA†C FƒŽ$48Ý÷ÿÿÿÿÿ A†C $\ Ý÷ÿÿÿÿÿA†C $„Ý÷ÿÿÿÿÿA†C 4Ý÷ÿÿÿÿÿN«ËüÿÿÿÿÿA†C MƒŒŽ4<(Þ÷ÿÿÿÿÿ “ËüÿÿÿÿÿA†C PƒŒŽ$è÷ÿÿÿÿÿÁA†C EƒŽ$D¨é÷ÿÿÿÿÿA†C $lé÷ÿÿÿÿÿXA†C $”Èé÷ÿÿÿÿÿA†C ,°é÷ÿÿÿÿÿ_ËüÿÿÿÿÿA†C IƒŽ,D ê÷ÿÿÿÿÿXwËüÿÿÿÿÿA†C GƒŽ4tÐë÷ÿÿÿÿÿNƒËüÿÿÿÿÿA†C PƒŒŽ,Tèî÷ÿÿÿÿÿAA†C NƒŒŽ,„ð÷ÿÿÿÿÿ¦A†C KƒŒŽ4 ˆð÷ÿÿÿÿÿKËüÿÿÿÿÿA†C KƒŒŽ,ì ñ÷ÿÿÿÿÿqA†C MƒŒŽ4tðó÷ÿÿÿÿÿEÛÊüÿÿÿÿÿA†C KƒŒŽ4¬õ÷ÿÿÿÿÿFëÊüÿÿÿÿÿA†C KƒŒŽ$Œ ö÷ÿÿÿÿÿæA†C 4 øö÷ÿÿÿÿÿœ$ÓÊüÿÿÿÿÿA†C PƒŒŽ4D`øÿÿÿÿÿ]{ÍüÿÿÿÿÿA†C PƒŒŽ4|ˆ"øÿÿÿÿÿ ¿ÍüÿÿÿÿÿA†C PƒŒŽzRx $H'øÿÿÿÿÿ’A†C CƒŽ$DÀ'øÿÿÿÿÿlA†C FƒŽ$l(øÿÿÿÿÿcA†C CƒŽ$”P(øÿÿÿÿÿA†C $¼8(øÿÿÿÿÿA†C zPLRx›Ý9 4$(øÿÿÿÿÿ¯ÍüÿÿÿÿÿA†C GƒŒŽ$<x(øÿÿÿÿÿ{A†C CƒŽ$dÐ(øÿÿÿÿÿ_A†C CƒŽ$Œ)øÿÿÿÿÿTA†C CƒŽ$´@)øÿÿÿÿÿÄA†C Eƒ$Üè)øÿÿÿÿÿÄA†C Eƒ$*øÿÿÿÿÿUA†C $,È*øÿÿÿÿÿUA†C $T+øÿÿÿÿÿA†C $|X+øÿÿÿÿÿƒA†C ,ÄÀ+øÿÿÿÿÿ¿ƒËüÿÿÿÿÿA†C Hƒ$ÔP,øÿÿÿÿÿA†C $ü¨,øÿÿÿÿÿA†C $$-øÿÿÿÿÿA†C ,lX-øÿÿÿÿÿéûÊüÿÿÿÿÿA†C Eƒ$|.øÿÿÿÿÿƒA†C ,Ä€.øÿÿÿÿÿ¹ÃÊüÿÿÿÿÿA†C Eƒ,ô/øÿÿÿÿÿñ³ÊüÿÿÿÿÿA†C Eƒ,$à/øÿÿÿÿÿÛ£ÊüÿÿÿÿÿA†C IƒŽ$40øÿÿÿÿÿUN†C CƒŽ,|È0øÿÿÿÿÿÁkÊüÿÿÿÿÿA†C IƒŽ$Œh1øÿÿÿÿÿUN†C CƒŽ$´ 1øÿÿÿÿÿFA†C CƒŽ,Ü2øÿÿÿÿÿŠA†C KƒŒŽ,,x2øÿÿÿÿÿ”ÛÉüÿÿÿÿÿA†C FƒŽ$<è2øÿÿÿÿÿ A†C $dÐ2øÿÿÿÿÿ A†C $Œ¸2øÿÿÿÿÿ A†C $´ 2øÿÿÿÿÿA†C $ܘ2øÿÿÿÿÿA†C ,2øÿÿÿÿÿrA†C MƒŒŽ$4à2øÿÿÿÿÿ A†C $\È2øÿÿÿÿÿA†C $„À2øÿÿÿÿÿ A†C $¬¨2øÿÿÿÿÿ A†C $Ô2øÿÿÿÿÿA†C $üˆ2øÿÿÿÿÿA†C GƒŽ$$ð2øÿÿÿÿÿA†C $Lè2øÿÿÿÿÿA†C $tà2øÿÿÿÿÿÒA†C $œ˜3øÿÿÿÿÿ0A†C Eƒ$Ä 3øÿÿÿÿÿ0A†C Eƒ$ì¨3øÿÿÿÿÿ0A†C Eƒ$°3øÿÿÿÿÿ0A†C Eƒ,<¸3øÿÿÿÿÿ»A†C KƒŒŽ$lH5øÿÿÿÿÿ A†C $”05øÿÿÿÿÿ A†C $¼5øÿÿÿÿÿXA†C $äP5øÿÿÿÿÿXA†C $ ˆ5øÿÿÿÿÿXA†C $4 À5øÿÿÿÿÿ A†C ,\ ¨5øÿÿÿÿÿöA†C GƒŒŽ$Œ x6øÿÿÿÿÿ A†C $´ `6øÿÿÿÿÿA†C $Ü H6øÿÿÿÿÿA†C $ 06øÿÿÿÿÿ\A†C $, h6øÿÿÿÿÿNA†C GƒŽ$T 6øÿÿÿÿÿ A†C $| x6øÿÿÿÿÿA†C $¤ p6øÿÿÿÿÿrA†C $Ì È6øÿÿÿÿÿBA†C CƒŽ$ô ð6øÿÿÿÿÿdA†C $ 87øÿÿÿÿÿA†C ,D 07øÿÿÿÿÿvA†C KƒŒŽ$t €7øÿÿÿÿÿ A†C 4¼ h7øÿÿÿÿÿvkÃüÿÿÿÿÿA†C KƒŒŽ4ô °9øÿÿÿÿÿ±£ÃüÿÿÿÿÿA†C MƒŒŽ4, 8<øÿÿÿÿÿdçÃüÿÿÿÿÿA†C MƒŒŽ$D p>øÿÿÿÿÿ A†C IƒŽ$l X?øÿÿÿÿÿ)A†C $” `?øÿÿÿÿÿA†C $¼ È?øÿÿÿÿÿA†C , °?øÿÿÿÿÿcÃüÿÿÿÿÿA†C IƒŽ$  @øÿÿÿÿÿA†C 4\ ˆ@øÿÿÿÿÿÈGÃüÿÿÿÿÿA†C KƒŒŽ4” Aøÿÿÿÿÿ«;ÃüÿÿÿÿÿA†C PƒŒŽ4Ì ˜CøÿÿÿÿÿsÃüÿÿÿÿÿA†C MƒŒŽ$ä Eøÿÿÿÿÿ>A†C Eƒ4, Eøÿÿÿÿÿh?ÃüÿÿÿÿÿA†C MƒŒŽ4d PHøÿÿÿÿÿÐgÃüÿÿÿÿÿA†C KƒŒŽ$|èHøÿÿÿÿÿ1A†C $¤IøÿÿÿÿÿiA†C GƒŽ$ÌHIøÿÿÿÿÿZA†C GƒŽ,€Iøÿÿÿÿÿ×ÂüÿÿÿÿÿA†C IƒŽ,$`JøÿÿÿÿÿgA†C PƒŒŽ,t Møÿÿÿÿÿ³ÂüÿÿÿÿÿA†C IƒŽ$„NøÿÿÿÿÿTA†C FƒŽ$¬HNøÿÿÿÿÿ A†C $Ô0NøÿÿÿÿÿN†C $ü(NøÿÿÿÿÿLA†C $$PNøÿÿÿÿÿA†C ,LHNøÿÿÿÿÿcA†C GƒŒŽ$|ˆNøÿÿÿÿÿ A†C $¤pNøÿÿÿÿÿ A†C $ÌXNøÿÿÿÿÿ?A†C Bƒ$ôpNøÿÿÿÿÿ?A†C Bƒ$ˆNøÿÿÿÿÿA†C $D€Nøÿÿÿÿÿ A†C $lhNøÿÿÿÿÿ A†C $”PNøÿÿÿÿÿ A†C $¼8Nøÿÿÿÿÿ A†C 4 NøÿÿÿÿÿúCÀüÿÿÿÿÿA†C KƒŒŽ4<èNøÿÿÿÿÿ€7ÀüÿÿÿÿÿA†C MƒŒŽ,T0Qøÿÿÿÿÿ0A†C MƒŒŽ,„0SøÿÿÿÿÿÉA†C MƒŒŽ$´ÐUøÿÿÿÿÿZA†C GƒŽ$ÜVøÿÿÿÿÿMA†C Eƒ,€Wøÿÿÿÿÿ~A†C KƒŒŽ$4ÐWøÿÿÿÿÿ!A†C $\ØWøÿÿÿÿÿeA†C ,¤Yøÿÿÿÿÿ #¿üÿÿÿÿÿA†C IƒŽ,ÔðYøÿÿÿÿÿÝ¿üÿÿÿÿÿA†C GƒŽ$ä ZøÿÿÿÿÿBA†C Bƒ$ ÈZøÿÿÿÿÿA†C $4°ZøÿÿÿÿÿA†C Bƒ$\¨ZøÿÿÿÿÿQA†C Eƒ$„àZøÿÿÿÿÿBA†C Bƒ,Ì[øÿÿÿÿÿS¾üÿÿÿÿÿA†C GƒŽ$Üø[øÿÿÿÿÿ¶A†C IƒŽ4$]øÿÿÿÿÿQ'¾üÿÿÿÿÿA†C MƒŒŽ4\¸^øÿÿÿÿÿ8¾üÿÿÿÿÿA†C KƒŒŽ4”À_øÿÿÿÿÿQ¾üÿÿÿÿÿA†C MƒŒŽ,Ìè`øÿÿÿÿÿ ¾üÿÿÿÿÿA†C LƒŽ4üXdøÿÿÿÿÿÊ3¾üÿÿÿÿÿA†C MƒŒŽ,4ðeøÿÿÿÿÿÒ7¾üÿÿÿÿÿA†C IƒŽ4d føÿÿÿÿÿÄC¾üÿÿÿÿÿA†C MƒŒŽ4œ8høÿÿÿÿÿÎk¾üÿÿÿÿÿA†C MƒŒŽ,ÔÐiøÿÿÿÿÿᇾüÿÿÿÿÿA†C LƒŽ$ämøÿÿÿÿÿA†C $ ˆmøÿÿÿÿÿrA†C IƒŽ4TànøÿÿÿÿÿBÓ¾üÿÿÿÿÿA†C MƒŒŽ,ŒøpøÿÿÿÿÿBã¾üÿÿÿÿÿA†C LƒŽ4¼søÿÿÿÿÿÞï¾üÿÿÿÿÿA†C KƒŒŽ4ôÀsøÿÿÿÿÿÞã¾üÿÿÿÿÿA†C KƒŒŽ, htøÿÿÿÿÿ^A†C MƒŒŽ,<˜uøÿÿÿÿÿÁA†C PƒŒŽ$lXxøÿÿÿÿÿæÞ†C $”0yøÿÿÿÿÿA†C ,¼zøÿÿÿÿÿîA†C KƒŒŽ,ìø{øÿÿÿÿÿ(A†C PƒŒŽ,€øÿÿÿÿÿTA†C GƒŒŽ$LHøÿÿÿÿÿ¡A†C Hƒ$tÐøÿÿÿÿÿA†C $œÈøÿÿÿÿÿ A†C $İøÿÿÿÿÿ A†C $ì˜øÿÿÿÿÿ A†C $€øÿÿÿÿÿ A†C $<høÿÿÿÿÿ A†C $dPøÿÿÿÿÿA†C Bƒ$ŒHøÿÿÿÿÿoA†C CƒŽ$´øÿÿÿÿÿ?A†C Bƒ,ü¨øÿÿÿÿÿr¼üÿÿÿÿÿA†C Bƒ4,øøÿÿÿÿÿê÷»üÿÿÿÿÿA†C KƒŒŽ$D°‚øÿÿÿÿÿFw†C $lØ‚øÿÿÿÿÿ0A†C Eƒ$”à‚øÿÿÿÿÿGA†C Eƒ$¼ƒøÿÿÿÿÿ A†C 4ð‚øÿÿÿÿÿ?»üÿÿÿÿÿA†C MƒŒŽ,<È„øÿÿÿÿÿ3[»üÿÿÿÿÿA†C GƒŽ$LØ…øÿÿÿÿÿBA†C $t†øÿÿÿÿÿ A†C $œè…øÿÿÿÿÿýA†C IƒŽ$ÄÀ†øÿÿÿÿÿ5A†C GƒŽ$ì؆øÿÿÿÿÿ?A†C Eƒ$ð†øÿÿÿÿÿ A†C Bƒ$<è†øÿÿÿÿÿ(A†C FƒŽ4„ð‡øÿÿÿÿÿ3ºüÿÿÿÿÿA†C GƒŒŽ,œ؈øÿÿÿÿÿ_A†C PƒŒŽ$Ì øÿÿÿÿÿA†C $ô øÿÿÿÿÿA†C ,<øŸøÿÿÿÿÿ—ϹüÿÿÿÿÿA†C GƒŽ,lh¢øÿÿÿÿÿóºüÿÿÿÿÿA†C LƒŽ4œ8¦øÿÿÿÿÿäKºüÿÿÿÿÿA†C KƒŒŽ$´ð¦øÿÿÿÿÿA†C GƒŽ$Üh§øÿÿÿÿÿƒA†C $ЧøÿÿÿÿÿBO†C $,ø§øÿÿÿÿÿ‘A†C IƒŽ4tp©øÿÿÿÿÿ©Ÿ¹üÿÿÿÿÿA†C PƒŒŽ,Œè«øÿÿÿÿÿþA†C MƒŒŽ$¼¸¬øÿÿÿÿÿ A†C ,ä ¬øÿÿÿÿÿA†C MƒŒŽ, €®øÿÿÿÿÿãA†C MƒŒŽ$D @¯øÿÿÿÿÿA†C LƒŽ$l 8°øÿÿÿÿÿ A†C $” °øÿÿÿÿÿÉA†C Hƒ,ÜȰøÿÿÿÿÿ•¸üÿÿÿÿÿA†C GƒŽ4 8±øÿÿÿÿÿc{¸üÿÿÿÿÿA†C NƒŒŽ$$!pµøÿÿÿÿÿ—A†C Eƒ4l èµøÿÿÿÿÿ ³¸üÿÿÿÿÿA†C PƒŒŽ,¤ À¹øÿÿÿÿÿÔ·¸üÿÿÿÿÿA†C IƒŽ$´!pºøÿÿÿÿÿ A†C $Ü!Xºøÿÿÿÿÿ A†C $"@ºøÿÿÿÿÿ A†C $,"(ºøÿÿÿÿÿ=A†C CƒŽ$T"@ºøÿÿÿÿÿ¥A†C Eƒ$|"ȺøÿÿÿÿÿA†C 4Ä!ÀºøÿÿÿÿÿÁ÷üÿÿÿÿÿA†C KƒŒŽ4ü!X½øÿÿÿÿÿšß·üÿÿÿÿÿA†C PƒŒŽ$#ÀÂøÿÿÿÿÿTA†C $<#øÂøÿÿÿÿÿA†C $d#àÂøÿÿÿÿÿQA†C $Œ#Ãøÿÿÿÿÿ8A†C ,Ô"0ÃøÿÿÿÿÿÀë·üÿÿÿÿÿA†C Eƒ$ä#ÀÃøÿÿÿÿÿEA†C FƒŽ$ $èÃøÿÿÿÿÿeA†C Eƒ4T#0ÄøÿÿÿÿÿÞ—·üÿÿÿÿÿA†C NƒŒŽ$l$ØÅøÿÿÿÿÿWA†C ,´#Æøÿÿÿÿÿ0·üÿÿÿÿÿA†C IƒŽ4ä#Çøÿÿÿÿÿ9‹·üÿÿÿÿÿA†C MƒŒŽ$ü$ÉøÿÿÿÿÿA†C $$%Éøÿÿÿÿÿ'X†C $L%Éøÿÿÿÿÿ$U†C ,t% ÉøÿÿÿÿÿïA†C PƒŒŽzRx $ØÊøÿÿÿÿÿKA†C CƒŽ,DËøÿÿÿÿÿ„A†C PƒŒŽ$t`ÍøÿÿÿÿÿœA†C FƒŽzPLRx›… 4$èÎøÿÿÿÿÿ\¶üÿÿÿÿÿA†C GƒŒŽ$ôÏøÿÿÿÿÿ™A†C GƒŽ$ˆÏøÿÿÿÿÿA†C $D€ÏøÿÿÿÿÿA†C zRx $`ÏøÿÿÿÿÿTA†C CƒŽ$D¨ÏøÿÿÿÿÿA†C $lÏøÿÿÿÿÿXA†C ,”ÈÏøÿÿÿÿÿöA†C GƒŒŽzPLRx›õ ,$xÐøÿÿÿÿÿ²·´üÿÿÿÿÿA†C Eƒ,ÑøÿÿÿÿÿcA†C GƒŒŽ4„HÑøÿÿÿÿÿ(w´üÿÿÿÿÿA†C MƒŒŽ,|@éøÿÿÿÿÿ¹A†C KƒŒŽ$¬ÐêøÿÿÿÿÿA†C ,ÔÈêøÿÿÿÿÿdA†C GƒŒŽ,ëøÿÿÿÿÿcA†C GƒŒŽ$4HëøÿÿÿÿÿA†C $\@ëøÿÿÿÿÿ{A†C CƒŽzRx $€ëøÿÿÿÿÿØA†C $D8ìøÿÿÿÿÿA†C $l0ìøÿÿÿÿÿA†C $”(ìøÿÿÿÿÿA†C $¼ìøÿÿÿÿÿ-Y†C ,äìøÿÿÿÿÿ{A†C MƒŒŽzRx $PíøÿÿÿÿÿA†C $D8íøÿÿÿÿÿ A†C $l íøÿÿÿÿÿ A†C zRx $ðìøÿÿÿÿÿ#A†C $Døìøÿÿÿÿÿ%A†C $líøÿÿÿÿÿ#A†C zRx $€ûÿÿÿÿÿ²A†C CƒŽ,D!ûÿÿÿÿÿÉA†C PƒŒŽ,t¸5ûÿÿÿÿÿ—A†C PƒŒŽ,¤(Fûÿÿÿÿÿ1 A†C PƒŒŽ,Ô8OûÿÿÿÿÿhA†C MƒŒŽ$xUûÿÿÿÿÿéA†C $,@VûÿÿÿÿÿóA†C Bƒ$TWûÿÿÿÿÿÆA†C FƒŽ,|ÀXûÿÿÿÿÿMA†C PƒŒŽ$¬à[ûÿÿÿÿÿAA†C $Ô\ûÿÿÿÿÿA†C Bƒ$ü\ûÿÿÿÿÿ A†C $$è\ûÿÿÿÿÿžA†C GƒŽ$L`]ûÿÿÿÿÿ-A†C $th]ûÿÿÿÿÿ'Z†C $œp]ûÿÿÿÿÿeA†C $ĸ]ûÿÿÿÿÿiA†C $ì^ûÿÿÿÿÿ…A†C $h^ûÿÿÿÿÿ^A†C $< ^ûÿÿÿÿÿjA†C $dè^ûÿÿÿÿÿjA†C ,Œ0_ûÿÿÿÿÿbA†C MƒŒŽ$¼pgûÿÿÿÿÿžA†C GƒŽ$äègûÿÿÿÿÿ A†C , Ðgûÿÿÿÿÿ7A†C GƒŒŽ$<àiûÿÿÿÿÿ™A†C $dXkûÿÿÿÿÿ A†C $Œ@kûÿÿÿÿÿŸA†C $´¸kûÿÿÿÿÿ A†C $Ü kûÿÿÿÿÿ˜A†C $lûÿÿÿÿÿ™A†C $,lûÿÿÿÿÿ›A†C $Tmûÿÿÿÿÿ A†C $|ðlûÿÿÿÿÿ„A†C $¤XmûÿÿÿÿÿšA†C $ÌÐmûÿÿÿÿÿšA†C $ôHnûÿÿÿÿÿ A†C $0nûÿÿÿÿÿ A†C $Dnûÿÿÿÿÿ A†C $lnûÿÿÿÿÿ A†C $”èmûÿÿÿÿÿ™A†C $¼`nûÿÿÿÿÿA†C $äHoûÿÿÿÿÿA†C Eƒ$ @pûÿÿÿÿÿýA†C $4qûÿÿÿÿÿAA†C GƒŽ$\@rûÿÿÿÿÿ%A†C Eƒ$„HsûÿÿÿÿÿAA†C GƒŽ$¬ptûÿÿÿÿÿ%A†C Eƒ,ÔxuûÿÿÿÿÿÂA†C JƒŒŽ$wûÿÿÿÿÿ0A†C CƒŽ$, wûÿÿÿÿÿzA†C Hƒ$TxxûÿÿÿÿÿMA†C Bƒ$| xûÿÿÿÿÿGA†C FƒŽ$¤Èxûÿÿÿÿÿ{A†C Hƒ$Ì zûÿÿÿÿÿ—A†C CƒŽ$ô˜zûÿÿÿÿÿpA†C JƒŽ$ à{ûÿÿÿÿÿfA†C GƒŽ$D (|ûÿÿÿÿÿA†C Bƒ$l |ûÿÿÿÿÿxA†C Bƒ$” x|ûÿÿÿÿÿfA†C GƒŽ$¼ À|ûÿÿÿÿÿ«A†C JƒŽ$ä H~ûÿÿÿÿÿ›A†C $ À~ûÿÿÿÿÿA†C $4 ¸~ûÿÿÿÿÿÃu†C $\ `ûÿÿÿÿÿUA†C $„ ˜ûÿÿÿÿÿ A†C $¬ €ûÿÿÿÿÿ A†C $Ô hûÿÿÿÿÿXA†C $ü  ûÿÿÿÿÿ A†C $$ ˆûÿÿÿÿÿA†C $L €ûÿÿÿÿÿQA†C ,t ¸ûÿÿÿÿÿ‘A†C MƒŒŽ,¤ (ƒûÿÿÿÿÿLA†C MƒŒŽ,Ô Hˆûÿÿÿÿÿ‰A†C MƒŒŽ, ¨‹ûÿÿÿÿÿýA†C MƒŒŽ,4 xŽûÿÿÿÿÿOA†C JƒŒŽ$d ˜ûÿÿÿÿÿTA†C $Œ Ðûÿÿÿÿÿ A†C $´ ¸ûÿÿÿÿÿA†C $Ü °ûÿÿÿÿÿ A†C $ ˜ûÿÿÿÿÿ A†C $, €ûÿÿÿÿÿA†C $T xûÿÿÿÿÿA†C $| àûÿÿÿÿÿA†C $¤ Øûÿÿÿÿÿ.A†C ,Ì àûÿÿÿÿÿÇA†C MƒŒŽ$ü •ûÿÿÿÿÿA†C $$•ûÿÿÿÿÿÝA†C ,LÀ•ûÿÿÿÿÿš A†C PƒŒŽ$|0 ûÿÿÿÿÿA†C $¤( ûÿÿÿÿÿA†C $Ì  ûÿÿÿÿÿfA†C gimli-0.19.0/rustfmt.toml010066400017500001750000000000001343337721300135220ustar0000000000000000gimli-0.19.0/src/arch.rs010066400017500001750000000120111346020377600132020ustar0000000000000000use crate::common::Register; macro_rules! registers { ($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? }) => { #[allow(missing_docs)] impl $struct_name { $( pub const $name: Register = Register($val); )+ } impl $struct_name { /// The name of a register, or `None` if the register number is unknown. pub fn register_name(register: Register) -> Option<&'static str> { match register { $( Self::$name => Some($disp), )+ _ => return None, } } } }; } /// ARM architecture specific definitions. /// /// See [DWARF for the ARM Architecture](http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf). #[derive(Debug, Clone, Copy)] pub struct Arm; // TODO: add more registers. registers!(Arm, { R0 = (0, "R0"), R1 = (1, "R1"), R2 = (2, "R2"), R3 = (3, "R3"), R4 = (4, "R4"), R5 = (5, "R5"), R6 = (6, "R6"), R7 = (7, "R7"), R8 = (8, "R8"), R9 = (9, "R9"), R10 = (10, "R10"), R11 = (11, "R11"), R12 = (12, "R12"), R13 = (13, "R13"), R14 = (14, "R14"), R15 = (15, "R15"), }); /// Intel i386 architecture specific definitions. /// /// See Intel386 psABi version 1.1 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). #[derive(Debug, Clone, Copy)] pub struct X86; registers!(X86, { EAX = (0, "eax"), ECX = (1, "ecx"), EDX = (2, "edx"), EBX = (3, "ebx"), ESP = (4, "esp"), EBP = (5, "ebp"), ESI = (6, "esi"), EDI = (7, "edi"), // Return Address register. This is stored in `0(%esp, "")` and is not a physical register. RA = (8, "RA"), ST0 = (11, "st0"), ST1 = (12, "st1"), ST2 = (13, "st2"), ST3 = (14, "st3"), ST4 = (15, "st4"), ST5 = (16, "st5"), ST6 = (17, "st6"), ST7 = (18, "st7"), XMM0 = (21, "xmm0"), XMM1 = (22, "xmm1"), XMM2 = (23, "xmm2"), XMM3 = (24, "xmm3"), XMM4 = (25, "xmm4"), XMM5 = (26, "xmm5"), XMM6 = (27, "xmm6"), XMM7 = (28, "xmm7"), MM0 = (29, "mm0"), MM1 = (30, "mm1"), MM2 = (31, "mm2"), MM3 = (32, "mm3"), MM4 = (33, "mm4"), MM5 = (34, "mm5"), MM6 = (35, "mm6"), MM7 = (36, "mm7"), MXCSR = (39, "mxcsr"), ES = (40, "es"), CS = (41, "cs"), SS = (42, "ss"), DS = (43, "ds"), FS = (44, "fs"), GS = (45, "gs"), TR = (48, "tr"), LDTR = (49, "ldtr"), FS_BASE = (93, "fs.base"), GS_BASE = (94, "gs.base"), }); /// AMD64 architecture specific definitions. /// /// See x86-64 psABI version 1.0 at the [X86 psABI wiki](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI). #[derive(Debug, Clone, Copy)] pub struct X86_64; registers!(X86_64, { RAX = (0, "rax"), RDX = (1, "rdx"), RCX = (2, "rcx"), RBX = (3, "rbx"), RSI = (4, "rsi"), RDI = (5, "rdi"), RBP = (6, "rbp"), RSP = (7, "rsp"), R8 = (8, "r8"), R9 = (9, "r9"), R10 = (10, "r10"), R11 = (11, "r11"), R12 = (12, "r12"), R13 = (13, "r13"), R14 = (14, "r14"), R15 = (15, "r15"), // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register. RA = (16, "RA"), XMM0 = (17, "xmm0"), XMM1 = (18, "xmm1"), XMM2 = (19, "xmm2"), XMM3 = (20, "xmm3"), XMM4 = (21, "xmm4"), XMM5 = (22, "xmm5"), XMM6 = (23, "xmm6"), XMM7 = (24, "xmm7"), XMM8 = (25, "xmm8"), XMM9 = (26, "xmm9"), XMM10 = (27, "xmm10"), XMM11 = (28, "xmm11"), XMM12 = (29, "xmm12"), XMM13 = (30, "xmm13"), XMM14 = (31, "xmm14"), XMM15 = (32, "xmm15"), ST0 = (33, "st0"), ST1 = (34, "st1"), ST2 = (35, "st2"), ST3 = (36, "st3"), ST4 = (37, "st4"), ST5 = (38, "st5"), ST6 = (39, "st6"), ST7 = (40, "st7"), MM0 = (41, "mm0"), MM1 = (42, "mm1"), MM2 = (43, "mm2"), MM3 = (44, "mm3"), MM4 = (45, "mm4"), MM5 = (46, "mm5"), MM6 = (47, "mm6"), MM7 = (48, "mm7"), RFLAGS = (49, "rFLAGS"), ES = (50, "es"), CS = (51, "cs"), SS = (52, "ss"), DS = (53, "ds"), FS = (54, "fs"), GS = (55, "gs"), FS_BASE = (58, "fs.base"), GS_BASE = (59, "gs.base"), TR = (62, "tr"), LDTR = (63, "ldtr"), MXCSR = (64, "mxcsr"), FCW = (65, "fcw"), FSW = (66, "fsw"), XMM16 = (67, "xmm16"), XMM17 = (68, "xmm17"), XMM18 = (69, "xmm18"), XMM19 = (70, "xmm19"), XMM20 = (71, "xmm20"), XMM21 = (72, "xmm21"), XMM22 = (73, "xmm22"), XMM23 = (74, "xmm23"), XMM24 = (75, "xmm24"), XMM25 = (76, "xmm25"), XMM26 = (77, "xmm26"), XMM27 = (78, "xmm27"), XMM28 = (79, "xmm28"), XMM29 = (80, "xmm29"), XMM30 = (81, "xmm30"), XMM31 = (82, "xmm31"), K0 = (118, "k0"), K1 = (119, "k1"), K2 = (120, "k2"), K3 = (121, "k3"), K4 = (122, "k4"), K5 = (123, "k5"), K6 = (124, "k6"), K7 = (125, "k7"), }); gimli-0.19.0/src/common.rs010066400017500001750000000210031346020377600135560ustar0000000000000000/// Whether the format of a compilation unit is 32- or 64-bit. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Format { /// 64-bit DWARF Dwarf64, /// 32-bit DWARF Dwarf32, } impl Format { /// Return the serialized size of an initial length field for the format. #[inline] pub fn initial_length_size(self) -> u8 { match self { Format::Dwarf32 => 4, Format::Dwarf64 => 12, } } /// Return the natural word size for the format #[inline] pub fn word_size(self) -> u8 { match self { Format::Dwarf32 => 4, Format::Dwarf64 => 8, } } } /// Encoding parameters that are commonly used for multiple DWARF sections. /// /// This is intended to be small enough to pass by value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Encoding { /// Whether the DWARF format is 32- or 64-bit. pub format: Format, /// The DWARF version of the header. pub version: u16, /// The size of an address. pub address_size: u8, // The size of a segment selector. // TODO: pub segment_size: u8, } /// Encoding parameters for a line number program. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LineEncoding { /// The size in bytes of the smallest target machine instruction. pub minimum_instruction_length: u8, /// The maximum number of individual operations that may be encoded in an /// instruction. pub maximum_operations_per_instruction: u8, /// The initial value of the `is_stmt` register. pub default_is_stmt: bool, /// The minimum value which a special opcode can add to the line register. pub line_base: i8, /// The range of values which a special opcode can add to the line register. pub line_range: u8, } impl Default for LineEncoding { fn default() -> Self { // Values from LLVM. LineEncoding { minimum_instruction_length: 1, maximum_operations_per_instruction: 1, default_is_stmt: true, line_base: -5, line_range: 14, } } } /// A DWARF register number. /// /// The meaning of this value is ABI dependent. This is generally encoded as /// a ULEB128, but supported architectures need 16 bits at most. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Register(pub u16); /// An offset into the `.debug_abbrev` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugAbbrevOffset(pub T); /// An offset to a set of entries in the `.debug_addr` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugAddrBase(pub T); /// An index into a set of addresses in the `.debug_addr` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugAddrIndex(pub T); /// An offset into the `.debug_info` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct DebugInfoOffset(pub T); /// An offset into the `.debug_line` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugLineOffset(pub T); /// An offset into the `.debug_line_str` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugLineStrOffset(pub T); /// An offset into either the `.debug_loc` section or the `.debug_loclists` section, /// depending on the version of the unit the offset was contained in. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LocationListsOffset(pub T); /// An offset to a set of location list offsets in the `.debug_loclists` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugLocListsBase(pub T); /// An index into a set of location list offsets in the `.debug_loclists` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugLocListsIndex(pub T); /// An offset into the `.debug_macinfo` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugMacinfoOffset(pub T); /// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, /// depending on the version of the unit the offset was contained in. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RangeListsOffset(pub T); /// An offset to a set of range list offsets in the `.debug_rnglists` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugRngListsBase(pub T); /// An index into a set of range list offsets in the `.debug_rnglists` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugRngListsIndex(pub T); /// An offset into the `.debug_str` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugStrOffset(pub T); /// An offset to a set of entries in the `.debug_str_offsets` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugStrOffsetsBase(pub T); /// An index into a set of entries in the `.debug_str_offsets` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugStrOffsetsIndex(pub T); /// An offset into the `.debug_types` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct DebugTypesOffset(pub T); /// A type signature as used in the `.debug_types` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugTypeSignature(pub u64); /// An offset into the `.debug_frame` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugFrameOffset(pub T); impl From for DebugFrameOffset { #[inline] fn from(o: T) -> Self { DebugFrameOffset(o) } } /// An offset into the `.eh_frame` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EhFrameOffset(pub T); impl From for EhFrameOffset { #[inline] fn from(o: T) -> Self { EhFrameOffset(o) } } /// An offset into the `.debug_info` or `.debug_types` sections. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum UnitSectionOffset { /// An offset into the `.debug_info` section. DebugInfoOffset(DebugInfoOffset), /// An offset into the `.debug_types` section. DebugTypesOffset(DebugTypesOffset), } /// An identifier for a DWARF section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum SectionId { /// The `.debug_abbrev` section. DebugAbbrev, /// The `.debug_addr` section. DebugAddr, /// The `.debug_aranges` section. DebugAranges, /// The `.debug_frame` section. DebugFrame, /// The `.eh_frame` section. EhFrame, /// The `.eh_frame_hdr` section. EhFrameHdr, /// The `.debug_info` section. DebugInfo, /// The `.debug_line` section. DebugLine, /// The `.debug_line_str` section. DebugLineStr, /// The `.debug_loc` section. DebugLoc, /// The `.debug_loclists` section. DebugLocLists, /// The `.debug_macinfo` section. DebugMacinfo, /// The `.debug_pubnames` section. DebugPubNames, /// The `.debug_pubtypes` section. DebugPubTypes, /// The `.debug_ranges` section. DebugRanges, /// The `.debug_rnglists` section. DebugRngLists, /// The `.debug_str` section. DebugStr, /// The `.debug_str_offsets` section. DebugStrOffsets, /// The `.debug_types` section. DebugTypes, } impl SectionId { /// Returns the ELF section name for this kind. pub fn name(self) -> &'static str { match self { SectionId::DebugAbbrev => ".debug_abbrev", SectionId::DebugAddr => ".debug_addr", SectionId::DebugAranges => ".debug_aranges", SectionId::DebugFrame => ".debug_frame", SectionId::EhFrame => ".eh_frame", SectionId::EhFrameHdr => ".eh_frame_hdr", SectionId::DebugInfo => ".debug_info", SectionId::DebugLine => ".debug_line", SectionId::DebugLineStr => ".debug_line_str", SectionId::DebugLoc => ".debug_loc", SectionId::DebugLocLists => ".debug_loclists", SectionId::DebugMacinfo => ".debug_macinfo", SectionId::DebugPubNames => ".debug_pubnames", SectionId::DebugPubTypes => ".debug_pubtypes", SectionId::DebugRanges => ".debug_ranges", SectionId::DebugRngLists => ".debug_rnglists", SectionId::DebugStr => ".debug_str", SectionId::DebugStrOffsets => ".debug_str_offsets", SectionId::DebugTypes => ".debug_types", } } } gimli-0.19.0/src/constants.rs010066400017500001750000001133301346020377600143070ustar0000000000000000// This file originally from https://github.com/philipc/rust-dwarf/ and // distributed under either MIT or Apache 2.0 licenses. // // Copyright 2016 The rust-dwarf Developers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Constant definitions. //! //! The DWARF spec's `DW_AT_*` type is represented as `struct DwAt(u16)`, //! `DW_FORM_*` as `DwForm(u16)`, etc. //! //! There are also exported const definitions for each constant. #![allow(non_upper_case_globals)] #![allow(missing_docs)] use std::fmt; // The `dw!` macro turns this: // // dw!(DwFoo(u32) { // DW_FOO_bar = 0, // DW_FOO_baz = 1, // DW_FOO_bang = 2, // }); // // into this: // // #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] // pub struct DwFoo(pub u32); // // pub const DW_FOO_bar: DwFoo = DwFoo(0); // pub const DW_FOO_baz: DwFoo = DwFoo(1); // pub const DW_FOO_bang: DwFoo = DwFoo(2); // // impl DwFoo { // pub fn static_string(&self) -> Option<&'static str> { // ... // } // } // // impl fmt::Display for DwFoo { // fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { // ... // } // } macro_rules! dw { ($(#[$meta:meta])* $struct_name:ident($struct_type:ty) { $($name:ident = $val:expr),+ $(,)? }) => { $(#[$meta])* #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct $struct_name(pub $struct_type); $( pub const $name: $struct_name = $struct_name($val); )+ impl $struct_name { pub fn static_string(&self) -> Option<&'static str> { Some(match *self { $( $name => stringify!($name), )+ _ => return None, }) } } impl fmt::Display for $struct_name { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { if let Some(s) = self.static_string() { f.pad(s) } else { f.pad(&format!("Unknown {}: {}", stringify!($struct_name), self.0)) } } } }; } dw!( /// The unit type field in a unit header. /// /// See Section 7.5.1, Table 7.2. DwUt(u8) { DW_UT_compile = 0x01, DW_UT_type = 0x02, DW_UT_partial = 0x03, DW_UT_skeleton = 0x04, DW_UT_split_compile = 0x05, DW_UT_split_type = 0x06, DW_UT_lo_user = 0x80, DW_UT_hi_user = 0xff, }); dw!( /// The opcode for a call frame instruction. /// /// Section 7.24: /// > Call frame instructions are encoded in one or more bytes. The primary /// > opcode is encoded in the high order two bits of the first byte (that is, /// > opcode = byte >> 6). An operand or extended opcode may be encoded in the /// > low order 6 bits. Additional operands are encoded in subsequent bytes. DwCfa(u8) { DW_CFA_advance_loc = 0x01 << 6, DW_CFA_offset = 0x02 << 6, DW_CFA_restore = 0x03 << 6, DW_CFA_nop = 0, DW_CFA_set_loc = 0x01, DW_CFA_advance_loc1 = 0x02, DW_CFA_advance_loc2 = 0x03, DW_CFA_advance_loc4 = 0x04, DW_CFA_offset_extended = 0x05, DW_CFA_restore_extended = 0x06, DW_CFA_undefined = 0x07, DW_CFA_same_value = 0x08, DW_CFA_register = 0x09, DW_CFA_remember_state = 0x0a, DW_CFA_restore_state = 0x0b, DW_CFA_def_cfa = 0x0c, DW_CFA_def_cfa_register = 0x0d, DW_CFA_def_cfa_offset = 0x0e, DW_CFA_def_cfa_expression = 0x0f, DW_CFA_expression = 0x10, DW_CFA_offset_extended_sf = 0x11, DW_CFA_def_cfa_sf = 0x12, DW_CFA_def_cfa_offset_sf = 0x13, DW_CFA_val_offset = 0x14, DW_CFA_val_offset_sf = 0x15, DW_CFA_val_expression = 0x16, DW_CFA_lo_user = 0x1c, DW_CFA_hi_user = 0x3f, DW_CFA_MIPS_advance_loc8 = 0x1d, DW_CFA_GNU_window_save = 0x2d, DW_CFA_GNU_args_size = 0x2e, DW_CFA_GNU_negative_offset_extended = 0x2f, }); dw!( /// The child determination encodings for DIE attributes. /// /// See Section 7.5.3, Table 7.4. DwChildren(u8) { DW_CHILDREN_no = 0, DW_CHILDREN_yes = 1, }); dw!( /// The tag encodings for DIE attributes. /// /// See Section 7.5.3, Table 7.3. DwTag(u64) { DW_TAG_null = 0x00, DW_TAG_array_type = 0x01, DW_TAG_class_type = 0x02, DW_TAG_entry_point = 0x03, DW_TAG_enumeration_type = 0x04, DW_TAG_formal_parameter = 0x05, DW_TAG_imported_declaration = 0x08, DW_TAG_label = 0x0a, DW_TAG_lexical_block = 0x0b, DW_TAG_member = 0x0d, DW_TAG_pointer_type = 0x0f, DW_TAG_reference_type = 0x10, DW_TAG_compile_unit = 0x11, DW_TAG_string_type = 0x12, DW_TAG_structure_type = 0x13, DW_TAG_subroutine_type = 0x15, DW_TAG_typedef = 0x16, DW_TAG_union_type = 0x17, DW_TAG_unspecified_parameters = 0x18, DW_TAG_variant = 0x19, DW_TAG_common_block = 0x1a, DW_TAG_common_inclusion = 0x1b, DW_TAG_inheritance = 0x1c, DW_TAG_inlined_subroutine = 0x1d, DW_TAG_module = 0x1e, DW_TAG_ptr_to_member_type = 0x1f, DW_TAG_set_type = 0x20, DW_TAG_subrange_type = 0x21, DW_TAG_with_stmt = 0x22, DW_TAG_access_declaration = 0x23, DW_TAG_base_type = 0x24, DW_TAG_catch_block = 0x25, DW_TAG_const_type = 0x26, DW_TAG_constant = 0x27, DW_TAG_enumerator = 0x28, DW_TAG_file_type = 0x29, DW_TAG_friend = 0x2a, DW_TAG_namelist = 0x2b, DW_TAG_namelist_item = 0x2c, DW_TAG_packed_type = 0x2d, DW_TAG_subprogram = 0x2e, DW_TAG_template_type_parameter = 0x2f, DW_TAG_template_value_parameter = 0x30, DW_TAG_thrown_type = 0x31, DW_TAG_try_block = 0x32, DW_TAG_variant_part = 0x33, DW_TAG_variable = 0x34, DW_TAG_volatile_type = 0x35, // DWARF 3. DW_TAG_dwarf_procedure = 0x36, DW_TAG_restrict_type = 0x37, DW_TAG_interface_type = 0x38, DW_TAG_namespace = 0x39, DW_TAG_imported_module = 0x3a, DW_TAG_unspecified_type = 0x3b, DW_TAG_partial_unit = 0x3c, DW_TAG_imported_unit = 0x3d, DW_TAG_condition = 0x3f, DW_TAG_shared_type = 0x40, // DWARF 4. DW_TAG_type_unit = 0x41, DW_TAG_rvalue_reference_type = 0x42, DW_TAG_template_alias = 0x43, // DWARF 5. DW_TAG_coarray_type = 0x44, DW_TAG_generic_subrange = 0x45, DW_TAG_dynamic_type = 0x46, DW_TAG_atomic_type = 0x47, DW_TAG_call_site = 0x48, DW_TAG_call_site_parameter = 0x49, DW_TAG_skeleton_unit = 0x4a, DW_TAG_immutable_type = 0x4b, DW_TAG_lo_user = 0x4080, DW_TAG_hi_user = 0xffff, // SGI/MIPS extensions. DW_TAG_MIPS_loop = 0x4081, // HP extensions. DW_TAG_HP_array_descriptor = 0x4090, DW_TAG_HP_Bliss_field = 0x4091, DW_TAG_HP_Bliss_field_set = 0x4092, // GNU extensions. DW_TAG_format_label = 0x4101, DW_TAG_function_template = 0x4102, DW_TAG_class_template = 0x4103, DW_TAG_GNU_BINCL = 0x4104, DW_TAG_GNU_EINCL = 0x4105, DW_TAG_GNU_template_template_param = 0x4106, DW_TAG_GNU_template_parameter_pack = 0x4107, DW_TAG_GNU_formal_parameter_pack = 0x4108, DW_TAG_GNU_call_site = 0x4109, DW_TAG_GNU_call_site_parameter = 0x410a, DW_TAG_APPLE_property = 0x4200, // SUN extensions. DW_TAG_SUN_function_template = 0x4201, DW_TAG_SUN_class_template = 0x4202, DW_TAG_SUN_struct_template = 0x4203, DW_TAG_SUN_union_template = 0x4204, DW_TAG_SUN_indirect_inheritance = 0x4205, DW_TAG_SUN_codeflags = 0x4206, DW_TAG_SUN_memop_info = 0x4207, DW_TAG_SUN_omp_child_func = 0x4208, DW_TAG_SUN_rtti_descriptor = 0x4209, DW_TAG_SUN_dtor_info = 0x420a, DW_TAG_SUN_dtor = 0x420b, DW_TAG_SUN_f90_interface = 0x420c, DW_TAG_SUN_fortran_vax_structure = 0x420d, // ALTIUM extensions. DW_TAG_ALTIUM_circ_type = 0x5101, DW_TAG_ALTIUM_mwa_circ_type = 0x5102, DW_TAG_ALTIUM_rev_carry_type = 0x5103, DW_TAG_ALTIUM_rom = 0x5111, // Extensions for UPC. DW_TAG_upc_shared_type = 0x8765, DW_TAG_upc_strict_type = 0x8766, DW_TAG_upc_relaxed_type = 0x8767, // PGI (STMicroelectronics) extensions. DW_TAG_PGI_kanji_type = 0xa000, DW_TAG_PGI_interface_block = 0xa020, // Borland extensions. DW_TAG_BORLAND_property = 0xb000, DW_TAG_BORLAND_Delphi_string = 0xb001, DW_TAG_BORLAND_Delphi_dynamic_array = 0xb002, DW_TAG_BORLAND_Delphi_set = 0xb003, DW_TAG_BORLAND_Delphi_variant = 0xb004, }); dw!( /// The attribute encodings for DIE attributes. /// /// See Section 7.5.4, Table 7.5. DwAt(u64) { DW_AT_null = 0x00, DW_AT_sibling = 0x01, DW_AT_location = 0x02, DW_AT_name = 0x03, DW_AT_ordering = 0x09, DW_AT_byte_size = 0x0b, DW_AT_bit_offset = 0x0c, DW_AT_bit_size = 0x0d, DW_AT_stmt_list = 0x10, DW_AT_low_pc = 0x11, DW_AT_high_pc = 0x12, DW_AT_language = 0x13, DW_AT_discr = 0x15, DW_AT_discr_value = 0x16, DW_AT_visibility = 0x17, DW_AT_import = 0x18, DW_AT_string_length = 0x19, DW_AT_common_reference = 0x1a, DW_AT_comp_dir = 0x1b, DW_AT_const_value = 0x1c, DW_AT_containing_type = 0x1d, DW_AT_default_value = 0x1e, DW_AT_inline = 0x20, DW_AT_is_optional = 0x21, DW_AT_lower_bound = 0x22, DW_AT_producer = 0x25, DW_AT_prototyped = 0x27, DW_AT_return_addr = 0x2a, DW_AT_start_scope = 0x2c, DW_AT_bit_stride = 0x2e, DW_AT_upper_bound = 0x2f, DW_AT_abstract_origin = 0x31, DW_AT_accessibility = 0x32, DW_AT_address_class = 0x33, DW_AT_artificial = 0x34, DW_AT_base_types = 0x35, DW_AT_calling_convention = 0x36, DW_AT_count = 0x37, DW_AT_data_member_location = 0x38, DW_AT_decl_column = 0x39, DW_AT_decl_file = 0x3a, DW_AT_decl_line = 0x3b, DW_AT_declaration = 0x3c, DW_AT_discr_list = 0x3d, DW_AT_encoding = 0x3e, DW_AT_external = 0x3f, DW_AT_frame_base = 0x40, DW_AT_friend = 0x41, DW_AT_identifier_case = 0x42, DW_AT_macro_info = 0x43, DW_AT_namelist_item = 0x44, DW_AT_priority = 0x45, DW_AT_segment = 0x46, DW_AT_specification = 0x47, DW_AT_static_link = 0x48, DW_AT_type = 0x49, DW_AT_use_location = 0x4a, DW_AT_variable_parameter = 0x4b, DW_AT_virtuality = 0x4c, DW_AT_vtable_elem_location = 0x4d, // DWARF 3. DW_AT_allocated = 0x4e, DW_AT_associated = 0x4f, DW_AT_data_location = 0x50, DW_AT_byte_stride = 0x51, DW_AT_entry_pc = 0x52, DW_AT_use_UTF8 = 0x53, DW_AT_extension = 0x54, DW_AT_ranges = 0x55, DW_AT_trampoline = 0x56, DW_AT_call_column = 0x57, DW_AT_call_file = 0x58, DW_AT_call_line = 0x59, DW_AT_description = 0x5a, DW_AT_binary_scale = 0x5b, DW_AT_decimal_scale = 0x5c, DW_AT_small = 0x5d, DW_AT_decimal_sign = 0x5e, DW_AT_digit_count = 0x5f, DW_AT_picture_string = 0x60, DW_AT_mutable = 0x61, DW_AT_threads_scaled = 0x62, DW_AT_explicit = 0x63, DW_AT_object_pointer = 0x64, DW_AT_endianity = 0x65, DW_AT_elemental = 0x66, DW_AT_pure = 0x67, DW_AT_recursive = 0x68, // DWARF 4. DW_AT_signature = 0x69, DW_AT_main_subprogram = 0x6a, DW_AT_data_bit_offset = 0x6b, DW_AT_const_expr = 0x6c, DW_AT_enum_class = 0x6d, DW_AT_linkage_name = 0x6e, // DWARF 5. DW_AT_string_length_bit_size = 0x6f, DW_AT_string_length_byte_size = 0x70, DW_AT_rank = 0x71, DW_AT_str_offsets_base = 0x72, DW_AT_addr_base = 0x73, DW_AT_rnglists_base = 0x74, DW_AT_dwo_name = 0x76, DW_AT_reference = 0x77, DW_AT_rvalue_reference = 0x78, DW_AT_macros = 0x79, DW_AT_call_all_calls = 0x7a, DW_AT_call_all_source_calls = 0x7b, DW_AT_call_all_tail_calls = 0x7c, DW_AT_call_return_pc = 0x7d, DW_AT_call_value = 0x7e, DW_AT_call_origin = 0x7f, DW_AT_call_parameter = 0x80, DW_AT_call_pc = 0x81, DW_AT_call_tail_call = 0x82, DW_AT_call_target = 0x83, DW_AT_call_target_clobbered = 0x84, DW_AT_call_data_location = 0x85, DW_AT_call_data_value = 0x86, DW_AT_noreturn = 0x87, DW_AT_alignment = 0x88, DW_AT_export_symbols = 0x89, DW_AT_deleted = 0x8a, DW_AT_defaulted = 0x8b, DW_AT_loclists_base = 0x8c, DW_AT_lo_user = 0x2000, DW_AT_hi_user = 0x3fff, // SGI/MIPS extensions. DW_AT_MIPS_fde = 0x2001, DW_AT_MIPS_loop_begin = 0x2002, DW_AT_MIPS_tail_loop_begin = 0x2003, DW_AT_MIPS_epilog_begin = 0x2004, DW_AT_MIPS_loop_unroll_factor = 0x2005, DW_AT_MIPS_software_pipeline_depth = 0x2006, DW_AT_MIPS_linkage_name = 0x2007, DW_AT_MIPS_stride = 0x2008, DW_AT_MIPS_abstract_name = 0x2009, DW_AT_MIPS_clone_origin = 0x200a, DW_AT_MIPS_has_inlines = 0x200b, DW_AT_MIPS_stride_byte = 0x200c, DW_AT_MIPS_stride_elem = 0x200d, DW_AT_MIPS_ptr_dopetype = 0x200e, DW_AT_MIPS_allocatable_dopetype = 0x200f, DW_AT_MIPS_assumed_shape_dopetype = 0x2010, // This one appears to have only been implemented by Open64 for // fortran and may conflict with other extensions. DW_AT_MIPS_assumed_size = 0x2011, // TODO: HP/CPQ extensions. // These conflict with the MIPS extensions. DW_AT_INTEL_other_endian = 0x2026, // GNU extensions DW_AT_sf_names = 0x2101, DW_AT_src_info = 0x2102, DW_AT_mac_info = 0x2103, DW_AT_src_coords = 0x2104, DW_AT_body_begin = 0x2105, DW_AT_body_end = 0x2106, DW_AT_GNU_vector = 0x2107, DW_AT_GNU_guarded_by = 0x2108, DW_AT_GNU_pt_guarded_by = 0x2109, DW_AT_GNU_guarded = 0x210a, DW_AT_GNU_pt_guarded = 0x210b, DW_AT_GNU_locks_excluded = 0x210c, DW_AT_GNU_exclusive_locks_required = 0x210d, DW_AT_GNU_shared_locks_required = 0x210e, DW_AT_GNU_odr_signature = 0x210f, DW_AT_GNU_template_name = 0x2110, DW_AT_GNU_call_site_value = 0x2111, DW_AT_GNU_call_site_data_value = 0x2112, DW_AT_GNU_call_site_target = 0x2113, DW_AT_GNU_call_site_target_clobbered = 0x2114, DW_AT_GNU_tail_call = 0x2115, DW_AT_GNU_all_tail_call_sites = 0x2116, DW_AT_GNU_all_call_sites = 0x2117, DW_AT_GNU_all_source_call_sites = 0x2118, DW_AT_GNU_macros = 0x2119, // Extensions for Fission proposal. DW_AT_GNU_dwo_name = 0x2130, DW_AT_GNU_dwo_id = 0x2131, DW_AT_GNU_ranges_base = 0x2132, DW_AT_GNU_addr_base = 0x2133, DW_AT_GNU_pubnames = 0x2134, DW_AT_GNU_pubtypes = 0x2135, DW_AT_GNU_discriminator = 0x2136, // Conflict with Sun. // DW_AT_VMS_rtnbeg_pd_address = 0x2201, // Sun extensions. DW_AT_SUN_template = 0x2201, DW_AT_SUN_alignment = 0x2202, DW_AT_SUN_vtable = 0x2203, DW_AT_SUN_count_guarantee = 0x2204, DW_AT_SUN_command_line = 0x2205, DW_AT_SUN_vbase = 0x2206, DW_AT_SUN_compile_options = 0x2207, DW_AT_SUN_language = 0x2208, DW_AT_SUN_browser_file = 0x2209, DW_AT_SUN_vtable_abi = 0x2210, DW_AT_SUN_func_offsets = 0x2211, DW_AT_SUN_cf_kind = 0x2212, DW_AT_SUN_vtable_index = 0x2213, DW_AT_SUN_omp_tpriv_addr = 0x2214, DW_AT_SUN_omp_child_func = 0x2215, DW_AT_SUN_func_offset = 0x2216, DW_AT_SUN_memop_type_ref = 0x2217, DW_AT_SUN_profile_id = 0x2218, DW_AT_SUN_memop_signature = 0x2219, DW_AT_SUN_obj_dir = 0x2220, DW_AT_SUN_obj_file = 0x2221, DW_AT_SUN_original_name = 0x2222, DW_AT_SUN_hwcprof_signature = 0x2223, DW_AT_SUN_amd64_parmdump = 0x2224, DW_AT_SUN_part_link_name = 0x2225, DW_AT_SUN_link_name = 0x2226, DW_AT_SUN_pass_with_const = 0x2227, DW_AT_SUN_return_with_const = 0x2228, DW_AT_SUN_import_by_name = 0x2229, DW_AT_SUN_f90_pointer = 0x222a, DW_AT_SUN_pass_by_ref = 0x222b, DW_AT_SUN_f90_allocatable = 0x222c, DW_AT_SUN_f90_assumed_shape_array = 0x222d, DW_AT_SUN_c_vla = 0x222e, DW_AT_SUN_return_value_ptr = 0x2230, DW_AT_SUN_dtor_start = 0x2231, DW_AT_SUN_dtor_length = 0x2232, DW_AT_SUN_dtor_state_initial = 0x2233, DW_AT_SUN_dtor_state_final = 0x2234, DW_AT_SUN_dtor_state_deltas = 0x2235, DW_AT_SUN_import_by_lname = 0x2236, DW_AT_SUN_f90_use_only = 0x2237, DW_AT_SUN_namelist_spec = 0x2238, DW_AT_SUN_is_omp_child_func = 0x2239, DW_AT_SUN_fortran_main_alias = 0x223a, DW_AT_SUN_fortran_based = 0x223b, DW_AT_ALTIUM_loclist = 0x2300, DW_AT_use_GNAT_descriptive_type = 0x2301, DW_AT_GNAT_descriptive_type = 0x2302, DW_AT_GNU_numerator = 0x2303, DW_AT_GNU_denominator = 0x2304, DW_AT_GNU_bias = 0x2305, DW_AT_upc_threads_scaled = 0x3210, // PGI (STMicroelectronics) extensions. DW_AT_PGI_lbase = 0x3a00, DW_AT_PGI_soffset = 0x3a01, DW_AT_PGI_lstride = 0x3a02, // Borland extensions. DW_AT_BORLAND_property_read = 0x3b11, DW_AT_BORLAND_property_write = 0x3b12, DW_AT_BORLAND_property_implements = 0x3b13, DW_AT_BORLAND_property_index = 0x3b14, DW_AT_BORLAND_property_default = 0x3b15, DW_AT_BORLAND_Delphi_unit = 0x3b20, DW_AT_BORLAND_Delphi_class = 0x3b21, DW_AT_BORLAND_Delphi_record = 0x3b22, DW_AT_BORLAND_Delphi_metaclass = 0x3b23, DW_AT_BORLAND_Delphi_constructor = 0x3b24, DW_AT_BORLAND_Delphi_destructor = 0x3b25, DW_AT_BORLAND_Delphi_anonymous_method = 0x3b26, DW_AT_BORLAND_Delphi_interface = 0x3b27, DW_AT_BORLAND_Delphi_ABI = 0x3b28, DW_AT_BORLAND_Delphi_return = 0x3b29, DW_AT_BORLAND_Delphi_frameptr = 0x3b30, DW_AT_BORLAND_closure = 0x3b31, // LLVM project extensions. DW_AT_LLVM_include_path = 0x3e00, DW_AT_LLVM_config_macros = 0x3e01, DW_AT_LLVM_isysroot = 0x3e02, // Apple extensions. DW_AT_APPLE_optimized = 0x3fe1, DW_AT_APPLE_flags = 0x3fe2, DW_AT_APPLE_isa = 0x3fe3, DW_AT_APPLE_block = 0x3fe4, DW_AT_APPLE_major_runtime_vers = 0x3fe5, DW_AT_APPLE_runtime_class = 0x3fe6, DW_AT_APPLE_omit_frame_ptr = 0x3fe7, DW_AT_APPLE_property_name = 0x3fe8, DW_AT_APPLE_property_getter = 0x3fe9, DW_AT_APPLE_property_setter = 0x3fea, DW_AT_APPLE_property_attribute = 0x3feb, DW_AT_APPLE_objc_complete_type = 0x3fec, DW_AT_APPLE_property = 0x3fed }); dw!( /// The attribute form encodings for DIE attributes. /// /// See Section 7.5.6, Table 7.6. DwForm(u64) { DW_FORM_null = 0x00, DW_FORM_addr = 0x01, DW_FORM_block2 = 0x03, DW_FORM_block4 = 0x04, DW_FORM_data2 = 0x05, DW_FORM_data4 = 0x06, DW_FORM_data8 = 0x07, DW_FORM_string = 0x08, DW_FORM_block = 0x09, DW_FORM_block1 = 0x0a, DW_FORM_data1 = 0x0b, DW_FORM_flag = 0x0c, DW_FORM_sdata = 0x0d, DW_FORM_strp = 0x0e, DW_FORM_udata = 0x0f, DW_FORM_ref_addr = 0x10, DW_FORM_ref1 = 0x11, DW_FORM_ref2 = 0x12, DW_FORM_ref4 = 0x13, DW_FORM_ref8 = 0x14, DW_FORM_ref_udata = 0x15, DW_FORM_indirect = 0x16, // DWARF 4. DW_FORM_sec_offset = 0x17, DW_FORM_exprloc = 0x18, DW_FORM_flag_present = 0x19, DW_FORM_ref_sig8 = 0x20, // DWARF 5. DW_FORM_strx = 0x1a, DW_FORM_addrx = 0x1b, DW_FORM_ref_sup4 = 0x1c, DW_FORM_strp_sup = 0x1d, DW_FORM_data16 = 0x1e, DW_FORM_line_strp = 0x1f, DW_FORM_implicit_const = 0x21, DW_FORM_loclistx = 0x22, DW_FORM_rnglistx = 0x23, DW_FORM_ref_sup8 = 0x24, DW_FORM_strx1 = 0x25, DW_FORM_strx2 = 0x26, DW_FORM_strx3 = 0x27, DW_FORM_strx4 = 0x28, DW_FORM_addrx1 = 0x29, DW_FORM_addrx2 = 0x2a, DW_FORM_addrx3 = 0x2b, DW_FORM_addrx4 = 0x2c, // Extensions for Fission proposal DW_FORM_GNU_addr_index = 0x1f01, DW_FORM_GNU_str_index = 0x1f02, // Alternate debug sections proposal (output of "dwz" tool). DW_FORM_GNU_ref_alt = 0x1f20, DW_FORM_GNU_strp_alt = 0x1f21 }); dw!( /// The encodings of the constants used in the `DW_AT_encoding` attribute. /// /// See Section 7.8, Table 7.11. DwAte(u8) { DW_ATE_address = 0x01, DW_ATE_boolean = 0x02, DW_ATE_complex_float = 0x03, DW_ATE_float = 0x04, DW_ATE_signed = 0x05, DW_ATE_signed_char = 0x06, DW_ATE_unsigned = 0x07, DW_ATE_unsigned_char = 0x08, // DWARF 3. DW_ATE_imaginary_float = 0x09, DW_ATE_packed_decimal = 0x0a, DW_ATE_numeric_string = 0x0b, DW_ATE_edited = 0x0c, DW_ATE_signed_fixed = 0x0d, DW_ATE_unsigned_fixed = 0x0e, DW_ATE_decimal_float = 0x0f , // DWARF 4. DW_ATE_UTF = 0x10, DW_ATE_UCS = 0x11, DW_ATE_ASCII = 0x12, DW_ATE_lo_user = 0x80, DW_ATE_hi_user = 0xff, }); dw!( /// The encodings of the constants used in location list entries. /// /// See Section 7.7.3, Table 7.10. DwLle(u8) { DW_LLE_end_of_list = 0x00, DW_LLE_base_addressx = 0x01, DW_LLE_startx_endx = 0x02, DW_LLE_startx_length = 0x03, DW_LLE_offset_pair = 0x04, DW_LLE_default_location = 0x05, DW_LLE_base_address = 0x06, DW_LLE_start_end = 0x07, DW_LLE_start_length = 0x08, }); dw!( /// The encodings of the constants used in the `DW_AT_decimal_sign` attribute. /// /// See Section 7.8, Table 7.12. DwDs(u8) { DW_DS_unsigned = 0x01, DW_DS_leading_overpunch = 0x02, DW_DS_trailing_overpunch = 0x03, DW_DS_leading_separate = 0x04, DW_DS_trailing_separate = 0x05, }); dw!( /// The encodings of the constants used in the `DW_AT_endianity` attribute. /// /// See Section 7.8, Table 7.13. DwEnd(u8) { DW_END_default = 0x00, DW_END_big = 0x01, DW_END_little = 0x02, DW_END_lo_user = 0x40, DW_END_hi_user = 0xff, }); dw!( /// The encodings of the constants used in the `DW_AT_accessibility` attribute. /// /// See Section 7.9, Table 7.14. DwAccess(u8) { DW_ACCESS_public = 0x01, DW_ACCESS_protected = 0x02, DW_ACCESS_private = 0x03, }); dw!( /// The encodings of the constants used in the `DW_AT_visibility` attribute. /// /// See Section 7.10, Table 7.15. DwVis(u8) { DW_VIS_local = 0x01, DW_VIS_exported = 0x02, DW_VIS_qualified = 0x03, }); dw!( /// The encodings of the constants used in the `DW_AT_virtuality` attribute. /// /// See Section 7.11, Table 7.16. DwVirtuality(u8) { DW_VIRTUALITY_none = 0x00, DW_VIRTUALITY_virtual = 0x01, DW_VIRTUALITY_pure_virtual = 0x02, }); dw!( /// The encodings of the constants used in the `DW_AT_language` attribute. /// /// See Section 7.12, Table 7.17. DwLang(u16) { DW_LANG_C89 = 0x0001, DW_LANG_C = 0x0002, DW_LANG_Ada83 = 0x0003, DW_LANG_C_plus_plus = 0x0004, DW_LANG_Cobol74 = 0x0005, DW_LANG_Cobol85 = 0x0006, DW_LANG_Fortran77 = 0x0007, DW_LANG_Fortran90 = 0x0008, DW_LANG_Pascal83 = 0x0009, DW_LANG_Modula2 = 0x000a, DW_LANG_Java = 0x000b, DW_LANG_C99 = 0x000c, DW_LANG_Ada95 = 0x000d, DW_LANG_Fortran95 = 0x000e, DW_LANG_PLI = 0x000f, DW_LANG_ObjC = 0x0010, DW_LANG_ObjC_plus_plus = 0x0011, DW_LANG_UPC = 0x0012, DW_LANG_D = 0x0013, DW_LANG_Python = 0x0014, DW_LANG_OpenCL = 0x0015, DW_LANG_Go = 0x0016, DW_LANG_Modula3 = 0x0017, DW_LANG_Haskell = 0x0018, DW_LANG_C_plus_plus_03 = 0x0019, DW_LANG_C_plus_plus_11 = 0x001a, DW_LANG_OCaml = 0x001b, DW_LANG_Rust = 0x001c, DW_LANG_C11 = 0x001d, DW_LANG_Swift = 0x001e, DW_LANG_Julia = 0x001f, DW_LANG_Dylan = 0x0020, DW_LANG_C_plus_plus_14 = 0x0021, DW_LANG_Fortran03 = 0x0022, DW_LANG_Fortran08 = 0x0023, DW_LANG_RenderScript = 0x0024, DW_LANG_BLISS = 0x0025, DW_LANG_lo_user = 0x8000, DW_LANG_hi_user = 0xffff, DW_LANG_Mips_Assembler = 0x8001, DW_LANG_GOOGLE_RenderScript = 0x8e57, DW_LANG_SUN_Assembler = 0x9001, DW_LANG_ALTIUM_Assembler = 0x9101, DW_LANG_BORLAND_Delphi = 0xb000, }); impl DwLang { /// Get the default DW_AT_lower_bound for this language. pub fn default_lower_bound(self) -> Option { match self { DW_LANG_C89 | DW_LANG_C | DW_LANG_C_plus_plus | DW_LANG_Java | DW_LANG_C99 | DW_LANG_ObjC | DW_LANG_ObjC_plus_plus | DW_LANG_UPC | DW_LANG_D | DW_LANG_Python | DW_LANG_OpenCL | DW_LANG_Go | DW_LANG_Haskell | DW_LANG_C_plus_plus_03 | DW_LANG_C_plus_plus_11 | DW_LANG_OCaml | DW_LANG_Rust | DW_LANG_C11 | DW_LANG_Swift | DW_LANG_Dylan | DW_LANG_C_plus_plus_14 | DW_LANG_RenderScript | DW_LANG_BLISS => Some(0), DW_LANG_Ada83 | DW_LANG_Cobol74 | DW_LANG_Cobol85 | DW_LANG_Fortran77 | DW_LANG_Fortran90 | DW_LANG_Pascal83 | DW_LANG_Modula2 | DW_LANG_Ada95 | DW_LANG_Fortran95 | DW_LANG_PLI | DW_LANG_Modula3 | DW_LANG_Julia | DW_LANG_Fortran03 | DW_LANG_Fortran08 => Some(1), _ => None, } } } dw!( /// The encodings of the constants used in the `DW_AT_address_class` attribute. /// /// There is only one value that is common to all target architectures. /// See Section 7.13. DwAddr(u64) { DW_ADDR_none = 0x00, }); dw!( /// The encodings of the constants used in the `DW_AT_identifier_case` attribute. /// /// See Section 7.14, Table 7.18. DwId(u8) { DW_ID_case_sensitive = 0x00, DW_ID_up_case = 0x01, DW_ID_down_case = 0x02, DW_ID_case_insensitive = 0x03, }); dw!( /// The encodings of the constants used in the `DW_AT_calling_convention` attribute. /// /// See Section 7.15, Table 7.19. DwCc(u8) { DW_CC_normal = 0x01, DW_CC_program = 0x02, DW_CC_nocall = 0x03, DW_CC_pass_by_reference = 0x04, DW_CC_pass_by_value = 0x05, DW_CC_lo_user = 0x40, DW_CC_hi_user = 0xff, }); dw!( /// The encodings of the constants used in the `DW_AT_inline` attribute. /// /// See Section 7.16, Table 7.20. DwInl(u8) { DW_INL_not_inlined = 0x00, DW_INL_inlined = 0x01, DW_INL_declared_not_inlined = 0x02, DW_INL_declared_inlined = 0x03, }); dw!( /// The encodings of the constants used in the `DW_AT_ordering` attribute. /// /// See Section 7.17, Table 7.17. DwOrd(u8) { DW_ORD_row_major = 0x00, DW_ORD_col_major = 0x01, }); dw!( /// The encodings of the constants used in the `DW_AT_discr_list` attribute. /// /// See Section 7.18, Table 7.22. DwDsc(u8) { DW_DSC_label = 0x00, DW_DSC_range = 0x01, }); dw!( /// Name index attribute encodings. /// /// See Section 7.19, Table 7.23. DwIdx(u16) { DW_IDX_compile_unit = 1, DW_IDX_type_unit = 2, DW_IDX_die_offset = 3, DW_IDX_parent = 4, DW_IDX_type_hash = 5, DW_IDX_lo_user = 0x2000, DW_IDX_hi_user = 0x3fff, }); dw!( /// The encodings of the constants used in the `DW_AT_defaulted` attribute. /// /// See Section 7.20, Table 7.24. DwDefaulted(u8) { DW_DEFAULTED_no = 0x00, DW_DEFAULTED_in_class = 0x01, DW_DEFAULTED_out_of_class = 0x02, }); dw!( /// The encodings for the standard opcodes for line number information. /// /// See Section 7.22, Table 7.25. DwLns(u8) { DW_LNS_copy = 0x01, DW_LNS_advance_pc = 0x02, DW_LNS_advance_line = 0x03, DW_LNS_set_file = 0x04, DW_LNS_set_column = 0x05, DW_LNS_negate_stmt = 0x06, DW_LNS_set_basic_block = 0x07, DW_LNS_const_add_pc = 0x08, DW_LNS_fixed_advance_pc = 0x09, DW_LNS_set_prologue_end = 0x0a, DW_LNS_set_epilogue_begin = 0x0b, DW_LNS_set_isa = 0x0c, }); dw!( /// The encodings for the extended opcodes for line number information. /// /// See Section 7.22, Table 7.26. DwLne(u8) { DW_LNE_end_sequence = 0x01, DW_LNE_set_address = 0x02, DW_LNE_define_file = 0x03, DW_LNE_set_discriminator = 0x04, DW_LNE_lo_user = 0x80, DW_LNE_hi_user = 0xff, }); dw!( /// The encodings for the line number header entry formats. /// /// See Section 7.22, Table 7.27. DwLnct(u16) { DW_LNCT_path = 0x1, DW_LNCT_directory_index = 0x2, DW_LNCT_timestamp = 0x3, DW_LNCT_size = 0x4, DW_LNCT_MD5 = 0x5, DW_LNCT_lo_user = 0x2000, DW_LNCT_hi_user = 0x3fff, }); dw!( /// The encodings for macro information entry types. /// /// See Section 7.23, Table 7.28. DwMacro(u8) { DW_MACRO_define = 0x01, DW_MACRO_undef = 0x02, DW_MACRO_start_file = 0x03, DW_MACRO_end_file = 0x04, DW_MACRO_define_strp = 0x05, DW_MACRO_undef_strp = 0x06, DW_MACRO_import = 0x07, DW_MACRO_define_sup = 0x08, DW_MACRO_undef_sup = 0x09, DW_MACRO_import_sup = 0x0a, DW_MACRO_define_strx = 0x0b, DW_MACRO_undef_strx = 0x0c, DW_MACRO_lo_user = 0xe0, DW_MACRO_hi_user = 0xff, }); dw!( /// Range list entry encoding values. /// /// See Section 7.25, Table 7.30. DwRle(u8) { DW_RLE_end_of_list = 0x00, DW_RLE_base_addressx = 0x01, DW_RLE_startx_endx = 0x02, DW_RLE_startx_length = 0x03, DW_RLE_offset_pair = 0x04, DW_RLE_base_address = 0x05, DW_RLE_start_end = 0x06, DW_RLE_start_length = 0x07, }); dw!( /// The encodings for DWARF expression operations. /// /// See Section 7.7.1, Table 7.9. DwOp(u8) { DW_OP_addr = 0x03, DW_OP_deref = 0x06, DW_OP_const1u = 0x08, DW_OP_const1s = 0x09, DW_OP_const2u = 0x0a, DW_OP_const2s = 0x0b, DW_OP_const4u = 0x0c, DW_OP_const4s = 0x0d, DW_OP_const8u = 0x0e, DW_OP_const8s = 0x0f, DW_OP_constu = 0x10, DW_OP_consts = 0x11, DW_OP_dup = 0x12, DW_OP_drop = 0x13, DW_OP_over = 0x14, DW_OP_pick = 0x15, DW_OP_swap = 0x16, DW_OP_rot = 0x17, DW_OP_xderef = 0x18, DW_OP_abs = 0x19, DW_OP_and = 0x1a, DW_OP_div = 0x1b, DW_OP_minus = 0x1c, DW_OP_mod = 0x1d, DW_OP_mul = 0x1e, DW_OP_neg = 0x1f, DW_OP_not = 0x20, DW_OP_or = 0x21, DW_OP_plus = 0x22, DW_OP_plus_uconst = 0x23, DW_OP_shl = 0x24, DW_OP_shr = 0x25, DW_OP_shra = 0x26, DW_OP_xor = 0x27, DW_OP_bra = 0x28, DW_OP_eq = 0x29, DW_OP_ge = 0x2a, DW_OP_gt = 0x2b, DW_OP_le = 0x2c, DW_OP_lt = 0x2d, DW_OP_ne = 0x2e, DW_OP_skip = 0x2f, DW_OP_lit0 = 0x30, DW_OP_lit1 = 0x31, DW_OP_lit2 = 0x32, DW_OP_lit3 = 0x33, DW_OP_lit4 = 0x34, DW_OP_lit5 = 0x35, DW_OP_lit6 = 0x36, DW_OP_lit7 = 0x37, DW_OP_lit8 = 0x38, DW_OP_lit9 = 0x39, DW_OP_lit10 = 0x3a, DW_OP_lit11 = 0x3b, DW_OP_lit12 = 0x3c, DW_OP_lit13 = 0x3d, DW_OP_lit14 = 0x3e, DW_OP_lit15 = 0x3f, DW_OP_lit16 = 0x40, DW_OP_lit17 = 0x41, DW_OP_lit18 = 0x42, DW_OP_lit19 = 0x43, DW_OP_lit20 = 0x44, DW_OP_lit21 = 0x45, DW_OP_lit22 = 0x46, DW_OP_lit23 = 0x47, DW_OP_lit24 = 0x48, DW_OP_lit25 = 0x49, DW_OP_lit26 = 0x4a, DW_OP_lit27 = 0x4b, DW_OP_lit28 = 0x4c, DW_OP_lit29 = 0x4d, DW_OP_lit30 = 0x4e, DW_OP_lit31 = 0x4f, DW_OP_reg0 = 0x50, DW_OP_reg1 = 0x51, DW_OP_reg2 = 0x52, DW_OP_reg3 = 0x53, DW_OP_reg4 = 0x54, DW_OP_reg5 = 0x55, DW_OP_reg6 = 0x56, DW_OP_reg7 = 0x57, DW_OP_reg8 = 0x58, DW_OP_reg9 = 0x59, DW_OP_reg10 = 0x5a, DW_OP_reg11 = 0x5b, DW_OP_reg12 = 0x5c, DW_OP_reg13 = 0x5d, DW_OP_reg14 = 0x5e, DW_OP_reg15 = 0x5f, DW_OP_reg16 = 0x60, DW_OP_reg17 = 0x61, DW_OP_reg18 = 0x62, DW_OP_reg19 = 0x63, DW_OP_reg20 = 0x64, DW_OP_reg21 = 0x65, DW_OP_reg22 = 0x66, DW_OP_reg23 = 0x67, DW_OP_reg24 = 0x68, DW_OP_reg25 = 0x69, DW_OP_reg26 = 0x6a, DW_OP_reg27 = 0x6b, DW_OP_reg28 = 0x6c, DW_OP_reg29 = 0x6d, DW_OP_reg30 = 0x6e, DW_OP_reg31 = 0x6f, DW_OP_breg0 = 0x70, DW_OP_breg1 = 0x71, DW_OP_breg2 = 0x72, DW_OP_breg3 = 0x73, DW_OP_breg4 = 0x74, DW_OP_breg5 = 0x75, DW_OP_breg6 = 0x76, DW_OP_breg7 = 0x77, DW_OP_breg8 = 0x78, DW_OP_breg9 = 0x79, DW_OP_breg10 = 0x7a, DW_OP_breg11 = 0x7b, DW_OP_breg12 = 0x7c, DW_OP_breg13 = 0x7d, DW_OP_breg14 = 0x7e, DW_OP_breg15 = 0x7f, DW_OP_breg16 = 0x80, DW_OP_breg17 = 0x81, DW_OP_breg18 = 0x82, DW_OP_breg19 = 0x83, DW_OP_breg20 = 0x84, DW_OP_breg21 = 0x85, DW_OP_breg22 = 0x86, DW_OP_breg23 = 0x87, DW_OP_breg24 = 0x88, DW_OP_breg25 = 0x89, DW_OP_breg26 = 0x8a, DW_OP_breg27 = 0x8b, DW_OP_breg28 = 0x8c, DW_OP_breg29 = 0x8d, DW_OP_breg30 = 0x8e, DW_OP_breg31 = 0x8f, DW_OP_regx = 0x90, DW_OP_fbreg = 0x91, DW_OP_bregx = 0x92, DW_OP_piece = 0x93, DW_OP_deref_size = 0x94, DW_OP_xderef_size = 0x95, DW_OP_nop = 0x96, DW_OP_push_object_address = 0x97, DW_OP_call2 = 0x98, DW_OP_call4 = 0x99, DW_OP_call_ref = 0x9a, DW_OP_form_tls_address = 0x9b, DW_OP_call_frame_cfa = 0x9c, DW_OP_bit_piece = 0x9d, DW_OP_implicit_value = 0x9e, DW_OP_stack_value = 0x9f, DW_OP_implicit_pointer = 0xa0, DW_OP_addrx = 0xa1, DW_OP_constx = 0xa2, DW_OP_entry_value = 0xa3, DW_OP_const_type = 0xa4, DW_OP_regval_type = 0xa5, DW_OP_deref_type = 0xa6, DW_OP_xderef_type = 0xa7, DW_OP_convert = 0xa8, DW_OP_reinterpret = 0xa9, // GNU extensions DW_OP_GNU_push_tls_address = 0xe0, DW_OP_GNU_implicit_pointer = 0xf2, DW_OP_GNU_entry_value = 0xf3, DW_OP_GNU_const_type = 0xf4, DW_OP_GNU_regval_type = 0xf5, DW_OP_GNU_deref_type = 0xf6, DW_OP_GNU_convert = 0xf7, DW_OP_GNU_reinterpret = 0xf9, DW_OP_GNU_parameter_ref = 0xfa, }); dw!( /// Pointer encoding used by `.eh_frame`. /// /// The four lower bits describe the /// format of the pointer, the upper four bits describe how the encoding should /// be applied. /// /// Defined in http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html DwEhPe(u8) { // Format of pointer encoding. // "Unsigned value is encoded using the Little Endian Base 128" DW_EH_PE_uleb128 = 0x1, // "A 2 bytes unsigned value." DW_EH_PE_udata2 = 0x2, // "A 4 bytes unsigned value." DW_EH_PE_udata4 = 0x3, // "An 8 bytes unsigned value." DW_EH_PE_udata8 = 0x4, // "Signed value is encoded using the Little Endian Base 128" DW_EH_PE_sleb128 = 0x9, // "A 2 bytes signed value." DW_EH_PE_sdata2 = 0x0a, // "A 4 bytes signed value." DW_EH_PE_sdata4 = 0x0b, // "An 8 bytes signed value." DW_EH_PE_sdata8 = 0x0c, // How the pointer encoding should be applied. // `DW_EH_PE_pcrel` pointers are relative to their own location. DW_EH_PE_pcrel = 0x10, // "Value is relative to the beginning of the .text section." DW_EH_PE_textrel = 0x20, // "Value is relative to the beginning of the .got or .eh_frame_hdr section." DW_EH_PE_datarel = 0x30, // "Value is relative to the beginning of the function." DW_EH_PE_funcrel = 0x40, // "Value is aligned to an address unit sized boundary." DW_EH_PE_aligned = 0x50, // This bit can be set for any of the above encoding applications. When set, // the encoded value is the address of the real pointer result, not the // pointer result itself. // // This isn't defined in the DWARF or the `.eh_frame` standards, but is // generated by both GNU/Linux and OSX tooling. DW_EH_PE_indirect = 0x80, // These constants apply to both the lower and upper bits. // "The Value is a literal pointer whose size is determined by the // architecture." DW_EH_PE_absptr = 0x0, // The absence of a pointer and encoding. DW_EH_PE_omit = 0xff, }); const DW_EH_PE_FORMAT_MASK: u8 = 0b0000_1111; // Ignores indirection bit. const DW_EH_PE_APPLICATION_MASK: u8 = 0b0111_0000; impl DwEhPe { /// Get the pointer encoding's format. #[inline] pub fn format(self) -> DwEhPe { DwEhPe(self.0 & DW_EH_PE_FORMAT_MASK) } /// Get the pointer encoding's application. #[inline] pub fn application(self) -> DwEhPe { DwEhPe(self.0 & DW_EH_PE_APPLICATION_MASK) } /// Is this encoding the absent pointer encoding? #[inline] pub fn is_absent(self) -> bool { self == DW_EH_PE_omit } /// Is this coding indirect? If so, its encoded value is the address of the /// real pointer result, not the pointer result itself. #[inline] pub fn is_indirect(self) -> bool { self.0 & DW_EH_PE_indirect.0 != 0 } /// Is this a known, valid pointer encoding? pub fn is_valid_encoding(self) -> bool { if self.is_absent() { return true; } match self.format() { DW_EH_PE_absptr | DW_EH_PE_uleb128 | DW_EH_PE_udata2 | DW_EH_PE_udata4 | DW_EH_PE_udata8 | DW_EH_PE_sleb128 | DW_EH_PE_sdata2 | DW_EH_PE_sdata4 | DW_EH_PE_sdata8 => {} _ => return false, } match self.application() { DW_EH_PE_absptr | DW_EH_PE_pcrel | DW_EH_PE_textrel | DW_EH_PE_datarel | DW_EH_PE_funcrel | DW_EH_PE_aligned => {} _ => return false, } true } } #[cfg(test)] mod tests { use super::*; #[test] fn test_dw_eh_pe_format() { let encoding = DwEhPe(DW_EH_PE_pcrel.0 | DW_EH_PE_uleb128.0); assert_eq!(encoding.format(), DW_EH_PE_uleb128); } #[test] fn test_dw_eh_pe_application() { let encoding = DwEhPe(DW_EH_PE_pcrel.0 | DW_EH_PE_uleb128.0); assert_eq!(encoding.application(), DW_EH_PE_pcrel); } #[test] fn test_dw_eh_pe_is_absent() { assert_eq!(DW_EH_PE_absptr.is_absent(), false); assert_eq!(DW_EH_PE_omit.is_absent(), true); } #[test] fn test_dw_eh_pe_is_valid_encoding_ok() { let encoding = DwEhPe(DW_EH_PE_uleb128.0 | DW_EH_PE_pcrel.0); assert!(encoding.is_valid_encoding()); assert!(DW_EH_PE_absptr.is_valid_encoding()); assert!(DW_EH_PE_omit.is_valid_encoding()); } #[test] fn test_dw_eh_pe_is_valid_encoding_bad_format() { let encoding = DwEhPe((DW_EH_PE_sdata8.0 + 1) | DW_EH_PE_pcrel.0); assert_eq!(encoding.is_valid_encoding(), false); } #[test] fn test_dw_eh_pe_is_valid_encoding_bad_application() { let encoding = DwEhPe(DW_EH_PE_sdata8.0 | (DW_EH_PE_aligned.0 + 1)); assert_eq!(encoding.is_valid_encoding(), false); } } gimli-0.19.0/src/endianity.rs010066400017500001750000000133461343337721300142630ustar0000000000000000//! Types for compile-time and run-time endianity. use byteorder; use byteorder::ByteOrder; use std::fmt::Debug; /// A trait describing the endianity of some buffer. pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { /// Return true for big endian byte order. fn is_big_endian(self) -> bool; /// Return true for little endian byte order. #[inline] fn is_little_endian(self) -> bool { !self.is_big_endian() } /// Reads an unsigned 16 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 2`. #[inline] fn read_u16(self, buf: &[u8]) -> u16 { if self.is_big_endian() { byteorder::BigEndian::read_u16(buf) } else { byteorder::LittleEndian::read_u16(buf) } } /// Reads an unsigned 32 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 4`. #[inline] fn read_u32(self, buf: &[u8]) -> u32 { if self.is_big_endian() { byteorder::BigEndian::read_u32(buf) } else { byteorder::LittleEndian::read_u32(buf) } } /// Reads an unsigned 64 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 8`. #[inline] fn read_u64(self, buf: &[u8]) -> u64 { if self.is_big_endian() { byteorder::BigEndian::read_u64(buf) } else { byteorder::LittleEndian::read_u64(buf) } } /// Read an unsigned n-bytes integer u64. /// /// # Panics /// /// Panics when `buf.len() < 1` or `buf.len() > 8`. #[inline] fn read_uint(&mut self, buf: &[u8]) -> u64 { if self.is_big_endian() { byteorder::BigEndian::read_uint(buf, buf.len()) } else { byteorder::LittleEndian::read_uint(buf, buf.len()) } } /// Reads a signed 16 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 2`. #[inline] fn read_i16(self, buf: &[u8]) -> i16 { self.read_u16(buf) as i16 } /// Reads a signed 32 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 4`. #[inline] fn read_i32(self, buf: &[u8]) -> i32 { self.read_u32(buf) as i32 } /// Reads a signed 64 bit integer from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 8`. #[inline] fn read_i64(self, buf: &[u8]) -> i64 { self.read_u64(buf) as i64 } /// Reads a 32 bit floating point number from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 8`. #[inline] fn read_f32(self, buf: &[u8]) -> f32 { f32::from_bits(self.read_u32(buf)) } /// Reads a 32 bit floating point number from `buf`. /// /// # Panics /// /// Panics when `buf.len() < 8`. #[inline] fn read_f64(self, buf: &[u8]) -> f64 { f64::from_bits(self.read_u64(buf)) } /// Writes an unsigned 16 bit integer `n` to `buf`. /// /// # Panics /// /// Panics when `buf.len() < 2`. #[inline] fn write_u16(self, buf: &mut [u8], n: u16) { if self.is_big_endian() { byteorder::BigEndian::write_u16(buf, n) } else { byteorder::LittleEndian::write_u16(buf, n) } } /// Writes an unsigned 32 bit integer `n` to `buf`. /// /// # Panics /// /// Panics when `buf.len() < 4`. #[inline] fn write_u32(self, buf: &mut [u8], n: u32) { if self.is_big_endian() { byteorder::BigEndian::write_u32(buf, n) } else { byteorder::LittleEndian::write_u32(buf, n) } } /// Writes an unsigned 64 bit integer `n` to `buf`. /// /// # Panics /// /// Panics when `buf.len() < 8`. #[inline] fn write_u64(self, buf: &mut [u8], n: u64) { if self.is_big_endian() { byteorder::BigEndian::write_u64(buf, n) } else { byteorder::LittleEndian::write_u64(buf, n) } } } /// Byte order that is selectable at runtime. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RunTimeEndian { /// Little endian byte order. Little, /// Big endian byte order. Big, } impl Default for RunTimeEndian { #[cfg(target_endian = "little")] #[inline] fn default() -> RunTimeEndian { RunTimeEndian::Little } #[cfg(target_endian = "big")] #[inline] fn default() -> RunTimeEndian { RunTimeEndian::Big } } impl Endianity for RunTimeEndian { #[inline] fn is_big_endian(self) -> bool { self != RunTimeEndian::Little } } /// Little endian byte order. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LittleEndian; impl Default for LittleEndian { #[inline] fn default() -> LittleEndian { LittleEndian } } impl Endianity for LittleEndian { #[inline] fn is_big_endian(self) -> bool { false } } /// Big endian byte order. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct BigEndian; impl Default for BigEndian { #[inline] fn default() -> BigEndian { BigEndian } } impl Endianity for BigEndian { #[inline] fn is_big_endian(self) -> bool { true } } /// The native endianity for the target platform. #[cfg(target_endian = "little")] pub type NativeEndian = LittleEndian; #[cfg(target_endian = "little")] #[allow(non_upper_case_globals)] #[doc(hidden)] pub const NativeEndian: LittleEndian = LittleEndian; /// The native endianity for the target platform. #[cfg(target_endian = "big")] pub type NativeEndian = BigEndian; #[cfg(target_endian = "big")] #[allow(non_upper_case_globals)] #[doc(hidden)] pub const NativeEndian: BigEndian = BigEndian; gimli-0.19.0/src/leb128.rs010066400017500001750000000364211346020377600132750ustar0000000000000000//! Read and write DWARF's "Little Endian Base 128" (LEB128) variable length //! integer encoding. //! //! The implementation is a direct translation of the psuedocode in the DWARF 4 //! standard's appendix C. //! //! Read and write signed integers: //! //! ``` //! use gimli::{EndianSlice, NativeEndian, leb128}; //! //! let mut buf = [0; 1024]; //! //! // Write to anything that implements `std::io::Write`. //! { //! let mut writable = &mut buf[..]; //! leb128::write::signed(&mut writable, -12345).expect("Should write number"); //! } //! //! // Read from anything that implements `gimli::Reader`. //! let mut readable = EndianSlice::new(&buf[..], NativeEndian); //! let val = leb128::read::signed(&mut readable).expect("Should read number"); //! assert_eq!(val, -12345); //! ``` //! //! Or read and write unsigned integers: //! //! ``` //! use gimli::{EndianSlice, NativeEndian, leb128}; //! //! let mut buf = [0; 1024]; //! //! { //! let mut writable = &mut buf[..]; //! leb128::write::unsigned(&mut writable, 98765).expect("Should write number"); //! } //! //! let mut readable = EndianSlice::new(&buf[..], NativeEndian); //! let val = leb128::read::unsigned(&mut readable).expect("Should read number"); //! assert_eq!(val, 98765); //! ``` use std; const CONTINUATION_BIT: u8 = 1 << 7; const SIGN_BIT: u8 = 1 << 6; #[inline] fn low_bits_of_byte(byte: u8) -> u8 { byte & !CONTINUATION_BIT } #[inline] #[allow(dead_code)] fn low_bits_of_u64(val: u64) -> u8 { let byte = val & u64::from(std::u8::MAX); low_bits_of_byte(byte as u8) } /// A module for reading signed and unsigned integers that have been LEB128 /// encoded. #[cfg(feature = "read")] pub mod read { use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT}; use crate::read::{Error, Reader, Result}; /// Read an unsigned LEB128 number from the given `Reader` and /// return it or an error if reading failed. pub fn unsigned(r: &mut R) -> Result { let mut result = 0; let mut shift = 0; loop { let byte = r.read_u8()?; if shift == 63 && byte != 0x00 && byte != 0x01 { return Err(Error::BadUnsignedLeb128); } let low_bits = u64::from(low_bits_of_byte(byte)); result |= low_bits << shift; if byte & CONTINUATION_BIT == 0 { return Ok(result); } shift += 7; } } /// Read a signed LEB128 number from the given `Reader` and /// return it or an error if reading failed. pub fn signed(r: &mut R) -> Result { let mut result = 0; let mut shift = 0; let size = 64; let mut byte; loop { byte = r.read_u8()?; if shift == 63 && byte != 0x00 && byte != 0x7f { return Err(Error::BadSignedLeb128); } let low_bits = i64::from(low_bits_of_byte(byte)); result |= low_bits << shift; shift += 7; if byte & CONTINUATION_BIT == 0 { break; } } if shift < size && (SIGN_BIT & byte) == SIGN_BIT { // Sign extend the result. result |= !0 << shift; } Ok(result) } } /// A module for writing integers encoded as LEB128. #[cfg(feature = "write")] pub mod write { use super::{low_bits_of_u64, CONTINUATION_BIT}; use std::io; /// Write the given unsigned number using the LEB128 encoding to the given /// `std::io::Write`able. Returns the number of bytes written to `w`, or an /// error if writing failed. pub fn unsigned(w: &mut W, mut val: u64) -> Result where W: io::Write, { let mut bytes_written = 0; loop { let mut byte = low_bits_of_u64(val); val >>= 7; if val != 0 { // More bytes to come, so set the continuation bit. byte |= CONTINUATION_BIT; } let buf = [byte]; w.write_all(&buf)?; bytes_written += 1; if val == 0 { return Ok(bytes_written); } } } /// Write the given signed number using the LEB128 encoding to the given /// `std::io::Write`able. Returns the number of bytes written to `w`, or an /// error if writing failed. pub fn signed(w: &mut W, mut val: i64) -> Result where W: io::Write, { let mut bytes_written = 0; loop { let mut byte = val as u8; // Keep the sign bit for testing val >>= 6; let done = val == 0 || val == -1; if done { byte &= !CONTINUATION_BIT; } else { // Remove the sign bit val >>= 1; // More bytes to come, so set the continuation bit. byte |= CONTINUATION_BIT; } let buf = [byte]; w.write_all(&buf)?; bytes_written += 1; if done { return Ok(bytes_written); } } } } #[cfg(test)] mod tests { use super::{low_bits_of_byte, low_bits_of_u64, read, write, CONTINUATION_BIT}; use crate::endianity::NativeEndian; use crate::read::{EndianSlice, Error, ReaderOffsetId}; use std; use std::io; trait ResultExt { fn map_eof(self, input: &[u8]) -> Self; } impl ResultExt for Result { fn map_eof(self, input: &[u8]) -> Self { match self { Err(Error::UnexpectedEof(id)) => { let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); Err(Error::UnexpectedEof(id)) } r => r, } } } #[test] fn test_low_bits_of_byte() { for i in 0..127 { assert_eq!(i, low_bits_of_byte(i)); assert_eq!(i, low_bits_of_byte(i | CONTINUATION_BIT)); } } #[test] fn test_low_bits_of_u64() { for i in 0u64..127 { assert_eq!(i as u8, low_bits_of_u64(1 << 16 | i)); assert_eq!( i as u8, low_bits_of_u64(i << 16 | i | (u64::from(CONTINUATION_BIT))) ); } } // Examples from the DWARF 4 standard, section 7.6, figure 22. #[test] fn test_read_unsigned() { let buf = [2u8]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 2, read::unsigned(&mut readable).expect("Should read number") ); let buf = [127u8]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 127, read::unsigned(&mut readable).expect("Should read number") ); let buf = [CONTINUATION_BIT, 1]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 128, read::unsigned(&mut readable).expect("Should read number") ); let buf = [1u8 | CONTINUATION_BIT, 1]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 129, read::unsigned(&mut readable).expect("Should read number") ); let buf = [2u8 | CONTINUATION_BIT, 1]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 130, read::unsigned(&mut readable).expect("Should read number") ); let buf = [57u8 | CONTINUATION_BIT, 100]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 12857, read::unsigned(&mut readable).expect("Should read number") ); } // Examples from the DWARF 4 standard, section 7.6, figure 23. #[test] fn test_read_signed() { let buf = [2u8]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!(2, read::signed(&mut readable).expect("Should read number")); let buf = [0x7eu8]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!(-2, read::signed(&mut readable).expect("Should read number")); let buf = [127u8 | CONTINUATION_BIT, 0]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 127, read::signed(&mut readable).expect("Should read number") ); let buf = [1u8 | CONTINUATION_BIT, 0x7f]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( -127, read::signed(&mut readable).expect("Should read number") ); let buf = [CONTINUATION_BIT, 1]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 128, read::signed(&mut readable).expect("Should read number") ); let buf = [CONTINUATION_BIT, 0x7f]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( -128, read::signed(&mut readable).expect("Should read number") ); let buf = [1u8 | CONTINUATION_BIT, 1]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( 129, read::signed(&mut readable).expect("Should read number") ); let buf = [0x7fu8 | CONTINUATION_BIT, 0x7e]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( -129, read::signed(&mut readable).expect("Should read number") ); } #[test] fn test_read_signed_63_bits() { let buf = [ CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, CONTINUATION_BIT, 0x40, ]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( -0x4000_0000_0000_0000, read::signed(&mut readable).expect("Should read number") ); } #[test] fn test_read_unsigned_not_enough_data() { let buf = [CONTINUATION_BIT]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( read::unsigned(&mut readable).map_eof(&buf), Err(Error::UnexpectedEof(ReaderOffsetId(1))) ); } #[test] fn test_read_signed_not_enough_data() { let buf = [CONTINUATION_BIT]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( read::signed(&mut readable).map_eof(&buf), Err(Error::UnexpectedEof(ReaderOffsetId(1))) ); } #[test] fn test_write_unsigned_not_enough_space() { let mut buf = [0; 1]; let mut writable = &mut buf[..]; match write::unsigned(&mut writable, 128) { Err(e) => assert_eq!(e.kind(), io::ErrorKind::WriteZero), otherwise => panic!("Unexpected: {:?}", otherwise), } } #[test] fn test_write_signed_not_enough_space() { let mut buf = [0; 1]; let mut writable = &mut buf[..]; match write::signed(&mut writable, 128) { Err(e) => assert_eq!(e.kind(), io::ErrorKind::WriteZero), otherwise => panic!("Unexpected: {:?}", otherwise), } } #[test] fn dogfood_signed() { fn inner(i: i64) { let mut buf = [0u8; 1024]; { let mut writable = &mut buf[..]; write::signed(&mut writable, i).expect("Should write signed number"); } let mut readable = EndianSlice::new(&buf[..], NativeEndian); let result = read::signed(&mut readable).expect("Should be able to read it back again"); assert_eq!(i, result); } for i in -513..513 { inner(i); } inner(std::i64::MIN); } #[test] fn dogfood_unsigned() { for i in 0..1025 { let mut buf = [0u8; 1024]; { let mut writable = &mut buf[..]; write::unsigned(&mut writable, i).expect("Should write signed number"); } let mut readable = EndianSlice::new(&buf[..], NativeEndian); let result = read::unsigned(&mut readable).expect("Should be able to read it back again"); assert_eq!(i, result); } } #[test] fn test_read_unsigned_overflow() { let buf = [ 2u8 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 1, ]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert!(read::unsigned(&mut readable).is_err()); } #[test] fn test_read_signed_overflow() { let buf = [ 2u8 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 2 | CONTINUATION_BIT, 1, ]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert!(read::signed(&mut readable).is_err()); } #[test] fn test_read_multiple() { let buf = [2u8 | CONTINUATION_BIT, 1u8, 1u8]; let mut readable = EndianSlice::new(&buf[..], NativeEndian); assert_eq!( read::unsigned(&mut readable).expect("Should read first number"), 130u64 ); assert_eq!( read::unsigned(&mut readable).expect("Should read first number"), 1u64 ); } } gimli-0.19.0/src/lib.rs010066400017500001750000000056021346020377600130430ustar0000000000000000//! `gimli` is a library for reading and writing the //! [DWARF debugging format](http://dwarfstd.org/). //! //! See the [read](./read/index.html) and [write](./write/index.html) modules //! for examples and API documentation. //! //! ## Cargo Features //! //! Cargo features that can be enabled with `gimli`: //! //! * `std`: Enabled by default. Use the `std` library. Disabling this feature //! allows using `gimli` in embedded environments that do not have access to //! `std`. Note that even when `std` is disabled, `gimli` still requires an //! implementation of the `alloc` crate, and you must enable the `nightly` //! feature. //! //! * `alloc`: Nightly only. Enables usage of the unstable, nightly-only //! `#![feature(alloc)]` Rust feature that allows `gimli` to use boxes and //! collection types in a `#[no_std]` environment. //! //! * `read`: Enabled by default. Enables the `read` module. Requires //! either `alloc` or `std` to also be enabled. //! //! * `write`: Enabled by default. Enables the `write` module. Automatically //! enables `std` too. #![deny(missing_docs)] #![deny(missing_debug_implementations)] // Selectively enable rust 2018 warnings #![warn(bare_trait_objects)] #![warn(unused_extern_crates)] #![warn(ellipsis_inclusive_range_patterns)] //#![warn(elided_lifetimes_in_paths)] #![warn(explicit_outlives_requirements)] // Allow clippy warnings when we aren't building with clippy. #![allow(unknown_lints)] // False positives with `fallible_iterator`. #![allow(clippy::should_implement_trait)] // Many false positives involving `continue`. #![allow(clippy::never_loop)] // False positives when block expressions are used inside an assertion. #![allow(clippy::panic_params)] #![no_std] #![cfg_attr(feature = "alloc", feature(alloc))] #[cfg(feature = "std")] #[macro_use] extern crate std; #[cfg(not(feature = "std"))] #[macro_use] extern crate alloc; #[cfg(not(feature = "std"))] #[macro_use] extern crate core as std; #[cfg(feature = "std")] mod imports { pub use std::borrow; pub use std::boxed; pub use std::collections; pub use std::rc; pub use std::string; pub use std::sync::Arc; pub use std::vec; } #[cfg(not(feature = "std"))] mod imports { pub use alloc::borrow; pub use alloc::boxed; pub use alloc::collections; pub use alloc::rc; pub use alloc::string; pub use alloc::sync::Arc; pub use alloc::vec; } use crate::imports::*; pub use stable_deref_trait::{CloneStableDeref, StableDeref}; mod common; pub use crate::common::*; mod arch; pub use crate::arch::*; pub mod constants; // For backwards compat. pub use crate::constants::*; mod endianity; pub use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian, RunTimeEndian}; pub mod leb128; #[cfg(feature = "read")] pub mod read; // For backwards compat. #[cfg(feature = "read")] pub use crate::read::*; #[cfg(feature = "write")] pub mod write; #[cfg(test)] mod test_util; gimli-0.19.0/src/read/abbrev.rs010066400017500001750000000705301346020377600144530ustar0000000000000000//! Functions for parsing DWARF debugging abbreviations. use crate::collections::btree_map; use crate::vec::Vec; use crate::common::{DebugAbbrevOffset, SectionId}; use crate::constants; use crate::endianity::Endianity; use crate::read::{EndianSlice, Error, Reader, Result, Section, UnitHeader}; /// The `DebugAbbrev` struct represents the abbreviations describing /// `DebuggingInformationEntry`s' attribute names and forms found in the /// `.debug_abbrev` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugAbbrev { debug_abbrev_section: R, } impl<'input, Endian> DebugAbbrev> where Endian: Endianity, { /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` /// section. /// /// It is the caller's responsibility to read the `.debug_abbrev` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugAbbrev, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_abbrev_section_somehow = || &buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// ``` pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_abbrev_section, endian)) } } impl DebugAbbrev { /// Parse the abbreviations at the given `offset` within this /// `.debug_abbrev` section. /// /// The `offset` should generally be retrieved from a unit header. pub fn abbreviations( &self, debug_abbrev_offset: DebugAbbrevOffset, ) -> Result { let input = &mut self.debug_abbrev_section.clone(); input.skip(debug_abbrev_offset.0)?; Abbreviations::parse(input) } } impl DebugAbbrev { /// Create a `DebugAbbrev` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugAbbrev> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev where F: FnMut(&'a T) -> R, { borrow(&self.debug_abbrev_section).into() } } impl Section for DebugAbbrev { fn id() -> SectionId { SectionId::DebugAbbrev } fn reader(&self) -> &R { &self.debug_abbrev_section } } impl From for DebugAbbrev { fn from(debug_abbrev_section: R) -> Self { DebugAbbrev { debug_abbrev_section, } } } /// A set of type abbreviations. /// /// Construct an `Abbreviations` instance with the /// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) /// method. #[derive(Debug, Default, Clone)] pub struct Abbreviations { vec: Vec, map: btree_map::BTreeMap, } impl Abbreviations { /// Construct a new, empty set of abbreviations. fn empty() -> Abbreviations { Abbreviations { vec: Vec::new(), map: btree_map::BTreeMap::new(), } } /// Insert an abbreviation into the set. /// /// Returns `Ok` if it is the first abbreviation in the set with its code, /// `Err` if the code is a duplicate and there already exists an /// abbreviation in the set with the given abbreviation's code. fn insert(&mut self, abbrev: Abbreviation) -> ::std::result::Result<(), ()> { let code_usize = abbrev.code as usize; if code_usize as u64 == abbrev.code { // Optimize for sequential abbreviation codes by storing them // in a Vec, as long as the map doesn't already contain them. // A potential further optimization would be to allow some // holes in the Vec, but there's no need for that yet. if code_usize - 1 < self.vec.len() { return Err(()); } else if code_usize - 1 == self.vec.len() { if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { return Err(()); } else { self.vec.push(abbrev); return Ok(()); } } } match self.map.entry(abbrev.code) { btree_map::Entry::Occupied(_) => Err(()), btree_map::Entry::Vacant(entry) => { entry.insert(abbrev); Ok(()) } } } /// Get the abbreviation associated with the given code. #[inline] pub fn get(&self, code: u64) -> Option<&Abbreviation> { let code_usize = code as usize; if code_usize as u64 == code && code_usize - 1 < self.vec.len() { Some(&self.vec[code_usize - 1]) } else { self.map.get(&code) } } /// Parse a series of abbreviations, terminated by a null abbreviation. fn parse(input: &mut R) -> Result { let mut abbrevs = Abbreviations::empty(); while let Some(abbrev) = Abbreviation::parse(input)? { if abbrevs.insert(abbrev).is_err() { return Err(Error::DuplicateAbbreviationCode); } } Ok(abbrevs) } } /// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: /// its code, tag type, whether it has children, and its set of attributes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Abbreviation { code: u64, tag: constants::DwTag, has_children: constants::DwChildren, attributes: Vec, } impl Abbreviation { /// Construct a new `Abbreviation`. /// /// ### Panics /// /// Panics if `code` is `0`. pub fn new( code: u64, tag: constants::DwTag, has_children: constants::DwChildren, attributes: Vec, ) -> Abbreviation { assert_ne!(code, 0); Abbreviation { code, tag, has_children, attributes, } } /// Get this abbreviation's code. #[inline] pub fn code(&self) -> u64 { self.code } /// Get this abbreviation's tag. #[inline] pub fn tag(&self) -> constants::DwTag { self.tag } /// Return true if this abbreviation's type has children, false otherwise. #[inline] pub fn has_children(&self) -> bool { self.has_children == constants::DW_CHILDREN_yes } /// Get this abbreviation's attributes. #[inline] pub fn attributes(&self) -> &[AttributeSpecification] { &self.attributes[..] } /// Parse an abbreviation's tag. fn parse_tag(input: &mut R) -> Result { let val = input.read_uleb128()?; if val == 0 { Err(Error::AbbreviationTagZero) } else { Ok(constants::DwTag(val)) } } /// Parse an abbreviation's "does the type have children?" byte. fn parse_has_children(input: &mut R) -> Result { let val = input.read_u8()?; let val = constants::DwChildren(val); if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes { Ok(val) } else { Err(Error::BadHasChildren) } } /// Parse a series of attribute specifications, terminated by a null attribute /// specification. fn parse_attributes(input: &mut R) -> Result> { let mut attrs = Vec::new(); while let Some(attr) = AttributeSpecification::parse(input)? { attrs.push(attr); } Ok(attrs) } /// Parse an abbreviation. Return `None` for the null abbreviation, `Some` /// for an actual abbreviation. fn parse(input: &mut R) -> Result> { let code = input.read_uleb128()?; if code == 0 { return Ok(None); } let tag = Self::parse_tag(input)?; let has_children = Self::parse_has_children(input)?; let attributes = Self::parse_attributes(input)?; let abbrev = Abbreviation::new(code, tag, has_children, attributes); Ok(Some(abbrev)) } } /// The description of an attribute in an abbreviated type. It is a pair of name /// and form. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AttributeSpecification { name: constants::DwAt, form: constants::DwForm, implicit_const_value: i64, } impl AttributeSpecification { /// Construct a new `AttributeSpecification` from the given name and form /// and implicit const value. #[inline] pub fn new( name: constants::DwAt, form: constants::DwForm, implicit_const_value: Option, ) -> AttributeSpecification { debug_assert!( (form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) || (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()) ); AttributeSpecification { name, form, implicit_const_value: implicit_const_value.unwrap_or(0), } } /// Get the attribute's name. #[inline] pub fn name(&self) -> constants::DwAt { self.name } /// Get the attribute's form. #[inline] pub fn form(&self) -> constants::DwForm { self.form } /// Get the attribute's implicit const value. #[inline] pub fn implicit_const_value(&self) -> i64 { assert!(self.form == constants::DW_FORM_implicit_const); self.implicit_const_value } /// Return the size of the attribute, in bytes. /// /// Note that because some attributes are variably sized, the size cannot /// always be known without parsing, in which case we return `None`. pub fn size(&self, header: &UnitHeader) -> Option { match self.form { constants::DW_FORM_addr => Some(header.address_size() as usize), constants::DW_FORM_implicit_const => Some(0), constants::DW_FORM_flag | constants::DW_FORM_flag_present | constants::DW_FORM_data1 | constants::DW_FORM_ref1 => Some(1), constants::DW_FORM_data2 | constants::DW_FORM_ref2 => Some(2), constants::DW_FORM_data4 | constants::DW_FORM_ref4 => Some(4), constants::DW_FORM_data8 | constants::DW_FORM_ref8 => Some(8), constants::DW_FORM_sec_offset | constants::DW_FORM_ref_addr | constants::DW_FORM_ref_sig8 | constants::DW_FORM_strp => Some(header.format().word_size() as usize), // Variably sized forms. constants::DW_FORM_block | constants::DW_FORM_block1 | constants::DW_FORM_block2 | constants::DW_FORM_block4 | constants::DW_FORM_exprloc | constants::DW_FORM_ref_udata | constants::DW_FORM_string | constants::DW_FORM_sdata | constants::DW_FORM_udata | constants::DW_FORM_indirect | // We don't know the size of unknown forms. _ => None, } } /// Parse an attribute's form. fn parse_form(input: &mut R) -> Result { let val = input.read_uleb128()?; if val == 0 { Err(Error::AttributeFormZero) } else { Ok(constants::DwForm(val)) } } /// Parse an attribute specification. Returns `None` for the null attribute /// specification, `Some` for an actual attribute specification. fn parse(input: &mut R) -> Result> { let name = input.read_uleb128()?; if name == 0 { // Parse the null attribute specification. let form = input.read_uleb128()?; return if form == 0 { Ok(None) } else { Err(Error::ExpectedZero) }; } let name = constants::DwAt(name); let form = Self::parse_form(input)?; let implicit_const_value = if form == constants::DW_FORM_implicit_const { Some(input.read_sleb128()?) } else { None }; let spec = AttributeSpecification::new(name, form, implicit_const_value); Ok(Some(spec)) } } #[cfg(test)] pub mod tests { use super::*; use crate::constants; use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Error}; use crate::test_util::GimliSectionMethods; #[cfg(target_pointer_width = "32")] use std::u32; use test_assembler::Section; pub trait AbbrevSectionMethods { fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self; fn abbrev_null(self) -> Self; fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self; fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self; fn abbrev_attr_null(self) -> Self; } impl AbbrevSectionMethods for Section { fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self { self.uleb(code).uleb(tag.0).D8(children.0) } fn abbrev_null(self) -> Self { self.D8(0) } fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self { self.uleb(name.0).uleb(form.0) } fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self { self.uleb(name.0) .uleb(constants::DW_FORM_implicit_const.0) .sleb(value) } fn abbrev_attr_null(self) -> Self { self.D8(0).D8(0) } } #[test] fn test_debug_abbrev_ok() { let extra_start = [1, 2, 3, 4]; let expected_rest = [5, 6, 7, 8]; #[rustfmt::skip] let buf = Section::new() .append_bytes(&extra_start) .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let abbrev1 = Abbreviation::new( 1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new( constants::DW_AT_producer, constants::DW_FORM_strp, None, ), AttributeSpecification::new( constants::DW_AT_language, constants::DW_FORM_data2, None, ), ], ); let abbrev2 = Abbreviation::new( 2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )], ); let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian); let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len()); let abbrevs = debug_abbrev .abbreviations(debug_abbrev_offset) .expect("Should parse abbreviations"); assert_eq!(abbrevs.get(1), Some(&abbrev1)); assert_eq!(abbrevs.get(2), Some(&abbrev2)); } #[test] fn test_abbreviations_insert() { fn abbrev(code: u64) -> Abbreviation { Abbreviation::new( code, constants::DwTag(code), constants::DW_CHILDREN_no, vec![], ) } fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { let abbrev = abbrevs.get(code).unwrap(); assert_eq!(abbrev.tag(), constants::DwTag(code)); } // Sequential insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.vec.len(), 2); assert!(abbrevs.map.is_empty()); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, 2); // Out of order insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); abbrevs.insert(abbrev(3)).unwrap(); assert!(abbrevs.vec.is_empty()); assert_abbrev(&abbrevs, 2); assert_abbrev(&abbrevs, 3); // Mixed order insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(3)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.vec.len(), 2); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, 2); assert_abbrev(&abbrevs, 3); // Duplicate code in vec. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.insert(abbrev(1)), Err(())); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // Duplicate code in map when adding to map. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // Duplicate code in map when adding to vec. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); abbrevs.insert(abbrev(1)).unwrap(); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // 32-bit usize conversions. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); } #[test] #[cfg(target_pointer_width = "32")] fn test_abbreviations_insert_32() { fn abbrev(code: u64) -> Abbreviation { Abbreviation::new( code, constants::DwTag(code), constants::DW_CHILDREN_no, vec![], ) } fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { let abbrev = abbrevs.get(code).unwrap(); assert_eq!(abbrev.tag(), constants::DwTag(code)); } let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); let wrap_code = (u32::MAX as u64 + 1) + 1; // `get` should not treat the wrapped code as `1`. assert_eq!(abbrevs.get(wrap_code), None); // `insert` should not treat the wrapped code as `1`. abbrevs.insert(abbrev(wrap_code)).unwrap(); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, wrap_code); } #[test] fn test_parse_abbreviations_ok() { let expected_rest = [1, 2, 3, 4]; #[rustfmt::skip] let buf = Section::new() .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let abbrev1 = Abbreviation::new( 1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new( constants::DW_AT_producer, constants::DW_FORM_strp, None, ), AttributeSpecification::new( constants::DW_AT_language, constants::DW_FORM_data2, None, ), ], ); let abbrev2 = Abbreviation::new( 2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )], ); let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations"); assert_eq!(abbrevs.get(1), Some(&abbrev1)); assert_eq!(abbrevs.get(2), Some(&abbrev2)); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviations_duplicate() { let expected_rest = [1, 2, 3, 4]; #[rustfmt::skip] let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let buf = &mut EndianSlice::new(&*buf, LittleEndian); match Abbreviations::parse(buf) { Err(Error::DuplicateAbbreviationCode) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_tag_ok() { let buf = [0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let tag = Abbreviation::parse_tag(rest).expect("Should parse tag"); assert_eq!(tag, constants::DW_TAG_array_type); assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); } #[test] fn test_parse_abbreviation_tag_zero() { let buf = [0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match Abbreviation::parse_tag(buf) { Err(Error::AbbreviationTagZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_has_children() { let buf = [0x00, 0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); assert_eq!(val, constants::DW_CHILDREN_no); let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); assert_eq!(val, constants::DW_CHILDREN_yes); match Abbreviation::parse_has_children(rest) { Err(Error::BadHasChildren) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let expect = Some(Abbreviation::new( 1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )], )); let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); assert_eq!(abbrev, expect); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviation_implicit_const_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr_implicit_const(constants::DW_AT_name, -42) .abbrev_attr_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let expect = Some(Abbreviation::new( 1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_implicit_const, Some(-42), )], )); let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); assert_eq!(abbrev, expect); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviation_implicit_const_no_const() { let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const) .get_contents() .unwrap(); let buf = &mut EndianSlice::new(&*buf, LittleEndian); match Abbreviation::parse(buf) { Err(Error::UnexpectedEof(_)) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_parse_null_abbreviation_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation"); assert!(abbrev.is_none()); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_attribute_form_ok() { let buf = [0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let tag = AttributeSpecification::parse_form(rest).expect("Should parse form"); assert_eq!(tag, constants::DW_FORM_addr); assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); } #[test] fn test_parse_attribute_form_zero() { let buf = [0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse_form(buf) { Err(Error::AttributeFormZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_null_attribute_specification_ok() { let buf = [0x00, 0x00, 0x01]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let attr = AttributeSpecification::parse(rest).expect("Should parse null attribute specification"); assert!(attr.is_none()); assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian)); } #[test] fn test_parse_attribute_specifications_name_zero() { let buf = [0x00, 0x01, 0x00, 0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse(buf) { Err(Error::ExpectedZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_attribute_specifications_form_zero() { let buf = [0x01, 0x00, 0x00, 0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse(buf) { Err(Error::AttributeFormZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } } gimli-0.19.0/src/read/addr.rs010066400017500001750000000103431346020377600141200ustar0000000000000000use crate::common::{DebugAddrBase, DebugAddrIndex, SectionId}; use crate::read::{Reader, ReaderOffset, Result, Section}; /// The raw contents of the `.debug_addr` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugAddr { section: R, } impl DebugAddr { // TODO: add an iterator over the sets of addresses in the section. // This is not needed for common usage of the section though. /// Returns the address at the given `base` and `index`. /// /// A set of addresses in the `.debug_addr` section consists of a header /// followed by a series of addresses. /// /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE. /// This is an offset that points to the first address following the header. /// /// The `index` is the value of a `DW_FORM_addrx` attribute. /// /// The `address_size` must be the size of the address for the compilation unit. /// This value must also match the header. However, note that we do not parse the /// header to validate this, since locating the header is unreliable, and the GNU /// extensions do not emit it. pub fn get_address( &self, address_size: u8, base: DebugAddrBase, index: DebugAddrIndex, ) -> Result { let input = &mut self.section.clone(); input.skip(base.0)?; input.skip(R::Offset::from_u64( index.0.into_u64() * u64::from(address_size), )?)?; input.read_address(address_size) } } impl DebugAddr { /// Create a `DebugAddr` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugAddr> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr where F: FnMut(&'a T) -> R, { borrow(&self.section).into() } } impl Section for DebugAddr { fn id() -> SectionId { SectionId::DebugAddr } fn reader(&self) -> &R { &self.section } } impl From for DebugAddr { fn from(section: R) -> Self { DebugAddr { section } } } #[cfg(test)] mod tests { use super::*; use crate::read::EndianSlice; use crate::test_util::GimliSectionMethods; use crate::{Format, LittleEndian}; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] fn test_get_address() { for format in vec![Format::Dwarf32, Format::Dwarf64] { for address_size in vec![4, 8] { let zero = Label::new(); let length = Label::new(); let start = Label::new(); let first = Label::new(); let end = Label::new(); let mut section = Section::with_endian(Endian::Little) .mark(&zero) .initial_length(format, &length, &start) .D16(5) .D8(address_size) .D8(0) .mark(&first); for i in 0..20 { section = section.word(address_size, 1000 + i); } section = section.mark(&end); length.set_const((&end - &start) as u64); let section = section.get_contents().unwrap(); let debug_addr = DebugAddr::from(EndianSlice::new(§ion, LittleEndian)); let base = DebugAddrBase((&first - &zero) as usize); assert_eq!( debug_addr.get_address(address_size, base, DebugAddrIndex(0)), Ok(1000) ); assert_eq!( debug_addr.get_address(address_size, base, DebugAddrIndex(19)), Ok(1019) ); } } } } gimli-0.19.0/src/read/aranges.rs010066400017500001750000000327101346020377600146300ustar0000000000000000use fallible_iterator::FallibleIterator; use std::cmp::Ordering; use std::marker::PhantomData; use crate::common::{DebugInfoOffset, Encoding, SectionId}; use crate::endianity::Endianity; use crate::read::lookup::{DebugLookup, LookupEntryIter, LookupParser}; use crate::read::{ parse_debug_info_offset, EndianSlice, Error, Reader, ReaderOffset, Result, Section, }; #[derive(Debug, Clone, PartialEq, Eq)] struct ArangeHeader { encoding: Encoding, length: T, offset: DebugInfoOffset, segment_size: u8, } /// A single parsed arange. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ArangeEntry { segment: Option, address: u64, length: u64, unit_header_offset: DebugInfoOffset, } impl ArangeEntry { /// Return the segment selector of this arange. #[inline] pub fn segment(&self) -> Option { self.segment } /// Return the beginning address of this arange. #[inline] pub fn address(&self) -> u64 { self.address } /// Return the length of this arange. #[inline] pub fn length(&self) -> u64 { self.length } /// Return the offset into the .debug_info section for this arange. #[inline] pub fn debug_info_offset(&self) -> DebugInfoOffset { self.unit_header_offset } } impl PartialOrd for ArangeEntry { fn partial_cmp(&self, other: &ArangeEntry) -> Option { Some(self.cmp(other)) } } impl Ord for ArangeEntry { fn cmp(&self, other: &ArangeEntry) -> Ordering { // The expected comparison, but ignore header. match ( self.segment.cmp(&other.segment), self.address.cmp(&other.address), self.length.cmp(&other.length), ) { (Ordering::Equal, Ordering::Equal, Ordering::Equal) => Ordering::Equal, (Ordering::Less, _, _) | (Ordering::Equal, Ordering::Less, _) | (Ordering::Equal, Ordering::Equal, Ordering::Less) => Ordering::Less, (Ordering::Greater, _, _) | (Ordering::Equal, Ordering::Greater, _) | (Ordering::Equal, Ordering::Equal, Ordering::Greater) => Ordering::Greater, } } } #[derive(Clone, Debug)] struct ArangeParser { // This struct is never instantiated. phantom: PhantomData, } impl LookupParser for ArangeParser { type Header = ArangeHeader; type Entry = ArangeEntry; /// Parse an arange set header. Returns a tuple of the aranges to be /// parsed for this set, and the newly created ArangeHeader struct. fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { let (length, format) = input.read_initial_length()?; let mut rest = input.split(length)?; let version = rest.read_u16()?; if version != 2 { return Err(Error::UnknownVersion(u64::from(version))); } let offset = parse_debug_info_offset(&mut rest, format)?; let address_size = rest.read_u8()?; let segment_size = rest.read_u8()?; // unit_length + version + offset + address_size + segment_size let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1; // The first tuple following the header in each set begins at an offset that is // a multiple of the size of a single tuple (that is, the size of a segment selector // plus twice the size of an address). let tuple_length = 2 * address_size + segment_size; let padding = if header_length % tuple_length == 0 { 0 } else { tuple_length - header_length % tuple_length }; rest.skip(R::Offset::from_u8(padding))?; let encoding = Encoding { format, version, address_size, // TODO: segment_size }; Ok(( rest, ArangeHeader { encoding, length, offset, segment_size, }, )) } /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. fn parse_entry(input: &mut R, header: &Self::Header) -> Result> { let address_size = header.encoding.address_size; let segment_size = header.segment_size; // May be zero! let tuple_length = R::Offset::from_u8(2 * address_size + segment_size); if tuple_length > input.len() { input.empty(); return Ok(None); } let segment = if segment_size != 0 { input.read_address(segment_size)? } else { 0 }; let address = input.read_address(address_size)?; let length = input.read_address(address_size)?; match (segment, address, length) { // There may be multiple sets of tuples, each terminated by a zero tuple. // It's not clear what purpose these zero tuples serve. For now, we // simply skip them. (0, 0, 0) => Self::parse_entry(input, header), _ => Ok(Some(ArangeEntry { segment: if segment_size != 0 { Some(segment) } else { None }, address, length, unit_header_offset: header.offset, })), } } } /// The `DebugAranges` struct represents the DWARF address range information /// found in the `.debug_aranges` section. #[derive(Debug, Clone)] pub struct DebugAranges(DebugLookup>); impl<'input, Endian> DebugAranges> where Endian: Endianity, { /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges` /// section. /// /// It is the caller's responsibility to read the `.debug_aranges` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugAranges, LittleEndian}; /// /// # let buf = []; /// # let read_debug_aranges_section = || &buf; /// let debug_aranges = /// DebugAranges::new(read_debug_aranges_section(), LittleEndian); /// ``` pub fn new(debug_aranges_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_aranges_section, endian)) } } impl DebugAranges { /// Iterate the aranges in the `.debug_aranges` section. /// /// ``` /// use gimli::{DebugAranges, EndianSlice, LittleEndian}; /// /// # let buf = []; /// # let read_debug_aranges_section = || &buf; /// let debug_aranges = DebugAranges::new(read_debug_aranges_section(), LittleEndian); /// /// let mut iter = debug_aranges.items(); /// while let Some(arange) = iter.next().unwrap() { /// println!("arange starts at {}, has length {}", arange.address(), arange.length()); /// } /// ``` pub fn items(&self) -> ArangeEntryIter { ArangeEntryIter(self.0.items()) } } impl Section for DebugAranges { fn id() -> SectionId { SectionId::DebugAranges } fn reader(&self) -> &R { self.0.reader() } } impl From for DebugAranges { fn from(debug_aranges_section: R) -> Self { DebugAranges(DebugLookup::from(debug_aranges_section)) } } /// An iterator over the aranges from a `.debug_aranges` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[derive(Debug, Clone)] pub struct ArangeEntryIter(LookupEntryIter>); impl ArangeEntryIter { /// Advance the iterator and return the next arange. /// /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)` /// when iteration is complete and all aranges have already been parsed and /// yielded. If an error occurs while parsing the next arange, then this error /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. pub fn next(&mut self) -> Result>> { self.0.next() } } impl FallibleIterator for ArangeEntryIter { type Item = ArangeEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { self.0.next() } } #[cfg(test)] mod tests { use super::*; use crate::common::{DebugInfoOffset, Format}; use crate::endianity::LittleEndian; use crate::read::lookup::LookupParser; use crate::read::EndianSlice; #[test] fn test_parse_header_ok() { #[rustfmt::skip] let buf = [ // 32-bit length = 32. 0x20, 0x00, 0x00, 0x00, // Version. 0x02, 0x00, // Offset. 0x01, 0x02, 0x03, 0x04, // Address size. 0x08, // Segment size. 0x04, // Length to here = 12, tuple length = 20. // Padding to tuple length multiple = 4. 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dummy arange tuple data. 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dummy next arange. 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let (tuples, header) = ArangeParser::parse_header(rest).expect("should parse header ok"); assert_eq!( *rest, EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) ); assert_eq!( tuples, EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian) ); assert_eq!( header, ArangeHeader { encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 8, }, length: 0x20, offset: DebugInfoOffset(0x0403_0201), segment_size: 4, } ); } #[test] fn test_parse_entry_ok() { let header = ArangeHeader { encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 4, }, length: 0, offset: DebugInfoOffset(0), segment_size: 0, }; let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, Some(ArangeEntry { segment: None, address: 0x0403_0201, length: 0x0807_0605, unit_header_offset: header.offset, }) ); } #[test] fn test_parse_entry_segment() { let header = ArangeHeader { encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 4, }, length: 0, offset: DebugInfoOffset(0), segment_size: 8, }; #[rustfmt::skip] let buf = [ // Segment. 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Address. 0x01, 0x02, 0x03, 0x04, // Length. 0x05, 0x06, 0x07, 0x08, // Next tuple. 0x09 ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, Some(ArangeEntry { segment: Some(0x1817_1615_1413_1211), address: 0x0403_0201, length: 0x0807_0605, unit_header_offset: header.offset, }) ); } #[test] fn test_parse_entry_zero() { let header = ArangeHeader { encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 4, }, length: 0, offset: DebugInfoOffset(0), segment_size: 0, }; #[rustfmt::skip] let buf = [ // Zero tuple. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address. 0x01, 0x02, 0x03, 0x04, // Length. 0x05, 0x06, 0x07, 0x08, // Next tuple. 0x09 ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, Some(ArangeEntry { segment: None, address: 0x0403_0201, length: 0x0807_0605, unit_header_offset: header.offset, }) ); } } gimli-0.19.0/src/read/cfi.rs010066400017500001750000007514761346020377600137720ustar0000000000000000use crate::boxed::Box; use arrayvec::ArrayVec; use fallible_iterator::FallibleIterator; use std::cmp::{Ord, Ordering}; use std::fmt::Debug; use std::iter::FromIterator; use std::mem; use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId}; use crate::constants::{self, DwEhPe}; use crate::endianity::Endianity; use crate::read::{EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section}; /// `DebugFrame` contains the `.debug_frame` section's frame unwinding /// information required to unwind to and recover registers from older frames on /// the stack. For example, this is useful for a debugger that wants to print /// locals in a backtrace. /// /// Most interesting methods are defined in the /// [`UnwindSection`](trait.UnwindSection.html) trait. /// /// ### Differences between `.debug_frame` and `.eh_frame` /// /// While the `.debug_frame` section's information has a lot of overlap with the /// `.eh_frame` section's information, the `.eh_frame` information tends to only /// encode the subset of information needed for exception handling. Often, only /// one of `.eh_frame` or `.debug_frame` will be present in an object file. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DebugFrame { section: R, address_size: u8, segment_size: u8, } impl DebugFrame { /// Set the size of a target address in bytes. /// /// This defaults to the native word size. /// This is only used if the CIE version is less than 4. pub fn set_address_size(&mut self, address_size: u8) { self.address_size = address_size } /// Set the size of a segment selector in bytes. /// /// This defaults to 0. /// This is only used if the CIE version is less than 4. pub fn set_segment_size(&mut self, segment_size: u8) { self.segment_size = segment_size } } impl<'input, Endian> DebugFrame> where Endian: Endianity, { /// Construct a new `DebugFrame` instance from the data in the /// `.debug_frame` section. /// /// It is the caller's responsibility to read the section and present it as /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O /// loader on OSX, etc. /// /// ``` /// use gimli::{DebugFrame, NativeEndian}; /// /// // Use with `.debug_frame` /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_frame_section_somehow = || &buf; /// let debug_frame = DebugFrame::new(read_debug_frame_section_somehow(), NativeEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for DebugFrame { fn id() -> SectionId { SectionId::DebugFrame } fn reader(&self) -> &R { &self.section } } impl From for DebugFrame { fn from(section: R) -> Self { // Default to no segments and native word size. DebugFrame { section, address_size: mem::size_of::() as u8, segment_size: 0, } } } /// `EhFrameHdr` contains the information about the `.eh_frame_hdr` section. /// /// A pointer to the start of the `.eh_frame` data, and optionally, a binary /// search table of pointers to the `.eh_frame` records that are found in this section. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct EhFrameHdr(R); /// `ParsedEhFrameHdr` contains the parsed information from the `.eh_frame_hdr` section. #[derive(Clone, Debug)] pub struct ParsedEhFrameHdr { address_size: u8, section: R, eh_frame_ptr: Pointer, fde_count: u64, table_enc: DwEhPe, table: R, } impl<'input, Endian> EhFrameHdr> where Endian: Endianity, { /// Constructs a new `EhFrameHdr` instance from the data in the `.eh_frame_hdr` section. pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl EhFrameHdr { /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`. pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result> { let mut reader = self.0.clone(); let version = reader.read_u8()?; if version != 1 { return Err(Error::UnknownVersion(u64::from(version))); } let eh_frame_ptr_enc = parse_pointer_encoding(&mut reader)?; let fde_count_enc = parse_pointer_encoding(&mut reader)?; let table_enc = parse_pointer_encoding(&mut reader)?; let parameters = PointerEncodingParameters { bases: &bases.eh_frame_hdr, func_base: None, address_size, section: &self.0, }; // Omitting this pointer is not valid (defeats the purpose of .eh_frame_hdr entirely) if eh_frame_ptr_enc == constants::DW_EH_PE_omit { return Err(Error::CannotParseOmitPointerEncoding); } let eh_frame_ptr = parse_encoded_pointer(eh_frame_ptr_enc, ¶meters, &mut reader)?; let fde_count; if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit { fde_count = 0 } else { let ptr = parse_encoded_pointer(fde_count_enc, ¶meters, &mut reader)?; fde_count = match ptr { Pointer::Direct(c) => c, Pointer::Indirect(_) => return Err(Error::UnsupportedPointerEncoding), } } Ok(ParsedEhFrameHdr { address_size, section: self.0.clone(), eh_frame_ptr, fde_count, table_enc, table: reader, }) } } impl Section for EhFrameHdr { fn id() -> SectionId { SectionId::EhFrameHdr } fn reader(&self) -> &R { &self.0 } } impl From for EhFrameHdr { fn from(section: R) -> Self { EhFrameHdr(section) } } impl ParsedEhFrameHdr { /// Returns the address of the binary's `.eh_frame` section. pub fn eh_frame_ptr(&self) -> Pointer { self.eh_frame_ptr } /// Retrieves the CFI binary search table, if there is one. pub fn table(&self) -> Option> { // There are two big edge cases here: // * You search the table for an invalid address. As this is just a binary // search table, we always have to return a valid result for that (unless // you specify an address that is lower than the first address in the // table). Since this means that you have to recheck that the FDE contains // your address anyways, we just return the first FDE even when the address // is too low. After all, we're just doing a normal binary search. // * This falls apart when the table is empty - there is no entry we could // return. We conclude that an empty table is not really a table at all. if self.fde_count == 0 { None } else { Some(EhHdrTable { hdr: self }) } } } /// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section. #[derive(Debug, Clone)] pub struct EhHdrTable<'a, R: Reader> { hdr: &'a ParsedEhFrameHdr, } impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { /// *Probably* returns a pointer to the FDE for the given address. /// /// This performs a binary search, so if there is no FDE for the given address, /// this function **will** return a pointer to any other FDE that's close by. /// /// To be sure, you **must** call `contains` on the FDE. pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result { let size = match self.hdr.table_enc.format() { constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { return Err(Error::VariableLengthSearchTable); } constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2, constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4, constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8, _ => return Err(Error::UnknownPointerEncoding), }; let row_size = size * 2; let mut len = self.hdr.fde_count; let mut reader = self.hdr.table.clone(); let parameters = PointerEncodingParameters { bases: &bases.eh_frame_hdr, func_base: None, address_size: self.hdr.address_size, section: &self.hdr.section, }; while len > 1 { let head = reader.split(R::Offset::from_u64((len / 2) * row_size)?)?; let tail = reader.clone(); let pivot = parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader)?; let pivot = match pivot { Pointer::Direct(x) => x, Pointer::Indirect(_) => return Err(Error::UnsupportedPointerEncoding), }; match pivot.cmp(&address) { Ordering::Equal => { reader = tail; break; } Ordering::Less => { reader = tail; len = len - (len / 2); } Ordering::Greater => { reader = head; len /= 2; } } } reader.skip(R::Offset::from_u64(size)?)?; parse_encoded_pointer(self.hdr.table_enc, ¶meters, &mut reader) } /// Convert a `Pointer` to a section offset. /// /// This does not support indirect pointers. pub fn pointer_to_offset(&self, ptr: Pointer) -> Result> { let ptr = match ptr { Pointer::Direct(x) => x, _ => return Err(Error::UnsupportedPointerEncoding), }; let eh_frame_ptr = match self.hdr.eh_frame_ptr() { Pointer::Direct(x) => x, _ => return Err(Error::UnsupportedPointerEncoding), }; // Calculate the offset in the EhFrame section R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset) } /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress` /// if there are none. /// /// You must provide a function to get its associated CIE. See /// `PartialFrameDescriptionEntry::parse` for more information. /// /// # Example /// /// ``` /// # use gimli::{BaseAddresses, EhFrame, ParsedEhFrameHdr, EndianRcSlice, NativeEndian, Error, UnwindSection}; /// # fn foo() -> Result<(), Error> { /// # let eh_frame: EhFrame> = unreachable!(); /// # let eh_frame_hdr: ParsedEhFrameHdr> = unimplemented!(); /// # let addr = 0; /// # let bases = unimplemented!(); /// let table = eh_frame_hdr.table().unwrap(); /// let fde = table.fde_for_address(&eh_frame, &bases, addr, EhFrame::cie_from_offset)?; /// # Ok(()) /// # } /// ``` pub fn fde_for_address( &self, frame: &EhFrame, bases: &BaseAddresses, address: u64, get_cie: F, ) -> Result> where F: FnMut( &EhFrame, &BaseAddresses, EhFrameOffset, ) -> Result>, { let fdeptr = self.lookup(address, bases)?; let offset = self.pointer_to_offset(fdeptr)?; let entry = frame.fde_from_offset(bases, offset, get_cie)?; if entry.contains(address) { Ok(entry) } else { Err(Error::NoUnwindInfoForAddress) } } #[inline] #[doc(hidden)] #[deprecated(note = "Method renamed to fde_for_address; use that instead.")] pub fn lookup_and_parse( &self, address: u64, bases: &BaseAddresses, frame: EhFrame, get_cie: F, ) -> Result> where F: FnMut( &EhFrame, &BaseAddresses, EhFrameOffset, ) -> Result>, { self.fde_for_address(&frame, bases, address, get_cie) } /// Returns the frame unwind information for the given address, /// or `NoUnwindInfoForAddress` if there are none. /// /// You must provide a function to get the associated CIE. See /// `PartialFrameDescriptionEntry::parse` for more information. pub fn unwind_info_for_address( &self, frame: &EhFrame, bases: &BaseAddresses, ctx: &mut UninitializedUnwindContext, address: u64, get_cie: F, ) -> Result> where F: FnMut( &EhFrame, &BaseAddresses, EhFrameOffset, ) -> Result>, { let fde = self.fde_for_address(frame, bases, address, get_cie)?; fde.unwind_info_for_address(frame, bases, ctx, address) } } /// `EhFrame` contains the frame unwinding information needed during exception /// handling found in the `.eh_frame` section. /// /// Most interesting methods are defined in the /// [`UnwindSection`](trait.UnwindSection.html) trait. /// /// See /// [`DebugFrame`](./struct.DebugFrame.html#differences-between-debug_frame-and-eh_frame) /// for some discussion on the differences between `.debug_frame` and /// `.eh_frame`. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct EhFrame { section: R, address_size: u8, } impl EhFrame { /// Set the size of a target address in bytes. /// /// This defaults to the native word size. pub fn set_address_size(&mut self, address_size: u8) { self.address_size = address_size } } impl<'input, Endian> EhFrame> where Endian: Endianity, { /// Construct a new `EhFrame` instance from the data in the /// `.debug_frame` section. /// /// It is the caller's responsibility to read the section and present it as /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O /// loader on OSX, etc. /// /// ``` /// use gimli::{EhFrame, EndianSlice, NativeEndian}; /// /// // Use with `.debug_frame` /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_frame_section_somehow = || &buf; /// let debug_frame = EhFrame::new(read_debug_frame_section_somehow(), NativeEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for EhFrame { fn id() -> SectionId { SectionId::EhFrame } fn reader(&self) -> &R { &self.section } } impl From for EhFrame { fn from(section: R) -> Self { // Default to native word size. EhFrame { section, address_size: mem::size_of::() as u8, } } } // This has to be `pub` to silence a warning (that is deny(..)'d by default) in // rustc. Eventually, not having this `pub` will become a hard error. #[doc(hidden)] #[allow(missing_docs)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CieOffsetEncoding { U32, U64, } // Ditto about being `pub`. #[doc(hidden)] #[allow(missing_docs)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ReturnAddressRegisterEncoding { U8, Uleb, } /// An offset into an `UnwindSection`. // // Needed to avoid conflicting implementations of `Into`. pub trait UnwindOffset: Copy + Debug + Eq + From where T: ReaderOffset, { /// Convert an `UnwindOffset` into a `T`. fn into(self) -> T; } impl UnwindOffset for DebugFrameOffset where T: ReaderOffset, { #[inline] fn into(self) -> T { self.0 } } impl UnwindOffset for EhFrameOffset where T: ReaderOffset, { #[inline] fn into(self) -> T { self.0 } } /// This trait completely encapsulates everything that is different between /// `.eh_frame` and `.debug_frame`, as well as all the bits that can change /// between DWARF versions. #[doc(hidden)] pub trait _UnwindSectionPrivate { /// Get the underlying section data. fn section(&self) -> &R; /// Returns true if the given length value should be considered an /// end-of-entries sentinel. fn length_value_is_end_of_entries(length: R::Offset) -> bool; /// Return true if the given offset if the CIE sentinel, false otherwise. fn is_cie(format: Format, id: u64) -> bool; /// Return the CIE offset/ID encoding used by this unwind section with the /// given DWARF format. fn cie_offset_encoding(format: Format) -> CieOffsetEncoding; /// For `.eh_frame`, CIE offsets are relative to the current position. For /// `.debug_frame`, they are relative to the start of the section. We always /// internally store them relative to the section, so we handle translating /// `.eh_frame`'s relative offsets in this method. If the offset calculation /// underflows, return `None`. fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option; /// Return true if our parser is compatible with the given version. fn compatible_version(version: u8) -> bool; /// Does this version of this unwind section encode address and segment /// sizes in its CIEs? fn has_address_and_segment_sizes(version: u8) -> bool; /// The address size to use if `has_address_and_segment_sizes` returns false. fn address_size(&self) -> u8; /// The segment size to use if `has_address_and_segment_sizes` returns false. fn segment_size(&self) -> u8; /// What is the encoding used for the return address register in CIEs for /// this unwind section? fn return_address_register_encoding(version: u8) -> ReturnAddressRegisterEncoding; } /// A section holding unwind information: either `.debug_frame` or /// `.eh_frame`. See [`DebugFrame`](./struct.DebugFrame.html) and /// [`EhFrame`](./struct.EhFrame.html) respectively. pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// The offset type associated with this CFI section. Either /// `DebugFrameOffset` or `EhFrameOffset`. type Offset: UnwindOffset; /// Iterate over the `CommonInformationEntry`s and `FrameDescriptionEntry`s /// in this `.debug_frame` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> { CfiEntriesIter { section: self.clone(), bases, input: self.section().clone(), } } /// Parse the `CommonInformationEntry` at the given offset. fn cie_from_offset( &self, bases: &BaseAddresses, offset: Self::Offset, ) -> Result> { let offset = UnwindOffset::into(offset); let input = &mut self.section().clone(); input.skip(offset)?; CommonInformationEntry::parse(bases, self, input) } /// Parse the `PartialFrameDescriptionEntry` at the given offset. fn partial_fde_from_offset<'bases>( &self, bases: &'bases BaseAddresses, offset: Self::Offset, ) -> Result> { let offset = UnwindOffset::into(offset); let input = &mut self.section().clone(); input.skip(offset)?; PartialFrameDescriptionEntry::parse_partial(self, bases, input) } /// Parse the `FrameDescriptionEntry` at the given offset. fn fde_from_offset( &self, bases: &BaseAddresses, offset: Self::Offset, get_cie: F, ) -> Result> where F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, { let partial = self.partial_fde_from_offset(bases, offset)?; partial.parse(get_cie) } /// Find the `FrameDescriptionEntry` for the given address. /// /// If found, the FDE is returned. If not found, /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. /// If parsing fails, the error is returned. /// /// You must provide a function to get its associated CIE. See /// `PartialFrameDescriptionEntry::parse` for more information. /// /// Note: this iterates over all FDEs. If available, it is possible /// to do a binary search with `EhFrameHdr::fde_for_address` instead. fn fde_for_address( &self, bases: &BaseAddresses, address: u64, mut get_cie: F, ) -> Result> where F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, { let mut entries = self.entries(bases); while let Some(entry) = entries.next()? { match entry { CieOrFde::Cie(_) => {} CieOrFde::Fde(partial) => { let fde = partial.parse(&mut get_cie)?; if fde.contains(address) { return Ok(fde); } } } } Err(Error::NoUnwindInfoForAddress) } /// Find the frame unwind information for the given address. /// /// If found, the unwind information is returned. If not found, /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or /// CFI evaluation fails, the error is returned. /// /// ``` /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UninitializedUnwindContext, /// UnwindSection}; /// /// # fn foo() -> gimli::Result<()> { /// # let read_eh_frame_section = || unimplemented!(); /// // Get the `.eh_frame` section from the object file. Alternatively, /// // use `EhFrame` with the `.eh_frame` section of the object file. /// let eh_frame = EhFrame::new(read_eh_frame_section(), NativeEndian); /// /// # let get_frame_pc = || unimplemented!(); /// // Get the address of the PC for a frame you'd like to unwind. /// let address = get_frame_pc(); /// /// // This context is reusable, which cuts down on heap allocations. /// let ctx = UninitializedUnwindContext::new(); /// /// // Optionally provide base addresses for any relative pointers. If a /// // base address isn't provided and a pointer is found that is relative to /// // it, we will return an `Err`. /// # let address_of_text_section_in_memory = unimplemented!(); /// # let address_of_got_section_in_memory = unimplemented!(); /// let bases = BaseAddresses::default() /// .set_text(address_of_text_section_in_memory) /// .set_got(address_of_got_section_in_memory); /// /// let unwind_info = eh_frame.unwind_info_for_address( /// &bases, /// &mut ctx, /// address, /// EhFrame::cie_from_offset, /// )?; /// /// # let do_stuff_with = |_| unimplemented!(); /// do_stuff_with(unwind_info); /// # let _ = ctx; /// # unreachable!() /// # } /// ``` #[inline] fn unwind_info_for_address( &self, bases: &BaseAddresses, ctx: &mut UninitializedUnwindContext, address: u64, get_cie: F, ) -> Result> where F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, { let fde = self.fde_for_address(bases, address, get_cie)?; fde.unwind_info_for_address(self, bases, ctx, address) } } impl _UnwindSectionPrivate for DebugFrame { fn section(&self) -> &R { &self.section } fn length_value_is_end_of_entries(_: R::Offset) -> bool { false } fn is_cie(format: Format, id: u64) -> bool { match format { Format::Dwarf32 => id == 0xffff_ffff, Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff, } } fn cie_offset_encoding(format: Format) -> CieOffsetEncoding { match format { Format::Dwarf32 => CieOffsetEncoding::U32, Format::Dwarf64 => CieOffsetEncoding::U64, } } fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option { Some(offset) } fn compatible_version(version: u8) -> bool { // Version 1 of `.debug_frame` corresponds to DWARF 2, and then for // DWARF 3 and 4, I think they decided to just match the standard's // version. match version { 1 | 3 | 4 => true, _ => false, } } fn has_address_and_segment_sizes(version: u8) -> bool { version == 4 } fn address_size(&self) -> u8 { self.address_size } fn segment_size(&self) -> u8 { self.segment_size } fn return_address_register_encoding(version: u8) -> ReturnAddressRegisterEncoding { if version == 1 { ReturnAddressRegisterEncoding::U8 } else { ReturnAddressRegisterEncoding::Uleb } } } impl UnwindSection for DebugFrame { type Offset = DebugFrameOffset; } impl _UnwindSectionPrivate for EhFrame { fn section(&self) -> &R { &self.section } fn length_value_is_end_of_entries(length: R::Offset) -> bool { length.into_u64() == 0 } fn is_cie(_: Format, id: u64) -> bool { id == 0 } fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding { // `.eh_frame` offsets are always 4 bytes, regardless of the DWARF // format. CieOffsetEncoding::U32 } fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option { base.checked_sub(offset) } fn compatible_version(version: u8) -> bool { version == 1 } fn has_address_and_segment_sizes(_version: u8) -> bool { false } fn address_size(&self) -> u8 { self.address_size } fn segment_size(&self) -> u8 { 0 } fn return_address_register_encoding(_version: u8) -> ReturnAddressRegisterEncoding { ReturnAddressRegisterEncoding::Uleb } } impl UnwindSection for EhFrame { type Offset = EhFrameOffset; } /// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers. /// /// During CIE/FDE parsing, if a relative pointer is encountered for a base /// address that is unknown, an Err will be returned. /// /// ``` /// use gimli::BaseAddresses; /// /// # fn foo() { /// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); /// # let address_of_eh_frame_section_in_memory = unimplemented!(); /// # let address_of_text_section_in_memory = unimplemented!(); /// # let address_of_got_section_in_memory = unimplemented!(); /// # let address_of_the_start_of_current_func = unimplemented!(); /// let bases = BaseAddresses::default() /// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) /// .set_eh_frame(address_of_eh_frame_section_in_memory) /// .set_text(address_of_text_section_in_memory) /// .set_got(address_of_got_section_in_memory); /// # let _ = bases; /// # } /// ``` #[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct BaseAddresses { /// The base addresses to use for pointers in the `.eh_frame_hdr` section. pub eh_frame_hdr: SectionBaseAddresses, /// The base addresses to use for pointers in the `.eh_frame` section. pub eh_frame: SectionBaseAddresses, } /// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers /// in a particular section. /// /// See `BaseAddresses` for methods that are helpful in setting these addresses. #[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct SectionBaseAddresses { /// The address of the section containing the pointer. pub section: Option, /// The base address for text relative pointers. /// This is generally the address of the `.text` section. pub text: Option, /// The base address for data relative pointers. /// /// For pointers in the `.eh_frame_hdr` section, this is the address /// of the `.eh_frame_hdr` section /// /// For pointers in the `.eh_frame` section, this is generally the /// global pointer, such as the address of the `.got` section. pub data: Option, } impl BaseAddresses { /// Set the `.eh_frame_hdr` section base address. #[inline] pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self { self.eh_frame_hdr.section = Some(addr); self.eh_frame_hdr.data = Some(addr); self } /// Set the `.eh_frame` section base address. #[inline] pub fn set_eh_frame(mut self, addr: u64) -> Self { self.eh_frame.section = Some(addr); self } /// Set the `.text` section base address. #[inline] pub fn set_text(mut self, addr: u64) -> Self { self.eh_frame_hdr.text = Some(addr); self.eh_frame.text = Some(addr); self } /// Set the `.got` section base address. #[inline] pub fn set_got(mut self, addr: u64) -> Self { self.eh_frame.data = Some(addr); self } } /// An iterator over CIE and FDE entries in a `.debug_frame` or `.eh_frame` /// section. /// /// Some pointers may be encoded relative to various base addresses. Use the /// [`BaseAddresses`](./struct.BaseAddresses.html) parameter to provide them. By /// default, none are provided. If a relative pointer is encountered for a base /// address that is unknown, an `Err` will be returned and iteration will abort. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). /// /// ``` /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindSection}; /// /// # fn foo() -> gimli::Result<()> { /// # let read_eh_frame_somehow = || unimplemented!(); /// let eh_frame = EhFrame::new(read_eh_frame_somehow(), NativeEndian); /// /// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!(); /// # let address_of_eh_frame_section_in_memory = unimplemented!(); /// # let address_of_text_section_in_memory = unimplemented!(); /// # let address_of_got_section_in_memory = unimplemented!(); /// # let address_of_the_start_of_current_func = unimplemented!(); /// // Provide base addresses for relative pointers. /// let bases = BaseAddresses::default() /// .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory) /// .set_eh_frame(address_of_eh_frame_section_in_memory) /// .set_text(address_of_text_section_in_memory) /// .set_got(address_of_got_section_in_memory); /// /// let mut entries = eh_frame.entries(&bases); /// /// # let do_stuff_with = |_| unimplemented!(); /// while let Some(entry) = entries.next()? { /// do_stuff_with(entry) /// } /// # unreachable!() /// # } /// ``` #[derive(Clone, Debug)] pub struct CfiEntriesIter<'bases, Section, R> where R: Reader, Section: UnwindSection, { section: Section, bases: &'bases BaseAddresses, input: R, } impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R> where R: Reader, Section: UnwindSection, { /// Advance the iterator to the next entry. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } match parse_cfi_entry(self.bases, &self.section, &mut self.input) { Err(e) => { self.input.empty(); Err(e) } Ok(None) => { self.input.empty(); Ok(None) } Ok(Some(entry)) => Ok(Some(entry)), } } } impl<'bases, Section, R> FallibleIterator for CfiEntriesIter<'bases, Section, R> where R: Reader, Section: UnwindSection, { type Item = CieOrFde<'bases, Section, R>; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { CfiEntriesIter::next(self) } } /// Either a `CommonInformationEntry` (CIE) or a `FrameDescriptionEntry` (FDE). #[derive(Clone, Debug, PartialEq, Eq)] pub enum CieOrFde<'bases, Section, R> where R: Reader, Section: UnwindSection, { /// This CFI entry is a `CommonInformationEntry`. Cie(CommonInformationEntry), /// This CFI entry is a `FrameDescriptionEntry`, however fully parsing it /// requires parsing its CIE first, so it is left in a partially parsed /// state. Fde(PartialFrameDescriptionEntry<'bases, Section, R>), } #[allow(clippy::type_complexity)] fn parse_cfi_entry<'bases, Section, R>( bases: &'bases BaseAddresses, section: &Section, input: &mut R, ) -> Result>> where R: Reader, Section: UnwindSection, { let offset = input.offset_from(section.section()); let (length, format) = input.read_initial_length()?; if Section::length_value_is_end_of_entries(length) { return Ok(None); } let mut rest = input.split(length)?; let cie_offset_base = rest.offset_from(section.section()); let cie_id_or_offset = match Section::cie_offset_encoding(format) { CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?, CieOffsetEncoding::U64 => rest.read_u64()?, }; if Section::is_cie(format, cie_id_or_offset) { let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?; Ok(Some(CieOrFde::Cie(cie))) } else { let cie_offset = R::Offset::from_u64(cie_id_or_offset)?; let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) { None => return Err(Error::OffsetOutOfBounds), Some(cie_offset) => cie_offset, }; let fde = PartialFrameDescriptionEntry { offset, length, format, cie_offset: cie_offset.into(), rest, section: section.clone(), bases, }; Ok(Some(CieOrFde::Fde(fde))) } } /// We support the z-style augmentation [defined by `.eh_frame`][ehframe]. /// /// [ehframe]: http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub struct Augmentation { /// > A 'L' may be present at any position after the first character of the /// > string. This character may only be present if 'z' is the first character /// > of the string. If present, it indicates the presence of one argument in /// > the Augmentation Data of the CIE, and a corresponding argument in the /// > Augmentation Data of the FDE. The argument in the Augmentation Data of /// > the CIE is 1-byte and represents the pointer encoding used for the /// > argument in the Augmentation Data of the FDE, which is the address of a /// > language-specific data area (LSDA). The size of the LSDA pointer is /// > specified by the pointer encoding used. lsda: Option, /// > A 'P' may be present at any position after the first character of the /// > string. This character may only be present if 'z' is the first character /// > of the string. If present, it indicates the presence of two arguments in /// > the Augmentation Data of the CIE. The first argument is 1-byte and /// > represents the pointer encoding used for the second argument, which is /// > the address of a personality routine handler. The size of the /// > personality routine pointer is specified by the pointer encoding used. personality: Option<(constants::DwEhPe, Pointer)>, /// > A 'R' may be present at any position after the first character of the /// > string. This character may only be present if 'z' is the first character /// > of the string. If present, The Augmentation Data shall include a 1 byte /// > argument that represents the pointer encoding for the address pointers /// > used in the FDE. fde_address_encoding: Option, /// True if this CIE's FDEs are trampolines for signal handlers. is_signal_trampoline: bool, } impl Augmentation { fn parse( augmentation_str: &mut R, bases: &BaseAddresses, address_size: u8, section: &Section, input: &mut R, ) -> Result where R: Reader, Section: UnwindSection, { debug_assert!( !augmentation_str.is_empty(), "Augmentation::parse should only be called if we have an augmentation" ); let first = augmentation_str.read_u8()?; if first != b'z' { return Err(Error::UnknownAugmentation); } let mut augmentation = Augmentation::default(); let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?; let rest = &mut input.split(augmentation_length)?; while !augmentation_str.is_empty() { let ch = augmentation_str.read_u8()?; match ch { b'L' => { let encoding = parse_pointer_encoding(rest)?; augmentation.lsda = Some(encoding); } b'P' => { let encoding = parse_pointer_encoding(rest)?; let parameters = PointerEncodingParameters { bases: &bases.eh_frame, func_base: None, address_size, section: section.section(), }; let personality = parse_encoded_pointer(encoding, ¶meters, rest)?; augmentation.personality = Some((encoding, personality)); } b'R' => { let encoding = parse_pointer_encoding(rest)?; augmentation.fde_address_encoding = Some(encoding); } b'S' => augmentation.is_signal_trampoline = true, _ => return Err(Error::UnknownAugmentation), } } Ok(augmentation) } } /// Parsed augmentation data for a `FrameDescriptEntry`. #[derive(Clone, Debug, Default, PartialEq, Eq)] struct AugmentationData { lsda: Option, } impl AugmentationData { fn parse( augmentation: &Augmentation, encoding_parameters: &PointerEncodingParameters, input: &mut R, ) -> Result { // In theory, we should be iterating over the original augmentation // string, interpreting each character, and reading the appropriate bits // out of the augmentation data as we go. However, the only character // that defines augmentation data in the FDE is the 'L' character, so we // can just check for its presence directly. let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?; let rest = &mut input.split(aug_data_len)?; let mut augmentation_data = AugmentationData::default(); if let Some(encoding) = augmentation.lsda { let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?; augmentation_data.lsda = Some(lsda); } Ok(augmentation_data) } } /// > A Common Information Entry holds information that is shared among many /// > Frame Description Entries. There is at least one CIE in every non-empty /// > `.debug_frame` section. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CommonInformationEntry::Offset> where R: Reader, Offset: ReaderOffset, { /// The offset of this entry from the start of its containing section. offset: Offset, /// > A constant that gives the number of bytes of the CIE structure, not /// > including the length field itself (see Section 7.2.2). The size of the /// > length field plus the value of length must be an integral multiple of /// > the address size. length: Offset, format: Format, /// > A version number (see Section 7.23). This number is specific to the /// > call frame information and is independent of the DWARF version number. version: u8, /// The parsed augmentation, if any. augmentation: Option, /// > The size of a target address in this CIE and any FDEs that use it, in /// > bytes. If a compilation unit exists for this frame, its address size /// > must match the address size here. address_size: u8, /// "The size of a segment selector in this CIE and any FDEs that use it, in /// bytes." segment_size: u8, /// "A constant that is factored out of all advance location instructions /// (see Section 6.4.2.1)." code_alignment_factor: u64, /// > A constant that is factored out of certain offset instructions (see /// > below). The resulting value is (operand * data_alignment_factor). data_alignment_factor: i64, /// > An unsigned LEB128 constant that indicates which column in the rule /// > table represents the return address of the function. Note that this /// > column might not correspond to an actual machine register. return_address_register: Register, /// > A sequence of rules that are interpreted to create the initial setting /// > of each column in the table. /// /// > The default rule for all columns before interpretation of the initial /// > instructions is the undefined rule. However, an ABI authoring body or a /// > compilation system authoring body may specify an alternate default /// > value for any or all columns. /// /// This is followed by `DW_CFA_nop` padding until the end of `length` bytes /// in the input. initial_instructions: R, } impl CommonInformationEntry { fn parse>( bases: &BaseAddresses, section: &Section, input: &mut R, ) -> Result> { match parse_cfi_entry(bases, section, input)? { Some(CieOrFde::Cie(cie)) => Ok(cie), Some(CieOrFde::Fde(_)) => Err(Error::NotCieId), None => Err(Error::NoEntryAtGivenOffset), } } fn parse_rest>( offset: R::Offset, length: R::Offset, format: Format, bases: &BaseAddresses, section: &Section, mut rest: R, ) -> Result> { let version = rest.read_u8()?; if !Section::compatible_version(version) { return Err(Error::UnknownVersion(u64::from(version))); } let mut augmentation_string = rest.read_null_terminated_slice()?; let (address_size, segment_size) = if Section::has_address_and_segment_sizes(version) { let address_size = rest.read_u8()?; let segment_size = rest.read_u8()?; (address_size, segment_size) } else { (section.address_size(), section.segment_size()) }; let code_alignment_factor = rest.read_uleb128()?; let data_alignment_factor = rest.read_sleb128()?; let return_address_register = match Section::return_address_register_encoding(version) { ReturnAddressRegisterEncoding::U8 => Register(rest.read_u8()?.into()), ReturnAddressRegisterEncoding::Uleb => { rest.read_uleb128().and_then(Register::from_u64)? } }; let augmentation = if augmentation_string.is_empty() { None } else { Some(Augmentation::parse( &mut augmentation_string, bases, address_size, section, &mut rest, )?) }; let entry = CommonInformationEntry { offset, length, format, version, augmentation, address_size, segment_size, code_alignment_factor, data_alignment_factor, return_address_register, initial_instructions: rest, }; Ok(entry) } } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. impl CommonInformationEntry { /// Get the offset of this entry from the start of its containing section. pub fn offset(&self) -> R::Offset { self.offset } /// Return the encoding parameters for this CIE. pub fn encoding(&self) -> Encoding { Encoding { format: self.format, version: u16::from(self.version), address_size: self.address_size, } } /// The size of addresses (in bytes) in this CIE. pub fn address_size(&self) -> u8 { self.address_size } /// Iterate over this CIE's initial instructions. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn instructions<'a, Section>( &self, section: &'a Section, bases: &'a BaseAddresses, ) -> CallFrameInstructionIter<'a, R> where Section: UnwindSection, { CallFrameInstructionIter { input: self.initial_instructions.clone(), address_encoding: None, parameters: PointerEncodingParameters { bases: &bases.eh_frame, func_base: None, address_size: self.address_size, section: section.section(), }, } } /// > A constant that gives the number of bytes of the CIE structure, not /// > including the length field itself (see Section 7.2.2). The size of the /// > length field plus the value of length must be an integral multiple of /// > the address size. pub fn entry_len(&self) -> R::Offset { self.length } /// > A version number (see Section 7.23). This number is specific to the /// > call frame information and is independent of the DWARF version number. pub fn version(&self) -> u8 { self.version } /// Get the augmentation data, if any exists. /// /// The only augmentation understood by `gimli` is that which is defined by /// `.eh_frame`. pub fn augmentation(&self) -> Option<&Augmentation> { self.augmentation.as_ref() } /// True if this CIE's FDEs have a LSDA. pub fn has_lsda(&self) -> bool { self.augmentation.map_or(false, |a| a.lsda.is_some()) } /// Return the encoding of the LSDA address for this CIE's FDEs. pub fn lsda_encoding(&self) -> Option { self.augmentation.and_then(|a| a.lsda) } /// Return the encoding and address of the personality routine handler /// for this CIE's FDEs. pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> { self.augmentation.as_ref().and_then(|a| a.personality) } /// Return the address of the personality routine handler /// for this CIE's FDEs. pub fn personality(&self) -> Option { self.augmentation .as_ref() .and_then(|a| a.personality) .map(|(_, p)| p) } /// Return the encoding of the addresses for this CIE's FDEs. pub fn fde_address_encoding(&self) -> Option { self.augmentation.and_then(|a| a.fde_address_encoding) } /// True if this CIE's FDEs are trampolines for signal handlers. pub fn is_signal_trampoline(&self) -> bool { self.augmentation.map_or(false, |a| a.is_signal_trampoline) } /// > A constant that is factored out of all advance location instructions /// > (see Section 6.4.2.1). pub fn code_alignment_factor(&self) -> u64 { self.code_alignment_factor } /// > A constant that is factored out of certain offset instructions (see /// > below). The resulting value is (operand * data_alignment_factor). pub fn data_alignment_factor(&self) -> i64 { self.data_alignment_factor } /// > An unsigned ... constant that indicates which column in the rule /// > table represents the return address of the function. Note that this /// > column might not correspond to an actual machine register. pub fn return_address_register(&self) -> Register { self.return_address_register } } /// A partially parsed `FrameDescriptionEntry`. /// /// Fully parsing this FDE requires first parsing its CIE. #[derive(Clone, Debug, PartialEq, Eq)] pub struct PartialFrameDescriptionEntry<'bases, Section, R> where R: Reader, Section: UnwindSection, { offset: R::Offset, length: R::Offset, format: Format, cie_offset: Section::Offset, rest: R, section: Section, bases: &'bases BaseAddresses, } impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R> where R: Reader, Section: UnwindSection, { fn parse_partial( section: &Section, bases: &'bases BaseAddresses, input: &mut R, ) -> Result> { match parse_cfi_entry(bases, section, input)? { Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer), Some(CieOrFde::Fde(partial)) => Ok(partial), None => Err(Error::NoEntryAtGivenOffset), } } /// Fully parse this FDE. /// /// You must provide a function get its associated CIE (either by parsing it /// on demand, or looking it up in some table mapping offsets to CIEs that /// you've already parsed, etc.) pub fn parse(&self, get_cie: F) -> Result> where F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, { FrameDescriptionEntry::parse_rest( self.offset, self.length, self.format, self.cie_offset, self.rest.clone(), &self.section, self.bases, get_cie, ) } } /// A `FrameDescriptionEntry` is a set of CFA instructions for an address range. #[derive(Clone, Debug, PartialEq, Eq)] pub struct FrameDescriptionEntry::Offset> where R: Reader, Offset: ReaderOffset, { /// The start of this entry within its containing section. offset: Offset, /// > A constant that gives the number of bytes of the header and /// > instruction stream for this function, not including the length field /// > itself (see Section 7.2.2). The size of the length field plus the value /// > of length must be an integral multiple of the address size. length: Offset, format: Format, /// "A constant offset into the .debug_frame section that denotes the CIE /// that is associated with this FDE." /// /// This is the CIE at that offset. cie: CommonInformationEntry, /// > The address of the first location associated with this table entry. If /// > the segment_size field of this FDE's CIE is non-zero, the initial /// > location is preceded by a segment selector of the given length. initial_segment: u64, initial_address: u64, /// "The number of bytes of program instructions described by this entry." address_range: u64, /// The parsed augmentation data, if we have any. augmentation: Option, /// "A sequence of table defining instructions that are described below." /// /// This is followed by `DW_CFA_nop` padding until `length` bytes of the /// input are consumed. instructions: R, } impl FrameDescriptionEntry { #[allow(clippy::too_many_arguments)] fn parse_rest( offset: R::Offset, length: R::Offset, format: Format, cie_pointer: Section::Offset, mut rest: R, section: &Section, bases: &BaseAddresses, mut get_cie: F, ) -> Result> where Section: UnwindSection, F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, { let cie = get_cie(section, bases, cie_pointer)?; let initial_segment = if cie.segment_size > 0 { rest.read_address(cie.segment_size)? } else { 0 }; let mut parameters = PointerEncodingParameters { bases: &bases.eh_frame, func_base: None, address_size: cie.address_size, section: section.section(), }; let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, ¶meters)?; parameters.func_base = Some(initial_address); let aug_data = if let Some(ref augmentation) = cie.augmentation { Some(AugmentationData::parse( augmentation, ¶meters, &mut rest, )?) } else { None }; let entry = FrameDescriptionEntry { offset, length, format, cie, initial_segment, initial_address, address_range, augmentation: aug_data, instructions: rest, }; Ok(entry) } fn parse_addresses( input: &mut R, cie: &CommonInformationEntry, parameters: &PointerEncodingParameters, ) -> Result<(u64, u64)> { let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding); if let Some(encoding) = encoding { let initial_address = parse_encoded_pointer(encoding, parameters, input)?; // Ignore indirection. let initial_address = initial_address.into(); // Address ranges cannot be relative to anything, so just grab the // data format bits from the encoding. let address_range = parse_encoded_pointer(encoding.format(), parameters, input)?; Ok((initial_address, address_range.into())) } else { let initial_address = input.read_address(cie.address_size)?; let address_range = input.read_address(cie.address_size)?; Ok((initial_address, address_range)) } } /// Return the table of unwind information for this FDE. #[inline] pub fn rows<'a, Section: UnwindSection>( &self, section: &'a Section, bases: &'a BaseAddresses, ctx: &'a mut UninitializedUnwindContext, ) -> Result> { UnwindTable::new(section, bases, ctx, self) } /// Find the frame unwind information for the given address. /// /// If found, the unwind information is returned along with the reset /// context in the form `Ok((unwind_info, context))`. If not found, /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or /// CFI evaluation fails, the error is returned. pub fn unwind_info_for_address>( &self, section: &Section, bases: &BaseAddresses, ctx: &mut UninitializedUnwindContext, address: u64, ) -> Result> { let mut table = self.rows(section, bases, ctx)?; while let Some(row) = table.next_row()? { if row.contains(address) { return Ok(row.clone()); } } Err(Error::NoUnwindInfoForAddress) } } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. #[allow(clippy::len_without_is_empty)] impl FrameDescriptionEntry { /// Get the offset of this entry from the start of its containing section. pub fn offset(&self) -> R::Offset { self.offset } /// Get a reference to this FDE's CIE. pub fn cie(&self) -> &CommonInformationEntry { &self.cie } /// > A constant that gives the number of bytes of the header and /// > instruction stream for this function, not including the length field /// > itself (see Section 7.2.2). The size of the length field plus the value /// > of length must be an integral multiple of the address size. pub fn entry_len(&self) -> R::Offset { self.length } /// Iterate over this FDE's instructions. /// /// Will not include the CIE's initial instructions, if you want those do /// `fde.cie().instructions()` first. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn instructions<'a, Section>( &self, section: &'a Section, bases: &'a BaseAddresses, ) -> CallFrameInstructionIter<'a, R> where Section: UnwindSection, { CallFrameInstructionIter { input: self.instructions.clone(), address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding), parameters: PointerEncodingParameters { bases: &bases.eh_frame, func_base: None, address_size: self.cie.address_size, section: section.section(), }, } } /// The first address for which this entry has unwind information for. pub fn initial_address(&self) -> u64 { self.initial_address } /// The number of bytes of instructions that this entry has unwind /// information for. pub fn len(&self) -> u64 { self.address_range } /// Return `true` if the given address is within this FDE, `false` /// otherwise. /// /// This is equivalent to `entry.initial_address() <= address < /// entry.initial_address() + entry.len()`. pub fn contains(&self, address: u64) -> bool { let start = self.initial_address(); let end = start + self.len(); start <= address && address < end } /// The address of this FDE's language-specific data area (LSDA), if it has /// any. pub fn lsda(&self) -> Option { self.augmentation.as_ref().and_then(|a| a.lsda) } /// Return true if this FDE's function is a trampoline for a signal handler. #[inline] pub fn is_signal_trampoline(&self) -> bool { self.cie().is_signal_trampoline() } /// Return the address of the FDE's function's personality routine /// handler. The personality routine does language-specific clean up when /// unwinding the stack frames with the intent to not run them again. #[inline] pub fn personality(&self) -> Option { self.cie().personality() } } /// Common context needed when evaluating the call frame unwinding information. /// /// To avoid re-allocating the context multiple times when evaluating multiple /// CFI programs, it can be reused. At first, a context is uninitialized /// (`UninitializedUnwindContext`). It can be initialized by providing the /// `CommonInformationEntry` for the CFI program about to be evaluated and /// calling `UninitializedUnwindContext::initialize`. The result is a `&mut UnwindContext` /// which borrows the uninitialized context, and can be used to evaluate and run a /// `FrameDescriptionEntry`'s CFI program. /// /// ``` /// use gimli::{UninitializedUnwindContext, UnwindTable}; /// /// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry>) /// # -> gimli::Result<()> { /// # let eh_frame: gimli::EhFrame<_> = unreachable!(); /// # let bases = unimplemented!(); /// // An uninitialized context. /// let mut ctx = UninitializedUnwindContext::new(); /// /// // Initialize the context by evaluating the CIE's initial instruction program, /// // and generate the unwind table. /// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?; /// while let Some(row) = table.next_row()? { /// // Do stuff with each row... /// # let _ = row; /// } /// # unreachable!() /// # } /// ``` #[derive(Clone, Debug)] pub struct UninitializedUnwindContext(Box>); impl UninitializedUnwindContext { /// Construct a new call frame unwinding context. pub fn new() -> UninitializedUnwindContext { UninitializedUnwindContext(Box::new(UnwindContext::new())) } } impl Default for UninitializedUnwindContext { fn default() -> Self { Self::new() } } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. impl UninitializedUnwindContext { /// Run the CIE's initial instructions, creating and return an /// `UnwindContext`. pub fn initialize>( &mut self, section: &Section, bases: &BaseAddresses, cie: &CommonInformationEntry, ) -> Result<&mut UnwindContext> { if self.0.is_initialized { self.0.reset(); } let mut table = UnwindTable::new_for_cie(section, bases, &mut self.0, cie); while let Some(_) = table.next_row()? {} self.0.save_initial_rules(); Ok(&mut self.0) } } const MAX_UNWIND_STACK_DEPTH: usize = 4; type UnwindContextStack = ArrayVec<[UnwindTableRow; MAX_UNWIND_STACK_DEPTH]>; /// An unwinding context. #[derive(Clone, Debug, PartialEq, Eq)] pub struct UnwindContext { // Stack of rows. The last row is the row currently being built by the // program. There is always at least one row. The vast majority of CFI // programs will only ever have one row on the stack. stack: UnwindContextStack, // If we are evaluating an FDE's instructions, then `is_initialized` will be // `true` and `initial_rules` will contain the initial register rules // described by the CIE's initial instructions. These rules are used by // `DW_CFA_restore`. Otherwise, when we are currently evaluating a CIE's // initial instructions, `is_initialized` will be `false` and // `initial_rules` is not to be read from. initial_rules: RegisterRuleMap, is_initialized: bool, } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. impl UnwindContext { fn new() -> UnwindContext { let mut ctx = UnwindContext { stack: Default::default(), is_initialized: false, initial_rules: Default::default(), }; ctx.reset(); ctx } fn reset(&mut self) { self.stack.clear(); let res = self.stack.try_push(UnwindTableRow::default()); debug_assert!(res.is_ok()); self.initial_rules.clear(); self.is_initialized = false; self.assert_fully_uninitialized(); } // Asserts that we are fully uninitialized, ie not initialized *and* not in // the process of initializing. #[inline] fn assert_fully_uninitialized(&self) { assert_eq!(self.is_initialized, false); assert_eq!(self.initial_rules.rules.len(), 0); assert_eq!(self.stack.len(), 1); assert!(self.stack[0].is_default()); } fn row(&self) -> &UnwindTableRow { self.stack.last().unwrap() } fn row_mut(&mut self) -> &mut UnwindTableRow { self.stack.last_mut().unwrap() } fn save_initial_rules(&mut self) { assert_eq!(self.is_initialized, false); self.initial_rules .clone_from(&self.stack.last().unwrap().registers); self.is_initialized = true; } fn start_address(&self) -> u64 { self.row().start_address } fn set_start_address(&mut self, start_address: u64) { let row = self.row_mut(); row.start_address = start_address; } fn set_register_rule(&mut self, register: Register, rule: RegisterRule) -> Result<()> { let row = self.row_mut(); row.registers.set(register, rule) } /// Returns `None` if we have not completed evaluation of a CIE's initial /// instructions. fn get_initial_rule(&self, register: Register) -> Option> { if !self.is_initialized { return None; } Some(self.initial_rules.get(register)) } fn set_cfa(&mut self, cfa: CfaRule) { self.row_mut().cfa = cfa; } fn cfa_mut(&mut self) -> &mut CfaRule { &mut self.row_mut().cfa } fn push_row(&mut self) -> Result<()> { let new_row = self.row().clone(); self.stack .try_push(new_row) .map_err(|_| Error::CfiStackFull) } fn pop_row(&mut self) { assert!(self.stack.len() > 1); self.stack.pop(); } } /// The `UnwindTable` iteratively evaluates a `FrameDescriptionEntry`'s /// `CallFrameInstruction` program, yielding the each row one at a time. /// /// > 6.4.1 Structure of Call Frame Information /// > /// > DWARF supports virtual unwinding by defining an architecture independent /// > basis for recording how procedures save and restore registers during their /// > lifetimes. This basis must be augmented on some machines with specific /// > information that is defined by an architecture specific ABI authoring /// > committee, a hardware vendor, or a compiler producer. The body defining a /// > specific augmentation is referred to below as the “augmenter.†/// > /// > Abstractly, this mechanism describes a very large table that has the /// > following structure: /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// >
LOCCFAR0R1...RN
L0
L1
...
LN
/// > /// > The first column indicates an address for every location that contains code /// > in a program. (In shared objects, this is an object-relative offset.) The /// > remaining columns contain virtual unwinding rules that are associated with /// > the indicated location. /// > /// > The CFA column defines the rule which computes the Canonical Frame Address /// > value; it may be either a register and a signed offset that are added /// > together, or a DWARF expression that is evaluated. /// > /// > The remaining columns are labeled by register number. This includes some /// > registers that have special designation on some architectures such as the PC /// > and the stack pointer register. (The actual mapping of registers for a /// > particular architecture is defined by the augmenter.) The register columns /// > contain rules that describe whether a given register has been saved and the /// > rule to find the value for the register in the previous frame. /// > /// > ... /// > /// > This table would be extremely large if actually constructed as /// > described. Most of the entries at any point in the table are identical to /// > the ones above them. The whole table can be represented quite compactly by /// > recording just the differences starting at the beginning address of each /// > subroutine in the program. #[derive(Debug)] pub struct UnwindTable<'a, R: Reader> { code_alignment_factor: u64, data_alignment_factor: i64, next_start_address: u64, last_end_address: u64, returned_last_row: bool, instructions: CallFrameInstructionIter<'a, R>, ctx: &'a mut UnwindContext, } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. impl<'a, R: Reader> UnwindTable<'a, R> { /// Construct a new `UnwindTable` for the given /// `FrameDescriptionEntry`'s CFI unwinding program. pub fn new>( section: &'a Section, bases: &'a BaseAddresses, ctx: &'a mut UninitializedUnwindContext, fde: &FrameDescriptionEntry, ) -> Result> { let ctx = ctx.initialize(section, bases, fde.cie())?; Ok(Self::new_for_fde(section, bases, ctx, fde)) } fn new_for_fde>( section: &'a Section, bases: &'a BaseAddresses, ctx: &'a mut UnwindContext, fde: &FrameDescriptionEntry, ) -> UnwindTable<'a, R> { assert!(ctx.stack.len() >= 1); UnwindTable { code_alignment_factor: fde.cie().code_alignment_factor(), data_alignment_factor: fde.cie().data_alignment_factor(), next_start_address: fde.initial_address(), last_end_address: fde.initial_address() + fde.len(), returned_last_row: false, instructions: fde.instructions(section, bases), ctx, } } fn new_for_cie>( section: &'a Section, bases: &'a BaseAddresses, ctx: &'a mut UnwindContext, cie: &CommonInformationEntry, ) -> UnwindTable<'a, R> { assert!(ctx.stack.len() >= 1); UnwindTable { code_alignment_factor: cie.code_alignment_factor(), data_alignment_factor: cie.data_alignment_factor(), next_start_address: 0, last_end_address: 0, returned_last_row: false, instructions: cie.instructions(section, bases), ctx, } } /// Evaluate call frame instructions until the next row of the table is /// completed, and return it. /// /// Unfortunately, this cannot be used with `FallibleIterator` because of /// the restricted lifetime of the yielded item. pub fn next_row(&mut self) -> Result>> { assert!(self.ctx.stack.len() >= 1); self.ctx.set_start_address(self.next_start_address); loop { match self.instructions.next() { Err(e) => return Err(e), Ok(None) => { if self.returned_last_row { return Ok(None); } let row = self.ctx.row_mut(); row.end_address = self.last_end_address; self.returned_last_row = true; return Ok(Some(row)); } Ok(Some(instruction)) => { if self.evaluate(instruction)? { return Ok(Some(self.ctx.row())); } } }; } } /// Evaluate one call frame instruction. Return `Ok(true)` if the row is /// complete, `Ok(false)` otherwise. fn evaluate(&mut self, instruction: CallFrameInstruction) -> Result { use crate::CallFrameInstruction::*; match instruction { // Instructions that complete the current row and advance the // address for the next row. SetLoc { address } => { if address < self.ctx.start_address() { return Err(Error::InvalidAddressRange); } self.next_start_address = address; self.ctx.row_mut().end_address = self.next_start_address; return Ok(true); } AdvanceLoc { delta } => { let delta = u64::from(delta) * self.code_alignment_factor; self.next_start_address = self.ctx.start_address() + delta; self.ctx.row_mut().end_address = self.next_start_address; return Ok(true); } // Instructions that modify the CFA. DefCfa { register, offset } => { self.ctx.set_cfa(CfaRule::RegisterAndOffset { register, offset: offset as i64, }); } DefCfaSf { register, factored_offset, } => { let data_align = self.data_alignment_factor; self.ctx.set_cfa(CfaRule::RegisterAndOffset { register, offset: factored_offset * data_align, }); } DefCfaRegister { register } => { if let CfaRule::RegisterAndOffset { register: ref mut reg, .. } = *self.ctx.cfa_mut() { *reg = register; } else { return Err(Error::CfiInstructionInInvalidContext); } } DefCfaOffset { offset } => { if let CfaRule::RegisterAndOffset { offset: ref mut off, .. } = *self.ctx.cfa_mut() { *off = offset as i64; } else { return Err(Error::CfiInstructionInInvalidContext); } } DefCfaOffsetSf { factored_offset } => { if let CfaRule::RegisterAndOffset { offset: ref mut off, .. } = *self.ctx.cfa_mut() { let data_align = self.data_alignment_factor; *off = factored_offset * data_align; } else { return Err(Error::CfiInstructionInInvalidContext); } } DefCfaExpression { expression } => { self.ctx.set_cfa(CfaRule::Expression(expression)); } // Instructions that define register rules. Undefined { register } => { self.ctx .set_register_rule(register, RegisterRule::Undefined)?; } SameValue { register } => { self.ctx .set_register_rule(register, RegisterRule::SameValue)?; } Offset { register, factored_offset, } => { let offset = factored_offset as i64 * self.data_alignment_factor; self.ctx .set_register_rule(register, RegisterRule::Offset(offset))?; } OffsetExtendedSf { register, factored_offset, } => { let offset = factored_offset * self.data_alignment_factor; self.ctx .set_register_rule(register, RegisterRule::Offset(offset))?; } ValOffset { register, factored_offset, } => { let offset = factored_offset as i64 * self.data_alignment_factor; self.ctx .set_register_rule(register, RegisterRule::ValOffset(offset))?; } ValOffsetSf { register, factored_offset, } => { let offset = factored_offset * self.data_alignment_factor; self.ctx .set_register_rule(register, RegisterRule::ValOffset(offset))?; } Register { dest_register, src_register, } => { self.ctx .set_register_rule(dest_register, RegisterRule::Register(src_register))?; } Expression { register, expression, } => { let expression = RegisterRule::Expression(expression); self.ctx.set_register_rule(register, expression)?; } ValExpression { register, expression, } => { let expression = RegisterRule::ValExpression(expression); self.ctx.set_register_rule(register, expression)?; } Restore { register } => { let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) { rule } else { // Can't restore the initial rule when we are // evaluating the initial rules! return Err(Error::CfiInstructionInInvalidContext); }; self.ctx.set_register_rule(register, initial_rule)?; } // Row push and pop instructions. RememberState => { self.ctx.push_row()?; } RestoreState => { assert!(self.ctx.stack.len() > 0); if self.ctx.stack.len() == 1 { return Err(Error::PopWithEmptyStack); } // Pop state while preserving current location. let start_address = self.ctx.start_address(); self.ctx.pop_row(); self.ctx.set_start_address(start_address); } // GNU Extension. Save the size somewhere so the unwinder can use // it when restoring IP ArgsSize { size } => { self.ctx.row_mut().saved_args_size = size; } // No operation. Nop => {} }; Ok(false) } } // We tend to have very few register rules: usually only a couple. Even if we // have a rule for every register, on x86-64 with SSE and everything we're // talking about ~100 rules. So rather than keeping the rules in a hash map, or // a vector indexed by register number (which would lead to filling lots of // empty entries), we store them as a vec of (register number, register rule) // pairs. // // Additionally, because every register's default rule is implicitly // `RegisterRule::Undefined`, we never store a register's rule in this vec if it // is undefined and save a little bit more space and do a little fewer // comparisons that way. #[derive(Clone, Debug)] struct RegisterRuleMap { rules: ArrayVec<[(Register, RegisterRule); 32]>, } impl Default for RegisterRuleMap { fn default() -> Self { RegisterRuleMap { rules: Default::default(), } } } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. impl RegisterRuleMap { fn is_default(&self) -> bool { self.rules.len() == 0 } fn get(&self, register: Register) -> RegisterRule { self.rules .iter() .find(|rule| rule.0 == register) .map(|r| { debug_assert!(r.1.is_defined()); r.1.clone() }) .unwrap_or(RegisterRule::Undefined) } fn set(&mut self, register: Register, rule: RegisterRule) -> Result<()> { if !rule.is_defined() { let idx = self .rules .iter() .enumerate() .find(|&(_, r)| r.0 == register) .map(|(i, _)| i); if let Some(idx) = idx { self.rules.swap_remove(idx); } return Ok(()); } for &mut (reg, ref mut old_rule) in &mut self.rules { debug_assert!(old_rule.is_defined()); if reg == register { mem::replace(old_rule, rule); return Ok(()); } } self.rules .try_push((register, rule)) .map_err(|_| Error::TooManyRegisterRules) } fn clear(&mut self) { self.rules.clear(); } fn iter(&self) -> RegisterRuleIter { RegisterRuleIter(self.rules.iter()) } } impl<'a, R> FromIterator<&'a (Register, RegisterRule)> for RegisterRuleMap where R: 'a + Reader, { fn from_iter(iter: T) -> RegisterRuleMap where T: IntoIterator)>, { let iter = iter.into_iter(); let mut rules = RegisterRuleMap::default(); for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) { rules.set(reg, rule.clone()).expect( "This is only used in tests, impl isn't exposed publicly. If you trip this, fix your test", ); } rules } } impl PartialEq for RegisterRuleMap where R: Reader + PartialEq, { fn eq(&self, rhs: &Self) -> bool { for &(reg, ref rule) in &self.rules { debug_assert!(rule.is_defined()); if *rule != rhs.get(reg) { return false; } } for &(reg, ref rhs_rule) in &rhs.rules { debug_assert!(rhs_rule.is_defined()); if *rhs_rule != self.get(reg) { return false; } } true } } impl Eq for RegisterRuleMap where R: Reader + Eq {} /// An unordered iterator for register rules. #[derive(Debug, Clone)] pub struct RegisterRuleIter<'iter, R>(::std::slice::Iter<'iter, (Register, RegisterRule)>) where R: Reader; impl<'iter, R: Reader> Iterator for RegisterRuleIter<'iter, R> { type Item = &'iter (Register, RegisterRule); fn next(&mut self) -> Option { self.0.next() } } /// A row in the virtual unwind table that describes how to find the values of /// the registers in the *previous* frame for a range of PC addresses. #[derive(Clone, Debug, PartialEq, Eq)] pub struct UnwindTableRow { start_address: u64, end_address: u64, saved_args_size: u64, cfa: CfaRule, registers: RegisterRuleMap, } impl Default for UnwindTableRow { fn default() -> Self { UnwindTableRow { start_address: 0, end_address: 0, saved_args_size: 0, cfa: Default::default(), registers: Default::default(), } } } impl UnwindTableRow { fn is_default(&self) -> bool { self.start_address == 0 && self.end_address == 0 && self.cfa.is_default() && self.registers.is_default() } /// Get the starting PC address that this row applies to. pub fn start_address(&self) -> u64 { self.start_address } /// Get the end PC address where this row's register rules become /// unapplicable. /// /// In other words, this row describes how to recover the last frame's /// registers for all PCs where `row.start_address() <= PC < /// row.end_address()`. This row does NOT describe how to recover registers /// when `PC == row.end_address()`. pub fn end_address(&self) -> u64 { self.end_address } /// Return `true` if the given `address` is within this row's address range, /// `false` otherwise. pub fn contains(&self, address: u64) -> bool { self.start_address <= address && address < self.end_address } /// Returns the amount of args currently on the stack. /// /// When unwinding, if the personality function requested a change in IP, /// the SP needs to be adjusted by saved_args_size. pub fn saved_args_size(&self) -> u64 { self.saved_args_size } /// Get the canonical frame address (CFA) recovery rule for this row. pub fn cfa(&self) -> &CfaRule { &self.cfa } /// Get the register recovery rule for the given register number. /// /// The register number mapping is architecture dependent. For example, in /// the x86-64 ABI the register number mapping is defined in Figure 3.36: /// /// > Figure 3.36: DWARF Register Number Mapping /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// > /// >
Register Name Number Abbreviation
General Purpose Register RAX 0 %rax
General Purpose Register RDX 1 %rdx
General Purpose Register RCX 2 %rcx
General Purpose Register RBX 3 %rbx
General Purpose Register RSI 4 %rsi
General Purpose Register RDI 5 %rdi
General Purpose Register RBP 6 %rbp
Stack Pointer Register RSP 7 %rsp
Extended Integer Registers 8-15 8-15 %r8-%r15
Return Address RA 16
Vector Registers 0–7 17-24 %xmm0–%xmm7
Extended Vector Registers 8–15 25-32 %xmm8–%xmm15
Floating Point Registers 0–7 33-40 %st0–%st7
MMX Registers 0–7 41-48 %mm0–%mm7
Flag Register 49 %rFLAGS
Segment Register ES 50 %es
Segment Register CS 51 %cs
Segment Register SS 52 %ss
Segment Register DS 53 %ds
Segment Register FS 54 %fs
Segment Register GS 55 %gs
Reserved 56-57
FS Base address 58 %fs.base
GS Base address 59 %gs.base
Reserved 60-61
Task Register 62 %tr
LDT Register 63 %ldtr
128-bit Media Control and Status 64 %mxcsr
x87 Control Word 65 %fcw
x87 Status Word 66 %fsw
Upper Vector Registers 16–31 67-82 %xmm16–%xmm31
Reserved 83-117
Vector Mask Registers 0–7 118-125 %k0–%k7
Reserved 126-129
pub fn register(&self, register: Register) -> RegisterRule { self.registers.get(register) } /// Iterate over all defined register `(number, rule)` pairs. /// /// The rules are not iterated in any guaranteed order. Any register that /// does not make an appearance in the iterator implicitly has the rule /// `RegisterRule::Undefined`. /// /// ``` /// # use gimli::{EndianSlice, LittleEndian, UnwindTableRow}; /// # fn foo<'input>(unwind_table_row: UnwindTableRow>) { /// for &(register, ref rule) in unwind_table_row.registers() { /// // ... /// # drop(register); drop(rule); /// } /// # } /// ``` pub fn registers(&self) -> RegisterRuleIter { self.registers.iter() } } /// The canonical frame address (CFA) recovery rules. #[derive(Clone, Debug, PartialEq, Eq)] pub enum CfaRule { /// The CFA is given offset from the given register's value. RegisterAndOffset { /// The register containing the base value. register: Register, /// The offset from the register's base value. offset: i64, }, /// The CFA is obtained by evaluating this `Reader` as a DWARF expression /// program. Expression(Expression), } impl Default for CfaRule { fn default() -> Self { CfaRule::RegisterAndOffset { register: Register(0), offset: 0, } } } impl CfaRule { fn is_default(&self) -> bool { match *self { CfaRule::RegisterAndOffset { register, offset } => { register == Register(0) && offset == 0 } _ => false, } } } /// An entry in the abstract CFI table that describes how to find the value of a /// register. /// /// "The register columns contain rules that describe whether a given register /// has been saved and the rule to find the value for the register in the /// previous frame." #[derive(Clone, Debug, PartialEq, Eq)] pub enum RegisterRule { /// > A register that has this rule has no recoverable value in the previous /// > frame. (By convention, it is not preserved by a callee.) Undefined, /// > This register has not been modified from the previous frame. (By /// > convention, it is preserved by the callee, but the callee has not /// > modified it.) SameValue, /// "The previous value of this register is saved at the address CFA+N where /// CFA is the current CFA value and N is a signed offset." Offset(i64), /// "The previous value of this register is the value CFA+N where CFA is the /// current CFA value and N is a signed offset." ValOffset(i64), /// "The previous value of this register is stored in another register /// numbered R." Register(Register), /// "The previous value of this register is located at the address produced /// by executing the DWARF expression." Expression(Expression), /// "The previous value of this register is the value produced by executing /// the DWARF expression." ValExpression(Expression), /// "The rule is defined externally to this specification by the augmenter." Architectural, } impl RegisterRule { fn is_defined(&self) -> bool { match *self { RegisterRule::Undefined => false, _ => true, } } } /// A parsed call frame instruction. #[derive(Clone, Debug, PartialEq, Eq)] pub enum CallFrameInstruction { // 6.4.2.1 Row Creation Methods /// > 1. DW_CFA_set_loc /// > /// > The DW_CFA_set_loc instruction takes a single operand that represents /// > a target address. The required action is to create a new table row /// > using the specified address as the location. All other values in the /// > new row are initially identical to the current row. The new location /// > value is always greater than the current one. If the segment_size /// > field of this FDE's CIE is non- zero, the initial location is preceded /// > by a segment selector of the given length. SetLoc { /// The target address. address: u64, }, /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and /// `DW_CFA_advance_loc{1,2,4}`. /// /// > 2. DW_CFA_advance_loc /// > /// > The DW_CFA_advance instruction takes a single operand (encoded with /// > the opcode) that represents a constant delta. The required action is /// > to create a new table row with a location value that is computed by /// > taking the current entry’s location value and adding the value of /// > delta * code_alignment_factor. All other values in the new row are /// > initially identical to the current row. AdvanceLoc { /// The delta to be added to the current address. delta: u32, }, // 6.4.2.2 CFA Definition Methods /// > 1. DW_CFA_def_cfa /// > /// > The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands /// > representing a register number and a (non-factored) offset. The /// > required action is to define the current CFA rule to use the provided /// > register and offset. DefCfa { /// The target register's number. register: Register, /// The non-factored offset. offset: u64, }, /// > 2. DW_CFA_def_cfa_sf /// > /// > The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned /// > LEB128 value representing a register number and a signed LEB128 /// > factored offset. This instruction is identical to DW_CFA_def_cfa /// > except that the second operand is signed and factored. The resulting /// > offset is factored_offset * data_alignment_factor. DefCfaSf { /// The target register's number. register: Register, /// The factored offset. factored_offset: i64, }, /// > 3. DW_CFA_def_cfa_register /// > /// > The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128 /// > operand representing a register number. The required action is to /// > define the current CFA rule to use the provided register (but to keep /// > the old offset). This operation is valid only if the current CFA rule /// > is defined to use a register and offset. DefCfaRegister { /// The target register's number. register: Register, }, /// > 4. DW_CFA_def_cfa_offset /// > /// > The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128 /// > operand representing a (non-factored) offset. The required action is /// > to define the current CFA rule to use the provided offset (but to keep /// > the old register). This operation is valid only if the current CFA /// > rule is defined to use a register and offset. DefCfaOffset { /// The non-factored offset. offset: u64, }, /// > 5. DW_CFA_def_cfa_offset_sf /// > /// > The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand /// > representing a factored offset. This instruction is identical to /// > DW_CFA_def_cfa_offset except that the operand is signed and /// > factored. The resulting offset is factored_offset * /// > data_alignment_factor. This operation is valid only if the current CFA /// > rule is defined to use a register and offset. DefCfaOffsetSf { /// The factored offset. factored_offset: i64, }, /// > 6. DW_CFA_def_cfa_expression /// > /// > The DW_CFA_def_cfa_expression instruction takes a single operand /// > encoded as a DW_FORM_exprloc value representing a DWARF /// > expression. The required action is to establish that expression as the /// > means by which the current CFA is computed. DefCfaExpression { /// The DWARF expression. expression: Expression, }, // 6.4.2.3 Register Rule Instructions /// > 1. DW_CFA_undefined /// > /// > The DW_CFA_undefined instruction takes a single unsigned LEB128 /// > operand that represents a register number. The required action is to /// > set the rule for the specified register to “undefined.†Undefined { /// The target register's number. register: Register, }, /// > 2. DW_CFA_same_value /// > /// > The DW_CFA_same_value instruction takes a single unsigned LEB128 /// > operand that represents a register number. The required action is to /// > set the rule for the specified register to “same value.†SameValue { /// The target register's number. register: Register, }, /// The `Offset` instruction represents both `DW_CFA_offset` and /// `DW_CFA_offset_extended`. /// /// > 3. DW_CFA_offset /// > /// > The DW_CFA_offset instruction takes two operands: a register number /// > (encoded with the opcode) and an unsigned LEB128 constant representing /// > a factored offset. The required action is to change the rule for the /// > register indicated by the register number to be an offset(N) rule /// > where the value of N is factored offset * data_alignment_factor. Offset { /// The target register's number. register: Register, /// The factored offset. factored_offset: u64, }, /// > 5. DW_CFA_offset_extended_sf /// > /// > The DW_CFA_offset_extended_sf instruction takes two operands: an /// > unsigned LEB128 value representing a register number and a signed /// > LEB128 factored offset. This instruction is identical to /// > DW_CFA_offset_extended except that the second operand is signed and /// > factored. The resulting offset is factored_offset * /// > data_alignment_factor. OffsetExtendedSf { /// The target register's number. register: Register, /// The factored offset. factored_offset: i64, }, /// > 6. DW_CFA_val_offset /// > /// > The DW_CFA_val_offset instruction takes two unsigned LEB128 operands /// > representing a register number and a factored offset. The required /// > action is to change the rule for the register indicated by the /// > register number to be a val_offset(N) rule where the value of N is /// > factored_offset * data_alignment_factor. ValOffset { /// The target register's number. register: Register, /// The factored offset. factored_offset: u64, }, /// > 7. DW_CFA_val_offset_sf /// > /// > The DW_CFA_val_offset_sf instruction takes two operands: an unsigned /// > LEB128 value representing a register number and a signed LEB128 /// > factored offset. This instruction is identical to DW_CFA_val_offset /// > except that the second operand is signed and factored. The resulting /// > offset is factored_offset * data_alignment_factor. ValOffsetSf { /// The target register's number. register: Register, /// The factored offset. factored_offset: i64, }, /// > 8. DW_CFA_register /// > /// > The DW_CFA_register instruction takes two unsigned LEB128 operands /// > representing register numbers. The required action is to set the rule /// > for the first register to be register(R) where R is the second /// > register. Register { /// The number of the register whose rule is being changed. dest_register: Register, /// The number of the register where the other register's value can be /// found. src_register: Register, }, /// > 9. DW_CFA_expression /// > /// > The DW_CFA_expression instruction takes two operands: an unsigned /// > LEB128 value representing a register number, and a DW_FORM_block value /// > representing a DWARF expression. The required action is to change the /// > rule for the register indicated by the register number to be an /// > expression(E) rule where E is the DWARF expression. That is, the DWARF /// > expression computes the address. The value of the CFA is pushed on the /// > DWARF evaluation stack prior to execution of the DWARF expression. Expression { /// The target register's number. register: Register, /// The DWARF expression. expression: Expression, }, /// > 10. DW_CFA_val_expression /// > /// > The DW_CFA_val_expression instruction takes two operands: an unsigned /// > LEB128 value representing a register number, and a DW_FORM_block value /// > representing a DWARF expression. The required action is to change the /// > rule for the register indicated by the register number to be a /// > val_expression(E) rule where E is the DWARF expression. That is, the /// > DWARF expression computes the value of the given register. The value /// > of the CFA is pushed on the DWARF evaluation stack prior to execution /// > of the DWARF expression. ValExpression { /// The target register's number. register: Register, /// The DWARF expression. expression: Expression, }, /// The `Restore` instruction represents both `DW_CFA_restore` and /// `DW_CFA_restore_extended`. /// /// > 11. DW_CFA_restore /// > /// > The DW_CFA_restore instruction takes a single operand (encoded with /// > the opcode) that represents a register number. The required action is /// > to change the rule for the indicated register to the rule assigned it /// > by the initial_instructions in the CIE. Restore { /// The register to be reset. register: Register, }, // 6.4.2.4 Row State Instructions /// > 1. DW_CFA_remember_state /// > /// > The DW_CFA_remember_state instruction takes no operands. The required /// > action is to push the set of rules for every register onto an implicit /// > stack. RememberState, /// > 2. DW_CFA_restore_state /// > /// > The DW_CFA_restore_state instruction takes no operands. The required /// > action is to pop the set of rules off the implicit stack and place /// > them in the current row. RestoreState, /// > DW_CFA_GNU_args_size /// > /// > GNU Extension /// > /// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand /// > representing an argument size. This instruction specifies the total of /// > the size of the arguments which have been pushed onto the stack. ArgsSize { /// The size of the arguments which have been pushed onto the stack size: u64, }, // 6.4.2.5 Padding Instruction /// > 1. DW_CFA_nop /// > /// > The DW_CFA_nop instruction has no operands and no required actions. It /// > is used as padding to make a CIE or FDE an appropriate size. Nop, } const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000; const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK; impl CallFrameInstruction { fn parse( input: &mut R, address_encoding: Option, parameters: &PointerEncodingParameters, ) -> Result> { let instruction = input.read_u8()?; let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK; if high_bits == constants::DW_CFA_advance_loc.0 { let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK; return Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(delta), }); } if high_bits == constants::DW_CFA_offset.0 { let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); let offset = input.read_uleb128()?; return Ok(CallFrameInstruction::Offset { register, factored_offset: offset, }); } if high_bits == constants::DW_CFA_restore.0 { let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into()); return Ok(CallFrameInstruction::Restore { register }); } debug_assert_eq!(high_bits, 0); let instruction = constants::DwCfa(instruction); match instruction { constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop), constants::DW_CFA_set_loc => { let address = if let Some(encoding) = address_encoding { match parse_encoded_pointer(encoding, parameters, input)? { Pointer::Direct(x) => x, _ => return Err(Error::UnsupportedPointerEncoding), } } else { input.read_address(parameters.address_size)? }; Ok(CallFrameInstruction::SetLoc { address }) } constants::DW_CFA_advance_loc1 => { let delta = input.read_u8()?; Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(delta), }) } constants::DW_CFA_advance_loc2 => { let delta = input.read_u16()?; Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(delta), }) } constants::DW_CFA_advance_loc4 => { let delta = input.read_u32()?; Ok(CallFrameInstruction::AdvanceLoc { delta }) } constants::DW_CFA_offset_extended => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_uleb128()?; Ok(CallFrameInstruction::Offset { register, factored_offset: offset, }) } constants::DW_CFA_restore_extended => { let register = input.read_uleb128().and_then(Register::from_u64)?; Ok(CallFrameInstruction::Restore { register }) } constants::DW_CFA_undefined => { let register = input.read_uleb128().and_then(Register::from_u64)?; Ok(CallFrameInstruction::Undefined { register }) } constants::DW_CFA_same_value => { let register = input.read_uleb128().and_then(Register::from_u64)?; Ok(CallFrameInstruction::SameValue { register }) } constants::DW_CFA_register => { let dest = input.read_uleb128().and_then(Register::from_u64)?; let src = input.read_uleb128().and_then(Register::from_u64)?; Ok(CallFrameInstruction::Register { dest_register: dest, src_register: src, }) } constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState), constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState), constants::DW_CFA_def_cfa => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_uleb128()?; Ok(CallFrameInstruction::DefCfa { register, offset }) } constants::DW_CFA_def_cfa_register => { let register = input.read_uleb128().and_then(Register::from_u64)?; Ok(CallFrameInstruction::DefCfaRegister { register }) } constants::DW_CFA_def_cfa_offset => { let offset = input.read_uleb128()?; Ok(CallFrameInstruction::DefCfaOffset { offset }) } constants::DW_CFA_def_cfa_expression => { let len = input.read_uleb128().and_then(R::Offset::from_u64)?; let expression = input.split(len)?; Ok(CallFrameInstruction::DefCfaExpression { expression: Expression(expression), }) } constants::DW_CFA_expression => { let register = input.read_uleb128().and_then(Register::from_u64)?; let len = input.read_uleb128().and_then(R::Offset::from_u64)?; let expression = input.split(len)?; Ok(CallFrameInstruction::Expression { register, expression: Expression(expression), }) } constants::DW_CFA_offset_extended_sf => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_sleb128()?; Ok(CallFrameInstruction::OffsetExtendedSf { register, factored_offset: offset, }) } constants::DW_CFA_def_cfa_sf => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_sleb128()?; Ok(CallFrameInstruction::DefCfaSf { register, factored_offset: offset, }) } constants::DW_CFA_def_cfa_offset_sf => { let offset = input.read_sleb128()?; Ok(CallFrameInstruction::DefCfaOffsetSf { factored_offset: offset, }) } constants::DW_CFA_val_offset => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_uleb128()?; Ok(CallFrameInstruction::ValOffset { register, factored_offset: offset, }) } constants::DW_CFA_val_offset_sf => { let register = input.read_uleb128().and_then(Register::from_u64)?; let offset = input.read_sleb128()?; Ok(CallFrameInstruction::ValOffsetSf { register, factored_offset: offset, }) } constants::DW_CFA_val_expression => { let register = input.read_uleb128().and_then(Register::from_u64)?; let len = input.read_uleb128().and_then(R::Offset::from_u64)?; let expression = input.split(len)?; Ok(CallFrameInstruction::ValExpression { register, expression: Expression(expression), }) } constants::DW_CFA_GNU_args_size => { let size = input.read_uleb128()?; Ok(CallFrameInstruction::ArgsSize { size }) } otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)), } } } /// A lazy iterator parsing call frame instructions. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[derive(Clone, Debug)] pub struct CallFrameInstructionIter<'a, R: Reader> { input: R, address_encoding: Option, parameters: PointerEncodingParameters<'a, R>, } impl<'a, R: Reader> CallFrameInstructionIter<'a, R> { /// Parse the next call frame instruction. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } match CallFrameInstruction::parse(&mut self.input, self.address_encoding, &self.parameters) { Ok(instruction) => Ok(Some(instruction)), Err(e) => { self.input.empty(); Err(e) } } } } impl<'a, R: Reader> FallibleIterator for CallFrameInstructionIter<'a, R> { type Item = CallFrameInstruction; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { CallFrameInstructionIter::next(self) } } /// Parse a `DW_EH_PE_*` pointer encoding. #[doc(hidden)] #[inline] fn parse_pointer_encoding(input: &mut R) -> Result { let eh_pe = input.read_u8()?; let eh_pe = constants::DwEhPe(eh_pe); if eh_pe.is_valid_encoding() { Ok(eh_pe) } else { Err(Error::UnknownPointerEncoding) } } /// A decoded pointer. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Pointer { /// This value is the decoded pointer value. Direct(u64), /// This value is *not* the pointer value, but points to the address of /// where the real pointer value lives. In other words, deref this pointer /// to get the real pointer value. /// /// Chase this pointer at your own risk: do you trust the DWARF data it came /// from? Indirect(u64), } impl Default for Pointer { #[inline] fn default() -> Self { Pointer::Direct(0) } } impl Into for Pointer { #[inline] fn into(self) -> u64 { match self { Pointer::Direct(p) | Pointer::Indirect(p) => p, } } } impl Pointer { #[inline] fn new(encoding: constants::DwEhPe, address: u64) -> Pointer { if encoding.is_indirect() { Pointer::Indirect(address) } else { Pointer::Direct(address) } } } #[derive(Clone, Debug)] struct PointerEncodingParameters<'a, R: Reader> { bases: &'a SectionBaseAddresses, func_base: Option, address_size: u8, section: &'a R, } fn parse_encoded_pointer( encoding: constants::DwEhPe, parameters: &PointerEncodingParameters, input: &mut R, ) -> Result { // TODO: check this once only in parse_pointer_encoding if !encoding.is_valid_encoding() { return Err(Error::UnknownPointerEncoding); } if encoding == constants::DW_EH_PE_omit { return Err(Error::CannotParseOmitPointerEncoding); } let base = match encoding.application() { constants::DW_EH_PE_absptr => 0, constants::DW_EH_PE_pcrel => { if let Some(section_base) = parameters.bases.section { let offset_from_section = input.offset_from(parameters.section); section_base.wrapping_add(offset_from_section.into_u64()) } else { return Err(Error::PcRelativePointerButSectionBaseIsUndefined); } } constants::DW_EH_PE_textrel => { if let Some(text) = parameters.bases.text { text } else { return Err(Error::TextRelativePointerButTextBaseIsUndefined); } } constants::DW_EH_PE_datarel => { if let Some(data) = parameters.bases.data { data } else { return Err(Error::DataRelativePointerButDataBaseIsUndefined); } } constants::DW_EH_PE_funcrel => { if let Some(func) = parameters.func_base { func } else { return Err(Error::FuncRelativePointerInBadContext); } } constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding), _ => unreachable!(), }; let offset = match encoding.format() { // Unsigned variants. constants::DW_EH_PE_absptr => input.read_address(parameters.address_size), constants::DW_EH_PE_uleb128 => input.read_uleb128(), constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from), constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from), constants::DW_EH_PE_udata8 => input.read_u64(), // Signed variants. Here we sign extend the values (happens by // default when casting a signed integer to a larger range integer // in Rust), return them as u64, and rely on wrapping addition to do // the right thing when adding these offsets to their bases. constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64), constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64), constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64), constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64), // That was all of the valid encoding formats. _ => unreachable!(), }?; Ok(Pointer::new(encoding, base.wrapping_add(offset))) } #[cfg(test)] mod tests { use super::*; use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext}; use crate::common::Format; use crate::constants; use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian}; use crate::read::{ EndianSlice, Error, Expression, Pointer, ReaderOffsetId, Result, Section as ReadSection, }; use crate::test_util::GimliSectionMethods; use crate::vec::Vec; use std::marker::PhantomData; use std::mem; use std::u64; use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum}; // Ensure each test tries to read the same section kind that it wrote. #[derive(Clone, Copy)] struct SectionKind
(PhantomData
); impl SectionKind { fn endian<'input, E>(self) -> Endian where E: Endianity, T: UnwindSection>, T::Offset: UnwindOffset, { if E::default().is_big_endian() { Endian::Big } else { Endian::Little } } fn section<'input, E>(self, contents: &'input [u8]) -> T where E: Endianity, T: UnwindSection> + ReadSection>, T::Offset: UnwindOffset, { EndianSlice::new(contents, E::default()).into() } } fn debug_frame_le<'a>() -> SectionKind>> { SectionKind(PhantomData) } fn debug_frame_be<'a>() -> SectionKind>> { SectionKind(PhantomData) } fn eh_frame_le<'a>() -> SectionKind>> { SectionKind(PhantomData) } fn parse_fde( section: Section, input: &mut R, get_cie: F, ) -> Result> where R: Reader, Section: UnwindSection, O: UnwindOffset, F: FnMut(&Section, &BaseAddresses, O) -> Result>, { let bases = Default::default(); match parse_cfi_entry(&bases, §ion, input) { Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie), Ok(_) => Err(Error::NoEntryAtGivenOffset), Err(e) => Err(e), } } // Mixin methods for `Section` to help define binary test data. trait CfiSectionMethods: GimliSectionMethods { fn cie<'aug, 'input, E, T>( self, _kind: SectionKind, augmentation: Option<&'aug str>, cie: &mut CommonInformationEntry>, ) -> Self where E: Endianity, T: UnwindSection>, T::Offset: UnwindOffset; fn fde<'a, 'input, E, T, L>( self, _kind: SectionKind, cie_offset: L, fde: &mut FrameDescriptionEntry>, ) -> Self where E: Endianity, T: UnwindSection>, T::Offset: UnwindOffset, L: ToLabelOrNum<'a, u64>; } impl CfiSectionMethods for Section { fn cie<'aug, 'input, E, T>( self, _kind: SectionKind, augmentation: Option<&'aug str>, cie: &mut CommonInformationEntry>, ) -> Self where E: Endianity, T: UnwindSection>, T::Offset: UnwindOffset, { cie.offset = self.size() as _; let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = match cie.format { Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff), Format::Dwarf64 => { let section = self.D32(0xffff_ffff); section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff) } }; let mut section = section.D8(cie.version); if let Some(augmentation) = augmentation { section = section.append_bytes(augmentation.as_bytes()); } // Null terminator for augmentation string. let section = section.D8(0); let section = if T::has_address_and_segment_sizes(cie.version) { section.D8(cie.address_size).D8(cie.segment_size) } else { section }; let section = section .uleb(cie.code_alignment_factor) .sleb(cie.data_alignment_factor) .uleb(cie.return_address_register.0.into()) .append_bytes(cie.initial_instructions.into()) .mark(&end); cie.length = (&end - &start) as usize; length.set_const(cie.length as u64); section } fn fde<'a, 'input, E, T, L>( self, _kind: SectionKind, cie_offset: L, fde: &mut FrameDescriptionEntry>, ) -> Self where E: Endianity, T: UnwindSection>, T::Offset: UnwindOffset, L: ToLabelOrNum<'a, u64>, { fde.offset = self.size() as _; let length = Label::new(); let start = Label::new(); let end = Label::new(); assert_eq!(fde.format, fde.cie.format); let section = match T::cie_offset_encoding(fde.format) { CieOffsetEncoding::U32 => { let section = self.D32(&length).mark(&start); match cie_offset.to_labelornum() { LabelOrNum::Label(ref l) => section.D32(l), LabelOrNum::Num(o) => section.D32(o as u32), } } CieOffsetEncoding::U64 => { let section = self.D32(0xffff_ffff); section.D64(&length).mark(&start).D64(cie_offset) } }; let section = match fde.cie.segment_size { 0 => section, 4 => section.D32(fde.initial_segment as u32), 8 => section.D64(fde.initial_segment), x => panic!("Unsupported test segment size: {}", x), }; let section = match fde.cie.address_size { 4 => section .D32(fde.initial_address() as u32) .D32(fde.len() as u32), 8 => section.D64(fde.initial_address()).D64(fde.len()), x => panic!("Unsupported address size: {}", x), }; let section = if let Some(ref augmentation) = fde.augmentation { let cie_aug = fde .cie .augmentation .expect("FDE has augmentation, but CIE doesn't"); if let Some(lsda) = augmentation.lsda { // We only support writing `DW_EH_PE_absptr` here. assert_eq!( cie_aug .lsda .expect("FDE has lsda, but CIE doesn't") .format(), constants::DW_EH_PE_absptr ); // Augmentation data length let section = section.uleb(u64::from(fde.cie.address_size)); match fde.cie.address_size { 4 => section.D32({ let x: u64 = lsda.into(); x as u32 }), 8 => section.D64({ let x: u64 = lsda.into(); x }), x => panic!("Unsupported address size: {}", x), } } else { // Even if we don't have any augmentation data, if there is // an augmentation defined, we need to put the length in. section.uleb(0) } } else { section }; let section = section.append_bytes(fde.instructions.into()).mark(&end); fde.length = (&end - &start) as usize; length.set_const(fde.length as u64); section } } trait ResultExt { fn map_eof(self, input: &[u8]) -> Self; } impl ResultExt for Result { fn map_eof(self, input: &[u8]) -> Self { match self { Err(Error::UnexpectedEof(id)) => { let id = ReaderOffsetId(id.0 - input.as_ptr() as u64); Err(Error::UnexpectedEof(id)) } r => r, } } } #[allow(clippy::type_complexity)] #[allow(clippy::needless_pass_by_value)] fn assert_parse_cie<'input, E>( kind: SectionKind>>, section: Section, address_size: u8, expected: Result<( EndianSlice<'input, E>, CommonInformationEntry>, )>, ) where E: Endianity, { let section = section.get_contents().unwrap(); let mut debug_frame = kind.section(§ion); debug_frame.set_address_size(address_size); let input = &mut EndianSlice::new(§ion, E::default()); let bases = Default::default(); let result = CommonInformationEntry::parse(&bases, &debug_frame, input); let result = result.map(|cie| (*input, cie)).map_eof(§ion); assert_eq!(result, expected); } #[test] fn test_parse_cie_incomplete_length_32() { let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()).L16(5); assert_parse_cie( kind, section, 8, Err(Error::UnexpectedEof(ReaderOffsetId(0))), ); } #[test] fn test_parse_cie_incomplete_length_64() { let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .L32(0xffff_ffff) .L32(12345); assert_parse_cie( kind, section, 8, Err(Error::UnexpectedEof(ReaderOffsetId(4))), ); } #[test] fn test_parse_cie_incomplete_id_32() { let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) // The length is not large enough to contain the ID. .B32(3) .B32(0xffff_ffff); assert_parse_cie( kind, section, 8, Err(Error::UnexpectedEof(ReaderOffsetId(4))), ); } #[test] fn test_parse_cie_bad_id_32() { let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) // Initial length .B32(4) // Not the CIE Id. .B32(0xbad1_bad2); assert_parse_cie(kind, section, 8, Err(Error::NotCieId)); } #[test] fn test_parse_cie_32_bad_version() { let mut cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 99, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 2, return_address_register: Register(3), initial_instructions: EndianSlice::new(&[], LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99))); } #[test] fn test_parse_cie_unknown_augmentation() { let length = Label::new(); let start = Label::new(); let end = Label::new(); let augmentation = Some("replicant"); let expected_rest = [1, 2, 3]; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) // Initial length .L32(&length) .mark(&start) // CIE Id .L32(0xffff_ffff) // Version .D8(4) // Augmentation .append_bytes(augmentation.unwrap().as_bytes()) // Null terminator .D8(0) // Extra augmented data that we can't understand. .L32(1) .L32(2) .L32(3) .L32(4) .L32(5) .L32(6) .mark(&end) .append_bytes(&expected_rest); let expected_length = (&end - &start) as u64; length.set_const(expected_length); assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation)); } fn test_parse_cie(format: Format, version: u8, address_size: u8) { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie = CommonInformationEntry { offset: 0, length: 0, format, version, augmentation: None, address_size, segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .cie(kind, None, &mut cie) .append_bytes(&expected_rest); assert_parse_cie( kind, section, address_size, Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)), ); } #[test] fn test_parse_cie_32_ok() { test_parse_cie(Format::Dwarf32, 1, 4); test_parse_cie(Format::Dwarf32, 1, 8); test_parse_cie(Format::Dwarf32, 4, 4); test_parse_cie(Format::Dwarf32, 4, 8); } #[test] fn test_parse_cie_64_ok() { test_parse_cie(Format::Dwarf64, 1, 4); test_parse_cie(Format::Dwarf64, 1, 8); test_parse_cie(Format::Dwarf64, 4, 4); test_parse_cie(Format::Dwarf64, 4, 8); } #[test] fn test_parse_cie_length_too_big() { let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 0, data_alignment_factor: 0, return_address_register: Register(3), initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie); let mut contents = section.get_contents().unwrap(); // Overwrite the length to be too big. contents[0] = 0; contents[1] = 0; contents[2] = 0; contents[3] = 255; let debug_frame = DebugFrame::new(&contents, LittleEndian); let bases = Default::default(); assert_eq!( CommonInformationEntry::parse( &bases, &debug_frame, &mut EndianSlice::new(&contents, LittleEndian) ) .map_eof(&contents), Err(Error::UnexpectedEof(ReaderOffsetId(4))) ); } #[test] fn test_parse_fde_incomplete_length_32() { let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()).L16(5); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, LittleEndian); assert_eq!( parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), Err(Error::UnexpectedEof(ReaderOffsetId(0))) ); } #[test] fn test_parse_fde_incomplete_length_64() { let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .L32(0xffff_ffff) .L32(12345); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, LittleEndian); assert_eq!( parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), Err(Error::UnexpectedEof(ReaderOffsetId(4))) ); } #[test] fn test_parse_fde_incomplete_cie_pointer_32() { let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) // The length is not large enough to contain the CIE pointer. .B32(3) .B32(1994); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, BigEndian); assert_eq!( parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion), Err(Error::UnexpectedEof(ReaderOffsetId(4))) ); } #[test] fn test_parse_fde_32_ok() { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let cie_offset = 0xbad0_bad1; let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); let cie = CommonInformationEntry { offset: 0, length: 100, format: Format::Dwarf32, version: 4, augmentation: None, // DWARF32 with a 64 bit address size! Holy moly! address_size: 8, segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), initial_instructions: EndianSlice::new(&[], LittleEndian), }; let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, instructions: EndianSlice::new(&expected_instrs, LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, LittleEndian); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); Ok(cie.clone()) }; assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_fde_32_with_segment_ok() { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let cie_offset = 0xbad0_bad1; let expected_instrs: Vec<_> = (0..92).map(|_| constants::DW_CFA_nop.0).collect(); let cie = CommonInformationEntry { offset: 0, length: 100, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 4, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), initial_instructions: EndianSlice::new(&[], LittleEndian), }; let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0xbadb_ad11, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, instructions: EndianSlice::new(&expected_instrs, LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, LittleEndian); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); Ok(cie.clone()) }; assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_fde_64_ok() { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let cie_offset = 0xbad0_bad1; let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect(); let cie = CommonInformationEntry { offset: 0, length: 100, format: Format::Dwarf64, version: 4, augmentation: None, address_size: 8, segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), initial_instructions: EndianSlice::new(&[], LittleEndian), }; let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf64, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, instructions: EndianSlice::new(&expected_instrs, LittleEndian), }; let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, LittleEndian); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); Ok(cie.clone()) }; assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_entry_on_cie_32_ok() { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), initial_instructions: EndianSlice::new(&expected_instrs, BigEndian), }; let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) .cie(kind, None, &mut cie) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, BigEndian); let bases = Default::default(); assert_eq!( parse_cfi_entry(&bases, &debug_frame, rest), Ok(Some(CieOrFde::Cie(cie))) ); assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); } #[test] fn test_parse_cfi_entry_on_fde_32_ok() { let cie_offset = 0x1234_5678; let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); let cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), initial_instructions: EndianSlice::new(&[], BigEndian), }; let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, instructions: EndianSlice::new(&expected_instrs, BigEndian), }; let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let debug_frame = kind.section(§ion); let rest = &mut EndianSlice::new(§ion, BigEndian); let bases = Default::default(); match parse_cfi_entry(&bases, &debug_frame, rest) { Ok(Some(CieOrFde::Fde(partial))) => { assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian)); assert_eq!(partial.length, fde.length); assert_eq!(partial.format, fde.format); assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize)); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); Ok(cie.clone()) }; assert_eq!(partial.parse(get_cie), Ok(fde)); } otherwise => panic!("Unexpected result: {:#?}", otherwise), } } #[test] fn test_cfi_entries_iter() { let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect(); let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect(); let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie1 = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 2, return_address_register: Register(3), initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian), }; let mut cie2 = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian), }; let cie1_location = Label::new(); let cie2_location = Label::new(); // Write the CIEs first so that their length gets set before we clone // them into the FDEs and our equality assertions down the line end up // with all the CIEs always having he correct length. let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) .mark(&cie1_location) .cie(kind, None, &mut cie1) .mark(&cie2_location) .cie(kind, None, &mut cie2); let mut fde1 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie1.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, instructions: EndianSlice::new(&expected_instrs3, BigEndian), }; let mut fde2 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie2.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, instructions: EndianSlice::new(&expected_instrs4, BigEndian), }; let section = section .fde(kind, &cie1_location, &mut fde1) .fde(kind, &cie2_location, &mut fde2); section.start().set_const(0); let cie1_offset = cie1_location.value().unwrap() as usize; let cie2_offset = cie2_location.value().unwrap() as usize; let contents = section.get_contents().unwrap(); let debug_frame = kind.section(&contents); let bases = Default::default(); let mut entries = debug_frame.entries(&bases); assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone())))); assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone())))); match entries.next() { Ok(Some(CieOrFde::Fde(partial))) => { assert_eq!(partial.length, fde1.length); assert_eq!(partial.format, fde1.format); assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset)); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie1_offset)); Ok(cie1.clone()) }; assert_eq!(partial.parse(get_cie), Ok(fde1)); } otherwise => panic!("Unexpected result: {:#?}", otherwise), } match entries.next() { Ok(Some(CieOrFde::Fde(partial))) => { assert_eq!(partial.length, fde2.length); assert_eq!(partial.format, fde2.format); assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset)); let get_cie = |_: &_, _: &_, offset| { assert_eq!(offset, DebugFrameOffset(cie2_offset)); Ok(cie2.clone()) }; assert_eq!(partial.parse(get_cie), Ok(fde2)); } otherwise => panic!("Unexpected result: {:#?}", otherwise), } assert_eq!(entries.next(), Ok(None)); } #[test] fn test_parse_cie_from_offset() { let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf64, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 4, data_alignment_factor: 8, return_address_register: Register(12), initial_instructions: EndianSlice::new(&instrs, LittleEndian), }; let cie_location = Label::new(); let kind = debug_frame_le(); let section = Section::with_endian(kind.endian()) .append_bytes(&filler) .mark(&cie_location) .cie(kind, None, &mut cie) .append_bytes(&filler); section.start().set_const(0); let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize); let contents = section.get_contents().unwrap(); let debug_frame = kind.section(&contents); let bases = Default::default(); assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie)); } fn parse_cfi_instruction( input: &mut R, address_size: u8, ) -> Result> { let parameters = &PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size, section: &R::default(), }; CallFrameInstruction::parse(input, None, parameters) } #[test] fn test_parse_cfi_instruction_advance_loc() { let expected_rest = [1, 2, 3, 4]; let expected_delta = 42; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_advance_loc.0 | expected_delta) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(expected_delta), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_offset() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 3; let expected_offset = 1997; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_offset.0 | expected_reg) .uleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Offset { register: Register(expected_reg.into()), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_restore() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 3; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_restore.0 | expected_reg) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Restore { register: Register(expected_reg.into()), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_nop() { let expected_rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_nop.0) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Nop) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_set_loc() { let expected_rest = [1, 2, 3, 4]; let expected_addr = 0xdead_beef; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_set_loc.0) .L64(expected_addr) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::SetLoc { address: expected_addr, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_set_loc_encoding() { let text_base = 0xfeed_face; let addr_offset = 0xbeef; let expected_addr = text_base + addr_offset; let expected_rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_set_loc.0) .L64(addr_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); let parameters = &PointerEncodingParameters { bases: &BaseAddresses::default().set_text(text_base).eh_frame, func_base: None, address_size: 8, section: &EndianSlice::new(&[], LittleEndian), }; assert_eq!( CallFrameInstruction::parse(input, Some(constants::DW_EH_PE_textrel), parameters), Ok(CallFrameInstruction::SetLoc { address: expected_addr, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_advance_loc1() { let expected_rest = [1, 2, 3, 4]; let expected_delta = 8; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_advance_loc1.0) .D8(expected_delta) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(expected_delta), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_advance_loc2() { let expected_rest = [1, 2, 3, 4]; let expected_delta = 500; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_advance_loc2.0) .L16(expected_delta) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::AdvanceLoc { delta: u32::from(expected_delta), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_advance_loc4() { let expected_rest = [1, 2, 3, 4]; let expected_delta = 1 << 20; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_advance_loc4.0) .L32(expected_delta) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::AdvanceLoc { delta: expected_delta, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_offset_extended() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 7; let expected_offset = 33; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_offset_extended.0) .uleb(expected_reg.into()) .uleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Offset { register: Register(expected_reg), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_restore_extended() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 7; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_restore_extended.0) .uleb(expected_reg.into()) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Restore { register: Register(expected_reg), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_undefined() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 7; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_undefined.0) .uleb(expected_reg.into()) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Undefined { register: Register(expected_reg), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_same_value() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 7; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_same_value.0) .uleb(expected_reg.into()) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::SameValue { register: Register(expected_reg), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_register() { let expected_rest = [1, 2, 3, 4]; let expected_dest_reg = 7; let expected_src_reg = 8; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_register.0) .uleb(expected_dest_reg.into()) .uleb(expected_src_reg.into()) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Register { dest_register: Register(expected_dest_reg), src_register: Register(expected_src_reg), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_remember_state() { let expected_rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_remember_state.0) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::RememberState) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_restore_state() { let expected_rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_restore_state.0) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::RestoreState) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 2; let expected_offset = 0; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa.0) .uleb(expected_reg.into()) .uleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfa { register: Register(expected_reg), offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa_register() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 2; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa_register.0) .uleb(expected_reg.into()) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfaRegister { register: Register(expected_reg), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa_offset() { let expected_rest = [1, 2, 3, 4]; let expected_offset = 23; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa_offset.0) .uleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfaOffset { offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa_expression() { let expected_rest = [1, 2, 3, 4]; let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa_expression.0) .D8(&length) .mark(&start) .append_bytes(&expected_expr) .mark(&end) .append_bytes(&expected_rest); length.set_const((&end - &start) as u64); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfaExpression { expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_expression() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 99; let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_expression.0) .uleb(expected_reg.into()) .D8(&length) .mark(&start) .append_bytes(&expected_expr) .mark(&end) .append_bytes(&expected_rest); length.set_const((&end - &start) as u64); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::Expression { register: Register(expected_reg), expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_offset_extended_sf() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 7; let expected_offset = -33; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_offset_extended_sf.0) .uleb(expected_reg.into()) .sleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::OffsetExtendedSf { register: Register(expected_reg), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa_sf() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 2; let expected_offset = -9999; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa_sf.0) .uleb(expected_reg.into()) .sleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfaSf { register: Register(expected_reg), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_def_cfa_offset_sf() { let expected_rest = [1, 2, 3, 4]; let expected_offset = -123; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_def_cfa_offset_sf.0) .sleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::DefCfaOffsetSf { factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_val_offset() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 50; let expected_offset = 23; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_val_offset.0) .uleb(expected_reg.into()) .uleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::ValOffset { register: Register(expected_reg), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_val_offset_sf() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 50; let expected_offset = -23; let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_val_offset_sf.0) .uleb(expected_reg.into()) .sleb(expected_offset) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::ValOffsetSf { register: Register(expected_reg), factored_offset: expected_offset, }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_val_expression() { let expected_rest = [1, 2, 3, 4]; let expected_reg = 50; let expected_expr = [2, 2, 1, 1, 5, 5]; let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = Section::with_endian(Endian::Little) .D8(constants::DW_CFA_val_expression.0) .uleb(expected_reg.into()) .D8(&length) .mark(&start) .append_bytes(&expected_expr) .mark(&end) .append_bytes(&expected_rest); length.set_const((&end - &start) as u64); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Ok(CallFrameInstruction::ValExpression { register: Register(expected_reg), expression: Expression(EndianSlice::new(&expected_expr, LittleEndian)), }) ); assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_cfi_instruction_unknown_instruction() { let expected_rest = [1, 2, 3, 4]; let unknown_instr = constants::DwCfa(0b0011_1111); let section = Section::with_endian(Endian::Little) .D8(unknown_instr.0) .append_bytes(&expected_rest); let contents = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&contents, LittleEndian); assert_eq!( parse_cfi_instruction(input, 8), Err(Error::UnknownCallFrameInstruction(unknown_instr)) ); } #[test] fn test_call_frame_instruction_iter_ok() { let expected_reg = 50; let expected_expr = [2, 2, 1, 1, 5, 5]; let expected_delta = 230; let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = Section::with_endian(Endian::Big) .D8(constants::DW_CFA_val_expression.0) .uleb(expected_reg.into()) .D8(&length) .mark(&start) .append_bytes(&expected_expr) .mark(&end) .D8(constants::DW_CFA_advance_loc1.0) .D8(expected_delta); length.set_const((&end - &start) as u64); let contents = section.get_contents().unwrap(); let input = EndianSlice::new(&contents, BigEndian); let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 8, section: &EndianSlice::default(), }; let mut iter = CallFrameInstructionIter { input, address_encoding: None, parameters, }; assert_eq!( iter.next(), Ok(Some(CallFrameInstruction::ValExpression { register: Register(expected_reg), expression: Expression(EndianSlice::new(&expected_expr, BigEndian)), })) ); assert_eq!( iter.next(), Ok(Some(CallFrameInstruction::AdvanceLoc { delta: u32::from(expected_delta), })) ); assert_eq!(iter.next(), Ok(None)); } #[test] fn test_call_frame_instruction_iter_err() { // DW_CFA_advance_loc1 without an operand. let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0); let contents = section.get_contents().unwrap(); let input = EndianSlice::new(&contents, BigEndian); let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 8, section: &EndianSlice::default(), }; let mut iter = CallFrameInstructionIter { input, address_encoding: None, parameters, }; assert_eq!( iter.next().map_eof(&contents), Err(Error::UnexpectedEof(ReaderOffsetId(1))) ); assert_eq!(iter.next(), Ok(None)); } #[allow(clippy::needless_pass_by_value)] fn assert_eval<'a, I>( mut initial_ctx: UnwindContext>, expected_ctx: UnwindContext>, cie: CommonInformationEntry>, fde: Option>>, instructions: I, ) where I: AsRef< [( Result, CallFrameInstruction>, )], >, { { let section = &DebugFrame::from(EndianSlice::default()); let bases = &BaseAddresses::default(); let mut table = match fde { Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde), None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie), }; for &(ref expected_result, ref instruction) in instructions.as_ref() { assert_eq!(*expected_result, table.evaluate(instruction.clone())); } } assert_eq!(expected_ctx, initial_ctx); } fn make_test_cie<'a>() -> CommonInformationEntry> { CommonInformationEntry { offset: 0, format: Format::Dwarf64, length: 0, return_address_register: Register(0), version: 4, address_size: mem::size_of::() as u8, initial_instructions: EndianSlice::new(&[], LittleEndian), augmentation: None, segment_size: 0, data_alignment_factor: 2, code_alignment_factor: 3, } } #[test] fn test_eval_set_loc() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected.row_mut().end_address = 42; let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_set_loc_backwards() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.row_mut().start_address = 999; let expected = ctx.clone(); let instructions = [( Err(Error::InvalidAddressRange), CallFrameInstruction::SetLoc { address: 42 }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_advance_loc() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.row_mut().start_address = 3; let mut expected = ctx.clone(); expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor; let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected.set_cfa(CfaRule::RegisterAndOffset { register: Register(42), offset: 36, }); let instructions = [( Ok(false), CallFrameInstruction::DefCfa { register: Register(42), offset: 36, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_sf() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected.set_cfa(CfaRule::RegisterAndOffset { register: Register(42), offset: 36 * cie.data_alignment_factor as i64, }); let instructions = [( Ok(false), CallFrameInstruction::DefCfaSf { register: Register(42), factored_offset: 36, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_register() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.set_cfa(CfaRule::RegisterAndOffset { register: Register(3), offset: 8, }); let mut expected = ctx.clone(); expected.set_cfa(CfaRule::RegisterAndOffset { register: Register(42), offset: 8, }); let instructions = [( Ok(false), CallFrameInstruction::DefCfaRegister { register: Register(42), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_register_invalid_context() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( &[], LittleEndian, )))); let expected = ctx.clone(); let instructions = [( Err(Error::CfiInstructionInInvalidContext), CallFrameInstruction::DefCfaRegister { register: Register(42), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_offset() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.set_cfa(CfaRule::RegisterAndOffset { register: Register(3), offset: 8, }); let mut expected = ctx.clone(); expected.set_cfa(CfaRule::RegisterAndOffset { register: Register(3), offset: 42, }); let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_offset_invalid_context() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( &[], LittleEndian, )))); let expected = ctx.clone(); let instructions = [( Err(Error::CfiInstructionInInvalidContext), CallFrameInstruction::DefCfaOffset { offset: 1993 }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_def_cfa_expression() { let expr = [1, 2, 3, 4]; let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected.set_cfa(CfaRule::Expression(Expression(EndianSlice::new( &expr, LittleEndian, )))); let instructions = [( Ok(false), CallFrameInstruction::DefCfaExpression { expression: Expression(EndianSlice::new(&expr, LittleEndian)), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_undefined() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule(Register(5), RegisterRule::Undefined) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::Undefined { register: Register(5), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_same_value() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule(Register(0), RegisterRule::SameValue) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::SameValue { register: Register(0), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_offset() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(2), RegisterRule::Offset(3 * cie.data_alignment_factor), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::Offset { register: Register(2), factored_offset: 3, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_offset_extended_sf() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(4), RegisterRule::Offset(-3 * cie.data_alignment_factor), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::OffsetExtendedSf { register: Register(4), factored_offset: -3, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_val_offset() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(5), RegisterRule::ValOffset(7 * cie.data_alignment_factor), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::ValOffset { register: Register(5), factored_offset: 7, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_val_offset_sf() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(5), RegisterRule::ValOffset(-7 * cie.data_alignment_factor), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::ValOffsetSf { register: Register(5), factored_offset: -7, }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_expression() { let expr = [1, 2, 3, 4]; let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(9), RegisterRule::Expression(Expression(EndianSlice::new(&expr, LittleEndian))), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::Expression { register: Register(9), expression: Expression(EndianSlice::new(&expr, LittleEndian)), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_val_expression() { let expr = [1, 2, 3, 4]; let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected .set_register_rule( Register(9), RegisterRule::ValExpression(Expression(EndianSlice::new(&expr, LittleEndian))), ) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::ValExpression { register: Register(9), expression: Expression(EndianSlice::new(&expr, LittleEndian)), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_restore() { let cie = make_test_cie(); let fde = FrameDescriptionEntry { offset: 0, format: Format::Dwarf64, length: 0, address_range: 0, augmentation: None, initial_address: 0, initial_segment: 0, cie: cie.clone(), instructions: EndianSlice::new(&[], LittleEndian), }; let mut ctx = UnwindContext::new(); ctx.set_register_rule(Register(0), RegisterRule::Offset(1)) .unwrap(); ctx.save_initial_rules(); let expected = ctx.clone(); ctx.set_register_rule(Register(0), RegisterRule::Offset(2)) .unwrap(); let instructions = [( Ok(false), CallFrameInstruction::Restore { register: Register(0), }, )]; assert_eval(ctx, expected, cie, Some(fde), instructions); } #[test] fn test_eval_restore_havent_saved_initial_context() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let expected = ctx.clone(); let instructions = [( Err(Error::CfiInstructionInInvalidContext), CallFrameInstruction::Restore { register: Register(0), }, )]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_remember_state() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let mut expected = ctx.clone(); expected.push_row().unwrap(); let instructions = [(Ok(false), CallFrameInstruction::RememberState)]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_restore_state() { let cie = make_test_cie(); let mut ctx = UnwindContext::new(); ctx.set_start_address(1); ctx.set_register_rule(Register(0), RegisterRule::SameValue) .unwrap(); let mut expected = ctx.clone(); ctx.push_row().unwrap(); ctx.set_start_address(2); ctx.set_register_rule(Register(0), RegisterRule::Offset(16)) .unwrap(); // Restore state should preserve current location. expected.set_start_address(2); let instructions = [ // First one pops just fine. (Ok(false), CallFrameInstruction::RestoreState), // Second pop would try to pop out of bounds. ( Err(Error::PopWithEmptyStack), CallFrameInstruction::RestoreState, ), ]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_eval_nop() { let cie = make_test_cie(); let ctx = UnwindContext::new(); let expected = ctx.clone(); let instructions = [(Ok(false), CallFrameInstruction::Nop)]; assert_eval(ctx, expected, cie, None, instructions); } #[test] fn test_unwind_table_next_row() { #[allow(clippy::identity_op)] let initial_instructions = Section::with_endian(Endian::Little) // The CFA is -12 from register 4. .D8(constants::DW_CFA_def_cfa_sf.0) .uleb(4) .sleb(-12) // Register 0 is 8 from the CFA. .D8(constants::DW_CFA_offset.0 | 0) .uleb(8) // Register 3 is 4 from the CFA. .D8(constants::DW_CFA_offset.0 | 3) .uleb(4) .append_repeated(constants::DW_CFA_nop.0, 4); let initial_instructions = initial_instructions.get_contents().unwrap(); let cie = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 8, segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian), }; let instructions = Section::with_endian(Endian::Little) // Initial instructions form a row, advance the address by 1. .D8(constants::DW_CFA_advance_loc1.0) .D8(1) // Register 0 is -16 from the CFA. .D8(constants::DW_CFA_offset_extended_sf.0) .uleb(0) .sleb(-16) // Finish this row, advance the address by 32. .D8(constants::DW_CFA_advance_loc1.0) .D8(32) // Register 3 is -4 from the CFA. .D8(constants::DW_CFA_offset_extended_sf.0) .uleb(3) .sleb(-4) // Finish this row, advance the address by 64. .D8(constants::DW_CFA_advance_loc1.0) .D8(64) // Register 5 is 4 from the CFA. .D8(constants::DW_CFA_offset.0 | 5) .uleb(4) // A bunch of nop padding. .append_repeated(constants::DW_CFA_nop.0, 8); let instructions = instructions.get_contents().unwrap(); let fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, instructions: EndianSlice::new(&instructions, LittleEndian), }; let section = &DebugFrame::from(EndianSlice::default()); let bases = &BaseAddresses::default(); let mut ctx = UninitializedUnwindContext::new(); ctx.0.assert_fully_uninitialized(); let mut table = fde .rows(section, bases, &mut ctx) .expect("Should run initial program OK"); assert!(table.ctx.is_initialized); let expected_initial_rules: RegisterRuleMap<_> = [ (Register(0), RegisterRule::Offset(8)), (Register(3), RegisterRule::Offset(4)), ] .into_iter() .collect(); assert_eq!(table.ctx.initial_rules, expected_initial_rules); { let row = table.next_row().expect("Should evaluate first row OK"); let expected = UnwindTableRow { start_address: 0, end_address: 1, saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), offset: -12, }, registers: [ (Register(0), RegisterRule::Offset(8)), (Register(3), RegisterRule::Offset(4)), ] .into_iter() .collect(), }; assert_eq!(Some(&expected), row); } { let row = table.next_row().expect("Should evaluate second row OK"); let expected = UnwindTableRow { start_address: 1, end_address: 33, saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), offset: -12, }, registers: [ (Register(0), RegisterRule::Offset(-16)), (Register(3), RegisterRule::Offset(4)), ] .into_iter() .collect(), }; assert_eq!(Some(&expected), row); } { let row = table.next_row().expect("Should evaluate third row OK"); let expected = UnwindTableRow { start_address: 33, end_address: 97, saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), offset: -12, }, registers: [ (Register(0), RegisterRule::Offset(-16)), (Register(3), RegisterRule::Offset(-4)), ] .into_iter() .collect(), }; assert_eq!(Some(&expected), row); } { let row = table.next_row().expect("Should evaluate fourth row OK"); let expected = UnwindTableRow { start_address: 97, end_address: 100, saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), offset: -12, }, registers: [ (Register(0), RegisterRule::Offset(-16)), (Register(3), RegisterRule::Offset(-4)), (Register(5), RegisterRule::Offset(4)), ] .into_iter() .collect(), }; assert_eq!(Some(&expected), row); } // All done! assert_eq!(Ok(None), table.next_row()); assert_eq!(Ok(None), table.next_row()); } #[test] fn test_unwind_info_for_address_ok() { let instrs1 = Section::with_endian(Endian::Big) // The CFA is -12 from register 4. .D8(constants::DW_CFA_def_cfa_sf.0) .uleb(4) .sleb(-12); let instrs1 = instrs1.get_contents().unwrap(); let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect(); let instrs3 = Section::with_endian(Endian::Big) // Initial instructions form a row, advance the address by 100. .D8(constants::DW_CFA_advance_loc1.0) .D8(100) // Register 0 is -16 from the CFA. .D8(constants::DW_CFA_offset_extended_sf.0) .uleb(0) .sleb(-16); let instrs3 = instrs3.get_contents().unwrap(); let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect(); let mut cie1 = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 8, segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), initial_instructions: EndianSlice::new(&instrs1, BigEndian), }; let mut cie2 = CommonInformationEntry { offset: 0, length: 0, format: Format::Dwarf32, version: 4, augmentation: None, address_size: 4, segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(1), initial_instructions: EndianSlice::new(&instrs2, BigEndian), }; let cie1_location = Label::new(); let cie2_location = Label::new(); // Write the CIEs first so that their length gets set before we clone // them into the FDEs and our equality assertions down the line end up // with all the CIEs always having he correct length. let kind = debug_frame_be(); let section = Section::with_endian(kind.endian()) .mark(&cie1_location) .cie(kind, None, &mut cie1) .mark(&cie2_location) .cie(kind, None, &mut cie2); let mut fde1 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie1.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 200, augmentation: None, instructions: EndianSlice::new(&instrs3, BigEndian), }; let mut fde2 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie2.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, instructions: EndianSlice::new(&instrs4, BigEndian), }; let section = section .fde(kind, &cie1_location, &mut fde1) .fde(kind, &cie2_location, &mut fde2); section.start().set_const(0); let contents = section.get_contents().unwrap(); let debug_frame = kind.section(&contents); // Get the second row of the unwind table in `instrs3`. let bases = Default::default(); let mut ctx = UninitializedUnwindContext::new(); let result = debug_frame.unwind_info_for_address( &bases, &mut ctx, 0xfeed_beef + 150, DebugFrame::cie_from_offset, ); assert!(result.is_ok()); let unwind_info = result.unwrap(); assert_eq!( unwind_info, UnwindTableRow { start_address: fde1.initial_address() + 100, end_address: fde1.initial_address() + fde1.len(), saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), offset: -12, }, registers: [(Register(0), RegisterRule::Offset(-16))] .into_iter() .collect(), } ); } #[test] fn test_unwind_info_for_address_not_found() { let debug_frame = DebugFrame::new(&[], NativeEndian); let bases = Default::default(); let mut ctx = UninitializedUnwindContext::new(); let result = debug_frame.unwind_info_for_address( &bases, &mut ctx, 0xbadb_ad99, DebugFrame::cie_from_offset, ); assert!(result.is_err()); assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress); } #[test] fn test_eh_frame_hdr_unknown_version() { let bases = BaseAddresses::default(); let buf = &[42]; let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8); assert!(result.is_err()); assert_eq!(result.unwrap_err(), Error::UnknownVersion(42)); } #[test] fn test_eh_frame_hdr_omit_ehptr() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0xff) .L8(0x03) .L8(0x0b) .L32(2) .L32(10) .L32(1) .L32(20) .L32(2) .L32(0); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_err()); assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding); } #[test] fn test_eh_frame_hdr_omit_count() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x0b) .L8(0xff) .L8(0x0b) .L32(0x12345); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); assert!(result.table().is_none()); } #[test] fn test_eh_frame_hdr_omit_table() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x0b) .L8(0x03) .L8(0xff) .L32(0x12345) .L32(2); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); assert!(result.table().is_none()); } #[test] fn test_eh_frame_hdr_varlen_table() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x0b) .L8(0x03) .L8(0x01) .L32(0x12345) .L32(2); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); let table = result.table(); assert!(table.is_some()); let table = table.unwrap(); assert_eq!( table.lookup(0, &bases), Err(Error::VariableLengthSearchTable) ); } #[test] fn test_eh_frame_hdr_indirect_length() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x0b) .L8(0x83) .L8(0x0b) .L32(0x12345) .L32(2); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_err()); assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding); } #[test] fn test_eh_frame_hdr_indirect_ptrs() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x8b) .L8(0x03) .L8(0x8b) .L32(0x12345) .L32(2) .L32(10) .L32(1) .L32(20) .L32(2); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345)); let table = result.table(); assert!(table.is_some()); let table = table.unwrap(); assert_eq!( table.lookup(0, &bases), Err(Error::UnsupportedPointerEncoding) ); } #[test] fn test_eh_frame_hdr_good() { let section = Section::with_endian(Endian::Little) .L8(1) .L8(0x0b) .L8(0x03) .L8(0x0b) .L32(0x12345) .L32(2) .L32(10) .L32(1) .L32(20) .L32(2); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345)); let table = result.table(); assert!(table.is_some()); let table = table.unwrap(); assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1))); assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1))); assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1))); assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1))); assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1))); assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2))); assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2))); assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2))); } #[test] fn test_eh_frame_fde_for_address_good() { // First, setup eh_frame // Write the CIE first so that its length gets set before we clone it // into the FDE. let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; let start_of_cie = Label::new(); let end_of_cie = Label::new(); let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .append_repeated(0, 16) .mark(&start_of_cie) .cie(kind, None, &mut cie) .mark(&end_of_cie); let mut fde1 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 9, address_range: 4, augmentation: None, instructions: EndianSlice::new(&[], LittleEndian), }; let mut fde2 = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 20, address_range: 8, augmentation: None, instructions: EndianSlice::new(&[], LittleEndian), }; let start_of_fde1 = Label::new(); let start_of_fde2 = Label::new(); let section = section // +4 for the FDE length before the CIE offset. .mark(&start_of_fde1) .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1) .mark(&start_of_fde2) .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2); section.start().set_const(0); let section = section.get_contents().unwrap(); let section = EndianSlice::new(§ion, LittleEndian); let eh_frame = kind.section(§ion); // Setup eh_frame_hdr let section = Section::with_endian(kind.endian()) .L8(1) .L8(0x0b) .L8(0x03) .L8(0x0b) .L32(0x12345) .L32(2) .L32(10) .L32(0x12345 + start_of_fde1.value().unwrap() as u32) .L32(20) .L32(0x12345 + start_of_fde2.value().unwrap() as u32); let section = section.get_contents().unwrap(); let bases = BaseAddresses::default(); let eh_frame_hdr = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8); assert!(eh_frame_hdr.is_ok()); let eh_frame_hdr = eh_frame_hdr.unwrap(); let table = eh_frame_hdr.table(); assert!(table.is_some()); let table = table.unwrap(); let bases = Default::default(); let f = |_: &_, _: &_, o: EhFrameOffset| { assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); Ok(cie.clone()) }; assert_eq!( table.fde_for_address(&eh_frame, &bases, 9, f), Ok(fde1.clone()) ); assert_eq!( table.fde_for_address(&eh_frame, &bases, 10, f), Ok(fde1.clone()) ); assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1)); assert_eq!( table.fde_for_address(&eh_frame, &bases, 19, f), Err(Error::NoUnwindInfoForAddress) ); assert_eq!( table.fde_for_address(&eh_frame, &bases, 20, f), Ok(fde2.clone()) ); assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2)); assert_eq!( table.fde_for_address(&eh_frame, &bases, 100_000, f), Err(Error::NoUnwindInfoForAddress) ); } #[test] fn test_eh_frame_stops_at_zero_length() { let section = Section::with_endian(Endian::Little).L32(0); let section = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(§ion, LittleEndian); let bases = Default::default(); assert_eq!( parse_cfi_entry(&bases, &EhFrame::new(&*section, LittleEndian), rest), Ok(None) ); assert_eq!( EhFrame::new(§ion, LittleEndian).cie_from_offset(&bases, EhFrameOffset(0)), Err(Error::NoEntryAtGivenOffset) ); } fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result { let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf64, cie: make_test_cie(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, instructions: EndianSlice::new(&[], LittleEndian), }; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .append_bytes(&buf) .fde(kind, cie_offset as u64, &mut fde) .append_bytes(&buf); let section = section.get_contents().unwrap(); let eh_frame = kind.section(§ion); let input = &mut EndianSlice::new(§ion[buf.len()..], LittleEndian); let bases = Default::default(); match parse_cfi_entry(&bases, &eh_frame, input) { Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0), Err(e) => Err(e), otherwise => panic!("Unexpected result: {:#?}", otherwise), } } #[test] fn test_eh_frame_resolve_cie_offset_ok() { let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let cie_offset = 2; // + 4 for size of length field assert_eq!( resolve_cie_offset(&buf, buf.len() + 4 - cie_offset), Ok(cie_offset) ); } #[test] fn test_eh_frame_resolve_cie_offset_out_of_bounds() { let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; assert_eq!( resolve_cie_offset(&buf, buf.len() + 4 + 2), Err(Error::OffsetOutOfBounds) ); } #[test] fn test_eh_frame_resolve_cie_offset_underflow() { let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; assert_eq!( resolve_cie_offset(&buf, ::std::usize::MAX), Err(Error::OffsetOutOfBounds) ); } #[test] fn test_eh_frame_fde_ok() { let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; let start_of_cie = Label::new(); let end_of_cie = Label::new(); // Write the CIE first so that its length gets set before we clone it // into the FDE. let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .append_repeated(0, 16) .mark(&start_of_cie) .cie(kind, None, &mut cie) .mark(&end_of_cie); let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, instructions: EndianSlice::new(&[], LittleEndian), }; let section = section // +4 for the FDE length before the CIE offset. .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde); section.start().set_const(0); let section = section.get_contents().unwrap(); let eh_frame = kind.section(§ion); let section = EndianSlice::new(§ion, LittleEndian); let mut offset = None; match parse_fde( eh_frame, &mut section.range_from(end_of_cie.value().unwrap() as usize..), |_, _, o| { offset = Some(o); assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize)); Ok(cie.clone()) }, ) { Ok(actual) => assert_eq!(actual, fde), otherwise => panic!("Unexpected result {:?}", otherwise), } assert!(offset.is_some()); } #[test] fn test_eh_frame_fde_out_of_bounds() { let mut cie = make_test_cie(); cie.version = 1; let end_of_cie = Label::new(); let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf64, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, instructions: EndianSlice::new(&[], LittleEndian), }; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .cie(kind, None, &mut cie) .mark(&end_of_cie) .fde(kind, 99_999_999_999_999, &mut fde); section.start().set_const(0); let section = section.get_contents().unwrap(); let eh_frame = kind.section(§ion); let section = EndianSlice::new(§ion, LittleEndian); let result = parse_fde( eh_frame, &mut section.range_from(end_of_cie.value().unwrap() as usize..), UnwindSection::cie_from_offset, ); assert_eq!(result, Err(Error::OffsetOutOfBounds)); } #[test] fn test_augmentation_parse_not_z_augmentation() { let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian); let bases = Default::default(); let address_size = 8; let section = EhFrame::new(&[], NativeEndian); let input = &mut EndianSlice::new(&[], NativeEndian); assert_eq!( Augmentation::parse(augmentation, &bases, address_size, §ion, input), Err(Error::UnknownAugmentation) ); } #[test] fn test_augmentation_parse_unknown_part_of_z_augmentation() { // The 'Z' character is not defined by the z-style augmentation. let bases = Default::default(); let address_size = 8; let section = Section::with_endian(Endian::Little) .uleb(4) .append_repeated(4, 4) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian); assert_eq!( Augmentation::parse(augmentation, &bases, address_size, §ion, input), Err(Error::UnknownAugmentation) ); } #[test] #[allow(non_snake_case)] fn test_augmentation_parse_L() { let bases = Default::default(); let address_size = 8; let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; let section = Section::with_endian(Endian::Little) .uleb(1) .D8(constants::DW_EH_PE_uleb128.0) .append_bytes(&rest) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let aug_str = &mut EndianSlice::new(b"zL", LittleEndian); let mut augmentation = Augmentation::default(); augmentation.lsda = Some(constants::DW_EH_PE_uleb128); assert_eq!( Augmentation::parse(aug_str, &bases, address_size, §ion, input), Ok(augmentation) ); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] #[allow(non_snake_case)] fn test_augmentation_parse_P() { let bases = Default::default(); let address_size = 8; let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; let section = Section::with_endian(Endian::Little) .uleb(9) .D8(constants::DW_EH_PE_udata8.0) .L64(0xf00d_f00d) .append_bytes(&rest) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let aug_str = &mut EndianSlice::new(b"zP", LittleEndian); let mut augmentation = Augmentation::default(); augmentation.personality = Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))); assert_eq!( Augmentation::parse(aug_str, &bases, address_size, §ion, input), Ok(augmentation) ); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] #[allow(non_snake_case)] fn test_augmentation_parse_R() { let bases = Default::default(); let address_size = 8; let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; let section = Section::with_endian(Endian::Little) .uleb(1) .D8(constants::DW_EH_PE_udata4.0) .append_bytes(&rest) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let aug_str = &mut EndianSlice::new(b"zR", LittleEndian); let mut augmentation = Augmentation::default(); augmentation.fde_address_encoding = Some(constants::DW_EH_PE_udata4); assert_eq!( Augmentation::parse(aug_str, &bases, address_size, §ion, input), Ok(augmentation) ); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] #[allow(non_snake_case)] fn test_augmentation_parse_S() { let bases = Default::default(); let address_size = 8; let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; let section = Section::with_endian(Endian::Little) .uleb(0) .append_bytes(&rest) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let aug_str = &mut EndianSlice::new(b"zS", LittleEndian); let mut augmentation = Augmentation::default(); augmentation.is_signal_trampoline = true; assert_eq!( Augmentation::parse(aug_str, &bases, address_size, §ion, input), Ok(augmentation) ); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_augmentation_parse_all() { let bases = Default::default(); let address_size = 8; let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1]; let section = Section::with_endian(Endian::Little) .uleb(1 + 9 + 1) // L .D8(constants::DW_EH_PE_uleb128.0) // P .D8(constants::DW_EH_PE_udata8.0) .L64(0x1bad_f00d) // R .D8(constants::DW_EH_PE_uleb128.0) .append_bytes(&rest) .get_contents() .unwrap(); let section = EhFrame::new(§ion, LittleEndian); let input = &mut section.section().clone(); let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian); let augmentation = Augmentation { lsda: Some(constants::DW_EH_PE_uleb128), personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))), fde_address_encoding: Some(constants::DW_EH_PE_uleb128), is_signal_trampoline: true, }; assert_eq!( Augmentation::parse(aug_str, &bases, address_size, §ion, input), Ok(augmentation) ); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_eh_frame_fde_no_augmentation() { let instrs = [1, 2, 3, 4]; let cie_offset = 1; let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, instructions: EndianSlice::new(&instrs, LittleEndian), }; let rest = [1, 2, 3, 4]; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); let section = kind.section(§ion); let input = &mut section.section().clone(); let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); assert_eq!(result, Ok(fde)); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_eh_frame_fde_empty_augmentation() { let instrs = [1, 2, 3, 4]; let cie_offset = 1; let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; cie.augmentation = Some(Augmentation::default()); let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData::default()), instructions: EndianSlice::new(&instrs, LittleEndian), }; let rest = [1, 2, 3, 4]; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); let section = kind.section(§ion); let input = &mut section.section().clone(); let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); assert_eq!(result, Ok(fde)); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_eh_frame_fde_lsda_augmentation() { let instrs = [1, 2, 3, 4]; let cie_offset = 1; let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; cie.augmentation = Some(Augmentation::default()); cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr); let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData { lsda: Some(Pointer::Direct(0x1122_3344)), }), instructions: EndianSlice::new(&instrs, LittleEndian), }; let rest = [1, 2, 3, 4]; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .fde(kind, cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); let section = kind.section(§ion); let input = &mut section.section().clone(); let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); assert_eq!(result, Ok(fde)); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_eh_frame_fde_lsda_function_relative() { let instrs = [1, 2, 3, 4]; let cie_offset = 1; let mut cie = make_test_cie(); cie.format = Format::Dwarf32; cie.version = 1; cie.augmentation = Some(Augmentation::default()); cie.augmentation.as_mut().unwrap().lsda = Some(constants::DwEhPe( constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_absptr.0, )); let mut fde = FrameDescriptionEntry { offset: 0, length: 0, format: Format::Dwarf32, cie: cie.clone(), initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData { lsda: Some(Pointer::Direct(0xbeef)), }), instructions: EndianSlice::new(&instrs, LittleEndian), }; let rest = [1, 2, 3, 4]; let kind = eh_frame_le(); let section = Section::with_endian(kind.endian()) .append_repeated(10, 10) .fde(kind, cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); let section = kind.section(§ion); let input = &mut section.section().range_from(10..); // Adjust the FDE's augmentation to be relative to the function. fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef)); let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); assert_eq!(result, Ok(fde)); assert_eq!(*input, EndianSlice::new(&rest, LittleEndian)); } #[test] fn test_eh_frame_cie_personality_function_relative_bad_context() { let instrs = [1, 2, 3, 4]; let length = Label::new(); let start = Label::new(); let end = Label::new(); let aug_len = Label::new(); let aug_start = Label::new(); let aug_end = Label::new(); let section = Section::with_endian(Endian::Little) // Length .L32(&length) .mark(&start) // CIE ID .L32(0) // Version .D8(1) // Augmentation .append_bytes(b"zP\0") // Code alignment factor .uleb(1) // Data alignment factor .sleb(1) // Return address register .uleb(1) // Augmentation data length. This is a uleb, be we rely on the value // being less than 2^7 and therefore a valid uleb (can't use Label // with uleb). .D8(&aug_len) .mark(&aug_start) // Augmentation data. Personality encoding and then encoded pointer. .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0) .uleb(1) .mark(&aug_end) // Initial instructions .append_bytes(&instrs) .mark(&end); length.set_const((&end - &start) as u64); aug_len.set_const((&aug_end - &aug_start) as u64); let section = section.get_contents().unwrap(); let section = EhFrame::new(§ion, LittleEndian); let bases = BaseAddresses::default(); let mut iter = section.entries(&bases); assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext)); } #[test] fn register_rule_map_eq() { // Different order, but still equal. let map1: RegisterRuleMap> = [ (Register(0), RegisterRule::SameValue), (Register(3), RegisterRule::Offset(1)), ] .iter() .collect(); let map2: RegisterRuleMap> = [ (Register(3), RegisterRule::Offset(1)), (Register(0), RegisterRule::SameValue), ] .iter() .collect(); assert_eq!(map1, map2); assert_eq!(map2, map1); // Not equal. let map3: RegisterRuleMap> = [ (Register(0), RegisterRule::SameValue), (Register(2), RegisterRule::Offset(1)), ] .iter() .collect(); let map4: RegisterRuleMap> = [ (Register(3), RegisterRule::Offset(1)), (Register(0), RegisterRule::SameValue), ] .iter() .collect(); assert!(map3 != map4); assert!(map4 != map3); // One has undefined explicitly set, other implicitly has undefined. let mut map5 = RegisterRuleMap::>::default(); map5.set(Register(0), RegisterRule::SameValue).unwrap(); map5.set(Register(0), RegisterRule::Undefined).unwrap(); let map6 = RegisterRuleMap::>::default(); assert_eq!(map5, map6); assert_eq!(map6, map5); } #[test] fn iter_register_rules() { let mut row = UnwindTableRow::>::default(); row.registers = [ (Register(0), RegisterRule::SameValue), (Register(1), RegisterRule::Offset(1)), (Register(2), RegisterRule::ValOffset(2)), ] .iter() .collect(); let mut found0 = false; let mut found1 = false; let mut found2 = false; for &(register, ref rule) in row.registers() { match register.0 { 0 => { assert_eq!(found0, false); found0 = true; assert_eq!(*rule, RegisterRule::SameValue); } 1 => { assert_eq!(found1, false); found1 = true; assert_eq!(*rule, RegisterRule::Offset(1)); } 2 => { assert_eq!(found2, false); found2 = true; assert_eq!(*rule, RegisterRule::ValOffset(2)); } x => panic!("Unexpected register rule: ({}, {:?})", x, rule), } } assert_eq!(found0, true); assert_eq!(found1, true); assert_eq!(found2, true); } #[test] #[cfg(target_pointer_width = "64")] fn size_of_unwind_ctx() { use std::mem; let size = mem::size_of::>>(); let max_size = 5416; if size > max_size { assert_eq!(size, max_size); } } #[test] #[cfg(target_pointer_width = "64")] fn size_of_register_rule_map() { use std::mem; let size = mem::size_of::>>(); let max_size = 1040; if size > max_size { assert_eq!(size, max_size); } } #[test] fn test_parse_pointer_encoding_ok() { use crate::endianity::NativeEndian; let expected = constants::DwEhPe(constants::DW_EH_PE_uleb128.0 | constants::DW_EH_PE_pcrel.0); let input = [expected.0, 1, 2, 3, 4]; let input = &mut EndianSlice::new(&input, NativeEndian); assert_eq!(parse_pointer_encoding(input), Ok(expected)); assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian)); } #[test] fn test_parse_pointer_encoding_bad_encoding() { use crate::endianity::NativeEndian; let expected = constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0); let input = [expected.0, 1, 2, 3, 4]; let input = &mut EndianSlice::new(&input, NativeEndian); assert_eq!( Err(Error::UnknownPointerEncoding), parse_pointer_encoding(input) ); } #[test] fn test_parse_encoded_pointer_absptr() { let encoding = constants::DW_EH_PE_absptr; let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L32(0xf00d_f00d) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0xf00d_f00d)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_pcrel() { let encoding = constants::DW_EH_PE_pcrel; let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .append_repeated(0, 0x10) .L32(0x1) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input.range_from(0x10..); let parameters = PointerEncodingParameters { bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame, func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x111)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_pcrel_undefined() { let encoding = constants::DW_EH_PE_pcrel; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::PcRelativePointerButSectionBaseIsUndefined) ); } #[test] fn test_parse_encoded_pointer_textrel() { let encoding = constants::DW_EH_PE_textrel; let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L32(0x1) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &BaseAddresses::default().set_text(0x10).eh_frame, func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_textrel_undefined() { let encoding = constants::DW_EH_PE_textrel; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::TextRelativePointerButTextBaseIsUndefined) ); } #[test] fn test_parse_encoded_pointer_datarel() { let encoding = constants::DW_EH_PE_datarel; let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L32(0x1) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &BaseAddresses::default().set_got(0x10).eh_frame, func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_datarel_undefined() { let encoding = constants::DW_EH_PE_datarel; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::DataRelativePointerButDataBaseIsUndefined) ); } #[test] fn test_parse_encoded_pointer_funcrel() { let encoding = constants::DW_EH_PE_funcrel; let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L32(0x1) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: Some(0x10), address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_funcrel_undefined() { let encoding = constants::DW_EH_PE_funcrel; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::FuncRelativePointerInBadContext) ); } #[test] fn test_parse_encoded_pointer_uleb128() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_uleb128.0); let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .uleb(0x12_3456) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x12_3456)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_udata2() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata2.0); let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L16(0x1234) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x1234)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_udata4() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata4.0); let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L32(0x1234_5678) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_udata8() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_udata8.0); let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .L64(0x1234_5678_1234_5678) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x1234_5678_1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_sleb128() { let encoding = constants::DwEhPe(constants::DW_EH_PE_textrel.0 | constants::DW_EH_PE_sleb128.0); let expected_rest = [1, 2, 3, 4]; let input = Section::with_endian(Endian::Little) .sleb(-0x1111) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame, func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(0x1111_0000)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_sdata2() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata2.0); let expected_rest = [1, 2, 3, 4]; let expected = 0x111 as i16; let input = Section::with_endian(Endian::Little) .L16(expected as u16) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_sdata4() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata4.0); let expected_rest = [1, 2, 3, 4]; let expected = 0x111_1111 as i32; let input = Section::with_endian(Endian::Little) .L32(expected as u32) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_sdata8() { let encoding = constants::DwEhPe(constants::DW_EH_PE_absptr.0 | constants::DW_EH_PE_sdata8.0); let expected_rest = [1, 2, 3, 4]; let expected = -0x11_1111_1222_2222 as i64; let input = Section::with_endian(Endian::Little) .L64(expected as u64) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_encoded_pointer_omit() { let encoding = constants::DW_EH_PE_omit; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::CannotParseOmitPointerEncoding) ); assert_eq!(rest, input); } #[test] fn test_parse_encoded_pointer_bad_encoding() { let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1); let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::UnknownPointerEncoding) ); } #[test] fn test_parse_encoded_pointer_aligned() { // FIXME: support this encoding! let encoding = constants::DW_EH_PE_aligned; let input = Section::with_endian(Endian::Little).L32(0x1); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Err(Error::UnsupportedPointerEncoding) ); } #[test] fn test_parse_encoded_pointer_indirect() { let expected_rest = [1, 2, 3, 4]; let encoding = constants::DW_EH_PE_indirect; let input = Section::with_endian(Endian::Little) .L32(0x1234_5678) .append_bytes(&expected_rest); let input = input.get_contents().unwrap(); let input = EndianSlice::new(&input, LittleEndian); let mut rest = input; let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, address_size: 4, section: &input, }; assert_eq!( parse_encoded_pointer(encoding, ¶meters, &mut rest), Ok(Pointer::Indirect(0x1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); } } gimli-0.19.0/src/read/dwarf.rs010066400017500001750000000712511351057326000143100ustar0000000000000000use fallible_iterator::FallibleIterator; use crate::common::{ DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypesOffset, Encoding, LocationListsOffset, RangeListsOffset, SectionId, UnitSectionOffset, }; use crate::constants; use crate::read::{ Abbreviations, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter, DebugAbbrev, DebugAddr, DebugInfo, DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, DebuggingInformationEntry, EntriesCursor, EntriesTree, Error, IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, ReaderOffset, ReaderOffsetId, Result, RngListIter, Section, TypeUnitHeader, TypeUnitHeadersIter, UnitHeader, UnitOffset, }; use crate::string::String; /// All of the commonly used DWARF sections, and other common information. #[derive(Debug, Default)] pub struct Dwarf { /// The `.debug_abbrev` section. pub debug_abbrev: DebugAbbrev, /// The `.debug_addr` section. pub debug_addr: DebugAddr, /// The `.debug_info` section. pub debug_info: DebugInfo, /// The `.debug_line` section. pub debug_line: DebugLine, /// The `.debug_line_str` section. pub debug_line_str: DebugLineStr, /// The `.debug_str` section. pub debug_str: DebugStr, /// The `.debug_str_offsets` section. pub debug_str_offsets: DebugStrOffsets, /// The `.debug_str` section for a supplementary object file. pub debug_str_sup: DebugStr, /// The `.debug_types` section. pub debug_types: DebugTypes, /// The location lists in the `.debug_loc` and `.debug_loclists` sections. pub locations: LocationLists, /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections. pub ranges: RangeLists, } impl Dwarf { /// Try to load the DWARF sections using the given loader functions. /// /// `section` loads a DWARF section from the main object file. /// `sup` loads a DWARF sections from the supplementary object file. /// These functions should return an empty section if the section does not exist. /// /// The provided callback functions may either directly return a `Reader` instance /// (such as `EndianSlice`), or they may return some other type and then convert /// that type into a `Reader` using `Dwarf::borrow`. pub fn load(mut section: F1, mut sup: F2) -> std::result::Result where F1: FnMut(SectionId) -> std::result::Result, F2: FnMut(SectionId) -> std::result::Result, { // Section types are inferred. let debug_loc = Section::load(&mut section)?; let debug_loclists = Section::load(&mut section)?; let debug_ranges = Section::load(&mut section)?; let debug_rnglists = Section::load(&mut section)?; Ok(Dwarf { debug_abbrev: Section::load(&mut section)?, debug_addr: Section::load(&mut section)?, debug_info: Section::load(&mut section)?, debug_line: Section::load(&mut section)?, debug_line_str: Section::load(&mut section)?, debug_str: Section::load(&mut section)?, debug_str_offsets: Section::load(&mut section)?, debug_str_sup: Section::load(&mut sup)?, debug_types: Section::load(&mut section)?, locations: LocationLists::new(debug_loc, debug_loclists), ranges: RangeLists::new(debug_ranges, debug_rnglists), }) } /// Create a `Dwarf` structure that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// It can be useful to load DWARF sections into owned data structures, /// such as `Vec`. However, we do not implement the `Reader` trait /// for `Vec`, because it would be very inefficient, but this trait /// is required for all of the methods that parse the DWARF data. /// So we first load the DWARF sections into `Vec`s, and then use /// `borrow` to create `Reader`s that reference the data. /// /// ```rust,no_run /// # fn example() -> Result<(), gimli::Error> { /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() }; /// # let sup_loader = |name| { unimplemented!() }; /// // Read the DWARF sections into `Vec`s with whatever object loader you're using. /// let owned_dwarf: gimli::Dwarf> = gimli::Dwarf::load(loader, sup_loader)?; /// // Create references to the DWARF sections. /// let dwarf = owned_dwarf.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// # unreachable!() /// # } /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf where F: FnMut(&'a T) -> R, { Dwarf { debug_abbrev: self.debug_abbrev.borrow(&mut borrow), debug_addr: self.debug_addr.borrow(&mut borrow), debug_info: self.debug_info.borrow(&mut borrow), debug_line: self.debug_line.borrow(&mut borrow), debug_line_str: self.debug_line_str.borrow(&mut borrow), debug_str: self.debug_str.borrow(&mut borrow), debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow), debug_str_sup: self.debug_str_sup.borrow(&mut borrow), debug_types: self.debug_types.borrow(&mut borrow), locations: self.locations.borrow(&mut borrow), ranges: self.ranges.borrow(&mut borrow), } } } impl Dwarf { /// Iterate the compilation- and partial-unit headers in the /// `.debug_info` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[inline] pub fn units(&self) -> CompilationUnitHeadersIter { self.debug_info.units() } /// Construct a new `Unit` from the given compilation unit header. #[inline] pub fn unit(&self, header: CompilationUnitHeader) -> Result> { Unit::new(self, header) } /// Iterate the type-unit headers in the `.debug_types` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[inline] pub fn type_units(&self) -> TypeUnitHeadersIter { self.debug_types.units() } /// Construct a new `Unit` from the given type unit header. #[inline] pub fn type_unit(&self, header: TypeUnitHeader) -> Result> { Unit::new_type_unit(self, header) } /// Parse the abbreviations for a compilation unit. // TODO: provide caching of abbreviations #[inline] pub fn abbreviations(&self, unit: &CompilationUnitHeader) -> Result { unit.abbreviations(&self.debug_abbrev) } /// Parse the abbreviations for a type unit. // TODO: provide caching of abbreviations #[inline] pub fn type_abbreviations(&self, unit: &TypeUnitHeader) -> Result { unit.abbreviations(&self.debug_abbrev) } /// Return the string offset at the given index. #[inline] pub fn string_offset( &self, unit: &Unit, index: DebugStrOffsetsIndex, ) -> Result> { self.debug_str_offsets .get_str_offset(unit.header.format(), unit.str_offsets_base, index) } /// Return the string at the given offset in `.debug_str`. #[inline] pub fn string(&self, offset: DebugStrOffset) -> Result { self.debug_str.get_str(offset) } /// Return the string at the given offset in `.debug_line_str`. #[inline] pub fn line_string(&self, offset: DebugLineStrOffset) -> Result { self.debug_line_str.get_str(offset) } /// Return an attribute value as a string slice. /// /// If the attribute value is one of: /// /// - an inline `DW_FORM_string` string /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary /// object file /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str` /// section /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit /// /// then return the attribute's string value. Returns an error if the attribute /// value does not have a string form, or if a string form has an invalid value. pub fn attr_string(&self, unit: &Unit, attr: AttributeValue) -> Result { match attr { AttributeValue::String(string) => Ok(string), AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset), AttributeValue::DebugStrRefSup(offset) => self.debug_str_sup.get_str(offset), AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset), AttributeValue::DebugStrOffsetsIndex(index) => { let offset = self.debug_str_offsets.get_str_offset( unit.header.format(), unit.str_offsets_base, index, )?; self.debug_str.get_str(offset) } _ => Err(Error::ExpectedStringAttributeValue), } } /// Return the address at the given index. pub fn address(&self, unit: &Unit, index: DebugAddrIndex) -> Result { self.debug_addr .get_address(unit.encoding().address_size, unit.addr_base, index) } /// Return the range list offset at the given index. pub fn ranges_offset( &self, unit: &Unit, index: DebugRngListsIndex, ) -> Result> { self.ranges .get_offset(unit.encoding(), unit.rnglists_base, index) } /// Iterate over the `RangeListEntry`s starting at the given offset. pub fn ranges( &self, unit: &Unit, offset: RangeListsOffset, ) -> Result> { self.ranges.ranges( offset, unit.encoding(), unit.low_pc, &self.debug_addr, unit.addr_base, ) } /// Try to return an attribute value as a range list offset. /// /// If the attribute value is one of: /// /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit /// /// then return the range list offset of the range list. /// Returns `None` for other forms. pub fn attr_ranges_offset( &self, unit: &Unit, attr: AttributeValue, ) -> Result>> { match attr { AttributeValue::RangeListsRef(offset) => Ok(Some(offset)), AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some), _ => Ok(None), } } /// Try to return an attribute value as a range list entry iterator. /// /// If the attribute value is one of: /// /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit /// /// then return an iterator over the entries in the range list. /// Returns `None` for other forms. pub fn attr_ranges( &self, unit: &Unit, attr: AttributeValue, ) -> Result>> { match self.attr_ranges_offset(unit, attr)? { Some(offset) => Ok(Some(self.ranges(unit, offset)?)), None => Ok(None), } } /// Return an iterator for the address ranges of a `DebuggingInformationEntry`. /// /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`. pub fn die_ranges( &self, unit: &Unit, entry: &DebuggingInformationEntry, ) -> Result> { let mut low_pc = None; let mut high_pc = None; let mut size = None; let mut attrs = entry.attrs(); while let Some(attr) = attrs.next()? { match attr.name() { constants::DW_AT_low_pc => { if let AttributeValue::Addr(val) = attr.value() { low_pc = Some(val); } } constants::DW_AT_high_pc => match attr.value() { AttributeValue::Addr(val) => high_pc = Some(val), AttributeValue::Udata(val) => size = Some(val), _ => return Err(Error::UnsupportedAttributeForm), }, constants::DW_AT_ranges => { if let Some(list) = self.attr_ranges(unit, attr.value())? { return Ok(RangeIter(RangeIterInner::List(list))); } } _ => {} } } let range = low_pc.and_then(|begin| { let end = size.map(|size| begin + size).or(high_pc); // TODO: perhaps return an error if `end` is `None` end.map(|end| Range { begin, end }) }); Ok(RangeIter(RangeIterInner::Single(range))) } /// Return an iterator for the address ranges of a `Unit`. /// /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the /// root `DebuggingInformationEntry`. pub fn unit_ranges(&self, unit: &Unit) -> Result> { let mut cursor = unit.header.entries(&unit.abbreviations); cursor.next_dfs()?; let root = cursor.current().ok_or(Error::MissingUnitDie)?; self.die_ranges(unit, root) } /// Return the location list offset at the given index. pub fn locations_offset( &self, unit: &Unit, index: DebugLocListsIndex, ) -> Result> { self.locations .get_offset(unit.encoding(), unit.loclists_base, index) } /// Iterate over the `LocationListEntry`s starting at the given offset. pub fn locations( &self, unit: &Unit, offset: LocationListsOffset, ) -> Result> { self.locations.locations( offset, unit.encoding(), unit.low_pc, &self.debug_addr, unit.addr_base, ) } /// Try to return an attribute value as a location list offset. /// /// If the attribute value is one of: /// /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit /// /// then return the location list offset of the location list. /// Returns `None` for other forms. pub fn attr_locations_offset( &self, unit: &Unit, attr: AttributeValue, ) -> Result>> { match attr { AttributeValue::LocationListsRef(offset) => Ok(Some(offset)), AttributeValue::DebugLocListsIndex(index) => { self.locations_offset(unit, index).map(Some) } _ => Ok(None), } } /// Try to return an attribute value as a location list entry iterator. /// /// If the attribute value is one of: /// /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit /// /// then return an iterator over the entries in the location list. /// Returns `None` for other forms. pub fn attr_locations( &self, unit: &Unit, attr: AttributeValue, ) -> Result>> { match self.attr_locations_offset(unit, attr)? { Some(offset) => Ok(Some(self.locations(unit, offset)?)), None => Ok(None), } } /// Call `Reader::lookup_offset_id` for each section, and return the first match. /// /// The first element of the tuple is `true` for supplementary sections. pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> { None.or_else(|| self.debug_abbrev.lookup_offset_id(id)) .or_else(|| self.debug_addr.lookup_offset_id(id)) .or_else(|| self.debug_info.lookup_offset_id(id)) .or_else(|| self.debug_line.lookup_offset_id(id)) .or_else(|| self.debug_line_str.lookup_offset_id(id)) .or_else(|| self.debug_str.lookup_offset_id(id)) .or_else(|| self.debug_str_offsets.lookup_offset_id(id)) .or_else(|| self.debug_types.lookup_offset_id(id)) .or_else(|| self.locations.lookup_offset_id(id)) .or_else(|| self.ranges.lookup_offset_id(id)) .map(|(id, offset)| (false, id, offset)) .or_else(|| { self.debug_str_sup .lookup_offset_id(id) .map(|(id, offset)| (true, id, offset)) }) } /// Returns a string representation of the given error. /// /// This uses information from the DWARF sections to provide more information in some cases. pub fn format_error(&self, err: Error) -> String { #[allow(clippy::single_match)] match err { Error::UnexpectedEof(id) => match self.lookup_offset_id(id) { Some((sup, section, offset)) => { return format!( "{} at {}{}+0x{:x}", err.description(), section.name(), if sup { "(sup)" } else { "" }, offset.into_u64(), ); } None => {} }, _ => {} } err.description().into() } } /// All of the commonly used information for a unit in the `.debug_info` or `.debug_types` /// sections. #[derive(Debug)] pub struct Unit::Offset> where R: Reader, Offset: ReaderOffset, { /// The section offset of the unit. pub offset: UnitSectionOffset, /// The header of the unit. pub header: UnitHeader, /// The parsed abbreviations for the unit. pub abbreviations: Abbreviations, /// The `DW_AT_name` attribute of the unit. pub name: Option, /// The `DW_AT_comp_dir` attribute of the unit. pub comp_dir: Option, /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0. pub low_pc: u64, /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0. pub str_offsets_base: DebugStrOffsetsBase, /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0. pub addr_base: DebugAddrBase, /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0. pub loclists_base: DebugLocListsBase, /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0. pub rnglists_base: DebugRngListsBase, /// The line number program of the unit. pub line_program: Option>, } impl Unit { /// Construct a new `Unit` from the given compilation unit header. #[inline] pub fn new(dwarf: &Dwarf, header: CompilationUnitHeader) -> Result { Self::new_internal( dwarf, UnitSectionOffset::DebugInfoOffset(header.offset()), header.header(), ) } /// Construct a new `Unit` from the given type unit header. #[inline] pub fn new_type_unit(dwarf: &Dwarf, header: TypeUnitHeader) -> Result { Self::new_internal( dwarf, UnitSectionOffset::DebugTypesOffset(header.offset()), header.header(), ) } fn new_internal( dwarf: &Dwarf, offset: UnitSectionOffset, header: UnitHeader, ) -> Result { let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?; let mut unit = Unit { offset, header, abbreviations, name: None, comp_dir: None, low_pc: 0, // Defaults to 0 for GNU extensions. str_offsets_base: DebugStrOffsetsBase(R::Offset::from_u8(0)), addr_base: DebugAddrBase(R::Offset::from_u8(0)), loclists_base: DebugLocListsBase(R::Offset::from_u8(0)), rnglists_base: DebugRngListsBase(R::Offset::from_u8(0)), line_program: None, }; let mut name = None; let mut comp_dir = None; let mut line_program_offset = None; { let mut cursor = unit.header.entries(&unit.abbreviations); cursor.next_dfs()?; let root = cursor.current().ok_or(Error::MissingUnitDie)?; let mut attrs = root.attrs(); while let Some(attr) = attrs.next()? { match attr.name() { constants::DW_AT_name => { name = Some(attr.value()); } constants::DW_AT_comp_dir => { comp_dir = Some(attr.value()); } constants::DW_AT_low_pc => { if let AttributeValue::Addr(address) = attr.value() { unit.low_pc = address; } } constants::DW_AT_stmt_list => { if let AttributeValue::DebugLineRef(offset) = attr.value() { line_program_offset = Some(offset); } } constants::DW_AT_str_offsets_base => { if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() { unit.str_offsets_base = base; } } constants::DW_AT_addr_base => { if let AttributeValue::DebugAddrBase(base) = attr.value() { unit.addr_base = base; } } constants::DW_AT_loclists_base => { if let AttributeValue::DebugLocListsBase(base) = attr.value() { unit.loclists_base = base; } } constants::DW_AT_rnglists_base => { if let AttributeValue::DebugRngListsBase(base) = attr.value() { unit.rnglists_base = base; } } _ => {} } } } unit.name = match name { Some(val) => Some(dwarf.attr_string(&unit, val)?), None => None, }; unit.comp_dir = match comp_dir { Some(val) => Some(dwarf.attr_string(&unit, val)?), None => None, }; unit.line_program = match line_program_offset { Some(offset) => Some(dwarf.debug_line.program( offset, unit.header.address_size(), unit.comp_dir.clone(), unit.name.clone(), )?), None => None, }; Ok(unit) } /// Return the encoding parameters for this unit. #[inline] pub fn encoding(&self) -> Encoding { self.header.encoding() } /// Navigate this unit's `DebuggingInformationEntry`s. #[inline] pub fn entries(&self) -> EntriesCursor { self.header.entries(&self.abbreviations) } /// Navigate this unit's `DebuggingInformationEntry`s /// starting at the given offset. #[inline] pub fn entries_at_offset(&self, offset: UnitOffset) -> Result> { self.header.entries_at_offset(&self.abbreviations, offset) } /// Navigate this unit's `DebuggingInformationEntry`s as a tree /// starting at the given offset. #[inline] pub fn entries_tree(&self, offset: Option>) -> Result> { self.header.entries_tree(&self.abbreviations, offset) } } impl UnitSectionOffset { /// Convert an offset to be relative to the start of the given unit, /// instead of relative to the start of the section. /// Returns `None` if the offset is not within the unit entries. pub fn to_unit_offset(&self, unit: &Unit) -> Option> where R: Reader, { let (offset, unit_offset) = match (self, unit.offset) { ( UnitSectionOffset::DebugInfoOffset(offset), UnitSectionOffset::DebugInfoOffset(unit_offset), ) => (offset.0, unit_offset.0), ( UnitSectionOffset::DebugTypesOffset(offset), UnitSectionOffset::DebugTypesOffset(unit_offset), ) => (offset.0, unit_offset.0), _ => return None, }; let offset = match offset.checked_sub(unit_offset) { Some(offset) => UnitOffset(offset), None => return None, }; if !unit.header.is_valid_offset(offset) { return None; } Some(offset) } } impl UnitOffset { /// Convert an offset to be relative to the start of the .debug_info section, /// instead of relative to the start of the given compilation unit. pub fn to_unit_section_offset(&self, unit: &Unit) -> UnitSectionOffset where R: Reader, { match unit.offset { UnitSectionOffset::DebugInfoOffset(unit_offset) => { UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(unit_offset.0 + self.0)) } UnitSectionOffset::DebugTypesOffset(unit_offset) => { UnitSectionOffset::DebugTypesOffset(DebugTypesOffset(unit_offset.0 + self.0)) } } } } /// An iterator for the address ranges of a `DebuggingInformationEntry`. /// /// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`. #[derive(Debug)] pub struct RangeIter(RangeIterInner); #[derive(Debug)] enum RangeIterInner { Single(Option), List(RngListIter), } impl Default for RangeIter { fn default() -> Self { RangeIter(RangeIterInner::Single(None)) } } impl RangeIter { /// Advance the iterator to the next range. pub fn next(&mut self) -> Result> { match self.0 { RangeIterInner::Single(ref mut range) => Ok(range.take()), RangeIterInner::List(ref mut list) => list.next(), } } } impl FallibleIterator for RangeIter { type Item = Range; type Error = Error; #[inline] fn next(&mut self) -> ::std::result::Result, Self::Error> { RangeIter::next(self) } } #[cfg(test)] mod tests { use super::*; use crate::read::EndianSlice; use crate::{Endianity, LittleEndian}; /// Ensure that `Dwarf` is covariant wrt R. #[test] fn test_dwarf_variance() { /// This only needs to compile. fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf>) -> Dwarf> { x } } /// Ensure that `Unit` is covariant wrt R. #[test] fn test_dwarf_unit_variance() { /// This only needs to compile. fn _f<'a: 'b, 'b, E: Endianity>(x: Unit>) -> Unit> { x } } #[test] fn test_format_error() { let owned_dwarf = Dwarf::load(|_| -> Result<_> { Ok(vec![1, 2]) }, |_| Ok(vec![1, 2])).unwrap(); let dwarf = owned_dwarf.borrow(|section| EndianSlice::new(§ion, LittleEndian)); match dwarf.debug_str.get_str(DebugStrOffset(1)) { Ok(r) => panic!("Unexpected str {:?}", r), Err(e) => { assert_eq!( dwarf.format_error(e), "Hit the end of input before it was expected at .debug_str+0x1" ); } } match dwarf.debug_str_sup.get_str(DebugStrOffset(1)) { Ok(r) => panic!("Unexpected str {:?}", r), Err(e) => { assert_eq!( dwarf.format_error(e), "Hit the end of input before it was expected at .debug_str(sup)+0x1" ); } } assert_eq!(dwarf.format_error(Error::Io), Error::Io.description()); } } gimli-0.19.0/src/read/endian_reader.rs010066400017500001750000000427261346020377600160000ustar0000000000000000//! Defining custom `Reader`s quickly. use crate::borrow::Cow; use crate::rc::Rc; use crate::string::String; use crate::Arc; use stable_deref_trait::CloneStableDeref; use std::fmt::Debug; use std::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use std::slice; use std::str; use crate::endianity::Endianity; use crate::read::{Error, Reader, ReaderOffsetId, Result}; /// A reference counted, non-thread-safe slice of bytes and associated /// endianity. /// /// ``` /// use std::rc::Rc; /// /// let buf = Rc::from(&[1, 2, 3, 4][..]); /// let reader = gimli::EndianRcSlice::new(buf, gimli::NativeEndian); /// # let _ = reader; /// ``` pub type EndianRcSlice = EndianReader>; /// An atomically reference counted, thread-safe slice of bytes and associated /// endianity. /// /// ``` /// use std::sync::Arc; /// /// let buf = Arc::from(&[1, 2, 3, 4][..]); /// let reader = gimli::EndianArcSlice::new(buf, gimli::NativeEndian); /// # let _ = reader; /// ``` pub type EndianArcSlice = EndianReader>; /// An easy way to define a custom `Reader` implementation with a reference to a /// generic buffer of bytes and an associated endianity. /// /// Note that the whole original buffer is kept alive in memory even if there is /// only one reader that references only a handful of bytes from that original /// buffer. That is, `EndianReader` will not do any copying, moving, or /// compacting in order to free up unused regions of the original buffer. If you /// require this kind of behavior, it is up to you to implement `Reader` /// directly by-hand. /// /// # Example /// /// Say you have an `mmap`ed file that you want to serve as a `gimli::Reader`. /// You can wrap that `mmap`ed file up in a `MmapFile` type and use /// `EndianReader>` or `EndianReader>` as readers as /// long as `MmapFile` dereferences to the underlying `[u8]` data. /// /// ``` /// use std::io; /// use std::ops::Deref; /// use std::path::Path; /// use std::slice; /// use std::sync::Arc; /// /// /// A type that represents an `mmap`ed file. /// #[derive(Debug)] /// pub struct MmapFile { /// ptr: *const u8, /// len: usize, /// } /// /// impl MmapFile { /// pub fn new(path: &Path) -> io::Result { /// // Call `mmap` and check for errors and all that... /// # unimplemented!() /// } /// } /// /// impl Drop for MmapFile { /// fn drop(&mut self) { /// // Call `munmap` to clean up after ourselves... /// # unimplemented!() /// } /// } /// /// // And `MmapFile` can deref to a slice of the `mmap`ed region of memory. /// impl Deref for MmapFile { /// type Target = [u8]; /// fn deref(&self) -> &[u8] { /// unsafe { /// slice::from_raw_parts(self.ptr, self.len) /// } /// } /// } /// /// /// A type that represents a shared `mmap`ed file. /// #[derive(Debug, Clone)] /// pub struct ArcMmapFile(Arc); /// /// // And `ArcMmapFile` can deref to a slice of the `mmap`ed region of memory. /// impl Deref for ArcMmapFile { /// type Target = [u8]; /// fn deref(&self) -> &[u8] { /// &self.0 /// } /// } /// /// // These are both valid for any `Rc` or `Arc`. /// unsafe impl gimli::StableDeref for ArcMmapFile {} /// unsafe impl gimli::CloneStableDeref for ArcMmapFile {} /// /// /// A `gimli::Reader` that is backed by an `mmap`ed file! /// pub type MmapFileReader = gimli::EndianReader; /// # fn test(_: &MmapFileReader) { } /// ``` #[derive(Debug, Clone, Copy, Hash)] pub struct EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { range: SubRange, endian: Endian, } impl PartialEq> for EndianReader where Endian: Endianity, T1: CloneStableDeref + Debug, T2: CloneStableDeref + Debug, { fn eq(&self, rhs: &EndianReader) -> bool { self.bytes() == rhs.bytes() } } impl Eq for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { } // This is separated out from `EndianReader` so that we can avoid running afoul // of borrowck. We need to `read_slice(&mut self, ...) -> &[u8]` and then call // `self.endian.read_whatever` on the result. The problem is that the returned // slice keeps the `&mut self` borrow active, so we wouldn't be able to access // `self.endian`. Splitting the sub-range out from the endian lets us work // around this, making it so that only the `self.range` borrow is held active, // not all of `self`. // // This also serves to encapsulate the unsafe code concerning `CloneStableDeref`. // The `bytes` member is held so that the bytes live long enough, and the // `CloneStableDeref` ensures these bytes never move. The `ptr` and `len` // members point inside `bytes`, and are updated during read operations. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct SubRange where T: CloneStableDeref + Debug, { bytes: T, ptr: *const u8, len: usize, } unsafe impl Send for SubRange where T: CloneStableDeref + Debug + Send {} unsafe impl Sync for SubRange where T: CloneStableDeref + Debug + Sync {} impl SubRange where T: CloneStableDeref + Debug, { #[inline] fn new(bytes: T) -> Self { let ptr = bytes.as_ptr(); let len = bytes.len(); SubRange { bytes, ptr, len } } #[inline] fn bytes(&self) -> &[u8] { // Safe because `T` implements `CloneStableDeref`, `bytes` can't be modified, // and all operations that modify `ptr` and `len` ensure they stay in range. unsafe { slice::from_raw_parts(self.ptr, self.len) } } #[inline] fn len(&self) -> usize { self.len } #[inline] fn truncate(&mut self, len: usize) { assert!(len <= self.len); self.len = len; } #[inline] fn skip(&mut self, len: usize) { assert!(len <= self.len); self.ptr = unsafe { self.ptr.add(len) }; self.len -= len; } #[inline] fn read_slice(&mut self, len: usize) -> Option<&[u8]> { if self.len() < len { None } else { // Same as for `bytes()`. let bytes = unsafe { slice::from_raw_parts(self.ptr, len) }; self.skip(len); Some(bytes) } } } impl EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { /// Construct a new `EndianReader` with the given bytes. #[inline] pub fn new(bytes: T, endian: Endian) -> EndianReader { EndianReader { range: SubRange::new(bytes), endian, } } /// Return a reference to the raw bytes underlying this reader. #[inline] pub fn bytes(&self) -> &[u8] { self.range.bytes() } } /// # Range Methods /// /// Unfortunately, `std::ops::Index` *must* return a reference, so we can't /// implement `Index>` to return a new `EndianReader` the way we /// would like to. Instead, we abandon fancy indexing operators and have these /// plain old methods. impl EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { /// Take the given `start..end` range of the underlying buffer and return a /// new `EndianReader`. /// /// ``` /// use gimli::{EndianReader, LittleEndian}; /// use std::sync::Arc; /// /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); /// let reader = EndianReader::new(buf.clone(), LittleEndian); /// assert_eq!(reader.range(1..3), /// EndianReader::new(&buf[1..3], LittleEndian)); /// ``` /// /// # Panics /// /// Panics if the range is out of bounds. pub fn range(&self, idx: Range) -> EndianReader { let mut r = self.clone(); r.range.skip(idx.start); r.range.truncate(idx.len()); r } /// Take the given `start..` range of the underlying buffer and return a new /// `EndianReader`. /// /// ``` /// use gimli::{EndianReader, LittleEndian}; /// use std::sync::Arc; /// /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); /// let reader = EndianReader::new(buf.clone(), LittleEndian); /// assert_eq!(reader.range_from(2..), /// EndianReader::new(&buf[2..], LittleEndian)); /// ``` /// /// # Panics /// /// Panics if the range is out of bounds. pub fn range_from(&self, idx: RangeFrom) -> EndianReader { let mut r = self.clone(); r.range.skip(idx.start); r } /// Take the given `..end` range of the underlying buffer and return a new /// `EndianReader`. /// /// ``` /// use gimli::{EndianReader, LittleEndian}; /// use std::sync::Arc; /// /// let buf = Arc::<[u8]>::from(&[0x01, 0x02, 0x03, 0x04][..]); /// let reader = EndianReader::new(buf.clone(), LittleEndian); /// assert_eq!(reader.range_to(..3), /// EndianReader::new(&buf[..3], LittleEndian)); /// ``` /// /// # Panics /// /// Panics if the range is out of bounds. pub fn range_to(&self, idx: RangeTo) -> EndianReader { let mut r = self.clone(); r.range.truncate(idx.end); r } } impl Index for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { type Output = u8; fn index(&self, idx: usize) -> &Self::Output { &self.bytes()[idx] } } impl Index> for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { type Output = [u8]; fn index(&self, idx: RangeFrom) -> &Self::Output { &self.bytes()[idx] } } impl Deref for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { type Target = [u8]; fn deref(&self) -> &Self::Target { self.bytes() } } impl Reader for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { type Endian = Endian; type Offset = usize; #[inline] fn endian(&self) -> Endian { self.endian } #[inline] fn len(&self) -> usize { self.range.len() } #[inline] fn empty(&mut self) { self.range.truncate(0); } #[inline] fn truncate(&mut self, len: usize) -> Result<()> { if self.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { self.range.truncate(len); Ok(()) } } #[inline] fn offset_from(&self, base: &EndianReader) -> usize { let base_ptr = base.bytes().as_ptr() as *const u8 as usize; let ptr = self.bytes().as_ptr() as *const u8 as usize; debug_assert!(base_ptr <= ptr); debug_assert!(ptr + self.bytes().len() <= base_ptr + base.bytes().len()); ptr - base_ptr } #[inline] fn offset_id(&self) -> ReaderOffsetId { ReaderOffsetId(self.bytes().as_ptr() as u64) } #[inline] fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { let id = id.0; let self_id = self.bytes().as_ptr() as u64; let self_len = self.bytes().len() as u64; if id >= self_id && id <= self_id + self_len { Some((id - self_id) as usize) } else { None } } #[inline] fn find(&self, byte: u8) -> Result { self.bytes() .iter() .position(|x| *x == byte) .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) } #[inline] fn skip(&mut self, len: usize) -> Result<()> { if self.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { self.range.skip(len); Ok(()) } } #[inline] fn split(&mut self, len: usize) -> Result { if self.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { let mut r = self.clone(); r.range.truncate(len); self.range.skip(len); Ok(r) } } #[inline] fn to_slice(&self) -> Result> { Ok(self.bytes().into()) } #[inline] fn to_string(&self) -> Result> { match str::from_utf8(self.bytes()) { Ok(s) => Ok(s.into()), _ => Err(Error::BadUtf8), } } #[inline] fn to_string_lossy(&self) -> Result> { Ok(String::from_utf8_lossy(self.bytes())) } #[inline] fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { match self.range.read_slice(buf.len()) { Some(slice) => { buf.clone_from_slice(slice); Ok(()) } None => Err(Error::UnexpectedEof(self.offset_id())), } } } #[cfg(test)] mod tests { use super::*; use crate::endianity::NativeEndian; use crate::read::Reader; fn native_reader + Debug>( bytes: T, ) -> EndianReader { EndianReader::new(bytes, NativeEndian) } const BUF: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; #[test] fn test_reader_split() { let mut reader = native_reader(BUF); let left = reader.split(3).unwrap(); assert_eq!(left, native_reader(&BUF[..3])); assert_eq!(reader, native_reader(&BUF[3..])); } #[test] fn test_reader_split_out_of_bounds() { let mut reader = native_reader(BUF); assert!(reader.split(30).is_err()); } #[test] fn bytes_and_len_and_range_and_eq() { let reader = native_reader(BUF); assert_eq!(reader.len(), BUF.len()); assert_eq!(reader.bytes(), BUF); assert_eq!(reader, native_reader(BUF)); let range = reader.range(2..8); let buf_range = &BUF[2..8]; assert_eq!(range.len(), buf_range.len()); assert_eq!(range.bytes(), buf_range); assert_ne!(range, native_reader(BUF)); assert_eq!(range, native_reader(buf_range)); let range_from = range.range_from(1..); let buf_range_from = &buf_range[1..]; assert_eq!(range_from.len(), buf_range_from.len()); assert_eq!(range_from.bytes(), buf_range_from); assert_ne!(range_from, native_reader(BUF)); assert_eq!(range_from, native_reader(buf_range_from)); let range_to = range_from.range_to(..4); let buf_range_to = &buf_range_from[..4]; assert_eq!(range_to.len(), buf_range_to.len()); assert_eq!(range_to.bytes(), buf_range_to); assert_ne!(range_to, native_reader(BUF)); assert_eq!(range_to, native_reader(buf_range_to)); } #[test] fn find() { let mut reader = native_reader(BUF); reader.skip(2).unwrap(); assert_eq!( reader.find(5), Ok(BUF[2..].iter().position(|x| *x == 5).unwrap()) ); } #[test] fn indexing() { let mut reader = native_reader(BUF); reader.skip(2).unwrap(); assert_eq!(reader[0], BUF[2]); } #[test] #[should_panic] fn indexing_out_of_bounds() { let mut reader = native_reader(BUF); reader.skip(2).unwrap(); let _ = reader[900]; } #[test] fn endian() { let reader = native_reader(BUF); assert_eq!(reader.endian(), NativeEndian); } #[test] fn empty() { let mut reader = native_reader(BUF); assert!(!reader.is_empty()); reader.empty(); assert!(reader.is_empty()); assert!(reader.bytes().is_empty()); } #[test] fn truncate() { let reader = native_reader(BUF); let mut reader = reader.range(2..8); reader.truncate(2).unwrap(); assert_eq!(reader.bytes(), &BUF[2..4]); } #[test] fn offset_from() { let reader = native_reader(BUF); let sub = reader.range(2..8); assert_eq!(sub.offset_from(&reader), 2); } #[test] fn skip() { let mut reader = native_reader(BUF); reader.skip(2).unwrap(); assert_eq!(reader.bytes(), &BUF[2..]); } #[test] fn to_slice() { assert_eq!( native_reader(BUF).range(2..5).to_slice(), Ok(Cow::from(&BUF[2..5])) ); } #[test] fn to_string_ok() { let buf = b"hello, world!"; let reader = native_reader(&buf[..]); let reader = reader.range_from(7..); assert_eq!(reader.to_string(), Ok(Cow::from("world!"))); } // The rocket emoji (🚀 = [0xf0, 0x9f, 0x9a, 0x80]) but rotated left by one // to make it invalid UTF-8. const BAD_UTF8: &[u8] = &[0x9f, 0x9a, 0x80, 0xf0]; #[test] fn to_string_err() { let reader = native_reader(BAD_UTF8); assert!(reader.to_string().is_err()); } #[test] fn to_string_lossy() { let reader = native_reader(BAD_UTF8); assert_eq!(reader.to_string_lossy(), Ok(Cow::from("����"))); } #[test] fn read_u8_array() { let mut reader = native_reader(BAD_UTF8); reader.skip(1).unwrap(); let arr: [u8; 2] = reader.read_u8_array().unwrap(); assert_eq!(arr, &BAD_UTF8[1..3]); assert_eq!(reader.bytes(), &BAD_UTF8[3..]); } } gimli-0.19.0/src/read/endian_slice.rs010066400017500001750000000220761346020377600156310ustar0000000000000000//! Working with byte slices that have an associated endianity. use crate::borrow::Cow; use crate::string::String; use std::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use std::str; use crate::endianity::Endianity; use crate::read::{Error, Reader, ReaderOffsetId, Result}; /// A `&[u8]` slice with endianity metadata. /// /// This implements the `Reader` trait, which is used for all reading of DWARF sections. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub struct EndianSlice<'input, Endian> where Endian: Endianity, { slice: &'input [u8], endian: Endian, } impl<'input, Endian> EndianSlice<'input, Endian> where Endian: Endianity, { /// Construct a new `EndianSlice` with the given slice and endianity. #[inline] pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> { EndianSlice { slice, endian } } /// Return a reference to the raw slice. #[inline] #[doc(hidden)] #[deprecated(note = "Method renamed to EndianSlice::slice; use that instead.")] pub fn buf(&self) -> &'input [u8] { self.slice } /// Return a reference to the raw slice. #[inline] pub fn slice(&self) -> &'input [u8] { self.slice } /// Split the slice in two at the given index, resulting in the tuple where /// the first item has range [0, idx), and the second has range [idx, /// len). Panics if the index is out of bounds. #[inline] pub fn split_at( &self, idx: usize, ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) { (self.range_to(..idx), self.range_from(idx..)) } /// Find the first occurence of a byte in the slice, and return its index. #[inline] pub fn find(&self, byte: u8) -> Option { self.slice.iter().position(|ch| *ch == byte) } /// Return the offset of the start of the slice relative to the start /// of the given slice. #[inline] pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize { let base_ptr = base.slice.as_ptr() as *const u8 as usize; let ptr = self.slice.as_ptr() as *const u8 as usize; debug_assert!(base_ptr <= ptr); debug_assert!(ptr + self.slice.len() <= base_ptr + base.slice.len()); ptr - base_ptr } /// Converts the slice to a string using `str::from_utf8`. /// /// Returns an error if the slice contains invalid characters. #[inline] pub fn to_string(&self) -> Result<&'input str> { str::from_utf8(self.slice).map_err(|_| Error::BadUtf8) } /// Converts the slice to a string, including invalid characters, /// using `String::from_utf8_lossy`. #[inline] pub fn to_string_lossy(&self) -> Cow<'input, str> { String::from_utf8_lossy(self.slice) } #[inline] fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> { if self.slice.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { let val = &self.slice[..len]; self.slice = &self.slice[len..]; Ok(val) } } } /// # Range Methods /// /// Unfortunately, `std::ops::Index` *must* return a reference, so we can't /// implement `Index>` to return a new `EndianSlice` the way we would /// like to. Instead, we abandon fancy indexing operators and have these plain /// old methods. impl<'input, Endian> EndianSlice<'input, Endian> where Endian: Endianity, { /// Take the given `start..end` range of the underlying slice and return a /// new `EndianSlice`. /// /// ``` /// use gimli::{EndianSlice, LittleEndian}; /// /// let slice = &[0x01, 0x02, 0x03, 0x04]; /// let endian_slice = EndianSlice::new(slice, LittleEndian); /// assert_eq!(endian_slice.range(1..3), /// EndianSlice::new(&slice[1..3], LittleEndian)); /// ``` pub fn range(&self, idx: Range) -> EndianSlice<'input, Endian> { EndianSlice { slice: &self.slice[idx], endian: self.endian, } } /// Take the given `start..` range of the underlying slice and return a new /// `EndianSlice`. /// /// ``` /// use gimli::{EndianSlice, LittleEndian}; /// /// let slice = &[0x01, 0x02, 0x03, 0x04]; /// let endian_slice = EndianSlice::new(slice, LittleEndian); /// assert_eq!(endian_slice.range_from(2..), /// EndianSlice::new(&slice[2..], LittleEndian)); /// ``` pub fn range_from(&self, idx: RangeFrom) -> EndianSlice<'input, Endian> { EndianSlice { slice: &self.slice[idx], endian: self.endian, } } /// Take the given `..end` range of the underlying slice and return a new /// `EndianSlice`. /// /// ``` /// use gimli::{EndianSlice, LittleEndian}; /// /// let slice = &[0x01, 0x02, 0x03, 0x04]; /// let endian_slice = EndianSlice::new(slice, LittleEndian); /// assert_eq!(endian_slice.range_to(..3), /// EndianSlice::new(&slice[..3], LittleEndian)); /// ``` pub fn range_to(&self, idx: RangeTo) -> EndianSlice<'input, Endian> { EndianSlice { slice: &self.slice[idx], endian: self.endian, } } } impl<'input, Endian> Index for EndianSlice<'input, Endian> where Endian: Endianity, { type Output = u8; fn index(&self, idx: usize) -> &Self::Output { &self.slice[idx] } } impl<'input, Endian> Index> for EndianSlice<'input, Endian> where Endian: Endianity, { type Output = [u8]; fn index(&self, idx: RangeFrom) -> &Self::Output { &self.slice[idx] } } impl<'input, Endian> Deref for EndianSlice<'input, Endian> where Endian: Endianity, { type Target = [u8]; fn deref(&self) -> &Self::Target { self.slice } } impl<'input, Endian> Into<&'input [u8]> for EndianSlice<'input, Endian> where Endian: Endianity, { fn into(self) -> &'input [u8] { self.slice } } impl<'input, Endian> Reader for EndianSlice<'input, Endian> where Endian: Endianity, { type Endian = Endian; type Offset = usize; #[inline] fn endian(&self) -> Endian { self.endian } #[inline] fn len(&self) -> usize { self.slice.len() } #[inline] fn is_empty(&self) -> bool { self.slice.is_empty() } #[inline] fn empty(&mut self) { self.slice = &[]; } #[inline] fn truncate(&mut self, len: usize) -> Result<()> { if self.slice.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { self.slice = &self.slice[..len]; Ok(()) } } #[inline] fn offset_from(&self, base: &Self) -> usize { self.offset_from(*base) } #[inline] fn offset_id(&self) -> ReaderOffsetId { ReaderOffsetId(self.slice.as_ptr() as u64) } #[inline] fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option { let id = id.0; let self_id = self.slice.as_ptr() as u64; let self_len = self.slice.len() as u64; if id >= self_id && id <= self_id + self_len { Some((id - self_id) as usize) } else { None } } #[inline] fn find(&self, byte: u8) -> Result { self.find(byte) .ok_or_else(|| Error::UnexpectedEof(self.offset_id())) } #[inline] fn skip(&mut self, len: usize) -> Result<()> { if self.slice.len() < len { Err(Error::UnexpectedEof(self.offset_id())) } else { self.slice = &self.slice[len..]; Ok(()) } } #[inline] fn split(&mut self, len: usize) -> Result { let slice = self.read_slice(len)?; Ok(EndianSlice::new(slice, self.endian)) } #[inline] fn to_slice(&self) -> Result> { Ok(self.slice.into()) } #[inline] fn to_string(&self) -> Result> { match str::from_utf8(self.slice) { Ok(s) => Ok(s.into()), _ => Err(Error::BadUtf8), } } #[inline] fn to_string_lossy(&self) -> Result> { Ok(String::from_utf8_lossy(self.slice)) } #[inline] fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { let slice = self.read_slice(buf.len())?; buf.clone_from_slice(slice); Ok(()) } } #[cfg(test)] mod tests { use super::*; use crate::endianity::NativeEndian; #[test] fn test_endian_slice_split_at() { let endian = NativeEndian; let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; let eb = EndianSlice::new(slice, endian); assert_eq!( eb.split_at(3), ( EndianSlice::new(&slice[..3], endian), EndianSlice::new(&slice[3..], endian) ) ); } #[test] #[should_panic] fn test_endian_slice_split_at_out_of_bounds() { let slice = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; let eb = EndianSlice::new(slice, NativeEndian); eb.split_at(30); } } gimli-0.19.0/src/read/line.rs010066400017500001750000003175551346020377600141540ustar0000000000000000use crate::vec::Vec; use std::fmt; use std::result; use crate::common::{ DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format, LineEncoding, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{AttributeValue, EndianSlice, Error, Reader, ReaderOffset, Result, Section}; /// The `DebugLine` struct contains the source location to instruction mapping /// found in the `.debug_line` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLine { debug_line_section: R, } impl<'input, Endian> DebugLine> where Endian: Endianity, { /// Construct a new `DebugLine` instance from the data in the `.debug_line` /// section. /// /// It is the caller's responsibility to read the `.debug_line` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugLine, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_line_section_somehow = || &buf; /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); /// ``` pub fn new(debug_line_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_line_section, endian)) } } impl DebugLine { /// Parse the line number program whose header is at the given `offset` in the /// `.debug_line` section. /// /// The `address_size` must match the compilation unit that the lines apply to. /// The `comp_dir` should be from the `DW_AT_comp_dir` attribute of the compilation /// unit. The `comp_name` should be from the `DW_AT_name` attribute of the /// compilation unit. /// /// ```rust,no_run /// use gimli::{DebugLine, DebugLineOffset, IncompleteLineProgram, EndianSlice, LittleEndian}; /// /// # let buf = []; /// # let read_debug_line_section_somehow = || &buf; /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian); /// /// // In a real example, we'd grab the offset via a compilation unit /// // entry's `DW_AT_stmt_list` attribute, and the address size from that /// // unit directly. /// let offset = DebugLineOffset(0); /// let address_size = 8; /// /// let program = debug_line.program(offset, address_size, None, None) /// .expect("should have found a header at that offset, and parsed it OK"); /// ``` pub fn program( &self, offset: DebugLineOffset, address_size: u8, comp_dir: Option, comp_name: Option, ) -> Result> { let input = &mut self.debug_line_section.clone(); input.skip(offset.0)?; let header = LineProgramHeader::parse(input, offset, address_size, comp_dir, comp_name)?; let program = IncompleteLineProgram { header }; Ok(program) } } impl DebugLine { /// Create a `DebugLine` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugLine> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLine where F: FnMut(&'a T) -> R, { borrow(&self.debug_line_section).into() } } impl Section for DebugLine { fn id() -> SectionId { SectionId::DebugLine } fn reader(&self) -> &R { &self.debug_line_section } } impl From for DebugLine { fn from(debug_line_section: R) -> Self { DebugLine { debug_line_section } } } /// Deprecated. `LineNumberProgram` has been renamed to `LineProgram`. #[deprecated(note = "LineNumberProgram has been renamed to LineProgram, use that instead.")] pub type LineNumberProgram = dyn LineProgram; /// A `LineProgram` provides access to a `LineProgramHeader` and /// a way to add files to the files table if necessary. Gimli consumers should /// never need to use or see this trait. pub trait LineProgram::Offset> where R: Reader, Offset: ReaderOffset, { /// Get a reference to the held `LineProgramHeader`. fn header(&self) -> &LineProgramHeader; /// Add a file to the file table if necessary. fn add_file(&mut self, file: FileEntry); } impl LineProgram for IncompleteLineProgram where R: Reader, Offset: ReaderOffset, { fn header(&self) -> &LineProgramHeader { &self.header } fn add_file(&mut self, file: FileEntry) { self.header.file_names.push(file); } } impl<'program, R, Offset> LineProgram for &'program CompleteLineProgram where R: Reader, Offset: ReaderOffset, { fn header(&self) -> &LineProgramHeader { &self.header } fn add_file(&mut self, _: FileEntry) { // Nop. Our file table is already complete. } } /// Deprecated. `StateMachine` has been renamed to `LineRows`. #[deprecated(note = "StateMachine has been renamed to LineRows, use that instead.")] pub type StateMachine = LineRows; /// Executes a `LineProgram` to iterate over the rows in the matrix of line number information. /// /// "The hypothetical machine used by a consumer of the line number information /// to expand the byte-coded instruction stream into a matrix of line number /// information." -- Section 6.2.1 #[derive(Debug, Clone)] pub struct LineRows::Offset> where Program: LineProgram, R: Reader, Offset: ReaderOffset, { program: Program, row: LineRow, instructions: LineInstructions, } type OneShotLineRows::Offset> = LineRows, Offset>; type ResumedLineRows<'program, R, Offset = ::Offset> = LineRows, Offset>; impl LineRows where Program: LineProgram, R: Reader, Offset: ReaderOffset, { #[allow(clippy::new_ret_no_self)] fn new(program: IncompleteLineProgram) -> OneShotLineRows { let row = LineRow::new(program.header()); let instructions = LineInstructions { input: program.header().program_buf.clone(), }; LineRows { program, row, instructions, } } fn resume<'program>( program: &'program CompleteLineProgram, sequence: &LineSequence, ) -> ResumedLineRows<'program, R, Offset> { let row = LineRow::new(program.header()); let instructions = sequence.instructions.clone(); LineRows { program, row, instructions, } } /// Get a reference to the header for this state machine's line number /// program. #[inline] pub fn header(&self) -> &LineProgramHeader { self.program.header() } /// Parse and execute the next instructions in the line number program until /// another row in the line number matrix is computed. /// /// The freshly computed row is returned as `Ok(Some((header, row)))`. /// If the matrix is complete, and there are no more new rows in the line /// number matrix, then `Ok(None)` is returned. If there was an error parsing /// an instruction, then `Err(e)` is returned. /// /// Unfortunately, the references mean that this cannot be a /// `FallibleIterator`. pub fn next_row(&mut self) -> Result, &LineRow)>> { // Perform any reset that was required after copying the previous row. self.row.reset(self.program.header()); loop { // Split the borrow here, rather than calling `self.header()`. match self.instructions.next_instruction(self.program.header()) { Err(err) => return Err(err), Ok(None) => return Ok(None), Ok(Some(instruction)) => { if self.row.execute(instruction, &mut self.program) { return Ok(Some((self.header(), &self.row))); } // Fall through, parse the next instruction, and see if that // yields a row. } } } } } /// Deprecated. `Opcode` has been renamed to `LineInstruction`. #[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")] pub type Opcode = LineInstruction::Offset>; /// A parsed line number program instruction. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LineInstruction::Offset> where R: Reader, Offset: ReaderOffset, { /// > ### 6.2.5.1 Special Opcodes /// > /// > Each ubyte special opcode has the following effect on the state machine: /// > /// > 1. Add a signed integer to the line register. /// > /// > 2. Modify the operation pointer by incrementing the address and /// > op_index registers as described below. /// > /// > 3. Append a row to the matrix using the current values of the state /// > machine registers. /// > /// > 4. Set the basic_block register to “false.†/// > /// > 5. Set the prologue_end register to “false.†/// > /// > 6. Set the epilogue_begin register to “false.†/// > /// > 7. Set the discriminator register to 0. /// > /// > All of the special opcodes do those same seven things; they differ from /// > one another only in what values they add to the line, address and /// > op_index registers. Special(u8), /// "[`LineInstruction::Copy`] appends a row to the matrix using the current /// values of the state machine registers. Then it sets the discriminator /// register to 0, and sets the basic_block, prologue_end and epilogue_begin /// registers to “false.â€" Copy, /// "The DW_LNS_advance_pc opcode takes a single unsigned LEB128 operand as /// the operation advance and modifies the address and op_index registers /// [the same as `LineInstruction::Special`]" AdvancePc(u64), /// "The DW_LNS_advance_line opcode takes a single signed LEB128 operand and /// adds that value to the line register of the state machine." AdvanceLine(i64), /// "The DW_LNS_set_file opcode takes a single unsigned LEB128 operand and /// stores it in the file register of the state machine." SetFile(u64), /// "The DW_LNS_set_column opcode takes a single unsigned LEB128 operand and /// stores it in the column register of the state machine." SetColumn(u64), /// "The DW_LNS_negate_stmt opcode takes no operands. It sets the is_stmt /// register of the state machine to the logical negation of its current /// value." NegateStatement, /// "The DW_LNS_set_basic_block opcode takes no operands. It sets the /// basic_block register of the state machine to “true.â€" SetBasicBlock, /// > The DW_LNS_const_add_pc opcode takes no operands. It advances the /// > address and op_index registers by the increments corresponding to /// > special opcode 255. /// > /// > When the line number program needs to advance the address by a small /// > amount, it can use a single special opcode, which occupies a single /// > byte. When it needs to advance the address by up to twice the range of /// > the last special opcode, it can use DW_LNS_const_add_pc followed by a /// > special opcode, for a total of two bytes. Only if it needs to advance /// > the address by more than twice that range will it need to use both /// > DW_LNS_advance_pc and a special opcode, requiring three or more bytes. ConstAddPc, /// > The DW_LNS_fixed_advance_pc opcode takes a single uhalf (unencoded) /// > operand and adds it to the address register of the state machine and /// > sets the op_index register to 0. This is the only standard opcode whose /// > operand is not a variable length number. It also does not multiply the /// > operand by the minimum_instruction_length field of the header. FixedAddPc(u16), /// "[`LineInstruction::SetPrologueEnd`] sets the prologue_end register to “trueâ€." SetPrologueEnd, /// "[`LineInstruction::SetEpilogueBegin`] sets the epilogue_begin register to /// “trueâ€." SetEpilogueBegin, /// "The DW_LNS_set_isa opcode takes a single unsigned LEB128 operand and /// stores that value in the isa register of the state machine." SetIsa(u64), /// An unknown standard opcode with zero operands. UnknownStandard0(constants::DwLns), /// An unknown standard opcode with one operand. UnknownStandard1(constants::DwLns, u64), /// An unknown standard opcode with multiple operands. UnknownStandardN(constants::DwLns, R), /// > [`LineInstruction::EndSequence`] sets the end_sequence register of the state /// > machine to “true†and appends a row to the matrix using the current /// > values of the state-machine registers. Then it resets the registers to /// > the initial values specified above (see Section 6.2.2). Every line /// > number program sequence must end with a DW_LNE_end_sequence instruction /// > which creates a row whose address is that of the byte after the last /// > target machine instruction of the sequence. EndSequence, /// > The DW_LNE_set_address opcode takes a single relocatable address as an /// > operand. The size of the operand is the size of an address on the target /// > machine. It sets the address register to the value given by the /// > relocatable address and sets the op_index register to 0. /// > /// > All of the other line number program opcodes that affect the address /// > register add a delta to it. This instruction stores a relocatable value /// > into it instead. SetAddress(u64), /// Defines a new source file in the line number program and appends it to /// the line number program header's list of source files. DefineFile(FileEntry), /// "The DW_LNE_set_discriminator opcode takes a single parameter, an /// unsigned LEB128 integer. It sets the discriminator register to the new /// value." SetDiscriminator(u64), /// An unknown extended opcode and the slice of its unparsed operands. UnknownExtended(constants::DwLne, R), } impl LineInstruction where R: Reader, Offset: ReaderOffset, { fn parse<'header>( header: &'header LineProgramHeader, input: &mut R, ) -> Result> where R: 'header, { let opcode = input.read_u8()?; if opcode == 0 { let length = input.read_uleb128().and_then(R::Offset::from_u64)?; let mut instr_rest = input.split(length)?; let opcode = instr_rest.read_u8()?; match constants::DwLne(opcode) { constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence), constants::DW_LNE_set_address => { let address = instr_rest.read_address(header.address_size())?; Ok(LineInstruction::SetAddress(address)) } constants::DW_LNE_define_file => { if header.version() <= 4 { let path_name = instr_rest.read_null_terminated_slice()?; let entry = FileEntry::parse(&mut instr_rest, path_name)?; Ok(LineInstruction::DefineFile(entry)) } else { Ok(LineInstruction::UnknownExtended( constants::DW_LNE_define_file, instr_rest, )) } } constants::DW_LNE_set_discriminator => { let discriminator = instr_rest.read_uleb128()?; Ok(LineInstruction::SetDiscriminator(discriminator)) } otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)), } } else if opcode >= header.opcode_base { Ok(LineInstruction::Special(opcode)) } else { match constants::DwLns(opcode) { constants::DW_LNS_copy => Ok(LineInstruction::Copy), constants::DW_LNS_advance_pc => { let advance = input.read_uleb128()?; Ok(LineInstruction::AdvancePc(advance)) } constants::DW_LNS_advance_line => { let increment = input.read_sleb128()?; Ok(LineInstruction::AdvanceLine(increment)) } constants::DW_LNS_set_file => { let file = input.read_uleb128()?; Ok(LineInstruction::SetFile(file)) } constants::DW_LNS_set_column => { let column = input.read_uleb128()?; Ok(LineInstruction::SetColumn(column)) } constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement), constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock), constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc), constants::DW_LNS_fixed_advance_pc => { let advance = input.read_u16()?; Ok(LineInstruction::FixedAddPc(advance)) } constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd), constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin), constants::DW_LNS_set_isa => { let isa = input.read_uleb128()?; Ok(LineInstruction::SetIsa(isa)) } otherwise => { let mut opcode_lengths = header.standard_opcode_lengths().clone(); opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?; let num_args = opcode_lengths.read_u8()? as usize; match num_args { 0 => Ok(LineInstruction::UnknownStandard0(otherwise)), 1 => { let arg = input.read_uleb128()?; Ok(LineInstruction::UnknownStandard1(otherwise, arg)) } _ => { let mut args = input.clone(); for _ in 0..num_args { input.read_uleb128()?; } let len = input.offset_from(&args); args.truncate(len)?; Ok(LineInstruction::UnknownStandardN(otherwise, args)) } } } } } } } impl fmt::Display for LineInstruction where R: Reader, Offset: ReaderOffset, { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { match *self { LineInstruction::Special(opcode) => write!(f, "Special opcode {}", opcode), LineInstruction::Copy => write!(f, "{}", constants::DW_LNS_copy), LineInstruction::AdvancePc(advance) => { write!(f, "{} by {}", constants::DW_LNS_advance_pc, advance) } LineInstruction::AdvanceLine(increment) => { write!(f, "{} by {}", constants::DW_LNS_advance_line, increment) } LineInstruction::SetFile(file) => { write!(f, "{} to {}", constants::DW_LNS_set_file, file) } LineInstruction::SetColumn(column) => { write!(f, "{} to {}", constants::DW_LNS_set_column, column) } LineInstruction::NegateStatement => write!(f, "{}", constants::DW_LNS_negate_stmt), LineInstruction::SetBasicBlock => write!(f, "{}", constants::DW_LNS_set_basic_block), LineInstruction::ConstAddPc => write!(f, "{}", constants::DW_LNS_const_add_pc), LineInstruction::FixedAddPc(advance) => { write!(f, "{} by {}", constants::DW_LNS_fixed_advance_pc, advance) } LineInstruction::SetPrologueEnd => write!(f, "{}", constants::DW_LNS_set_prologue_end), LineInstruction::SetEpilogueBegin => { write!(f, "{}", constants::DW_LNS_set_epilogue_begin) } LineInstruction::SetIsa(isa) => write!(f, "{} to {}", constants::DW_LNS_set_isa, isa), LineInstruction::UnknownStandard0(opcode) => write!(f, "Unknown {}", opcode), LineInstruction::UnknownStandard1(opcode, arg) => { write!(f, "Unknown {} with operand {}", opcode, arg) } LineInstruction::UnknownStandardN(opcode, ref args) => { write!(f, "Unknown {} with operands {:?}", opcode, args) } LineInstruction::EndSequence => write!(f, "{}", constants::DW_LNE_end_sequence), LineInstruction::SetAddress(address) => { write!(f, "{} to {}", constants::DW_LNE_set_address, address) } LineInstruction::DefineFile(_) => write!(f, "{}", constants::DW_LNE_define_file), LineInstruction::SetDiscriminator(discr) => { write!(f, "{} to {}", constants::DW_LNE_set_discriminator, discr) } LineInstruction::UnknownExtended(opcode, _) => write!(f, "Unknown {}", opcode), } } } /// Deprecated. `OpcodesIter` has been renamed to `LineInstructions`. #[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")] pub type OpcodesIter = LineInstructions; /// An iterator yielding parsed instructions. /// /// See /// [`LineProgramHeader::instructions`](./struct.LineProgramHeader.html#method.instructions) /// for more details. #[derive(Clone, Debug)] pub struct LineInstructions { input: R, } impl LineInstructions { fn remove_trailing(&self, other: &LineInstructions) -> Result> { let offset = other.input.offset_from(&self.input); let mut input = self.input.clone(); input.truncate(offset)?; Ok(LineInstructions { input }) } } impl LineInstructions { /// Advance the iterator and return the next instruction. /// /// Returns the newly parsed instruction as `Ok(Some(instruction))`. Returns /// `Ok(None)` when iteration is complete and all instructions have already been /// parsed and yielded. If an error occurs while parsing the next attribute, /// then this error is returned as `Err(e)`, and all subsequent calls return /// `Ok(None)`. /// /// Unfortunately, the `header` parameter means that this cannot be a /// `FallibleIterator`. #[allow(clippy::inline_always)] #[inline(always)] pub fn next_instruction( &mut self, header: &LineProgramHeader, ) -> Result>> { if self.input.is_empty() { return Ok(None); } match LineInstruction::parse(header, &mut self.input) { Ok(instruction) => Ok(Some(instruction)), Err(e) => { self.input.empty(); Err(e) } } } } /// Deprecated. `LineNumberRow` has been renamed to `LineRow`. #[deprecated(note = "LineNumberRow has been renamed to LineRow, use that instead.")] pub type LineNumberRow = LineRow; /// A row in the line number program's resulting matrix. /// /// Each row is a copy of the registers of the state machine, as defined in section 6.2.2. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LineRow { address: u64, op_index: u64, file: u64, line: u64, column: u64, is_stmt: bool, basic_block: bool, end_sequence: bool, prologue_end: bool, epilogue_begin: bool, isa: u64, discriminator: u64, } impl LineRow { /// Create a line number row in the initial state for the given program. pub fn new(header: &LineProgramHeader) -> Self { LineRow { // "At the beginning of each sequence within a line number program, the // state of the registers is:" -- Section 6.2.2 address: 0, op_index: 0, file: 1, line: 1, column: 0, // "determined by default_is_stmt in the line number program header" is_stmt: header.line_encoding.default_is_stmt, basic_block: false, end_sequence: false, prologue_end: false, epilogue_begin: false, // "The isa value 0 specifies that the instruction set is the // architecturally determined default instruction set. This may be fixed // by the ABI, or it may be specified by other means, for example, by // the object file description." isa: 0, discriminator: 0, } } /// "The program-counter value corresponding to a machine instruction /// generated by the compiler." #[inline] pub fn address(&self) -> u64 { self.address } /// > An unsigned integer representing the index of an operation within a VLIW /// > instruction. The index of the first operation is 0. For non-VLIW /// > architectures, this register will always be 0. /// > /// > The address and op_index registers, taken together, form an operation /// > pointer that can reference any individual operation with the /// > instruction stream. #[inline] pub fn op_index(&self) -> u64 { self.op_index } /// "An unsigned integer indicating the identity of the source file /// corresponding to a machine instruction." #[inline] pub fn file_index(&self) -> u64 { self.file } /// The source file corresponding to the current machine instruction. #[inline] pub fn file<'header, R: Reader>( &self, header: &'header LineProgramHeader, ) -> Option<&'header FileEntry> { header.file(self.file) } /// "An unsigned integer indicating a source line number. Lines are numbered /// beginning at 1. The compiler may emit the value 0 in cases where an /// instruction cannot be attributed to any source line." #[inline] pub fn line(&self) -> Option { if self.line == 0 { None } else { Some(self.line) } } /// "An unsigned integer indicating a column number within a source /// line. Columns are numbered beginning at 1. The value 0 is reserved to /// indicate that a statement begins at the “left edge†of the line." #[inline] pub fn column(&self) -> ColumnType { if self.column == 0 { ColumnType::LeftEdge } else { ColumnType::Column(self.column) } } /// "A boolean indicating that the current instruction is a recommended /// breakpoint location. A recommended breakpoint location is intended to /// “represent†a line, a statement and/or a semantically distinct subpart /// of a statement." #[inline] pub fn is_stmt(&self) -> bool { self.is_stmt } /// "A boolean indicating that the current instruction is the beginning of a /// basic block." #[inline] pub fn basic_block(&self) -> bool { self.basic_block } /// "A boolean indicating that the current address is that of the first byte /// after the end of a sequence of target machine instructions. end_sequence /// terminates a sequence of lines; therefore other information in the same /// row is not meaningful." #[inline] pub fn end_sequence(&self) -> bool { self.end_sequence } /// "A boolean indicating that the current address is one (of possibly many) /// where execution should be suspended for an entry breakpoint of a /// function." #[inline] pub fn prologue_end(&self) -> bool { self.prologue_end } /// "A boolean indicating that the current address is one (of possibly many) /// where execution should be suspended for an exit breakpoint of a /// function." #[inline] pub fn epilogue_begin(&self) -> bool { self.epilogue_begin } /// Tag for the current instruction set architecture. /// /// > An unsigned integer whose value encodes the applicable instruction set /// > architecture for the current instruction. /// > /// > The encoding of instruction sets should be shared by all users of a /// > given architecture. It is recommended that this encoding be defined by /// > the ABI authoring committee for each architecture. #[inline] pub fn isa(&self) -> u64 { self.isa } /// "An unsigned integer identifying the block to which the current /// instruction belongs. Discriminator values are assigned arbitrarily by /// the DWARF producer and serve to distinguish among multiple blocks that /// may all be associated with the same source file, line, and column. Where /// only one block exists for a given source position, the discriminator /// value should be zero." #[inline] pub fn discriminator(&self) -> u64 { self.discriminator } /// Execute the given instruction, and return true if a new row in the /// line number matrix needs to be generated. /// /// Unknown opcodes are treated as no-ops. #[inline] pub fn execute( &mut self, instruction: LineInstruction, program: &mut Program, ) -> bool where Program: LineProgram, R: Reader, { match instruction { LineInstruction::Special(opcode) => { self.exec_special_opcode(opcode, program.header()); true } LineInstruction::Copy => true, LineInstruction::AdvancePc(operation_advance) => { self.apply_operation_advance(operation_advance, program.header()); false } LineInstruction::AdvanceLine(line_increment) => { self.apply_line_advance(line_increment); false } LineInstruction::SetFile(file) => { self.file = file; false } LineInstruction::SetColumn(column) => { self.column = column; false } LineInstruction::NegateStatement => { self.is_stmt = !self.is_stmt; false } LineInstruction::SetBasicBlock => { self.basic_block = true; false } LineInstruction::ConstAddPc => { let adjusted = self.adjust_opcode(255, program.header()); let operation_advance = adjusted / program.header().line_encoding.line_range; self.apply_operation_advance(u64::from(operation_advance), program.header()); false } LineInstruction::FixedAddPc(operand) => { self.address += u64::from(operand); self.op_index = 0; false } LineInstruction::SetPrologueEnd => { self.prologue_end = true; false } LineInstruction::SetEpilogueBegin => { self.epilogue_begin = true; false } LineInstruction::SetIsa(isa) => { self.isa = isa; false } LineInstruction::EndSequence => { self.end_sequence = true; true } LineInstruction::SetAddress(address) => { self.address = address; self.op_index = 0; false } LineInstruction::DefineFile(entry) => { program.add_file(entry); false } LineInstruction::SetDiscriminator(discriminator) => { self.discriminator = discriminator; false } // Compatibility with future opcodes. LineInstruction::UnknownStandard0(_) | LineInstruction::UnknownStandard1(_, _) | LineInstruction::UnknownStandardN(_, _) | LineInstruction::UnknownExtended(_, _) => false, } } /// Perform any reset that was required after copying the previous row. #[inline] pub fn reset(&mut self, header: &LineProgramHeader) { if self.end_sequence { // Previous instruction was EndSequence, so reset everything // as specified in Section 6.2.5.3. *self = Self::new(header); } else { // Previous instruction was one of: // - Special - specified in Section 6.2.5.1, steps 4-7 // - Copy - specified in Section 6.2.5.2 // The reset behaviour is the same in both cases. self.discriminator = 0; self.basic_block = false; self.prologue_end = false; self.epilogue_begin = false; } } /// Step 1 of section 6.2.5.1 fn apply_line_advance(&mut self, line_increment: i64) { if line_increment < 0 { let decrement = -line_increment as u64; if decrement <= self.line { self.line -= decrement; } else { self.line = 0; } } else { self.line += line_increment as u64; } } /// Step 2 of section 6.2.5.1 fn apply_operation_advance( &mut self, operation_advance: u64, header: &LineProgramHeader, ) { let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length); let maximum_operations_per_instruction = u64::from(header.line_encoding.maximum_operations_per_instruction); if maximum_operations_per_instruction == 1 { self.address += minimum_instruction_length * operation_advance; self.op_index = 0; } else { let op_index_with_advance = self.op_index + operation_advance; self.address += minimum_instruction_length * (op_index_with_advance / maximum_operations_per_instruction); self.op_index = op_index_with_advance % maximum_operations_per_instruction; } } #[inline] fn adjust_opcode(&self, opcode: u8, header: &LineProgramHeader) -> u8 { opcode - header.opcode_base } /// Section 6.2.5.1 fn exec_special_opcode(&mut self, opcode: u8, header: &LineProgramHeader) { let adjusted_opcode = self.adjust_opcode(opcode, header); let line_range = header.line_encoding.line_range; let line_advance = adjusted_opcode % line_range; let operation_advance = adjusted_opcode / line_range; // Step 1 let line_base = i64::from(header.line_encoding.line_base); self.apply_line_advance(line_base + i64::from(line_advance)); // Step 2 self.apply_operation_advance(u64::from(operation_advance), header); } } /// The type of column that a row is referring to. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum ColumnType { /// The `LeftEdge` means that the statement begins at the start of the new /// line. LeftEdge, /// A column number, whose range begins at 1. Column(u64), } /// Deprecated. `LineNumberSequence` has been renamed to `LineSequence`. #[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")] pub type LineNumberSequence = LineSequence; /// A sequence within a line number program. A sequence, as defined in section /// 6.2.5 of the standard, is a linear subset of a line number program within /// which addresses are monotonically increasing. #[derive(Clone, Debug)] pub struct LineSequence { /// The first address that is covered by this sequence within the line number /// program. pub start: u64, /// The first address that is *not* covered by this sequence within the line /// number program. pub end: u64, instructions: LineInstructions, } /// Deprecated. `LineNumberProgramHeader` has been renamed to `LineProgramHeader`. #[deprecated( note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead." )] pub type LineNumberProgramHeader = LineProgramHeader; /// A header for a line number program in the `.debug_line` section, as defined /// in section 6.2.4 of the standard. #[derive(Clone, Debug, Eq, PartialEq)] pub struct LineProgramHeader::Offset> where R: Reader, Offset: ReaderOffset, { encoding: Encoding, offset: DebugLineOffset, unit_length: Offset, header_length: Offset, line_encoding: LineEncoding, /// "The number assigned to the first special opcode." opcode_base: u8, /// "This array specifies the number of LEB128 operands for each of the /// standard opcodes. The first element of the array corresponds to the /// opcode whose value is 1, and the last element corresponds to the opcode /// whose value is `opcode_base - 1`." standard_opcode_lengths: R, /// "A sequence of directory entry format descriptions." directory_entry_format: Vec, /// > Entries in this sequence describe each path that was searched for /// > included source files in this compilation. (The paths include those /// > directories specified explicitly by the user for the compiler to search /// > and those the compiler searches without explicit direction.) Each path /// > entry is either a full path name or is relative to the current directory /// > of the compilation. /// > /// > The last entry is followed by a single null byte. include_directories: Vec>, /// "A sequence of file entry format descriptions." file_name_entry_format: Vec, /// "Entries in this sequence describe source files that contribute to the /// line number information for this compilation unit or is used in other /// contexts." file_names: Vec>, /// The encoded line program instructions. program_buf: R, /// The current directory of the compilation. comp_dir: Option, /// The primary source file. comp_file: Option>, } impl LineProgramHeader where R: Reader, Offset: ReaderOffset, { /// Return the offset of the line number program header in the `.debug_line` section. pub fn offset(&self) -> DebugLineOffset { self.offset } /// Return the length of the line number program and header, not including /// the length of the encoded length itself. pub fn unit_length(&self) -> R::Offset { self.unit_length } /// Return the encoding parameters for this header's line program. pub fn encoding(&self) -> Encoding { self.encoding } /// Get the version of this header's line program. pub fn version(&self) -> u16 { self.encoding.version } /// Get the length of the encoded line number program header, not including /// the length of the encoded length itself. pub fn header_length(&self) -> R::Offset { self.header_length } /// Get the size in bytes of a target machine address. pub fn address_size(&self) -> u8 { self.encoding.address_size } /// Whether this line program is encoded in 64- or 32-bit DWARF. pub fn format(&self) -> Format { self.encoding.format } /// Get the line encoding parameters for this header's line program. pub fn line_encoding(&self) -> LineEncoding { self.line_encoding } /// Get the minimum instruction length any instruction in this header's line /// program may have. pub fn minimum_instruction_length(&self) -> u8 { self.line_encoding.minimum_instruction_length } /// Get the maximum number of operations each instruction in this header's /// line program may have. pub fn maximum_operations_per_instruction(&self) -> u8 { self.line_encoding.maximum_operations_per_instruction } /// Get the default value of the `is_stmt` register for this header's line /// program. pub fn default_is_stmt(&self) -> bool { self.line_encoding.default_is_stmt } /// Get the line base for this header's line program. pub fn line_base(&self) -> i8 { self.line_encoding.line_base } /// Get the line range for this header's line program. pub fn line_range(&self) -> u8 { self.line_encoding.line_range } /// Get opcode base for this header's line program. pub fn opcode_base(&self) -> u8 { self.opcode_base } /// An array of `u8` that specifies the number of LEB128 operands for /// each of the standard opcodes. pub fn standard_opcode_lengths(&self) -> &R { &self.standard_opcode_lengths } /// Get the format of a directory entry. pub fn directory_entry_format(&self) -> &[FileEntryFormat] { &self.directory_entry_format[..] } /// Get the set of include directories for this header's line program. /// /// For DWARF version <= 4, the compilation's current directory is not included /// in the return value, but is implicitly considered to be in the set per spec. pub fn include_directories(&self) -> &[AttributeValue] { &self.include_directories[..] } /// The include directory with the given directory index. /// /// A directory index of 0 corresponds to the compilation unit directory. pub fn directory(&self, directory: u64) -> Option> { if self.encoding.version <= 4 { if directory == 0 { self.comp_dir.clone().map(AttributeValue::String) } else { let directory = directory as usize - 1; self.include_directories.get(directory).cloned() } } else { self.include_directories.get(directory as usize).cloned() } } /// Get the format of a file name entry. pub fn file_name_entry_format(&self) -> &[FileEntryFormat] { &self.file_name_entry_format[..] } /// Return true if the file entries may have valid timestamps. /// /// Only returns false if we definitely know that all timestamp fields /// are invalid. pub fn file_has_timestamp(&self) -> bool { self.encoding.version <= 4 || self .file_name_entry_format .iter() .any(|x| x.content_type == constants::DW_LNCT_timestamp) } /// Return true if the file entries may have valid sizes. /// /// Only returns false if we definitely know that all size fields /// are invalid. pub fn file_has_size(&self) -> bool { self.encoding.version <= 4 || self .file_name_entry_format .iter() .any(|x| x.content_type == constants::DW_LNCT_size) } /// Return true if the file name entry format contains an MD5 field. pub fn file_has_md5(&self) -> bool { self.file_name_entry_format .iter() .any(|x| x.content_type == constants::DW_LNCT_MD5) } /// Get the list of source files that appear in this header's line program. pub fn file_names(&self) -> &[FileEntry] { &self.file_names[..] } /// The source file with the given file index. /// /// A file index of 0 corresponds to the compilation unit file. /// Note that a file index of 0 is invalid for DWARF version <= 4, /// but we support it anyway. pub fn file(&self, file: u64) -> Option<&FileEntry> { if self.encoding.version <= 4 { if file == 0 { self.comp_file.as_ref() } else { let file = file as usize - 1; self.file_names.get(file) } } else { self.file_names.get(file as usize) } } /// Get the raw, un-parsed `EndianSlice` containing this header's line number /// program. /// /// ``` /// # fn foo() { /// use gimli::{LineProgramHeader, EndianSlice, NativeEndian}; /// /// fn get_line_number_program_header<'a>() -> LineProgramHeader> { /// // Get a line number program header from some offset in a /// // `.debug_line` section... /// # unimplemented!() /// } /// /// let header = get_line_number_program_header(); /// let raw_program = header.raw_program_buf(); /// println!("The length of the raw program in bytes is {}", raw_program.len()); /// # } /// ``` pub fn raw_program_buf(&self) -> R { self.program_buf.clone() } /// Iterate over the instructions in this header's line number program, parsing /// them as we go. pub fn instructions(&self) -> LineInstructions { LineInstructions { input: self.program_buf.clone(), } } fn parse( input: &mut R, offset: DebugLineOffset, mut address_size: u8, mut comp_dir: Option, comp_name: Option, ) -> Result> { let (unit_length, format) = input.read_initial_length()?; let rest = &mut input.split(unit_length)?; let version = rest.read_u16()?; if version < 2 || version > 5 { return Err(Error::UnknownVersion(u64::from(version))); } if version >= 5 { address_size = rest.read_u8()?; let segment_selector_size = rest.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); } } let encoding = Encoding { format, version, address_size, }; let header_length = rest.read_length(format)?; let mut program_buf = rest.clone(); program_buf.skip(header_length)?; rest.truncate(header_length)?; let minimum_instruction_length = rest.read_u8()?; if minimum_instruction_length == 0 { return Err(Error::MinimumInstructionLengthZero); } // This field did not exist before DWARF 4, but is specified to be 1 for // non-VLIW architectures, which makes it a no-op. let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 }; if maximum_operations_per_instruction == 0 { return Err(Error::MaximumOperationsPerInstructionZero); } let default_is_stmt = rest.read_u8()? != 0; let line_base = rest.read_i8()?; let line_range = rest.read_u8()?; if line_range == 0 { return Err(Error::LineRangeZero); } let line_encoding = LineEncoding { minimum_instruction_length, maximum_operations_per_instruction, default_is_stmt, line_base, line_range, }; let opcode_base = rest.read_u8()?; if opcode_base == 0 { return Err(Error::OpcodeBaseZero); } let standard_opcode_count = R::Offset::from_u8(opcode_base - 1); let standard_opcode_lengths = rest.split(standard_opcode_count)?; let directory_entry_format; let mut include_directories = Vec::new(); if version <= 4 { directory_entry_format = Vec::new(); loop { let directory = rest.read_null_terminated_slice()?; if directory.is_empty() { break; } include_directories.push(AttributeValue::String(directory)); } } else { comp_dir = None; directory_entry_format = FileEntryFormat::parse(rest)?; let count = rest.read_uleb128()?; for _ in 0..count { include_directories.push(parse_directory_v5( rest, encoding, &directory_entry_format, )?); } } let comp_file; let file_name_entry_format; let mut file_names = Vec::new(); if version <= 4 { comp_file = comp_name.map(|name| FileEntry { path_name: AttributeValue::String(name), directory_index: 0, timestamp: 0, size: 0, md5: [0; 16], }); file_name_entry_format = Vec::new(); loop { let path_name = rest.read_null_terminated_slice()?; if path_name.is_empty() { break; } file_names.push(FileEntry::parse(rest, path_name)?); } } else { comp_file = None; file_name_entry_format = FileEntryFormat::parse(rest)?; let count = rest.read_uleb128()?; for _ in 0..count { file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?); } } let header = LineProgramHeader { encoding, offset, unit_length, header_length, line_encoding, opcode_base, standard_opcode_lengths, directory_entry_format, include_directories, file_name_entry_format, file_names, program_buf, comp_dir, comp_file, }; Ok(header) } } /// Deprecated. `IncompleteLineNumberProgram` has been renamed to `IncompleteLineProgram`. #[deprecated( note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead." )] pub type IncompleteLineNumberProgram = IncompleteLineProgram; /// A line number program that has not been run to completion. #[derive(Clone, Debug, Eq, PartialEq)] pub struct IncompleteLineProgram::Offset> where R: Reader, Offset: ReaderOffset, { header: LineProgramHeader, } impl IncompleteLineProgram where R: Reader, Offset: ReaderOffset, { /// Retrieve the `LineProgramHeader` for this program. pub fn header(&self) -> &LineProgramHeader { &self.header } /// Construct a new `LineRows` for executing this program to iterate /// over rows in the line information matrix. pub fn rows(self) -> OneShotLineRows { OneShotLineRows::new(self) } /// Execute the line number program, completing the `IncompleteLineProgram` /// into a `CompleteLineProgram` and producing an array of sequences within /// the line number program that can later be used with /// `CompleteLineProgram::resume_from`. /// /// ``` /// # fn foo() { /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; /// /// fn get_line_number_program<'a>() -> IncompleteLineProgram> { /// // Get a line number program from some offset in a /// // `.debug_line` section... /// # unimplemented!() /// } /// /// let program = get_line_number_program(); /// let (program, sequences) = program.sequences().unwrap(); /// println!("There are {} sequences in this line number program", sequences.len()); /// # } /// ``` #[allow(clippy::type_complexity)] pub fn sequences(self) -> Result<(CompleteLineProgram, Vec>)> { let mut sequences = Vec::new(); let mut rows = self.rows(); let mut instructions = rows.instructions.clone(); let mut sequence_start_addr = None; loop { let sequence_end_addr; if rows.next_row()?.is_none() { break; } let row = &rows.row; if row.end_sequence() { sequence_end_addr = row.address(); } else if sequence_start_addr.is_none() { sequence_start_addr = Some(row.address()); continue; } else { continue; } // We just finished a sequence. sequences.push(LineSequence { // In theory one could have multiple DW_LNE_end_sequence instructions // in a row. start: sequence_start_addr.unwrap_or(0), end: sequence_end_addr, instructions: instructions.remove_trailing(&rows.instructions)?, }); sequence_start_addr = None; instructions = rows.instructions.clone(); } let program = CompleteLineProgram { header: rows.program.header, }; Ok((program, sequences)) } } /// Deprecated. `CompleteLineNumberProgram` has been renamed to `CompleteLineProgram`. #[deprecated( note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead." )] pub type CompleteLineNumberProgram = CompleteLineProgram; /// A line number program that has previously been run to completion. #[derive(Clone, Debug, Eq, PartialEq)] pub struct CompleteLineProgram::Offset> where R: Reader, Offset: ReaderOffset, { header: LineProgramHeader, } impl CompleteLineProgram where R: Reader, Offset: ReaderOffset, { /// Retrieve the `LineProgramHeader` for this program. pub fn header(&self) -> &LineProgramHeader { &self.header } /// Construct a new `LineRows` for executing the subset of the line /// number program identified by 'sequence' and generating the line information /// matrix. /// /// ``` /// # fn foo() { /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian}; /// /// fn get_line_number_program<'a>() -> IncompleteLineProgram> { /// // Get a line number program from some offset in a /// // `.debug_line` section... /// # unimplemented!() /// } /// /// let program = get_line_number_program(); /// let (program, sequences) = program.sequences().unwrap(); /// for sequence in &sequences { /// let mut sm = program.resume_from(sequence); /// } /// # } /// ``` pub fn resume_from<'program>( &'program self, sequence: &LineSequence, ) -> ResumedLineRows<'program, R, Offset> { ResumedLineRows::resume(self, sequence) } } /// An entry in the `LineProgramHeader`'s `file_names` set. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct FileEntry::Offset> where R: Reader, Offset: ReaderOffset, { path_name: AttributeValue, directory_index: u64, timestamp: u64, size: u64, md5: [u8; 16], } impl FileEntry where R: Reader, Offset: ReaderOffset, { // version 2-4 fn parse(input: &mut R, path_name: R) -> Result> { let directory_index = input.read_uleb128()?; let timestamp = input.read_uleb128()?; let size = input.read_uleb128()?; let entry = FileEntry { path_name: AttributeValue::String(path_name), directory_index, timestamp, size, md5: [0; 16], }; Ok(entry) } /// > A slice containing the full or relative path name of /// > a source file. If the entry contains a file name or a relative path /// > name, the file is located relative to either the compilation directory /// > (as specified by the DW_AT_comp_dir attribute given in the compilation /// > unit) or one of the directories in the include_directories section. pub fn path_name(&self) -> AttributeValue { self.path_name.clone() } /// > An unsigned LEB128 number representing the directory index of the /// > directory in which the file was found. /// > /// > ... /// > /// > The directory index represents an entry in the include_directories /// > section of the line number program header. The index is 0 if the file /// > was found in the current directory of the compilation, 1 if it was found /// > in the first directory in the include_directories section, and so /// > on. The directory index is ignored for file names that represent full /// > path names. pub fn directory_index(&self) -> u64 { self.directory_index } /// Get this file's directory. /// /// A directory index of 0 corresponds to the compilation unit directory. pub fn directory(&self, header: &LineProgramHeader) -> Option> { header.directory(self.directory_index) } /// The implementation-defined time of last modification of the file, /// or 0 if not available. pub fn timestamp(&self) -> u64 { self.timestamp } /// "An unsigned LEB128 number representing the time of last modification of /// the file, or 0 if not available." // Terminology changed in DWARF version 5. #[doc(hidden)] pub fn last_modification(&self) -> u64 { self.timestamp } /// The size of the file in bytes, or 0 if not available. pub fn size(&self) -> u64 { self.size } /// "An unsigned LEB128 number representing the length in bytes of the file, /// or 0 if not available." // Terminology changed in DWARF version 5. #[doc(hidden)] pub fn length(&self) -> u64 { self.size } /// A 16-byte MD5 digest of the file contents. /// /// Only valid if `LineProgramHeader::file_has_md5` returns `true`. pub fn md5(&self) -> &[u8; 16] { &self.md5 } } /// The format of a compononent of an include directory or file name entry. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct FileEntryFormat { /// The type of information that is represented by the component. pub content_type: constants::DwLnct, /// The encoding form of the component value. pub form: constants::DwForm, } impl FileEntryFormat { fn parse(input: &mut R) -> Result> { let format_count = input.read_u8()? as usize; let mut format = Vec::with_capacity(format_count); let mut path_count = 0; for _ in 0..format_count { let content_type = input.read_uleb128()?; let content_type = if content_type > u64::from(u16::max_value()) { constants::DwLnct(u16::max_value()) } else { constants::DwLnct(content_type as u16) }; if content_type == constants::DW_LNCT_path { path_count += 1; } let form = constants::DwForm(input.read_uleb128()?); format.push(FileEntryFormat { content_type, form }); } if path_count != 1 { return Err(Error::MissingFileEntryFormatPath); } Ok(format) } } fn parse_directory_v5( input: &mut R, encoding: Encoding, formats: &[FileEntryFormat], ) -> Result> { let mut path_name = None; for format in formats { let value = parse_attribute(input, encoding, format.form)?; if format.content_type == constants::DW_LNCT_path { path_name = Some(value); } } Ok(path_name.unwrap()) } fn parse_file_v5( input: &mut R, encoding: Encoding, formats: &[FileEntryFormat], ) -> Result> { let mut path_name = None; let mut directory_index = 0; let mut timestamp = 0; let mut size = 0; let mut md5 = [0; 16]; for format in formats { let value = parse_attribute(input, encoding, format.form)?; match format.content_type { constants::DW_LNCT_path => path_name = Some(value), constants::DW_LNCT_directory_index => { if let Some(value) = value.udata_value() { directory_index = value; } } constants::DW_LNCT_timestamp => { if let Some(value) = value.udata_value() { timestamp = value; } } constants::DW_LNCT_size => { if let Some(value) = value.udata_value() { size = value; } } constants::DW_LNCT_MD5 => { if let AttributeValue::Block(mut value) = value { if value.len().into_u64() == 16 { md5 = value.read_u8_array()?; } } } // Ignore unknown content types. _ => {} } } Ok(FileEntry { path_name: path_name.unwrap(), directory_index, timestamp, size, md5, }) } // TODO: this should be shared with unit::parse_attribute(), but that is hard to do. fn parse_attribute( input: &mut R, encoding: Encoding, form: constants::DwForm, ) -> Result> { Ok(match form { constants::DW_FORM_block1 => { let len = input.read_u8().map(R::Offset::from_u8)?; let block = input.split(len)?; AttributeValue::Block(block) } constants::DW_FORM_block2 => { let len = input.read_u16().map(R::Offset::from_u16)?; let block = input.split(len)?; AttributeValue::Block(block) } constants::DW_FORM_block4 => { let len = input.read_u32().map(R::Offset::from_u32)?; let block = input.split(len)?; AttributeValue::Block(block) } constants::DW_FORM_block => { let len = input.read_uleb128().and_then(R::Offset::from_u64)?; let block = input.split(len)?; AttributeValue::Block(block) } constants::DW_FORM_data1 => { let data = input.read_u8()?; AttributeValue::Data1(data) } constants::DW_FORM_data2 => { let data = input.read_u16()?; AttributeValue::Data2(data) } constants::DW_FORM_data4 => { let data = input.read_u32()?; AttributeValue::Data4(data) } constants::DW_FORM_data8 => { let data = input.read_u64()?; AttributeValue::Data8(data) } constants::DW_FORM_data16 => { let block = input.split(R::Offset::from_u8(16))?; AttributeValue::Block(block) } constants::DW_FORM_udata => { let data = input.read_uleb128()?; AttributeValue::Udata(data) } constants::DW_FORM_sdata => { let data = input.read_sleb128()?; AttributeValue::Sdata(data) } constants::DW_FORM_flag => { let present = input.read_u8()?; AttributeValue::Flag(present != 0) } constants::DW_FORM_sec_offset => { let offset = input.read_offset(encoding.format)?; AttributeValue::SecOffset(offset) } constants::DW_FORM_string => { let string = input.read_null_terminated_slice()?; AttributeValue::String(string) } constants::DW_FORM_strp => { let offset = input.read_offset(encoding.format)?; AttributeValue::DebugStrRef(DebugStrOffset(offset)) } constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { let offset = input.read_offset(encoding.format)?; AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) } constants::DW_FORM_line_strp => { let offset = input.read_offset(encoding.format)?; AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) } constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { let index = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx1 => { let index = input.read_u8().map(R::Offset::from_u8)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx2 => { let index = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx3 => { let index = input.read_uint(3).and_then(R::Offset::from_u64)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx4 => { let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } _ => { return Err(Error::UnknownForm); } }) } #[cfg(test)] mod tests { use super::*; use crate::constants; use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Error}; use crate::test_util::GimliSectionMethods; use std::u8; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] fn test_parse_debug_line_32_ok() { #[rustfmt::skip] let buf = [ // 32-bit length = 62. 0x3e, 0x00, 0x00, 0x00, // Version. 0x04, 0x00, // Header length = 40. 0x28, 0x00, 0x00, 0x00, // Minimum instruction length. 0x01, // Maximum operations per byte. 0x01, // Default is_stmt. 0x01, // Line base. 0x00, // Line range. 0x01, // Opcode base. 0x03, // Standard opcode lengths for opcodes 1 .. opcode base - 1. 0x01, 0x02, // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, // File names // foo.rs 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00, // bar.h 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, 0x01, 0x00, 0x00, // End file names. 0x00, // Dummy line program data. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dummy next line program. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian); let comp_name = EndianSlice::new(b"/comp_name", LittleEndian); let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name)) .expect("should parse header ok"); assert_eq!( *rest, EndianSlice::new(&buf[buf.len() - 16..], LittleEndian) ); assert_eq!(header.offset, DebugLineOffset(0)); assert_eq!(header.version(), 4); assert_eq!(header.minimum_instruction_length(), 1); assert_eq!(header.maximum_operations_per_instruction(), 1); assert_eq!(header.default_is_stmt(), true); assert_eq!(header.line_base(), 0); assert_eq!(header.line_range(), 1); assert_eq!(header.opcode_base(), 3); assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir))); assert_eq!( header.file(0).unwrap().path_name, AttributeValue::String(comp_name) ); let expected_lengths = [1, 2]; assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths); let expected_include_directories = [ AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)), AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)), ]; assert_eq!(header.include_directories(), &expected_include_directories); let expected_file_names = [ FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)), directory_index: 0, timestamp: 0, size: 0, md5: [0; 16], }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)), directory_index: 1, timestamp: 0, size: 0, md5: [0; 16], }, ]; assert_eq!(&*header.file_names(), &expected_file_names); } #[test] fn test_parse_debug_line_header_length_too_short() { #[rustfmt::skip] let buf = [ // 32-bit length = 62. 0x3e, 0x00, 0x00, 0x00, // Version. 0x04, 0x00, // Header length = 20. TOO SHORT!!! 0x15, 0x00, 0x00, 0x00, // Minimum instruction length. 0x01, // Maximum operations per byte. 0x01, // Default is_stmt. 0x01, // Line base. 0x00, // Line range. 0x01, // Opcode base. 0x03, // Standard opcode lengths for opcodes 1 .. opcode base - 1. 0x01, 0x02, // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, // File names // foo.rs 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00, // bar.h 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, 0x01, 0x00, 0x00, // End file names. 0x00, // Dummy line program data. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dummy next line program. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let input = &mut EndianSlice::new(&buf, LittleEndian); match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { Err(Error::UnexpectedEof(_)) => return, otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_parse_debug_line_unit_length_too_short() { #[rustfmt::skip] let buf = [ // 32-bit length = 40. TOO SHORT!!! 0x28, 0x00, 0x00, 0x00, // Version. 0x04, 0x00, // Header length = 40. 0x28, 0x00, 0x00, 0x00, // Minimum instruction length. 0x01, // Maximum operations per byte. 0x01, // Default is_stmt. 0x01, // Line base. 0x00, // Line range. 0x01, // Opcode base. 0x03, // Standard opcode lengths for opcodes 1 .. opcode base - 1. 0x01, 0x02, // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0' 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00, // File names // foo.rs 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00, // bar.h 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00, 0x01, 0x00, 0x00, // End file names. 0x00, // Dummy line program data. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dummy next line program. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let input = &mut EndianSlice::new(&buf, LittleEndian); match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) { Err(Error::UnexpectedEof(_)) => return, otherwise => panic!("Unexpected result: {:?}", otherwise), } } const OPCODE_BASE: u8 = 13; const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1]; fn make_test_header( buf: EndianSlice, ) -> LineProgramHeader> { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 8, }; let line_encoding = LineEncoding { line_base: -3, line_range: 12, ..Default::default() }; LineProgramHeader { encoding, offset: DebugLineOffset(0), unit_length: 1, header_length: 1, line_encoding, opcode_base: OPCODE_BASE, standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian), file_names: vec![ FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), directory_index: 0, timestamp: 0, size: 0, md5: [0; 16], }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)), directory_index: 0, timestamp: 0, size: 0, md5: [0; 16], }, ], include_directories: vec![], directory_entry_format: vec![], file_name_entry_format: vec![], program_buf: buf, comp_dir: None, comp_file: None, } } fn make_test_program( buf: EndianSlice, ) -> IncompleteLineProgram> { IncompleteLineProgram { header: make_test_header(buf), } } #[test] fn test_parse_special_opcodes() { for i in OPCODE_BASE..u8::MAX { let input = [i, 0, 0, 0]; let input = EndianSlice::new(&input, LittleEndian); let header = make_test_header(input); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!(*rest, *input.range_from(1..)); assert_eq!(opcode, LineInstruction::Special(i)); } } #[test] fn test_parse_standard_opcodes() { fn test( raw: constants::DwLns, operands: Operands, expected: LineInstruction>, ) where Operands: AsRef<[u8]>, { let mut input = Vec::new(); input.push(raw.0); input.extend_from_slice(operands.as_ref()); let expected_rest = [0, 1, 2, 3, 4]; input.extend_from_slice(&expected_rest); let input = EndianSlice::new(&*input, LittleEndian); let header = make_test_header(input); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!(opcode, expected); assert_eq!(*rest, expected_rest); } test(constants::DW_LNS_copy, [], LineInstruction::Copy); test( constants::DW_LNS_advance_pc, [42], LineInstruction::AdvancePc(42), ); test( constants::DW_LNS_advance_line, [9], LineInstruction::AdvanceLine(9), ); test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7)); test( constants::DW_LNS_set_column, [1], LineInstruction::SetColumn(1), ); test( constants::DW_LNS_negate_stmt, [], LineInstruction::NegateStatement, ); test( constants::DW_LNS_set_basic_block, [], LineInstruction::SetBasicBlock, ); test( constants::DW_LNS_const_add_pc, [], LineInstruction::ConstAddPc, ); test( constants::DW_LNS_fixed_advance_pc, [42, 0], LineInstruction::FixedAddPc(42), ); test( constants::DW_LNS_set_prologue_end, [], LineInstruction::SetPrologueEnd, ); test( constants::DW_LNS_set_isa, [57 + 0x80, 100], LineInstruction::SetIsa(12857), ); } #[test] fn test_parse_unknown_standard_opcode_no_args() { let input = [OPCODE_BASE, 1, 2, 3]; let input = EndianSlice::new(&input, LittleEndian); let mut standard_opcode_lengths = Vec::new(); let mut header = make_test_header(input); standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); standard_opcode_lengths.push(0); header.opcode_base += 1; header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!( opcode, LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE)) ); assert_eq!(*rest, *input.range_from(1..)); } #[test] fn test_parse_unknown_standard_opcode_one_arg() { let input = [OPCODE_BASE, 1, 2, 3]; let input = EndianSlice::new(&input, LittleEndian); let mut standard_opcode_lengths = Vec::new(); let mut header = make_test_header(input); standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); standard_opcode_lengths.push(1); header.opcode_base += 1; header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!( opcode, LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1) ); assert_eq!(*rest, *input.range_from(2..)); } #[test] fn test_parse_unknown_standard_opcode_many_args() { let input = [OPCODE_BASE, 1, 2, 3]; let input = EndianSlice::new(&input, LittleEndian); let args = EndianSlice::new(&input[1..], LittleEndian); let mut standard_opcode_lengths = Vec::new(); let mut header = make_test_header(input); standard_opcode_lengths.extend(header.standard_opcode_lengths.slice()); standard_opcode_lengths.push(3); header.opcode_base += 1; header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!( opcode, LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args) ); assert_eq!(*rest, []); } #[test] fn test_parse_extended_opcodes() { fn test( raw: constants::DwLne, operands: Operands, expected: LineInstruction>, ) where Operands: AsRef<[u8]>, { let mut input = Vec::new(); input.push(0); let operands = operands.as_ref(); input.push(1 + operands.len() as u8); input.push(raw.0); input.extend_from_slice(operands); let expected_rest = [0, 1, 2, 3, 4]; input.extend_from_slice(&expected_rest); let input = EndianSlice::new(&input, LittleEndian); let header = make_test_header(input); let mut rest = input; let opcode = LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK"); assert_eq!(opcode, expected); assert_eq!(*rest, expected_rest); } test( constants::DW_LNE_end_sequence, [], LineInstruction::EndSequence, ); test( constants::DW_LNE_set_address, [1, 2, 3, 4, 5, 6, 7, 8], LineInstruction::SetAddress(578_437_695_752_307_201), ); test( constants::DW_LNE_set_discriminator, [42], LineInstruction::SetDiscriminator(42), ); let mut file = Vec::new(); // "foo.c" let path_name = [b'f', b'o', b'o', b'.', b'c', 0]; file.extend_from_slice(&path_name); // Directory index. file.push(0); // Last modification of file. file.push(1); // Size of file. file.push(2); test( constants::DW_LNE_define_file, file, LineInstruction::DefineFile(FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)), directory_index: 0, timestamp: 1, size: 2, md5: [0; 16], }), ); // Unknown extended opcode. let operands = [1, 2, 3, 4, 5, 6]; let opcode = constants::DwLne(99); test( opcode, operands, LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)), ); } #[test] fn test_file_entry_directory() { let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0]; let mut file = FileEntry { path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)), directory_index: 1, timestamp: 0, size: 0, md5: [0; 16], }; let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian)); header.include_directories.push(dir); assert_eq!(file.directory(&header), Some(dir)); // Now test the compilation's current directory. file.directory_index = 0; assert_eq!(file.directory(&header), None); } fn assert_exec_opcode<'input>( header: LineProgramHeader>, mut registers: LineRow, opcode: LineInstruction>, expected_registers: LineRow, expect_new_row: bool, ) { let mut program = IncompleteLineProgram { header }; let is_new_row = registers.execute(opcode, &mut program); assert_eq!(is_new_row, expect_new_row); assert_eq!(registers, expected_registers); } #[test] fn test_exec_special_noop() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::Special(16); let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_negative_line_advance() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.line = 10; let opcode = LineInstruction::Special(13); let mut expected_registers = initial_registers; expected_registers.line -= 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_positive_line_advance() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::Special(19); let mut expected_registers = initial_registers; expected_registers.line += 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_positive_address_advance() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::Special(52); let mut expected_registers = initial_registers; expected_registers.address += 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_positive_address_and_line_advance() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::Special(55); let mut expected_registers = initial_registers; expected_registers.address += 3; expected_registers.line += 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_positive_address_and_negative_line_advance() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.line = 10; let opcode = LineInstruction::Special(49); let mut expected_registers = initial_registers; expected_registers.address += 3; expected_registers.line -= 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_special_line_underflow() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.line = 2; // -3 line advance. let opcode = LineInstruction::Special(13); let mut expected_registers = initial_registers; // Clamp at 0. No idea if this is the best way to handle this situation // or not... expected_registers.line = 0; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_copy() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.address = 1337; initial_registers.line = 42; let opcode = LineInstruction::Copy; let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_advance_pc() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::AdvancePc(42); let mut expected_registers = initial_registers; expected_registers.address += 42; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_advance_line() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::AdvanceLine(42); let mut expected_registers = initial_registers; expected_registers.line += 42; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_set_file_in_bounds() { for file_idx in 1..3 { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetFile(file_idx); let mut expected_registers = initial_registers; expected_registers.file = file_idx; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } } #[test] fn test_exec_set_file_out_of_bounds() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetFile(100); // The spec doesn't say anything about rejecting input programs // that set the file register out of bounds of the actual number // of files that have been defined. Instead, we cross our // fingers and hope that one gets defined before // `LineRow::file` gets called and handle the error at // that time if need be. let mut expected_registers = initial_registers; expected_registers.file = 100; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_file_entry_file_index_out_of_bounds() { // These indices are 1-based, so 0 is invalid. 100 is way more than the // number of files defined in the header. let out_of_bounds_indices = [0, 100]; for file_idx in &out_of_bounds_indices[..] { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut row = LineRow::new(&header); row.file = *file_idx; assert_eq!(row.file(&header), None); } } #[test] fn test_file_entry_file_index_in_bounds() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut row = LineRow::new(&header); row.file = 2; assert_eq!(row.file(&header), Some(&header.file_names()[1])); } #[test] fn test_exec_set_column() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetColumn(42); let mut expected_registers = initial_registers; expected_registers.column = 42; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_negate_statement() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::NegateStatement; let mut expected_registers = initial_registers; expected_registers.is_stmt = !initial_registers.is_stmt; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_set_basic_block() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.basic_block = false; let opcode = LineInstruction::SetBasicBlock; let mut expected_registers = initial_registers; expected_registers.basic_block = true; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_const_add_pc() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::ConstAddPc; let mut expected_registers = initial_registers; expected_registers.address += 20; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_fixed_add_pc() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.op_index = 1; let opcode = LineInstruction::FixedAddPc(10); let mut expected_registers = initial_registers; expected_registers.address += 10; expected_registers.op_index = 0; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_set_prologue_end() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); initial_registers.prologue_end = false; let opcode = LineInstruction::SetPrologueEnd; let mut expected_registers = initial_registers; expected_registers.prologue_end = true; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_set_isa() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetIsa(1993); let mut expected_registers = initial_registers; expected_registers.isa = 1993; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_unknown_standard_0() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111)); let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_unknown_standard_1() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2); let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_unknown_standard_n() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::UnknownStandardN( constants::DwLns(111), EndianSlice::new(&[2, 2, 2], LittleEndian), ); let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_end_sequence() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::EndSequence; let mut expected_registers = initial_registers; expected_registers.end_sequence = true; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } #[test] fn test_exec_set_address() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetAddress(3030); let mut expected_registers = initial_registers; expected_registers.address = 3030; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_define_file() { let mut program = make_test_program(EndianSlice::new(&[], LittleEndian)); let mut row = LineRow::new(program.header()); let file = FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)), directory_index: 0, timestamp: 0, size: 0, md5: [0; 16], }; let opcode = LineInstruction::DefineFile(file); let is_new_row = row.execute(opcode, &mut program); assert_eq!(is_new_row, false); assert_eq!(Some(&file), program.header().file_names.last()); } #[test] fn test_exec_set_discriminator() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::SetDiscriminator(9); let mut expected_registers = initial_registers; expected_registers.discriminator = 9; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] fn test_exec_unknown_extended() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let initial_registers = LineRow::new(&header); let opcode = LineInstruction::UnknownExtended( constants::DwLne(74), EndianSlice::new(&[], LittleEndian), ); let expected_registers = initial_registers; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } /// Ensure that `LineRows` is covariant wrt R. /// This only needs to compile. #[allow(dead_code, unreachable_code, unused_variables)] fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8]) where 'a: 'b, { let a: &OneShotLineRows> = unimplemented!(); let _: &OneShotLineRows> = a; } #[test] fn test_parse_debug_line_v5_ok() { let expected_lengths = &[1, 2]; let expected_program = &[0, 1, 2, 3, 4]; let expected_rest = &[5, 6, 7, 8, 9]; let expected_include_directories = [ AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)), AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)), ]; let expected_file_names = [ FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)), directory_index: 0, timestamp: 0, size: 0, md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)), directory_index: 1, timestamp: 0, size: 0, md5: [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, ], }, ]; for format in vec![Format::Dwarf32, Format::Dwarf64] { let length = Label::new(); let header_length = Label::new(); let start = Label::new(); let header_start = Label::new(); let end = Label::new(); let header_end = Label::new(); let section = Section::with_endian(Endian::Little) .initial_length(format, &length, &start) .D16(5) // Address size. .D8(4) // Segment selector size. .D8(0) .word_label(format.word_size(), &header_length) .mark(&header_start) // Minimum instruction length. .D8(1) // Maximum operations per byte. .D8(1) // Default is_stmt. .D8(1) // Line base. .D8(0) // Line range. .D8(1) // Opcode base. .D8(expected_lengths.len() as u8 + 1) // Standard opcode lengths for opcodes 1 .. opcode base - 1. .append_bytes(expected_lengths) // Directory entry format count. .D8(1) .uleb(constants::DW_LNCT_path.0 as u64) .uleb(constants::DW_FORM_string.0 as u64) // Directory count. .D8(2) .append_bytes(b"dir1\0") .append_bytes(b"dir2\0") // File entry format count. .D8(3) .uleb(constants::DW_LNCT_path.0 as u64) .uleb(constants::DW_FORM_string.0 as u64) .uleb(constants::DW_LNCT_directory_index.0 as u64) .uleb(constants::DW_FORM_data1.0 as u64) .uleb(constants::DW_LNCT_MD5.0 as u64) .uleb(constants::DW_FORM_data16.0 as u64) // File count. .D8(2) .append_bytes(b"file1\0") .D8(0) .append_bytes(&expected_file_names[0].md5) .append_bytes(b"file2\0") .D8(1) .append_bytes(&expected_file_names[1].md5) .mark(&header_end) // Dummy line program data. .append_bytes(expected_program) .mark(&end) // Dummy trailing data. .append_bytes(expected_rest); length.set_const((&end - &start) as u64); header_length.set_const((&header_end - &header_start) as u64); let section = section.get_contents().unwrap(); let input = &mut EndianSlice::new(§ion, LittleEndian); let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None) .expect("should parse header ok"); println!("{:?}", header); assert_eq!(header.raw_program_buf().slice(), expected_program); assert_eq!(input.slice(), expected_rest); assert_eq!(header.offset, DebugLineOffset(0)); assert_eq!(header.version(), 5); assert_eq!(header.address_size(), 4); assert_eq!(header.minimum_instruction_length(), 1); assert_eq!(header.maximum_operations_per_instruction(), 1); assert_eq!(header.default_is_stmt(), true); assert_eq!(header.line_base(), 0); assert_eq!(header.line_range(), 1); assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1); assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths); assert_eq!( header.directory_entry_format(), &[FileEntryFormat { content_type: constants::DW_LNCT_path, form: constants::DW_FORM_string, }] ); assert_eq!(header.include_directories(), expected_include_directories); assert_eq!(header.directory(0), Some(expected_include_directories[0])); assert_eq!( header.file_name_entry_format(), &[ FileEntryFormat { content_type: constants::DW_LNCT_path, form: constants::DW_FORM_string, }, FileEntryFormat { content_type: constants::DW_LNCT_directory_index, form: constants::DW_FORM_data1, }, FileEntryFormat { content_type: constants::DW_LNCT_MD5, form: constants::DW_FORM_data16, } ] ); assert_eq!(header.file_names(), expected_file_names); assert_eq!(header.file(0), Some(&expected_file_names[0])); } } } gimli-0.19.0/src/read/loclists.rs010066400017500001750000001342331351057326000150410ustar0000000000000000use fallible_iterator::FallibleIterator; use crate::common::{ DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, Encoding, Format, LocationListsOffset, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{ DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, ReaderOffset, ReaderOffsetId, Result, Section, }; /// The raw contents of the `.debug_loc` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLoc { pub(crate) section: R, } impl<'input, Endian> DebugLoc> where Endian: Endianity, { /// Construct a new `DebugLoc` instance from the data in the `.debug_loc` /// section. /// /// It is the caller's responsibility to read the `.debug_loc` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugLoc, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_loc_section_somehow = || &buf; /// let debug_loc = DebugLoc::new(read_debug_loc_section_somehow(), LittleEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for DebugLoc { fn id() -> SectionId { SectionId::DebugLoc } fn reader(&self) -> &R { &self.section } } impl From for DebugLoc { fn from(section: R) -> Self { DebugLoc { section } } } /// The `DebugLocLists` struct represents the DWARF data /// found in the `.debug_loclists` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLocLists { section: R, } impl<'input, Endian> DebugLocLists> where Endian: Endianity, { /// Construct a new `DebugLocLists` instance from the data in the `.debug_loclists` /// section. /// /// It is the caller's responsibility to read the `.debug_loclists` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugLocLists, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_loclists_section_somehow = || &buf; /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for DebugLocLists { fn id() -> SectionId { SectionId::DebugLocLists } fn reader(&self) -> &R { &self.section } } impl From for DebugLocLists { fn from(section: R) -> Self { DebugLocLists { section } } } #[derive(Debug, Clone, Copy)] struct LocListsHeader { encoding: Encoding, offset_entry_count: u32, } impl Default for LocListsHeader { fn default() -> Self { LocListsHeader { encoding: Encoding { format: Format::Dwarf32, version: 5, address_size: 0, }, offset_entry_count: 0, } } } impl LocListsHeader { /// Return the serialized size of the table header. #[allow(dead_code)] #[inline] fn size(self) -> u8 { // initial_length + version + address_size + segment_selector_size + offset_entry_count self.encoding.format.initial_length_size() + 2 + 1 + 1 + 4 } } // TODO: add an iterator over headers in the .debug_loclists section #[allow(dead_code)] fn parse_header(input: &mut R) -> Result { let (length, format) = input.read_initial_length()?; input.truncate(length)?; let version = input.read_u16()?; if version != 5 { return Err(Error::UnknownVersion(u64::from(version))); } let address_size = input.read_u8()?; let segment_selector_size = input.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); } let offset_entry_count = input.read_u32()?; let encoding = Encoding { format, version, address_size, }; Ok(LocListsHeader { encoding, offset_entry_count, }) } /// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. #[derive(Debug, Default, Clone, Copy)] pub struct LocationLists { debug_loc: DebugLoc, debug_loclists: DebugLocLists, } impl LocationLists { /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and /// `.debug_loclists` sections. pub fn new(debug_loc: DebugLoc, debug_loclists: DebugLocLists) -> LocationLists { LocationLists { debug_loc, debug_loclists, } } } impl LocationLists { /// Create a `LocationLists` that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::LocationLists> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> LocationLists where F: FnMut(&'a T) -> R, { LocationLists { debug_loc: borrow(&self.debug_loc.section).into(), debug_loclists: borrow(&self.debug_loclists.section).into(), } } } impl LocationLists { /// Iterate over the `LocationListEntry`s starting at the given offset. /// /// The `unit_encoding` must match the compilation unit that the /// offset was contained in. /// /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location /// list. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn locations( &self, offset: LocationListsOffset, unit_encoding: Encoding, base_address: u64, debug_addr: &DebugAddr, debug_addr_base: DebugAddrBase, ) -> Result> { Ok(LocListIter::new( self.raw_locations(offset, unit_encoding)?, base_address, debug_addr.clone(), debug_addr_base, )) } /// Iterate over the raw `LocationListEntry`s starting at the given offset. /// /// The `unit_encoding` must match the compilation unit that the /// offset was contained in. /// /// This iterator does not perform any processing of the location entries, /// such as handling base addresses. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn raw_locations( &self, offset: LocationListsOffset, unit_encoding: Encoding, ) -> Result> { let mut input = if unit_encoding.version <= 4 { self.debug_loc.section.clone() } else { self.debug_loclists.section.clone() }; input.skip(offset.0)?; Ok(RawLocListIter::new(input, unit_encoding)) } /// Returns the `.debug_loclists` offset at the given `base` and `index`. /// /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE. /// This is an offset that points to the first entry following the header. /// /// The `index` is the value of a `DW_FORM_loclistx` attribute. pub fn get_offset( &self, unit_encoding: Encoding, base: DebugLocListsBase, index: DebugLocListsIndex, ) -> Result> { let format = unit_encoding.format; let input = &mut self.debug_loclists.section.clone(); input.skip(base.0)?; input.skip(R::Offset::from_u64( index.0.into_u64() * u64::from(format.word_size()), )?)?; input .read_offset(format) .map(|x| LocationListsOffset(base.0 + x)) } /// Call `Reader::lookup_offset_id` for each section, and return the first match. pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { self.debug_loc .lookup_offset_id(id) .or_else(|| self.debug_loclists.lookup_offset_id(id)) } } /// A raw iterator over a location list. /// /// This iterator does not perform any processing of the location entries, /// such as handling base addresses. #[derive(Debug)] pub struct RawLocListIter { input: R, encoding: Encoding, } /// A raw entry in .debug_loclists. #[derive(Clone, Debug)] pub enum RawLocListEntry { /// A location from DWARF version <= 4. AddressOrOffsetPair { /// Start of range. May be an address or an offset. begin: u64, /// End of range. May be an address or an offset. end: u64, /// expression data: Expression, }, /// DW_LLE_base_address BaseAddress { /// base address addr: u64, }, /// DW_LLE_base_addressx BaseAddressx { /// base address addr: DebugAddrIndex, }, /// DW_LLE_startx_endx StartxEndx { /// start of range begin: DebugAddrIndex, /// end of range end: DebugAddrIndex, /// expression data: Expression, }, /// DW_LLE_startx_length StartxLength { /// start of range begin: DebugAddrIndex, /// length of range length: u64, /// expression data: Expression, }, /// DW_LLE_offset_pair OffsetPair { /// start of range begin: u64, /// end of range end: u64, /// expression data: Expression, }, /// DW_LLE_default_location DefaultLocation { /// expression data: Expression, }, /// DW_LLE_start_end StartEnd { /// start of range begin: u64, /// end of range end: u64, /// expression data: Expression, }, /// DW_LLE_start_length StartLength { /// start of range begin: u64, /// length of range length: u64, /// expression data: Expression, }, } fn parse_data(input: &mut R) -> Result> { let len = R::Offset::from_u64(input.read_uleb128()?)?; Ok(Expression(input.split(len)?)) } impl RawLocListEntry { /// Parse a location list entry from `.debug_loclists` fn parse(input: &mut R, encoding: Encoding) -> Result> { if encoding.version < 5 { let range = RawRange::parse(input, encoding.address_size)?; return Ok(if range.is_end() { None } else if range.is_base_address(encoding.address_size) { Some(RawLocListEntry::BaseAddress { addr: range.end }) } else { let len = R::Offset::from_u16(input.read_u16()?); let data = Expression(input.split(len)?); Some(RawLocListEntry::AddressOrOffsetPair { begin: range.begin, end: range.end, data, }) }); } Ok(match constants::DwLle(input.read_u8()?) { constants::DW_LLE_end_of_list => None, constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), data: parse_data(input)?, }), constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), length: input.read_uleb128()?, data: parse_data(input)?, }), constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { begin: input.read_uleb128()?, end: input.read_uleb128()?, data: parse_data(input)?, }), constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { data: parse_data(input)?, }), constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { addr: input.read_address(encoding.address_size)?, }), constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { begin: input.read_address(encoding.address_size)?, end: input.read_address(encoding.address_size)?, data: parse_data(input)?, }), constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { begin: input.read_address(encoding.address_size)?, length: input.read_uleb128()?, data: parse_data(input)?, }), _ => { return Err(Error::InvalidAddressRange); } }) } } impl RawLocListIter { /// Construct a `RawLocListIter`. pub fn new(input: R, encoding: Encoding) -> RawLocListIter { RawLocListIter { input, encoding } } /// Advance the iterator to the next location. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } match RawLocListEntry::parse(&mut self.input, self.encoding) { Ok(entry) => { if entry.is_none() { self.input.empty(); } Ok(entry) } Err(e) => { self.input.empty(); Err(e) } } } } impl FallibleIterator for RawLocListIter { type Item = RawLocListEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { RawLocListIter::next(self) } } /// An iterator over a location list. /// /// This iterator internally handles processing of base address selection entries /// and list end entries. Thus, it only returns location entries that are valid /// and already adjusted for the base address. #[derive(Debug)] pub struct LocListIter { raw: RawLocListIter, base_address: u64, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, } impl LocListIter { /// Construct a `LocListIter`. fn new( raw: RawLocListIter, base_address: u64, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, ) -> LocListIter { LocListIter { raw, base_address, debug_addr, debug_addr_base, } } #[inline] fn get_address(&self, index: DebugAddrIndex) -> Result { self.debug_addr .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) } /// Advance the iterator to the next location. pub fn next(&mut self) -> Result>> { loop { let raw_loc = match self.raw.next()? { Some(loc) => loc, None => return Ok(None), }; let (range, data) = match raw_loc { RawLocListEntry::BaseAddress { addr } => { self.base_address = addr; continue; } RawLocListEntry::BaseAddressx { addr } => { self.base_address = self.get_address(addr)?; continue; } RawLocListEntry::StartxEndx { begin, end, data } => { let begin = self.get_address(begin)?; let end = self.get_address(end)?; (Range { begin, end }, data) } RawLocListEntry::StartxLength { begin, length, data, } => { let begin = self.get_address(begin)?; let end = begin + length; (Range { begin, end }, data) } RawLocListEntry::DefaultLocation { data } => ( Range { begin: 0, end: u64::max_value(), }, data, ), RawLocListEntry::AddressOrOffsetPair { begin, end, data } | RawLocListEntry::OffsetPair { begin, end, data } => { let mut range = Range { begin, end }; range.add_base_address(self.base_address, self.raw.encoding.address_size); (range, data) } RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data), RawLocListEntry::StartLength { begin, length, data, } => ( Range { begin, end: begin + length, }, data, ), }; if range.begin > range.end { self.raw.input.empty(); return Err(Error::InvalidLocationAddressRange); } return Ok(Some(LocationListEntry { range, data })); } } } impl FallibleIterator for LocListIter { type Item = LocationListEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { LocListIter::next(self) } } /// A location list entry from the `.debug_loc` or `.debug_loclists` sections. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LocationListEntry { /// The address range that this location is valid for. pub range: Range, /// The data containing a single location description. pub data: Expression, } #[cfg(test)] mod tests { use super::*; use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Range}; use crate::test_util::GimliSectionMethods; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] fn test_loclists_32() { let encoding = Encoding { format: Format::Dwarf32, version: 5, address_size: 4, }; let section = Section::with_endian(Endian::Little) .L32(0x0300_0000) .L32(0x0301_0300) .L32(0x0301_0400) .L32(0x0301_0500); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); let start = Label::new(); let first = Label::new(); let size = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // Header .mark(&start) .L32(&size) .L16(encoding.version) .L8(encoding.address_size) .L8(0) .L32(0) .mark(&first) // OffsetPair .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2) // A base address selection followed by an OffsetPair. .L8(6).L32(0x0200_0000) .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3) // An empty OffsetPair followed by a normal OffsetPair. .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4) .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5) // A StartEnd .L8(7).L32(0x201_0a00).L32(0x201_0b00).uleb(4).L32(6) // A StartLength .L8(8).L32(0x201_0c00).uleb(0x100).uleb(4).L32(7) // An OffsetPair that starts at 0. .L8(4).uleb(0).uleb(1).uleb(4).L32(8) // An OffsetPair that ends at -1. .L8(6).L32(0) .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) // A DefaultLocation .L8(5).uleb(4).L32(10) // A BaseAddressx + OffsetPair .L8(1).uleb(0) .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) // A StartxEndx .L8(2).uleb(1).uleb(2).uleb(4).L32(12) // A StartxLength .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) // A range end. .L8(0) // Some extra data. .L32(0xffff_ffff); size.set_const((§ion.here() - &start - 4) as u64); let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&[], LittleEndian); let debug_loclists = DebugLocLists::new(&buf, LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let offset = LocationListsOffset((&first - &start) as usize); let mut locations = loclists .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0101_0200, end: 0x0101_0300, }, data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), })) ); // A base address selection followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0400, end: 0x0201_0500, }, data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), })) ); // An empty location range followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0600, end: 0x0201_0600, }, data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), })) ); assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0800, end: 0x0201_0900, }, data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), })) ); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0a00, end: 0x0201_0b00, }, data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), })) ); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0c00, end: 0x0201_0d00, }, data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), })) ); // A location range that starts at 0. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0200_0000, end: 0x0200_0001, }, data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)), })) ); // A location range that ends at -1. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0000_0000, end: 0xffff_ffff, }, data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)), })) ); // A DefaultLocation. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0, end: u64::max_value(), }, data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), })) ); // A BaseAddressx + OffsetPair assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0100, end: 0x0301_0200, }, data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), })) ); // A StartxEndx assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0300, end: 0x0301_0400, }, data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), })) ); // A StartxLength assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0500, end: 0x0301_0600, }, data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), })) ); // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists .locations( LocationListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } #[test] fn test_loclists_64() { let encoding = Encoding { format: Format::Dwarf64, version: 5, address_size: 8, }; let section = Section::with_endian(Endian::Little) .L64(0x0300_0000) .L64(0x0301_0300) .L64(0x0301_0400) .L64(0x0301_0500); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); let start = Label::new(); let first = Label::new(); let size = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // Header .mark(&start) .L32(0xffff_ffff) .L64(&size) .L16(encoding.version) .L8(encoding.address_size) .L8(0) .L32(0) .mark(&first) // OffsetPair .L8(4).uleb(0x10200).uleb(0x10300).uleb(4).L32(2) // A base address selection followed by an OffsetPair. .L8(6).L64(0x0200_0000) .L8(4).uleb(0x10400).uleb(0x10500).uleb(4).L32(3) // An empty OffsetPair followed by a normal OffsetPair. .L8(4).uleb(0x10600).uleb(0x10600).uleb(4).L32(4) .L8(4).uleb(0x10800).uleb(0x10900).uleb(4).L32(5) // A StartEnd .L8(7).L64(0x201_0a00).L64(0x201_0b00).uleb(4).L32(6) // A StartLength .L8(8).L64(0x201_0c00).uleb(0x100).uleb(4).L32(7) // An OffsetPair that starts at 0. .L8(4).uleb(0).uleb(1).uleb(4).L32(8) // An OffsetPair that ends at -1. .L8(6).L64(0) .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) // A DefaultLocation .L8(5).uleb(4).L32(10) // A BaseAddressx + OffsetPair .L8(1).uleb(0) .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) // A StartxEndx .L8(2).uleb(1).uleb(2).uleb(4).L32(12) // A StartxLength .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) // A range end. .L8(0) // Some extra data. .L32(0xffff_ffff); size.set_const((§ion.here() - &start - 12) as u64); let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&[], LittleEndian); let debug_loclists = DebugLocLists::new(&buf, LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let offset = LocationListsOffset((&first - &start) as usize); let mut locations = loclists .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0101_0200, end: 0x0101_0300, }, data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), })) ); // A base address selection followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0400, end: 0x0201_0500, }, data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), })) ); // An empty location range followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0600, end: 0x0201_0600, }, data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), })) ); assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0800, end: 0x0201_0900, }, data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), })) ); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0a00, end: 0x0201_0b00, }, data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), })) ); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0c00, end: 0x0201_0d00, }, data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), })) ); // A location range that starts at 0. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0200_0000, end: 0x0200_0001, }, data: Expression(EndianSlice::new(&[8, 0, 0, 0], LittleEndian)), })) ); // A location range that ends at -1. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0000_0000, end: 0xffff_ffff, }, data: Expression(EndianSlice::new(&[9, 0, 0, 0], LittleEndian)), })) ); // A DefaultLocation. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0, end: u64::max_value(), }, data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), })) ); // A BaseAddressx + OffsetPair assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0100, end: 0x0301_0200, }, data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), })) ); // A StartxEndx assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0300, end: 0x0301_0400, }, data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), })) ); // A StartxLength assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0301_0500, end: 0x0301_0600, }, data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), })) ); // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists .locations( LocationListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } #[test] fn test_location_list_32() { let start = Label::new(); let first = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // A location before the offset. .mark(&start) .L32(0x10000).L32(0x10100).L16(4).L32(1) .mark(&first) // A normal location. .L32(0x10200).L32(0x10300).L16(4).L32(2) // A base address selection followed by a normal location. .L32(0xffff_ffff).L32(0x0200_0000) .L32(0x10400).L32(0x10500).L16(4).L32(3) // An empty location range followed by a normal location. .L32(0x10600).L32(0x10600).L16(4).L32(4) .L32(0x10800).L32(0x10900).L16(4).L32(5) // A location range that starts at 0. .L32(0).L32(1).L16(4).L32(6) // A location range that ends at -1. .L32(0xffff_ffff).L32(0x0000_0000) .L32(0).L32(0xffff_ffff).L16(4).L32(7) // A location list end. .L32(0).L32(0) // Some extra data. .L32(0); let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let offset = LocationListsOffset((&first - &start) as usize); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut locations = loclists .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0101_0200, end: 0x0101_0300, }, data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), })) ); // A base address selection followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0400, end: 0x0201_0500, }, data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), })) ); // An empty location range followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0600, end: 0x0201_0600, }, data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), })) ); assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0800, end: 0x0201_0900, }, data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), })) ); // A location range that starts at 0. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0200_0000, end: 0x0200_0001, }, data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), })) ); // A location range that ends at -1. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0000_0000, end: 0xffff_ffff, }, data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), })) ); // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists .locations( LocationListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } #[test] fn test_location_list_64() { let start = Label::new(); let first = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // A location before the offset. .mark(&start) .L64(0x10000).L64(0x10100).L16(4).L32(1) .mark(&first) // A normal location. .L64(0x10200).L64(0x10300).L16(4).L32(2) // A base address selection followed by a normal location. .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000) .L64(0x10400).L64(0x10500).L16(4).L32(3) // An empty location range followed by a normal location. .L64(0x10600).L64(0x10600).L16(4).L32(4) .L64(0x10800).L64(0x10900).L16(4).L32(5) // A location range that starts at 0. .L64(0).L64(1).L16(4).L32(6) // A location range that ends at -1. .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7) // A location list end. .L64(0).L64(0) // Some extra data. .L64(0); let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let offset = LocationListsOffset((&first - &start) as usize); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf64, version: 4, address_size: 8, }; let mut locations = loclists .locations(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0101_0200, end: 0x0101_0300, }, data: Expression(EndianSlice::new(&[2, 0, 0, 0], LittleEndian)), })) ); // A base address selection followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0400, end: 0x0201_0500, }, data: Expression(EndianSlice::new(&[3, 0, 0, 0], LittleEndian)), })) ); // An empty location range followed by a normal location. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0600, end: 0x0201_0600, }, data: Expression(EndianSlice::new(&[4, 0, 0, 0], LittleEndian)), })) ); assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0201_0800, end: 0x0201_0900, }, data: Expression(EndianSlice::new(&[5, 0, 0, 0], LittleEndian)), })) ); // A location range that starts at 0. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0200_0000, end: 0x0200_0001, }, data: Expression(EndianSlice::new(&[6, 0, 0, 0], LittleEndian)), })) ); // A location range that ends at -1. assert_eq!( locations.next(), Ok(Some(LocationListEntry { range: Range { begin: 0x0, end: 0xffff_ffff_ffff_ffff, }, data: Expression(EndianSlice::new(&[7, 0, 0, 0], LittleEndian)), })) ); // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists .locations( LocationListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } #[test] fn test_locations_invalid() { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // An invalid location range. .L32(0x20000).L32(0x10000).L16(4).L32(1) // An invalid range after wrapping. .L32(0x20000).L32(0xff01_0000).L16(4).L32(2); let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; // An invalid location range. let mut locations = loclists .locations( LocationListsOffset(0x0), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid location range after wrapping. let mut locations = loclists .locations( LocationListsOffset(14), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid offset. match loclists.locations( LocationListsOffset(buf.len() + 1), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) { Err(Error::UnexpectedEof(_)) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_get_offset() { for format in vec![Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version: 5, address_size: 4, }; let zero = Label::new(); let length = Label::new(); let start = Label::new(); let first = Label::new(); let end = Label::new(); let mut section = Section::with_endian(Endian::Little) .mark(&zero) .initial_length(format, &length, &start) .D16(encoding.version) .D8(encoding.address_size) .D8(0) .D32(20) .mark(&first); for i in 0..20 { section = section.word(format.word_size(), 1000 + i); } section = section.mark(&end); length.set_const((&end - &start) as u64); let section = section.get_contents().unwrap(); let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian)); let debug_loclists = DebugLocLists::from(EndianSlice::new(§ion, LittleEndian)); let locations = LocationLists::new(debug_loc, debug_loclists); let base = DebugLocListsBase((&first - &zero) as usize); assert_eq!( locations.get_offset(encoding, base, DebugLocListsIndex(0)), Ok(LocationListsOffset(base.0 + 1000)) ); assert_eq!( locations.get_offset(encoding, base, DebugLocListsIndex(19)), Ok(LocationListsOffset(base.0 + 1019)) ); } } } gimli-0.19.0/src/read/lookup.rs010066400017500001750000000140111346020377600145130ustar0000000000000000use std::marker::PhantomData; use crate::common::{DebugInfoOffset, Format}; use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset}; // The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have // similar structures. They consist of a header with metadata and an offset into the // .debug_info section for the entire compilation unit, and a series // of following entries that list addresses (for .debug_aranges) or names // (for .debug_pubnames and .debug_pubtypes) that are covered. // // Because these three tables all have similar structures, we abstract out some of // the parsing mechanics. pub trait LookupParser { /// The type of the produced header. type Header; /// The type of the produced entry. type Entry; /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries /// corresponding to this header (without the header itself), and the parsed representation of /// the header itself. fn parse_header(input: &mut R) -> Result<(R, Self::Header)>; /// Parse a single entry from `input`. Returns either a parsed representation of the entry /// or None if `input` is exhausted. fn parse_entry(input: &mut R, header: &Self::Header) -> Result>; } #[derive(Clone, Debug)] pub struct DebugLookup where R: Reader, Parser: LookupParser, { input_buffer: R, phantom: PhantomData, } impl From for DebugLookup where R: Reader, Parser: LookupParser, { fn from(input_buffer: R) -> Self { DebugLookup { input_buffer, phantom: PhantomData, } } } impl DebugLookup where R: Reader, Parser: LookupParser, { pub fn items(&self) -> LookupEntryIter { LookupEntryIter { current_set: None, remaining_input: self.input_buffer.clone(), } } pub fn reader(&self) -> &R { &self.input_buffer } } #[derive(Clone, Debug)] pub struct LookupEntryIter where R: Reader, Parser: LookupParser, { current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end. remaining_input: R, } impl LookupEntryIter where R: Reader, Parser: LookupParser, { /// Advance the iterator and return the next entry. /// /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns /// `Ok(None)` when iteration is complete and all entries have already been /// parsed and yielded. If an error occurs while parsing the next entry, /// then this error is returned as `Err(e)`, and all subsequent calls return /// `Ok(None)`. /// /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn next(&mut self) -> Result> { loop { if let Some((ref mut input, ref header)) = self.current_set { if !input.is_empty() { match Parser::parse_entry(input, header) { Ok(Some(entry)) => return Ok(Some(entry)), Ok(None) => {} Err(e) => { input.empty(); self.remaining_input.empty(); return Err(e); } } } } if self.remaining_input.is_empty() { self.current_set = None; return Ok(None); } match Parser::parse_header(&mut self.remaining_input) { Ok(set) => { self.current_set = Some(set); } Err(e) => { self.current_set = None; self.remaining_input.empty(); return Err(e); } } } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PubStuffHeader { format: Format, length: T, version: u16, unit_offset: DebugInfoOffset, unit_length: T, } pub trait PubStuffEntry { fn new( die_offset: UnitOffset, name: R, unit_header_offset: DebugInfoOffset, ) -> Self; } #[derive(Clone, Debug)] pub struct PubStuffParser where R: Reader, Entry: PubStuffEntry, { // This struct is never instantiated. phantom: PhantomData<(R, Entry)>, } impl LookupParser for PubStuffParser where R: Reader, Entry: PubStuffEntry, { type Header = PubStuffHeader; type Entry = Entry; /// Parse an pubthings set header. Returns a tuple of the /// pubthings to be parsed for this set, and the newly created PubThingHeader struct. fn parse_header(input: &mut R) -> Result<(R, Self::Header)> { let (length, format) = input.read_initial_length()?; let mut rest = input.split(length)?; let version = rest.read_u16()?; if version != 2 { return Err(Error::UnknownVersion(u64::from(version))); } let unit_offset = parse_debug_info_offset(&mut rest, format)?; let unit_length = rest.read_length(format)?; let header = PubStuffHeader { format, length, version, unit_offset, unit_length, }; Ok((rest, header)) } /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing. fn parse_entry(input: &mut R, header: &Self::Header) -> Result> { let offset = input.read_offset(header.format)?; if offset.into_u64() == 0 { input.empty(); Ok(None) } else { let name = input.read_null_terminated_slice()?; Ok(Some(Self::Entry::new( UnitOffset(offset), name, header.unit_offset, ))) } } } gimli-0.19.0/src/read/mod.rs010066400017500001750000000720071351057326000137640ustar0000000000000000//! Read DWARF debugging information. //! //! * [Example Usage](#example-usage) //! * [API Structure](#api-structure) //! * [Using with `FallibleIterator`](#using-with-fallibleiterator) //! //! ## Example Usage //! //! Print out all of the functions in the debuggee program: //! //! ```rust,no_run //! # fn example() -> Result<(), gimli::Error> { //! # type R = gimli::EndianSlice<'static, gimli::LittleEndian>; //! # let get_file_section_reader = |name| -> Result { unimplemented!() }; //! # let get_sup_file_section_reader = |name| -> Result { unimplemented!() }; //! // Read the DWARF sections with whatever object loader you're using. //! // These closures should return a `Reader` instance (e.g. `EndianSlice`). //! let loader = |section: gimli::SectionId| { get_file_section_reader(section.name()) }; //! let sup_loader = |section: gimli::SectionId| { get_sup_file_section_reader(section.name()) }; //! let dwarf = gimli::Dwarf::load(loader, sup_loader)?; //! //! // Iterate over all compilation units. //! let mut iter = dwarf.units(); //! while let Some(header) = iter.next()? { //! // Parse the abbreviations and other information for this compilation unit. //! let unit = dwarf.unit(header)?; //! //! // Iterate over all of this compilation unit's entries. //! let mut entries = unit.entries(); //! while let Some((_, entry)) = entries.next_dfs()? { //! // If we find an entry for a function, print it. //! if entry.tag() == gimli::DW_TAG_subprogram { //! println!("Found a function: {:?}", entry); //! } //! } //! } //! # unreachable!() //! # } //! ``` //! //! Full example programs: //! //! * [A simple parser](https://github.com/gimli-rs/gimli/blob/master/examples/simple.rs) //! //! * [A `dwarfdump` //! clone](https://github.com/gimli-rs/gimli/blob/master/examples/dwarfdump.rs) //! //! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) //! //! * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into //! code generation by making debugging information readable //! //! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the //! compilers used to create each compilation unit within a shared library or //! executable (via `DW_AT_producer`) //! //! * [`dwarf-validate`](http://github.com/gimli-rs/gimli/blob/master/examples/dwarf-validate.rs), //! a program to validate the integrity of some DWARF and its references //! between sections and compilation units. //! //! ## API Structure //! //! * Basic familiarity with DWARF is assumed. //! //! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF //! sections. It has methods that simplify access to debugging data that spans //! multiple sections. Use of this type is optional, but recommended. //! //! * Each section gets its own type. Consider these types the entry points to //! the library: //! //! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section. //! //! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section. //! //! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges` //! section. //! //! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section. //! //! * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section. //! //! * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section. //! //! * [`DebugLineStr`](./struct.DebugLineStr.html): The `.debug_line_str` section. //! //! * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section. //! //! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section. //! //! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames` //! section. //! //! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes` //! section. //! //! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section. //! //! * [`DebugRngLists`](./struct.DebugRngLists.html): The `.debug_rnglists` section. //! //! * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section. //! //! * [`DebugStrOffsets`](./struct.DebugStrOffsets.html): The `.debug_str_offsets` section. //! //! * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section. //! //! * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section. //! //! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section. //! //! * Each section type exposes methods for accessing the debugging data encoded //! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) //! struct has the [`units`](./struct.DebugInfo.html#method.units) method for //! iterating over the compilation units defined within it. //! //! * Offsets into a section are strongly typed: an offset into `.debug_info` is //! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be //! used to index into the [`DebugLine`](./struct.DebugLine.html) type because //! `DebugLine` represents the `.debug_line` section. There are similar types //! for offsets relative to a compilation unit rather than a section. //! //! ## Using with `FallibleIterator` //! //! The standard library's `Iterator` trait and related APIs do not play well //! with iterators where the `next` operation is fallible. One can make the //! `Iterator`'s associated `Item` type be a `Result`, however the //! provided methods cannot gracefully handle the case when an `Err` is //! returned. //! //! This situation led to the //! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's //! existence. You can read more of the rationale for its existence in its //! docs. The crate provides the helpers you have come to expect (eg `map`, //! `filter`, etc) for iterators that can fail. //! //! `gimli`'s many lazy parsing iterators are a perfect match for the //! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not //! done eagerly. Parse errors later in the input might only be discovered after //! having iterated through many items. //! //! To use `gimli` iterators with `FallibleIterator`, import the crate and trait //! into your code: //! //! ``` //! // Use the `FallibleIterator` trait so its methods are in scope! //! use fallible_iterator::FallibleIterator; //! use gimli::{DebugAranges, EndianSlice, LittleEndian}; //! //! fn find_sum_of_address_range_lengths(aranges: DebugAranges>) //! -> gimli::Result //! { //! // `DebugAranges::items` returns a `FallibleIterator`! //! aranges.items() //! // `map` is provided by `FallibleIterator`! //! .map(|arange| Ok(arange.length())) //! // `fold` is provided by `FallibleIterator`! //! .fold(0, |sum, len| Ok(sum + len)) //! } //! //! # fn main() {} //! ``` use std::fmt::{self, Debug}; use std::result; #[cfg(feature = "std")] use std::{error, io}; use crate::common::{Register, SectionId}; use crate::constants; mod addr; pub use self::addr::*; mod cfi; pub use self::cfi::*; mod dwarf; pub use self::dwarf::*; mod endian_slice; pub use self::endian_slice::*; mod endian_reader; pub use self::endian_reader::*; mod reader; pub use self::reader::*; mod abbrev; pub use self::abbrev::*; mod aranges; pub use self::aranges::*; mod line; pub use self::line::*; mod loclists; pub use self::loclists::*; mod lookup; mod op; pub use self::op::*; mod pubnames; pub use self::pubnames::*; mod pubtypes; pub use self::pubtypes::*; mod rnglists; pub use self::rnglists::*; mod str; pub use self::str::*; mod unit; pub use self::unit::*; mod value; pub use self::value::*; /// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across /// `gimli` versions, we export this type alias. #[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")] pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; /// An error that occurred when parsing. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { /// An I/O error occurred while reading. Io, /// Found a PC relative pointer, but the section base is undefined. PcRelativePointerButSectionBaseIsUndefined, /// Found a `.text` relative pointer, but the `.text` base is undefined. TextRelativePointerButTextBaseIsUndefined, /// Found a data relative pointer, but the data base is undefined. DataRelativePointerButDataBaseIsUndefined, /// Found a function relative pointer in a context that does not have a /// function base. FuncRelativePointerInBadContext, /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding. CannotParseOmitPointerEncoding, /// An error parsing an unsigned LEB128 value. BadUnsignedLeb128, /// An error parsing a signed LEB128 value. BadSignedLeb128, /// An abbreviation declared that its tag is zero, but zero is reserved for /// null records. AbbreviationTagZero, /// An attribute specification declared that its form is zero, but zero is /// reserved for null records. AttributeFormZero, /// The abbreviation's has-children byte was not one of /// `DW_CHILDREN_{yes,no}`. BadHasChildren, /// The specified length is impossible. BadLength, /// Found an unknown `DW_FORM_*` type. UnknownForm, /// Expected a zero, found something else. ExpectedZero, /// Found an abbreviation code that has already been used. DuplicateAbbreviationCode, /// Found a duplicate arange. DuplicateArange, /// Found an unknown reserved length value. UnknownReservedLength, /// Found an unknown DWARF version. UnknownVersion(u64), /// Found a record with an unknown abbreviation code. UnknownAbbreviation, /// Hit the end of input before it was expected. UnexpectedEof(ReaderOffsetId), /// Read a null entry before it was expected. UnexpectedNull, /// Found an unknown standard opcode. UnknownStandardOpcode(constants::DwLns), /// Found an unknown extended opcode. UnknownExtendedOpcode(constants::DwLne), /// The specified address size is not supported. UnsupportedAddressSize(u8), /// The specified offset size is not supported. UnsupportedOffsetSize(u8), /// The specified field size is not supported. UnsupportedFieldSize(u8), /// The minimum instruction length must not be zero. MinimumInstructionLengthZero, /// The maximum operations per instruction must not be zero. MaximumOperationsPerInstructionZero, /// The line range must not be zero. LineRangeZero, /// The opcode base must not be zero. OpcodeBaseZero, /// Found an invalid UTF-8 string. BadUtf8, /// Expected to find the CIE ID, but found something else. NotCieId, /// Expected to find a pointer to a CIE, but found the CIE ID instead. NotCiePointer, /// Expected to find a pointer to an FDE, but found a CIE instead. NotFdePointer, /// Invalid branch target for a DW_OP_bra or DW_OP_skip. BadBranchTarget(u64), /// DW_OP_push_object_address used but no address passed in. InvalidPushObjectAddress, /// Not enough items on the stack when evaluating an expression. NotEnoughStackItems, /// Too many iterations to compute the expression. TooManyIterations, /// An unrecognized operation was found while parsing a DWARF /// expression. InvalidExpression(constants::DwOp), /// The expression had a piece followed by an expression /// terminator without a piece. InvalidPiece, /// An expression-terminating operation was followed by something /// other than the end of the expression or a piece operation. InvalidExpressionTerminator(u64), /// Division or modulus by zero when evaluating an expression. DivisionByZero, /// An expression operation used mismatching types. TypeMismatch, /// An expression operation required an integral type but saw a /// floating point type. IntegralTypeRequired, /// An expression operation used types that are not supported. UnsupportedTypeOperation, /// The shift value in an expression must be a non-negative integer. InvalidShiftExpression, /// An unknown DW_CFA_* instruction. UnknownCallFrameInstruction(constants::DwCfa), /// The end of an address range was before the beginning. InvalidAddressRange, /// The end offset of a loc list entry was before the beginning. InvalidLocationAddressRange, /// Encountered a call frame instruction in a context in which it is not /// valid. CfiInstructionInInvalidContext, /// When evaluating call frame instructions, found a `DW_CFA_restore_state` /// stack pop instruction, but the stack was empty, and had nothing to pop. PopWithEmptyStack, /// Do not have unwind info for the given address. NoUnwindInfoForAddress, /// An offset value was larger than the maximum supported value. UnsupportedOffset, /// The given pointer encoding is either unknown or invalid. UnknownPointerEncoding, /// Did not find an entry at the given offset. NoEntryAtGivenOffset, /// The given offset is out of bounds. OffsetOutOfBounds, /// Found an unknown CFI augmentation. UnknownAugmentation, /// We do not support the given pointer encoding yet. UnsupportedPointerEncoding, /// Registers larger than `u16` are not supported. UnsupportedRegister(u64), /// The CFI program defined more register rules than we have storage for. TooManyRegisterRules, /// Attempted to push onto the CFI stack, but it was already at full /// capacity. CfiStackFull, /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded, /// which makes binary search impossible. VariableLengthSearchTable, /// The `DW_UT_*` value for this unit is not supported yet. UnsupportedUnitType, /// Ranges using AddressIndex are not supported yet. UnsupportedAddressIndex, /// Nonzero segment selector sizes aren't supported yet. UnsupportedSegmentSize, /// A compilation unit or type unit is missing its top level DIE. MissingUnitDie, /// A DIE attribute used an unsupported form. UnsupportedAttributeForm, /// Missing DW_LNCT_path in file entry format. MissingFileEntryFormatPath, /// Expected an attribute value to be a string form. ExpectedStringAttributeValue, } impl fmt::Display for Error { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { Debug::fmt(self, f) } } impl Error { /// A short description of the error. pub fn description(&self) -> &str { match *self { Error::Io => "An I/O error occurred while reading.", Error::PcRelativePointerButSectionBaseIsUndefined => { "Found a PC relative pointer, but the section base is undefined." } Error::TextRelativePointerButTextBaseIsUndefined => { "Found a `.text` relative pointer, but the `.text` base is undefined." } Error::DataRelativePointerButDataBaseIsUndefined => { "Found a data relative pointer, but the data base is undefined." } Error::FuncRelativePointerInBadContext => { "Found a function relative pointer in a context that does not have a function base." } Error::CannotParseOmitPointerEncoding => { "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." } Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", Error::AbbreviationTagZero => { "An abbreviation declared that its tag is zero, but zero is reserved for null records" } Error::AttributeFormZero => { "An attribute specification declared that its form is zero, but zero is reserved for null records" } Error::BadHasChildren => { "The abbreviation's has-children byte was not one of `DW_CHILDREN_{yes,no}`" } Error::BadLength => "The specified length is impossible", Error::UnknownForm => "Found an unknown `DW_FORM_*` type", Error::ExpectedZero => "Expected a zero, found something else", Error::DuplicateAbbreviationCode => { "Found an abbreviation code that has already been used" } Error::DuplicateArange => "Found a duplicate arange", Error::UnknownReservedLength => "Found an unknown reserved length value", Error::UnknownVersion(_) => "Found an unknown DWARF version", Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code", Error::UnexpectedEof(_) => "Hit the end of input before it was expected", Error::UnexpectedNull => "Read a null entry before it was expected.", Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", Error::UnsupportedAddressSize(_) => "The specified address size is not supported", Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", Error::UnsupportedFieldSize(_) => "The specified field size is not supported", Error::MinimumInstructionLengthZero => { "The minimum instruction length must not be zero." } Error::MaximumOperationsPerInstructionZero => { "The maximum operations per instruction must not be zero." } Error::LineRangeZero => "The line range must not be zero.", Error::OpcodeBaseZero => "The opcode base must not be zero.", Error::BadUtf8 => "Found an invalid UTF-8 string.", Error::NotCieId => "Expected to find the CIE ID, but found something else.", Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", Error::NotFdePointer => { "Expected to find an FDE pointer, but found a CIE pointer instead." } Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", Error::InvalidPushObjectAddress => { "DW_OP_push_object_address used but no object address given" } Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", Error::InvalidPiece => { "DWARF expression has piece followed by non-piece expression at end" } Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", Error::DivisionByZero => "Division or modulus by zero when evaluating expression", Error::TypeMismatch => "Type mismatch when evaluating expression", Error::IntegralTypeRequired => "Integral type expected when evaluating expression", Error::UnsupportedTypeOperation => { "An expression operation used types that are not supported" } Error::InvalidShiftExpression => { "The shift value in an expression must be a non-negative integer." } Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", Error::InvalidAddressRange => { "The end of an address range must not be before the beginning." } Error::InvalidLocationAddressRange => { "The end offset of a location list entry must not be before the beginning." } Error::CfiInstructionInInvalidContext => { "Encountered a call frame instruction in a context in which it is not valid." } Error::PopWithEmptyStack => { "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ instruction, but the stack was empty, and had nothing to pop." } Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", Error::UnsupportedOffset => { "An offset value was larger than the maximum supported value." } Error::UnknownPointerEncoding => { "The given pointer encoding is either unknown or invalid." } Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", Error::OffsetOutOfBounds => "The given offset is out of bounds.", Error::UnknownAugmentation => "Found an unknown CFI augmentation.", Error::UnsupportedPointerEncoding => { "We do not support the given pointer encoding yet." } Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", Error::TooManyRegisterRules => { "The CFI program defined more register rules than we have storage for." } Error::CfiStackFull => { "Attempted to push onto the CFI stack, but it was already at full capacity." } Error::VariableLengthSearchTable => { "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ which makes binary search impossible." } Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", Error::MissingUnitDie => { "A compilation unit or type unit is missing its top level DIE." } Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", Error::ExpectedStringAttributeValue => { "Expected an attribute value to be a string form." } } } } #[cfg(feature = "std")] impl error::Error for Error { fn description(&self) -> &str { Error::description(self) } } #[cfg(feature = "std")] impl From for Error { fn from(_: io::Error) -> Self { Error::Io } } /// The result of a parse. pub type Result = result::Result; /// A convenience trait for loading DWARF sections from object files. To be /// used like: /// /// ``` /// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; /// /// let buf = [0x00, 0x01, 0x02, 0x03]; /// let reader = EndianSlice::new(&buf, LittleEndian); /// let loader = |name| -> Result<_, ()> { Ok(reader) }; /// /// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); /// ``` pub trait Section: From { /// Returns the section id for this type. fn id() -> SectionId; /// Returns the ELF section name for this type. fn section_name() -> &'static str { Self::id().name() } /// Try to load the section using the given loader function. fn load(f: F) -> std::result::Result where F: FnOnce(SectionId) -> std::result::Result, { f(Self::id()).map(From::from) } /// Returns the `Reader` for this section. fn reader(&self) -> &R where R: Reader; /// Returns the `Reader` for this section. fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> where R: Reader, { self.reader() .lookup_offset_id(id) .map(|offset| (Self::id(), offset)) } } impl Register { pub(crate) fn from_u64(x: u64) -> Result { let y = x as u16; if u64::from(y) == x { Ok(Register(y)) } else { Err(Error::UnsupportedRegister(x)) } } } #[cfg(test)] mod tests { use super::*; use crate::common::Format; use crate::endianity::LittleEndian; use test_assembler::{Endian, Section}; #[test] fn test_parse_initial_length_32_ok() { let section = Section::with_endian(Endian::Little).L32(0x7856_3412); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_initial_length() { Ok((length, format)) => { assert_eq!(input.len(), 0); assert_eq!(format, Format::Dwarf32); assert_eq!(0x7856_3412, length); } otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_parse_initial_length_64_ok() { let section = Section::with_endian(Endian::Little) // Dwarf_64_INITIAL_UNIT_LENGTH .L32(0xffff_ffff) // Actual length .L64(0xffde_bc9a_7856_3412); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); #[cfg(target_pointer_width = "64")] match input.read_initial_length() { Ok((length, format)) => { assert_eq!(input.len(), 0); assert_eq!(format, Format::Dwarf64); assert_eq!(0xffde_bc9a_7856_3412, length); } otherwise => panic!("Unexpected result: {:?}", otherwise), } #[cfg(target_pointer_width = "32")] match input.read_initial_length() { Err(Error::UnsupportedOffset) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_initial_length_unknown_reserved_value() { let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_initial_length() { Err(Error::UnknownReservedLength) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_initial_length_incomplete() { let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_initial_length() { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_initial_length_64_incomplete() { let section = Section::with_endian(Endian::Little) // Dwarf_64_INITIAL_UNIT_LENGTH .L32(0xffff_ffff) // Actual length is not long enough. .L32(0x7856_3412); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_initial_length() { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_offset_32() { let section = Section::with_endian(Endian::Little).L32(0x0123_4567); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_offset(Format::Dwarf32) { Ok(val) => { assert_eq!(input.len(), 0); assert_eq!(val, 0x0123_4567); } otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_offset_64_small() { let section = Section::with_endian(Endian::Little).L64(0x0123_4567); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_offset(Format::Dwarf64) { Ok(val) => { assert_eq!(input.len(), 0); assert_eq!(val, 0x0123_4567); } otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_offset_64_large() { let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_offset(Format::Dwarf64) { Ok(val) => { assert_eq!(input.len(), 0); assert_eq!(val, 0x0123_4567_89ab_cdef); } otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] #[cfg(target_pointer_width = "32")] fn test_parse_offset_64_large() { let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); let buf = section.get_contents().unwrap(); let input = &mut EndianSlice::new(&buf, LittleEndian); match input.read_offset(Format::Dwarf64) { Err(Error::UnsupportedOffset) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } } gimli-0.19.0/src/read/op.rs010066400017500001750000004134331346020377600136330ustar0000000000000000//! Functions for parsing and evaluating DWARF expressions. use crate::vec::Vec; use std::mem; use crate::common::{DebugAddrIndex, DebugInfoOffset, Encoding, Register}; use crate::constants; use crate::read::{Error, Reader, ReaderOffset, Result, UnitOffset, Value, ValueType}; /// A reference to a DIE, either relative to the current CU or /// relative to the section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DieReference { /// A CU-relative reference. UnitRef(UnitOffset), /// A section-relative reference. DebugInfoRef(DebugInfoOffset), } /// A single decoded DWARF expression operation. /// /// DWARF expression evaluation is done in two parts: first the raw /// bytes of the next part of the expression are decoded; and then the /// decoded operation is evaluated. This approach lets other /// consumers inspect the DWARF expression without reimplementing the /// decoding operation. /// /// Multiple DWARF opcodes may decode into a single `Operation`. For /// example, both `DW_OP_deref` and `DW_OP_xderef` are represented /// using `Operation::Deref`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Operation::Offset> where R: Reader, Offset: ReaderOffset, { /// Dereference the topmost value of the stack. Deref { /// The DIE of the base type or 0 to indicate the generic type base_type: UnitOffset, /// The size of the data to dereference. size: u8, /// True if the dereference operation takes an address space /// argument from the stack; false otherwise. space: bool, }, /// Drop an item from the stack. Drop, /// Pick an item from the stack and push it on top of the stack. /// This operation handles `DW_OP_pick`, `DW_OP_dup`, and /// `DW_OP_over`. Pick { /// The index, from the top of the stack, of the item to copy. index: u8, }, /// Swap the top two stack items. Swap, /// Rotate the top three stack items. Rot, /// Take the absolute value of the top of the stack. Abs, /// Bitwise `and` of the top two values on the stack. And, /// Divide the top two values on the stack. Div, /// Subtract the top two values on the stack. Minus, /// Modulus of the top two values on the stack. Mod, /// Multiply the top two values on the stack. Mul, /// Negate the top of the stack. Neg, /// Bitwise `not` of the top of the stack. Not, /// Bitwise `or` of the top two values on the stack. Or, /// Add the top two values on the stack. Plus, /// Add a constant to the topmost value on the stack. PlusConstant { /// The value to add. value: u64, }, /// Logical left shift of the 2nd value on the stack by the number /// of bits given by the topmost value on the stack. Shl, /// Right shift of the 2nd value on the stack by the number of /// bits given by the topmost value on the stack. Shr, /// Arithmetic left shift of the 2nd value on the stack by the /// number of bits given by the topmost value on the stack. Shra, /// Bitwise `xor` of the top two values on the stack. Xor, /// Branch to the target location if the top of stack is nonzero. Bra { /// The target bytecode. target: R, }, /// Compare the top two stack values for equality. Eq, /// Compare the top two stack values using `>=`. Ge, /// Compare the top two stack values using `>`. Gt, /// Compare the top two stack values using `<=`. Le, /// Compare the top two stack values using `<`. Lt, /// Compare the top two stack values using `!=`. Ne, /// Unconditional branch to the target location. Skip { /// The target bytecode. target: R, }, /// Push a constant value on the stack. This handles multiple /// DWARF opcodes. Literal { /// The value to push. value: u64, }, /// Indicate that this piece's location is in the given register. /// Completes the piece or expression. Register { /// The register number. register: Register, }, /// Find the value of the given register, add the offset, and then /// push the resulting sum on the stack. RegisterOffset { /// The register number. register: Register, /// The offset to add. offset: i64, /// The DIE of the base type or 0 to indicate the generic type base_type: UnitOffset, }, /// Compute the frame base (using `DW_AT_frame_base`), add the /// given offset, and then push the resulting sum on the stack. FrameOffset { /// The offset to add. offset: i64, }, /// No operation. Nop, /// Push the object address on the stack. PushObjectAddress, /// Evaluate a DWARF expression as a subroutine. The expression /// comes from the `DW_AT_location` attribute of the indicated /// DIE. Call { /// The DIE to use. offset: DieReference, }, /// Compute the address of a thread-local variable and push it on /// the stack. TLS, /// Compute the call frame CFA and push it on the stack. CallFrameCFA, /// Terminate a piece. Piece { /// The size of this piece in bits. size_in_bits: u64, /// The bit offset of this piece. If `None`, then this piece /// was specified using `DW_OP_piece` and should start at the /// next byte boundary. bit_offset: Option, }, /// Represents `DW_OP_implicit_value`. /// The object has no location, but has a known constant value. /// Completes the piece or expression. ImplicitValue { /// The implicit value to use. data: R, }, /// Represents `DW_OP_stack_value`. /// The object has no location, but its value is at the top of the stack. /// Completes the piece or expression. StackValue, /// Represents `DW_OP_implicit_pointer`. The object is a pointer to /// a value which has no actual location, such as an implicit value or /// a stack value. /// Completes the piece or expression. ImplicitPointer { /// The `.debug_info` offset of the value that this is an implicit pointer into. value: DebugInfoOffset, /// The byte offset into the value that the implicit pointer points to. byte_offset: i64, }, /// Represents `DW_OP_entry_value`. Evaluate an expression at the entry to /// the current subprogram, and push it on the stack. EntryValue { /// The expression to be evaluated. expression: R, }, /// Represents `DW_OP_GNU_parameter_ref`. This represents a parameter that was /// optimized out. The offset points to the definition of the parameter, and is /// matched to the `DW_TAG_GNU_call_site_parameter` in the caller that also /// points to the same definition of the parameter. ParameterRef { /// The DIE to use. offset: UnitOffset, }, /// Represents `DW_OP_addr`. /// Relocate the address if needed, and push it on the stack. Address { /// The offset to add. address: u64, }, /// Represents `DW_OP_addrx`. /// Read the address at the given index in `.debug_addr, relocate the address if needed, /// and push it on the stack. AddressIndex { /// The index of the address in `.debug_addr`. index: DebugAddrIndex, }, /// Represents `DW_OP_constx`. /// Read the address at the given index in `.debug_addr, and push it on the stack. /// Do not relocate the address. ConstantIndex { /// The index of the address in `.debug_addr`. index: DebugAddrIndex, }, /// Represents `DW_OP_const_type`. /// Interpret the value bytes as a constant of a given type, and push it on the stack. TypedLiteral { /// The DIE of the base type. base_type: UnitOffset, /// The value bytes. value: R, }, /// Represents `DW_OP_convert`. /// Pop the top stack entry, convert it to a different type, and push it on the stack. Convert { /// The DIE of the base type. base_type: UnitOffset, }, /// Represents `DW_OP_reinterpret`. /// Pop the top stack entry, reinterpret the bits in its value as a different type, /// and push it on the stack. Reinterpret { /// The DIE of the base type. base_type: UnitOffset, }, } #[derive(Debug)] enum OperationEvaluationResult { Piece, Incomplete, Complete { location: Location }, Waiting(EvaluationWaiting, EvaluationResult), } /// A single location of a piece of the result of a DWARF expression. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Location::Offset> where R: Reader, Offset: ReaderOffset, { /// The piece is empty. Ordinarily this means the piece has been /// optimized away. Empty, /// The piece is found in a register. Register { /// The register number. register: Register, }, /// The piece is found in memory. Address { /// The address. address: u64, }, /// The piece has no location but its value is known. Value { /// The value. value: Value, }, /// The piece is represented by some constant bytes. Bytes { /// The value. value: R, }, /// The piece is a pointer to a value which has no actual location. ImplicitPointer { /// The `.debug_info` offset of the value that this is an implicit pointer into. value: DebugInfoOffset, /// The byte offset into the value that the implicit pointer points to. byte_offset: i64, }, } impl Location where R: Reader, Offset: ReaderOffset, { /// Return true if the piece is empty. pub fn is_empty(&self) -> bool { match *self { Location::Empty => true, _ => false, } } } /// The description of a single piece of the result of a DWARF /// expression. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Piece::Offset> where R: Reader, Offset: ReaderOffset, { /// If given, the size of the piece in bits. If `None`, there /// must be only one piece whose size is all of the object. pub size_in_bits: Option, /// If given, the bit offset of the piece within the location. /// If the location is a `Location::Register` or `Location::Value`, /// then this offset is from the least significant bit end of /// the register or value. /// If the location is a `Location::Address` then the offset uses /// the bit numbering and direction conventions of the language /// and target system. /// /// If `None`, the piece starts at the location. If the /// location is a register whose size is larger than the piece, /// then placement within the register is defined by the ABI. pub bit_offset: Option, /// Where this piece is to be found. pub location: Location, } // A helper function to handle branch offsets. fn compute_pc(pc: &R, bytecode: &R, offset: i16) -> Result { let pc_offset = pc.offset_from(bytecode); let new_pc_offset = pc_offset.wrapping_add(R::Offset::from_i16(offset)); if new_pc_offset > bytecode.len() { Err(Error::BadBranchTarget(new_pc_offset.into_u64())) } else { let mut new_pc = bytecode.clone(); new_pc.skip(new_pc_offset)?; Ok(new_pc) } } fn generic_type() -> UnitOffset { UnitOffset(O::from_u64(0).unwrap()) } impl Operation where R: Reader, Offset: ReaderOffset, { /// Parse a single DWARF expression operation. /// /// This is useful when examining a DWARF expression for reasons other /// than direct evaluation. /// /// `bytes` points to a the operation to decode. It should point into /// the same array as `bytecode`, which should be the entire /// expression. pub fn parse(bytes: &mut R, bytecode: &R, encoding: Encoding) -> Result> { let opcode = bytes.read_u8()?; let name = constants::DwOp(opcode); match name { constants::DW_OP_addr => { let address = bytes.read_address(encoding.address_size)?; Ok(Operation::Address { address }) } constants::DW_OP_deref => Ok(Operation::Deref { base_type: generic_type(), size: encoding.address_size, space: false, }), constants::DW_OP_const1u => { let value = bytes.read_u8()?; Ok(Operation::Literal { value: u64::from(value), }) } constants::DW_OP_const1s => { let value = bytes.read_i8()?; Ok(Operation::Literal { value: value as u64, }) } constants::DW_OP_const2u => { let value = bytes.read_u16()?; Ok(Operation::Literal { value: u64::from(value), }) } constants::DW_OP_const2s => { let value = bytes.read_i16()?; Ok(Operation::Literal { value: value as u64, }) } constants::DW_OP_const4u => { let value = bytes.read_u32()?; Ok(Operation::Literal { value: u64::from(value), }) } constants::DW_OP_const4s => { let value = bytes.read_i32()?; Ok(Operation::Literal { value: value as u64, }) } constants::DW_OP_const8u => { let value = bytes.read_u64()?; Ok(Operation::Literal { value }) } constants::DW_OP_const8s => { let value = bytes.read_i64()?; Ok(Operation::Literal { value: value as u64, }) } constants::DW_OP_constu => { let value = bytes.read_uleb128()?; Ok(Operation::Literal { value }) } constants::DW_OP_consts => { let value = bytes.read_sleb128()?; Ok(Operation::Literal { value: value as u64, }) } constants::DW_OP_dup => Ok(Operation::Pick { index: 0 }), constants::DW_OP_drop => Ok(Operation::Drop), constants::DW_OP_over => Ok(Operation::Pick { index: 1 }), constants::DW_OP_pick => { let value = bytes.read_u8()?; Ok(Operation::Pick { index: value }) } constants::DW_OP_swap => Ok(Operation::Swap), constants::DW_OP_rot => Ok(Operation::Rot), constants::DW_OP_xderef => Ok(Operation::Deref { base_type: generic_type(), size: encoding.address_size, space: true, }), constants::DW_OP_abs => Ok(Operation::Abs), constants::DW_OP_and => Ok(Operation::And), constants::DW_OP_div => Ok(Operation::Div), constants::DW_OP_minus => Ok(Operation::Minus), constants::DW_OP_mod => Ok(Operation::Mod), constants::DW_OP_mul => Ok(Operation::Mul), constants::DW_OP_neg => Ok(Operation::Neg), constants::DW_OP_not => Ok(Operation::Not), constants::DW_OP_or => Ok(Operation::Or), constants::DW_OP_plus => Ok(Operation::Plus), constants::DW_OP_plus_uconst => { let value = bytes.read_uleb128()?; Ok(Operation::PlusConstant { value }) } constants::DW_OP_shl => Ok(Operation::Shl), constants::DW_OP_shr => Ok(Operation::Shr), constants::DW_OP_shra => Ok(Operation::Shra), constants::DW_OP_xor => Ok(Operation::Xor), constants::DW_OP_bra => { let value = bytes.read_i16()?; Ok(Operation::Bra { target: compute_pc(bytes, bytecode, value)?, }) } constants::DW_OP_eq => Ok(Operation::Eq), constants::DW_OP_ge => Ok(Operation::Ge), constants::DW_OP_gt => Ok(Operation::Gt), constants::DW_OP_le => Ok(Operation::Le), constants::DW_OP_lt => Ok(Operation::Lt), constants::DW_OP_ne => Ok(Operation::Ne), constants::DW_OP_skip => { let value = bytes.read_i16()?; Ok(Operation::Skip { target: compute_pc(bytes, bytecode, value)?, }) } constants::DW_OP_lit0 | constants::DW_OP_lit1 | constants::DW_OP_lit2 | constants::DW_OP_lit3 | constants::DW_OP_lit4 | constants::DW_OP_lit5 | constants::DW_OP_lit6 | constants::DW_OP_lit7 | constants::DW_OP_lit8 | constants::DW_OP_lit9 | constants::DW_OP_lit10 | constants::DW_OP_lit11 | constants::DW_OP_lit12 | constants::DW_OP_lit13 | constants::DW_OP_lit14 | constants::DW_OP_lit15 | constants::DW_OP_lit16 | constants::DW_OP_lit17 | constants::DW_OP_lit18 | constants::DW_OP_lit19 | constants::DW_OP_lit20 | constants::DW_OP_lit21 | constants::DW_OP_lit22 | constants::DW_OP_lit23 | constants::DW_OP_lit24 | constants::DW_OP_lit25 | constants::DW_OP_lit26 | constants::DW_OP_lit27 | constants::DW_OP_lit28 | constants::DW_OP_lit29 | constants::DW_OP_lit30 | constants::DW_OP_lit31 => Ok(Operation::Literal { value: (opcode - constants::DW_OP_lit0.0).into(), }), constants::DW_OP_reg0 | constants::DW_OP_reg1 | constants::DW_OP_reg2 | constants::DW_OP_reg3 | constants::DW_OP_reg4 | constants::DW_OP_reg5 | constants::DW_OP_reg6 | constants::DW_OP_reg7 | constants::DW_OP_reg8 | constants::DW_OP_reg9 | constants::DW_OP_reg10 | constants::DW_OP_reg11 | constants::DW_OP_reg12 | constants::DW_OP_reg13 | constants::DW_OP_reg14 | constants::DW_OP_reg15 | constants::DW_OP_reg16 | constants::DW_OP_reg17 | constants::DW_OP_reg18 | constants::DW_OP_reg19 | constants::DW_OP_reg20 | constants::DW_OP_reg21 | constants::DW_OP_reg22 | constants::DW_OP_reg23 | constants::DW_OP_reg24 | constants::DW_OP_reg25 | constants::DW_OP_reg26 | constants::DW_OP_reg27 | constants::DW_OP_reg28 | constants::DW_OP_reg29 | constants::DW_OP_reg30 | constants::DW_OP_reg31 => Ok(Operation::Register { register: Register((opcode - constants::DW_OP_reg0.0).into()), }), constants::DW_OP_breg0 | constants::DW_OP_breg1 | constants::DW_OP_breg2 | constants::DW_OP_breg3 | constants::DW_OP_breg4 | constants::DW_OP_breg5 | constants::DW_OP_breg6 | constants::DW_OP_breg7 | constants::DW_OP_breg8 | constants::DW_OP_breg9 | constants::DW_OP_breg10 | constants::DW_OP_breg11 | constants::DW_OP_breg12 | constants::DW_OP_breg13 | constants::DW_OP_breg14 | constants::DW_OP_breg15 | constants::DW_OP_breg16 | constants::DW_OP_breg17 | constants::DW_OP_breg18 | constants::DW_OP_breg19 | constants::DW_OP_breg20 | constants::DW_OP_breg21 | constants::DW_OP_breg22 | constants::DW_OP_breg23 | constants::DW_OP_breg24 | constants::DW_OP_breg25 | constants::DW_OP_breg26 | constants::DW_OP_breg27 | constants::DW_OP_breg28 | constants::DW_OP_breg29 | constants::DW_OP_breg30 | constants::DW_OP_breg31 => { let value = bytes.read_sleb128()?; Ok(Operation::RegisterOffset { register: Register((opcode - constants::DW_OP_breg0.0).into()), offset: value, base_type: generic_type(), }) } constants::DW_OP_regx => { let register = bytes.read_uleb128().and_then(Register::from_u64)?; Ok(Operation::Register { register }) } constants::DW_OP_fbreg => { let value = bytes.read_sleb128()?; Ok(Operation::FrameOffset { offset: value }) } constants::DW_OP_bregx => { let register = bytes.read_uleb128().and_then(Register::from_u64)?; let offset = bytes.read_sleb128()?; Ok(Operation::RegisterOffset { register, offset, base_type: generic_type(), }) } constants::DW_OP_piece => { let size = bytes.read_uleb128()?; Ok(Operation::Piece { size_in_bits: 8 * size, bit_offset: None, }) } constants::DW_OP_deref_size => { let size = bytes.read_u8()?; Ok(Operation::Deref { base_type: generic_type(), size, space: false, }) } constants::DW_OP_xderef_size => { let size = bytes.read_u8()?; Ok(Operation::Deref { base_type: generic_type(), size, space: true, }) } constants::DW_OP_nop => Ok(Operation::Nop), constants::DW_OP_push_object_address => Ok(Operation::PushObjectAddress), constants::DW_OP_call2 => { let value = bytes.read_u16().map(R::Offset::from_u16)?; Ok(Operation::Call { offset: DieReference::UnitRef(UnitOffset(value)), }) } constants::DW_OP_call4 => { let value = bytes.read_u32().map(R::Offset::from_u32)?; Ok(Operation::Call { offset: DieReference::UnitRef(UnitOffset(value)), }) } constants::DW_OP_call_ref => { let value = bytes.read_offset(encoding.format)?; Ok(Operation::Call { offset: DieReference::DebugInfoRef(DebugInfoOffset(value)), }) } constants::DW_OP_form_tls_address | constants::DW_OP_GNU_push_tls_address => { Ok(Operation::TLS) } constants::DW_OP_call_frame_cfa => Ok(Operation::CallFrameCFA), constants::DW_OP_bit_piece => { let size = bytes.read_uleb128()?; let offset = bytes.read_uleb128()?; Ok(Operation::Piece { size_in_bits: size, bit_offset: Some(offset), }) } constants::DW_OP_implicit_value => { let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; let data = bytes.split(len)?; Ok(Operation::ImplicitValue { data }) } constants::DW_OP_stack_value => Ok(Operation::StackValue), constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => { let value = bytes.read_offset(encoding.format)?; let byte_offset = bytes.read_sleb128()?; Ok(Operation::ImplicitPointer { value: DebugInfoOffset(value), byte_offset, }) } constants::DW_OP_addrx => { let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::AddressIndex { index: DebugAddrIndex(index), }) } constants::DW_OP_constx => { let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::ConstantIndex { index: DebugAddrIndex(index), }) } constants::DW_OP_entry_value | constants::DW_OP_GNU_entry_value => { let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; let expression = bytes.split(len)?; Ok(Operation::EntryValue { expression }) } constants::DW_OP_GNU_parameter_ref => { let value = bytes.read_u32().map(R::Offset::from_u32)?; Ok(Operation::ParameterRef { offset: UnitOffset(value), }) } constants::DW_OP_const_type | constants::DW_OP_GNU_const_type => { let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; let len = bytes.read_u8()?; let value = bytes.split(R::Offset::from_u8(len))?; Ok(Operation::TypedLiteral { base_type: UnitOffset(base_type), value, }) } constants::DW_OP_regval_type | constants::DW_OP_GNU_regval_type => { let register = bytes.read_uleb128().and_then(Register::from_u64)?; let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::RegisterOffset { register, offset: 0, base_type: UnitOffset(base_type), }) } constants::DW_OP_deref_type | constants::DW_OP_GNU_deref_type => { let size = bytes.read_u8()?; let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::Deref { base_type: UnitOffset(base_type), size, space: false, }) } constants::DW_OP_xderef_type => { let size = bytes.read_u8()?; let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::Deref { base_type: UnitOffset(base_type), size, space: true, }) } constants::DW_OP_convert | constants::DW_OP_GNU_convert => { let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::Convert { base_type: UnitOffset(base_type), }) } constants::DW_OP_reinterpret | constants::DW_OP_GNU_reinterpret => { let base_type = bytes.read_uleb128().and_then(R::Offset::from_u64)?; Ok(Operation::Reinterpret { base_type: UnitOffset(base_type), }) } _ => Err(Error::InvalidExpression(name)), } } } #[derive(Debug)] enum EvaluationState { Start(Option), Ready, Error(Error), Complete, Waiting(EvaluationWaiting), } #[derive(Debug)] enum EvaluationWaiting { Memory, Register { offset: i64 }, FrameBase { offset: i64 }, Tls, Cfa, AtLocation, EntryValue, ParameterRef, RelocatedAddress, IndexedAddress, TypedLiteral { value: R }, Convert, Reinterpret, } /// The state of an `Evaluation` after evaluating a DWARF expression. /// The evaluation is either `Complete`, or it requires more data /// to continue, as described by the variant. #[derive(Debug, PartialEq)] pub enum EvaluationResult { /// The `Evaluation` is complete, and `Evaluation::result()` can be called. Complete, /// The `Evaluation` needs a value from memory to proceed further. Once the /// caller determines what value to provide it should resume the `Evaluation` /// by calling `Evaluation::resume_with_memory`. RequiresMemory { /// The address of the value required. address: u64, /// The size of the value required. This is guaranteed to be at most the /// word size of the target architecture. size: u8, /// If not `None`, a target-specific address space value. space: Option, /// The DIE of the base type or 0 to indicate the generic type base_type: UnitOffset, }, /// The `Evaluation` needs a value from a register to proceed further. Once /// the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_register`. RequiresRegister { /// The register number. register: Register, /// The DIE of the base type or 0 to indicate the generic type base_type: UnitOffset, }, /// The `Evaluation` needs the frame base address to proceed further. Once /// the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_frame_base`. The frame /// base address is the address produced by the location description in the /// `DW_AT_frame_base` attribute of the current function. RequiresFrameBase, /// The `Evaluation` needs a value from TLS to proceed further. Once the /// caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_tls`. RequiresTls(u64), /// The `Evaluation` needs the CFA to proceed further. Once the caller /// determines what value to provide it should resume the `Evaluation` by /// calling `Evaluation::resume_with_call_frame_cfa`. RequiresCallFrameCfa, /// The `Evaluation` needs the DWARF expression at the given location to /// proceed further. Once the caller determines what value to provide it /// should resume the `Evaluation` by calling /// `Evaluation::resume_with_at_location`. RequiresAtLocation(DieReference), /// The `Evaluation` needs the value produced by evaluating a DWARF /// expression at the entry point of the current subprogram. Once the /// caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_entry_value`. RequiresEntryValue(Expression), /// The `Evaluation` needs the value of the parameter at the given location /// in the current function's caller. Once the caller determines what value /// to provide it should resume the `Evaluation` by calling /// `Evaluation::resume_with_parameter_ref`. RequiresParameterRef(UnitOffset), /// The `Evaluation` needs an address to be relocated to proceed further. /// Once the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`. RequiresRelocatedAddress(u64), /// The `Evaluation` needs an address from the `.debug_addr` section. /// This address may also need to be relocated. /// Once the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_indexed_address`. RequiresIndexedAddress { /// The index of the address in the `.debug_addr` section, /// relative to the `DW_AT_addr_base` of the compilation unit. index: DebugAddrIndex, /// Whether the address also needs to be relocated. relocate: bool, }, /// The `Evaluation` needs the `ValueType` for the base type DIE at /// the give unit offset. Once the caller determines what value to provide it /// should resume the `Evaluation` by calling /// `Evaluation::resume_with_base_type`. RequiresBaseType(UnitOffset), } /// The bytecode for a DWARF expression or location description. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Expression(pub R); impl Expression { /// Create an evaluation for this expression. /// /// The `encoding` is determined by the /// [`CompilationUnitHeader`](struct.CompilationUnitHeader.html) or /// [`TypeUnitHeader`](struct.TypeUnitHeader.html) that this expression /// relates to. /// /// # Examples /// ```rust,no_run /// use gimli::Expression; /// # let endian = gimli::LittleEndian; /// # let debug_info = gimli::DebugInfo::from(gimli::EndianSlice::new(&[], endian)); /// # let unit = debug_info.units().next().unwrap().unwrap(); /// # let bytecode = gimli::EndianSlice::new(&[], endian); /// let expression = gimli::Expression(bytecode); /// let mut eval = expression.evaluation(unit.encoding()); /// let mut result = eval.evaluate().unwrap(); /// ``` #[inline] pub fn evaluation(self, encoding: Encoding) -> Evaluation { Evaluation::new(self.0, encoding) } } /// A DWARF expression evaluator. /// /// # Usage /// A DWARF expression may require additional data to produce a final result, /// such as the value of a register or a memory location. Once initial setup /// is complete (i.e. `set_initial_value()`, `set_object_address()`) the /// consumer calls the `evaluate()` method. That returns an `EvaluationResult`, /// which is either `EvaluationResult::Complete` or a value indicating what /// data is needed to resume the `Evaluation`. The consumer is responsible for /// producing that data and resuming the computation with the correct method, /// as documented for `EvaluationResult`. Only once an `EvaluationResult::Complete` /// is returned can the consumer call `result()`. /// /// This design allows the consumer of `Evaluation` to decide how and when to /// produce the required data and resume the computation. The `Evaluation` can /// be driven synchronously (as shown below) or by some asynchronous mechanism /// such as futures. /// /// # Examples /// ```rust,no_run /// use gimli::{EndianSlice, Evaluation, EvaluationResult, Format, LittleEndian, Value}; /// # let bytecode = EndianSlice::new(&[], LittleEndian); /// # let encoding = unimplemented!(); /// # let get_register_value = |_, _| Value::Generic(42); /// # let get_frame_base = || 0xdeadbeef; /// /// let mut eval = Evaluation::new(bytecode, encoding); /// let mut result = eval.evaluate().unwrap(); /// while result != EvaluationResult::Complete { /// match result { /// EvaluationResult::RequiresRegister { register, base_type } => { /// let value = get_register_value(register, base_type); /// result = eval.resume_with_register(value).unwrap(); /// }, /// EvaluationResult::RequiresFrameBase => { /// let frame_base = get_frame_base(); /// result = eval.resume_with_frame_base(frame_base).unwrap(); /// }, /// _ => unimplemented!(), /// }; /// } /// /// let result = eval.result(); /// println!("{:?}", result); /// ``` #[derive(Debug)] pub struct Evaluation { bytecode: R, encoding: Encoding, object_address: Option, max_iterations: Option, iteration: u32, state: EvaluationState, // Stack operations are done on word-sized values. We do all // operations on 64-bit values, and then mask the results // appropriately when popping. addr_mask: u64, // The stack. stack: Vec, // The next operation to decode and evaluate. pc: R, // If we see a DW_OP_call* operation, the previous PC and bytecode // is stored here while evaluating the subroutine. expression_stack: Vec<(R, R)>, result: Vec>, } impl Evaluation { /// Create a new DWARF expression evaluator. /// /// The new evaluator is created without an initial value, without /// an object address, and without a maximum number of iterations. pub fn new(bytecode: R, encoding: Encoding) -> Evaluation { let pc = bytecode.clone(); Evaluation { bytecode, encoding, object_address: None, max_iterations: None, iteration: 0, state: EvaluationState::Start(None), addr_mask: if encoding.address_size == 8 { !0u64 } else { (1 << (8 * u64::from(encoding.address_size))) - 1 }, stack: Vec::new(), expression_stack: Vec::new(), pc, result: Vec::new(), } } /// Set an initial value to be pushed on the DWARF expression /// evaluator's stack. This can be used in cases like /// `DW_AT_vtable_elem_location`, which require a value on the /// stack before evaluation commences. If no initial value is /// set, and the expression uses an opcode requiring the initial /// value, then evaluation will fail with an error. /// /// # Panics /// Panics if `set_initial_value()` has already been called, or if /// `evaluate()` has already been called. pub fn set_initial_value(&mut self, value: u64) { match self.state { EvaluationState::Start(None) => { self.state = EvaluationState::Start(Some(value)); } _ => panic!( "`Evaluation::set_initial_value` was called twice, or after evaluation began." ), }; } /// Set the enclosing object's address, as used by /// `DW_OP_push_object_address`. If no object address is set, and /// the expression uses an opcode requiring the object address, /// then evaluation will fail with an error. pub fn set_object_address(&mut self, value: u64) { self.object_address = Some(value); } /// Set the maximum number of iterations to be allowed by the /// expression evaluator. /// /// An iteration corresponds approximately to the evaluation of a /// single operation in an expression ("approximately" because the /// implementation may allow two such operations in some cases). /// The default is not to have a maximum; once set, it's not /// possible to go back to this default state. This value can be /// set to avoid denial of service attacks by bad DWARF bytecode. pub fn set_max_iterations(&mut self, value: u32) { self.max_iterations = Some(value); } fn pop(&mut self) -> Result { match self.stack.pop() { Some(value) => Ok(value), None => Err(Error::NotEnoughStackItems), } } fn push(&mut self, value: Value) { self.stack.push(value); } #[allow(clippy::cyclomatic_complexity)] fn evaluate_one_operation(&mut self) -> Result> { let operation = Operation::parse(&mut self.pc, &self.bytecode, self.encoding)?; match operation { Operation::Deref { base_type, size, space, } => { let entry = self.pop()?; let addr = entry.to_u64(self.addr_mask)?; let addr_space = if space { let entry = self.pop()?; let value = entry.to_u64(self.addr_mask)?; Some(value) } else { None }; return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Memory, EvaluationResult::RequiresMemory { address: addr, size, space: addr_space, base_type, }, )); } Operation::Drop => { self.pop()?; } Operation::Pick { index } => { let len = self.stack.len(); let index = index as usize; if index >= len { return Err(Error::NotEnoughStackItems); } let value = self.stack[len - index - 1]; self.push(value); } Operation::Swap => { let top = self.pop()?; let next = self.pop()?; self.push(top); self.push(next); } Operation::Rot => { let one = self.pop()?; let two = self.pop()?; let three = self.pop()?; self.push(one); self.push(three); self.push(two); } Operation::Abs => { let value = self.pop()?; let result = value.abs(self.addr_mask)?; self.push(result); } Operation::And => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.and(rhs, self.addr_mask)?; self.push(result); } Operation::Div => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.div(rhs, self.addr_mask)?; self.push(result); } Operation::Minus => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.sub(rhs, self.addr_mask)?; self.push(result); } Operation::Mod => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.rem(rhs, self.addr_mask)?; self.push(result); } Operation::Mul => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.mul(rhs, self.addr_mask)?; self.push(result); } Operation::Neg => { let v = self.pop()?; let result = v.neg(self.addr_mask)?; self.push(result); } Operation::Not => { let value = self.pop()?; let result = value.not(self.addr_mask)?; self.push(result); } Operation::Or => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.or(rhs, self.addr_mask)?; self.push(result); } Operation::Plus => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.add(rhs, self.addr_mask)?; self.push(result); } Operation::PlusConstant { value } => { let lhs = self.pop()?; let rhs = Value::from_u64(lhs.value_type(), value)?; let result = lhs.add(rhs, self.addr_mask)?; self.push(result); } Operation::Shl => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.shl(rhs, self.addr_mask)?; self.push(result); } Operation::Shr => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.shr(rhs, self.addr_mask)?; self.push(result); } Operation::Shra => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.shra(rhs, self.addr_mask)?; self.push(result); } Operation::Xor => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.xor(rhs, self.addr_mask)?; self.push(result); } Operation::Bra { target } => { let entry = self.pop()?; let v = entry.to_u64(self.addr_mask)?; if v != 0 { self.pc = target.clone(); } } Operation::Eq => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.eq(rhs, self.addr_mask)?; self.push(result); } Operation::Ge => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.ge(rhs, self.addr_mask)?; self.push(result); } Operation::Gt => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.gt(rhs, self.addr_mask)?; self.push(result); } Operation::Le => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.le(rhs, self.addr_mask)?; self.push(result); } Operation::Lt => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.lt(rhs, self.addr_mask)?; self.push(result); } Operation::Ne => { let rhs = self.pop()?; let lhs = self.pop()?; let result = lhs.ne(rhs, self.addr_mask)?; self.push(result); } Operation::Skip { ref target } => { self.pc = target.clone(); } Operation::Literal { value } => { self.push(Value::Generic(value)); } Operation::RegisterOffset { register, offset, base_type, } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Register { offset }, EvaluationResult::RequiresRegister { register, base_type, }, )); } Operation::FrameOffset { offset } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::FrameBase { offset }, EvaluationResult::RequiresFrameBase, )); } Operation::Nop => {} Operation::PushObjectAddress => { if let Some(value) = self.object_address { self.push(Value::Generic(value)); } else { return Err(Error::InvalidPushObjectAddress); } } Operation::Call { offset } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::AtLocation, EvaluationResult::RequiresAtLocation(offset), )); } Operation::TLS => { let entry = self.pop()?; let index = entry.to_u64(self.addr_mask)?; return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Tls, EvaluationResult::RequiresTls(index), )); } Operation::CallFrameCFA => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Cfa, EvaluationResult::RequiresCallFrameCfa, )); } Operation::Register { register } => { let location = Location::Register { register }; return Ok(OperationEvaluationResult::Complete { location }); } Operation::ImplicitValue { ref data } => { let location = Location::Bytes { value: data.clone(), }; return Ok(OperationEvaluationResult::Complete { location }); } Operation::StackValue => { let value = self.pop()?; let location = Location::Value { value }; return Ok(OperationEvaluationResult::Complete { location }); } Operation::ImplicitPointer { value, byte_offset } => { let location = Location::ImplicitPointer { value, byte_offset }; return Ok(OperationEvaluationResult::Complete { location }); } Operation::EntryValue { ref expression } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::EntryValue, EvaluationResult::RequiresEntryValue(Expression(expression.clone())), )); } Operation::ParameterRef { offset } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::ParameterRef, EvaluationResult::RequiresParameterRef(offset), )); } Operation::Address { address } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::RelocatedAddress, EvaluationResult::RequiresRelocatedAddress(address), )); } Operation::AddressIndex { index } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::IndexedAddress, EvaluationResult::RequiresIndexedAddress { index, relocate: true, }, )); } Operation::ConstantIndex { index } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::IndexedAddress, EvaluationResult::RequiresIndexedAddress { index, relocate: false, }, )); } Operation::Piece { size_in_bits, bit_offset, } => { let location = if self.stack.is_empty() { Location::Empty } else { let entry = self.pop()?; let address = entry.to_u64(self.addr_mask)?; Location::Address { address } }; self.result.push(Piece { size_in_bits: Some(size_in_bits), bit_offset, location, }); return Ok(OperationEvaluationResult::Piece); } Operation::TypedLiteral { base_type, value } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::TypedLiteral { value }, EvaluationResult::RequiresBaseType(base_type), )); } Operation::Convert { base_type } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Convert, EvaluationResult::RequiresBaseType(base_type), )); } Operation::Reinterpret { base_type } => { return Ok(OperationEvaluationResult::Waiting( EvaluationWaiting::Reinterpret, EvaluationResult::RequiresBaseType(base_type), )); } } Ok(OperationEvaluationResult::Incomplete) } /// Get the result of this `Evaluation`. /// /// # Panics /// Panics if this `Evaluation` has not been driven to completion. pub fn result(self) -> Vec> { match self.state { EvaluationState::Complete => self.result, _ => { panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed") } } } /// Evaluate a DWARF expression. This method should only ever be called /// once. If the returned `EvaluationResult` is not /// `EvaluationResult::Complete`, the caller should provide the required /// value and resume the evaluation by calling the appropriate resume_with /// method on `Evaluation`. pub fn evaluate(&mut self) -> Result> { match self.state { EvaluationState::Start(initial_value) => { if let Some(value) = initial_value { self.push(Value::Generic(value)); } self.state = EvaluationState::Ready; } EvaluationState::Ready => {} EvaluationState::Error(err) => return Err(err), EvaluationState::Complete => return Ok(EvaluationResult::Complete), EvaluationState::Waiting(_) => panic!(), }; match self.evaluate_internal() { Ok(r) => Ok(r), Err(e) => { self.state = EvaluationState::Error(e); Err(e) } } } /// Resume the `Evaluation` with the provided memory `value`. This will apply /// the provided memory value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresMemory`. pub fn resume_with_memory(&mut self, value: Value) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::Memory) => { self.push(value); } _ => panic!( "Called `Evaluation::resume_with_memory` without a preceding `EvaluationResult::RequiresMemory`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `register` value. This will apply /// the provided register value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresRegister`. pub fn resume_with_register(&mut self, value: Value) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::Register { offset }) => { let offset = Value::from_u64(value.value_type(), offset as u64)?; let value = value.add(offset, self.addr_mask)?; self.push(value); } _ => panic!( "Called `Evaluation::resume_with_register` without a preceding `EvaluationResult::RequiresRegister`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `frame_base`. This will /// apply the provided frame base value to the evaluation and continue /// evaluating opcodes until the evaluation is completed, reaches an error, /// or needs more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresFrameBase`. pub fn resume_with_frame_base(&mut self, frame_base: u64) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::FrameBase { offset }) => { self.push(Value::Generic(frame_base.wrapping_add(offset as u64))); } _ => panic!( "Called `Evaluation::resume_with_frame_base` without a preceding `EvaluationResult::RequiresFrameBase`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `value`. This will apply /// the provided TLS value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresTls`. pub fn resume_with_tls(&mut self, value: u64) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::Tls) => { self.push(Value::Generic(value)); } _ => panic!( "Called `Evaluation::resume_with_tls` without a preceding `EvaluationResult::RequiresTls`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `cfa`. This will /// apply the provided CFA value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresCallFrameCfa`. pub fn resume_with_call_frame_cfa(&mut self, cfa: u64) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::Cfa) => { self.push(Value::Generic(cfa)); } _ => panic!( "Called `Evaluation::resume_with_call_frame_cfa` without a preceding `EvaluationResult::RequiresCallFrameCfa`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `bytes`. This will /// continue processing the evaluation with the new expression provided /// until the evaluation is completed, reaches an error, or needs more /// information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresAtLocation`. pub fn resume_with_at_location(&mut self, mut bytes: R) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::AtLocation) => { if !bytes.is_empty() { let mut pc = bytes.clone(); mem::swap(&mut pc, &mut self.pc); mem::swap(&mut bytes, &mut self.bytecode); self.expression_stack.push((pc, bytes)); } } _ => panic!( "Called `Evaluation::resume_with_at_location` without a precedeing `EvaluationResult::RequiresAtLocation`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `entry_value`. This will /// apply the provided entry value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresEntryValue`. pub fn resume_with_entry_value(&mut self, entry_value: Value) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::EntryValue) => { self.push(entry_value); } _ => panic!( "Called `Evaluation::resume_with_entry_value` without a preceding `EvaluationResult::RequiresEntryValue`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `parameter_value`. This will /// apply the provided parameter value to the evaluation and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresParameterRef`. pub fn resume_with_parameter_ref( &mut self, parameter_value: u64, ) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::ParameterRef) => { self.push(Value::Generic(parameter_value)); } _ => panic!( "Called `Evaluation::resume_with_parameter_ref` without a preceding `EvaluationResult::RequiresParameterRef`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided relocated `address`. This will use the /// provided relocated address for the operation that required it, and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with /// `EvaluationResult::RequiresRelocatedAddress`. pub fn resume_with_relocated_address(&mut self, address: u64) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::RelocatedAddress) => { self.push(Value::Generic(address)); } _ => panic!( "Called `Evaluation::resume_with_relocated_address` without a preceding `EvaluationResult::RequiresRelocatedAddress`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided indexed `address`. This will use the /// provided indexed address for the operation that required it, and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with /// `EvaluationResult::RequiresIndexedAddress`. pub fn resume_with_indexed_address(&mut self, address: u64) -> Result> { match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::IndexedAddress) => { self.push(Value::Generic(address)); } _ => panic!( "Called `Evaluation::resume_with_indexed_address` without a preceding `EvaluationResult::RequiresIndexedAddress`" ), }; self.evaluate_internal() } /// Resume the `Evaluation` with the provided `base_type`. This will use the /// provided base type for the operation that required it, and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs /// more information again. /// /// # Panics /// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresBaseType`. pub fn resume_with_base_type(&mut self, base_type: ValueType) -> Result> { let value = match self.state { EvaluationState::Error(err) => return Err(err), EvaluationState::Waiting(EvaluationWaiting::TypedLiteral { ref value }) => { Value::parse(base_type, value.clone())? } EvaluationState::Waiting(EvaluationWaiting::Convert) => { let entry = self.pop()?; entry.convert(base_type, self.addr_mask)? } EvaluationState::Waiting(EvaluationWaiting::Reinterpret) => { let entry = self.pop()?; entry.reinterpret(base_type, self.addr_mask)? } _ => panic!( "Called `Evaluation::resume_with_base_type` without a preceding `EvaluationResult::RequiresBaseType`" ), }; self.push(value); self.evaluate_internal() } fn end_of_expression(&mut self) -> bool { while self.pc.is_empty() { match self.expression_stack.pop() { Some((newpc, newbytes)) => { self.pc = newpc; self.bytecode = newbytes; } None => return true, } } false } fn evaluate_internal(&mut self) -> Result> { while !self.end_of_expression() { self.iteration += 1; if let Some(max_iterations) = self.max_iterations { if self.iteration > max_iterations { return Err(Error::TooManyIterations); } } let op_result = self.evaluate_one_operation()?; match op_result { OperationEvaluationResult::Piece => {} OperationEvaluationResult::Incomplete => { if self.end_of_expression() && !self.result.is_empty() { // We saw a piece earlier and then some // unterminated piece. It's not clear this is // well-defined. return Err(Error::InvalidPiece); } } OperationEvaluationResult::Complete { location } => { if self.end_of_expression() { if !self.result.is_empty() { // We saw a piece earlier and then some // unterminated piece. It's not clear this is // well-defined. return Err(Error::InvalidPiece); } self.result.push(Piece { size_in_bits: None, bit_offset: None, location, }); } else { // If there are more operations, then the next operation must // be a Piece. match Operation::parse(&mut self.pc, &self.bytecode, self.encoding)? { Operation::Piece { size_in_bits, bit_offset, } => { self.result.push(Piece { size_in_bits: Some(size_in_bits), bit_offset, location, }); } _ => { let value = self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1; return Err(Error::InvalidExpressionTerminator(value)); } } } } OperationEvaluationResult::Waiting(waiting, result) => { self.state = EvaluationState::Waiting(waiting); return Ok(result); } }; } // If no pieces have been seen, use the stack top as the // result. if self.result.is_empty() { let entry = self.pop()?; let addr = entry.to_u64(self.addr_mask)?; self.result.push(Piece { size_in_bits: None, bit_offset: None, location: Location::Address { address: addr }, }); } self.state = EvaluationState::Complete; Ok(EvaluationResult::Complete) } } #[cfg(test)] mod tests { use super::*; use crate::common::Format; use crate::constants; use crate::endianity::LittleEndian; use crate::leb128; use crate::read::{EndianSlice, Error, Result, UnitOffset}; use crate::test_util::GimliSectionMethods; use std::usize; use test_assembler::{Endian, Section}; fn encoding4() -> Encoding { Encoding { format: Format::Dwarf32, version: 4, address_size: 4, } } fn encoding8() -> Encoding { Encoding { format: Format::Dwarf64, version: 4, address_size: 8, } } #[test] fn test_compute_pc() { // Contents don't matter for this test, just length. let bytes = [0, 1, 2, 3, 4]; let bytecode = &bytes[..]; let ebuf = &EndianSlice::new(bytecode, LittleEndian); assert_eq!(compute_pc(ebuf, ebuf, 0), Ok(*ebuf)); assert_eq!( compute_pc(ebuf, ebuf, -1), Err(Error::BadBranchTarget(usize::MAX as u64)) ); assert_eq!(compute_pc(ebuf, ebuf, 5), Ok(ebuf.range_from(5..))); assert_eq!( compute_pc(&ebuf.range_from(3..), ebuf, -2), Ok(ebuf.range_from(1..)) ); assert_eq!( compute_pc(&ebuf.range_from(2..), ebuf, 2), Ok(ebuf.range_from(4..)) ); } fn check_op_parse_simple<'input>( input: &'input [u8], expect: &Operation>, encoding: Encoding, ) { let buf = EndianSlice::new(input, LittleEndian); let mut pc = buf; let value = Operation::parse(&mut pc, &buf, encoding); match value { Ok(val) => { assert_eq!(val, *expect); assert_eq!(pc.len(), 0); } _ => panic!("Unexpected result"), } } fn check_op_parse_failure(input: &[u8], expect: Error, encoding: Encoding) { let buf = EndianSlice::new(input, LittleEndian); let mut pc = buf; match Operation::parse(&mut pc, &buf, encoding) { Err(x) => { assert_eq!(x, expect); } _ => panic!("Unexpected result"), } } fn check_op_parse_eof(input: &[u8], encoding: Encoding) { let buf = EndianSlice::new(input, LittleEndian); let mut pc = buf; match Operation::parse(&mut pc, &buf, encoding) { Err(Error::UnexpectedEof(id)) => { assert!(buf.lookup_offset_id(id).is_some()); } _ => panic!("Unexpected result"), } } fn check_op_parse( input: F, expect: &Operation>, encoding: Encoding, ) where F: Fn(Section) -> Section, { let input = input(Section::with_endian(Endian::Little)) .get_contents() .unwrap(); for i in 1..input.len() { check_op_parse_eof(&input[..i], encoding); } check_op_parse_simple(&input, expect, encoding); } #[test] fn test_op_parse_onebyte() { // Doesn't matter for this test. let encoding = encoding4(); // Test all single-byte opcodes. #[rustfmt::skip] let inputs = [ ( constants::DW_OP_deref, Operation::Deref { base_type: generic_type(), size: encoding.address_size, space: false, }, ), (constants::DW_OP_dup, Operation::Pick { index: 0 }), (constants::DW_OP_drop, Operation::Drop), (constants::DW_OP_over, Operation::Pick { index: 1 }), (constants::DW_OP_swap, Operation::Swap), (constants::DW_OP_rot, Operation::Rot), ( constants::DW_OP_xderef, Operation::Deref { base_type: generic_type(), size: encoding.address_size, space: true, }, ), (constants::DW_OP_abs, Operation::Abs), (constants::DW_OP_and, Operation::And), (constants::DW_OP_div, Operation::Div), (constants::DW_OP_minus, Operation::Minus), (constants::DW_OP_mod, Operation::Mod), (constants::DW_OP_mul, Operation::Mul), (constants::DW_OP_neg, Operation::Neg), (constants::DW_OP_not, Operation::Not), (constants::DW_OP_or, Operation::Or), (constants::DW_OP_plus, Operation::Plus), (constants::DW_OP_shl, Operation::Shl), (constants::DW_OP_shr, Operation::Shr), (constants::DW_OP_shra, Operation::Shra), (constants::DW_OP_xor, Operation::Xor), (constants::DW_OP_eq, Operation::Eq), (constants::DW_OP_ge, Operation::Ge), (constants::DW_OP_gt, Operation::Gt), (constants::DW_OP_le, Operation::Le), (constants::DW_OP_lt, Operation::Lt), (constants::DW_OP_ne, Operation::Ne), (constants::DW_OP_lit0, Operation::Literal { value: 0 }), (constants::DW_OP_lit1, Operation::Literal { value: 1 }), (constants::DW_OP_lit2, Operation::Literal { value: 2 }), (constants::DW_OP_lit3, Operation::Literal { value: 3 }), (constants::DW_OP_lit4, Operation::Literal { value: 4 }), (constants::DW_OP_lit5, Operation::Literal { value: 5 }), (constants::DW_OP_lit6, Operation::Literal { value: 6 }), (constants::DW_OP_lit7, Operation::Literal { value: 7 }), (constants::DW_OP_lit8, Operation::Literal { value: 8 }), (constants::DW_OP_lit9, Operation::Literal { value: 9 }), (constants::DW_OP_lit10, Operation::Literal { value: 10 }), (constants::DW_OP_lit11, Operation::Literal { value: 11 }), (constants::DW_OP_lit12, Operation::Literal { value: 12 }), (constants::DW_OP_lit13, Operation::Literal { value: 13 }), (constants::DW_OP_lit14, Operation::Literal { value: 14 }), (constants::DW_OP_lit15, Operation::Literal { value: 15 }), (constants::DW_OP_lit16, Operation::Literal { value: 16 }), (constants::DW_OP_lit17, Operation::Literal { value: 17 }), (constants::DW_OP_lit18, Operation::Literal { value: 18 }), (constants::DW_OP_lit19, Operation::Literal { value: 19 }), (constants::DW_OP_lit20, Operation::Literal { value: 20 }), (constants::DW_OP_lit21, Operation::Literal { value: 21 }), (constants::DW_OP_lit22, Operation::Literal { value: 22 }), (constants::DW_OP_lit23, Operation::Literal { value: 23 }), (constants::DW_OP_lit24, Operation::Literal { value: 24 }), (constants::DW_OP_lit25, Operation::Literal { value: 25 }), (constants::DW_OP_lit26, Operation::Literal { value: 26 }), (constants::DW_OP_lit27, Operation::Literal { value: 27 }), (constants::DW_OP_lit28, Operation::Literal { value: 28 }), (constants::DW_OP_lit29, Operation::Literal { value: 29 }), (constants::DW_OP_lit30, Operation::Literal { value: 30 }), (constants::DW_OP_lit31, Operation::Literal { value: 31 }), (constants::DW_OP_reg0, Operation::Register { register: Register(0) }), (constants::DW_OP_reg1, Operation::Register { register: Register(1) }), (constants::DW_OP_reg2, Operation::Register { register: Register(2) }), (constants::DW_OP_reg3, Operation::Register { register: Register(3) }), (constants::DW_OP_reg4, Operation::Register { register: Register(4) }), (constants::DW_OP_reg5, Operation::Register { register: Register(5) }), (constants::DW_OP_reg6, Operation::Register { register: Register(6) }), (constants::DW_OP_reg7, Operation::Register { register: Register(7) }), (constants::DW_OP_reg8, Operation::Register { register: Register(8) }), (constants::DW_OP_reg9, Operation::Register { register: Register(9) }), (constants::DW_OP_reg10, Operation::Register { register: Register(10) }), (constants::DW_OP_reg11, Operation::Register { register: Register(11) }), (constants::DW_OP_reg12, Operation::Register { register: Register(12) }), (constants::DW_OP_reg13, Operation::Register { register: Register(13) }), (constants::DW_OP_reg14, Operation::Register { register: Register(14) }), (constants::DW_OP_reg15, Operation::Register { register: Register(15) }), (constants::DW_OP_reg16, Operation::Register { register: Register(16) }), (constants::DW_OP_reg17, Operation::Register { register: Register(17) }), (constants::DW_OP_reg18, Operation::Register { register: Register(18) }), (constants::DW_OP_reg19, Operation::Register { register: Register(19) }), (constants::DW_OP_reg20, Operation::Register { register: Register(20) }), (constants::DW_OP_reg21, Operation::Register { register: Register(21) }), (constants::DW_OP_reg22, Operation::Register { register: Register(22) }), (constants::DW_OP_reg23, Operation::Register { register: Register(23) }), (constants::DW_OP_reg24, Operation::Register { register: Register(24) }), (constants::DW_OP_reg25, Operation::Register { register: Register(25) }), (constants::DW_OP_reg26, Operation::Register { register: Register(26) }), (constants::DW_OP_reg27, Operation::Register { register: Register(27) }), (constants::DW_OP_reg28, Operation::Register { register: Register(28) }), (constants::DW_OP_reg29, Operation::Register { register: Register(29) }), (constants::DW_OP_reg30, Operation::Register { register: Register(30) }), (constants::DW_OP_reg31, Operation::Register { register: Register(31) }), (constants::DW_OP_nop, Operation::Nop), (constants::DW_OP_push_object_address, Operation::PushObjectAddress), (constants::DW_OP_form_tls_address, Operation::TLS), (constants::DW_OP_GNU_push_tls_address, Operation::TLS), (constants::DW_OP_call_frame_cfa, Operation::CallFrameCFA), (constants::DW_OP_stack_value, Operation::StackValue), ]; let input = []; check_op_parse_eof(&input[..], encoding); for item in inputs.iter() { let (opcode, ref result) = *item; check_op_parse(|s| s.D8(opcode.0), result, encoding); } } #[test] fn test_op_parse_twobyte() { // Doesn't matter for this test. let encoding = encoding4(); let inputs = [ ( constants::DW_OP_const1u, 23, Operation::Literal { value: 23 }, ), ( constants::DW_OP_const1s, (-23i8) as u8, Operation::Literal { value: (-23i64) as u64, }, ), (constants::DW_OP_pick, 7, Operation::Pick { index: 7 }), ( constants::DW_OP_deref_size, 19, Operation::Deref { base_type: generic_type(), size: 19, space: false, }, ), ( constants::DW_OP_xderef_size, 19, Operation::Deref { base_type: generic_type(), size: 19, space: true, }, ), ]; for item in inputs.iter() { let (opcode, arg, ref result) = *item; check_op_parse(|s| s.D8(opcode.0).D8(arg), result, encoding); } } #[test] fn test_op_parse_threebyte() { // Doesn't matter for this test. let encoding = encoding4(); // While bra and skip are 3-byte opcodes, they aren't tested here, // but rather specially in their own function. let inputs = [ ( constants::DW_OP_const2u, 23, Operation::Literal { value: 23 }, ), ( constants::DW_OP_const2s, (-23i16) as u16, Operation::Literal { value: (-23i64) as u64, }, ), ( constants::DW_OP_call2, 1138, Operation::Call { offset: DieReference::UnitRef(UnitOffset(1138)), }, ), ]; for item in inputs.iter() { let (opcode, arg, ref result) = *item; check_op_parse(|s| s.D8(opcode.0).L16(arg), result, encoding); } } #[test] fn test_op_parse_branches() { // Doesn't matter for this test. const ENCODING: Encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let inputs = [constants::DW_OP_bra, constants::DW_OP_skip]; fn check_one_branch(input: &[u8], target: &[u8]) { // Test sanity checking. assert!(input.len() >= 3); let expect = if input[0] == constants::DW_OP_bra.0 { Operation::Bra { target: EndianSlice::new(target, LittleEndian), } } else { assert!(input[0] == constants::DW_OP_skip.0); Operation::Skip { target: EndianSlice::new(target, LittleEndian), } }; check_op_parse(|s| s.append_bytes(input), &expect, ENCODING); } for opcode in inputs.iter() { // Branch to start. let input = [opcode.0, 0xfd, 0xff]; check_one_branch(&input[..], &input[..]); // Branch to middle of an instruction -- ok as far as DWARF is // concerned. let input = [opcode.0, 0xfe, 0xff]; check_one_branch(&input[..], &input[1..]); // Branch to end. DWARF is silent on this but it seems valid // to branch to just after the last operation. let input = [opcode.0, 0, 0]; check_one_branch(&input[..], &input[3..]); // Invalid branches. let input = [opcode.0, 2, 0]; check_op_parse_failure(&input[..], Error::BadBranchTarget(5), ENCODING); let input = [opcode.0, 0xfc, 0xff]; check_op_parse_failure( &input[..], Error::BadBranchTarget(usize::MAX as u64), ENCODING, ); } } #[test] fn test_op_parse_fivebyte() { // There are some tests here that depend on address size. let encoding = encoding4(); let inputs = [ ( constants::DW_OP_addr, 0x1234_5678, Operation::Address { address: 0x1234_5678, }, ), ( constants::DW_OP_const4u, 0x1234_5678, Operation::Literal { value: 0x1234_5678 }, ), ( constants::DW_OP_const4s, (-23i32) as u32, Operation::Literal { value: (-23i32) as u64, }, ), ( constants::DW_OP_call4, 0x1234_5678, Operation::Call { offset: DieReference::UnitRef(UnitOffset(0x1234_5678)), }, ), ( constants::DW_OP_call_ref, 0x1234_5678, Operation::Call { offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678)), }, ), ]; for item in inputs.iter() { let (op, arg, ref expect) = *item; check_op_parse(|s| s.D8(op.0).L32(arg), expect, encoding); } } #[test] #[cfg(target_pointer_width = "64")] fn test_op_parse_ninebyte() { // There are some tests here that depend on address size. let encoding = encoding8(); let inputs = [ ( constants::DW_OP_addr, 0x1234_5678_1234_5678, Operation::Address { address: 0x1234_5678_1234_5678, }, ), ( constants::DW_OP_const8u, 0x1234_5678_1234_5678, Operation::Literal { value: 0x1234_5678_1234_5678, }, ), ( constants::DW_OP_const8s, (-23i32) as u64, Operation::Literal { value: (-23i32) as u64, }, ), ( constants::DW_OP_call_ref, 0x1234_5678_1234_5678, Operation::Call { offset: DieReference::DebugInfoRef(DebugInfoOffset(0x1234_5678_1234_5678)), }, ), ]; for item in inputs.iter() { let (op, arg, ref expect) = *item; check_op_parse(|s| s.D8(op.0).L64(arg), expect, encoding); } } #[test] fn test_op_parse_sleb() { // Doesn't matter for this test. let encoding = encoding4(); let values = [ -1i64, 0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, -0x100, -0x1eee_eeee, -0x7fff_ffff_ffff_ffff, ]; for value in values.iter() { let mut inputs = vec![ ( constants::DW_OP_consts.0, Operation::Literal { value: *value as u64, }, ), ( constants::DW_OP_fbreg.0, Operation::FrameOffset { offset: *value }, ), ]; for i in 0..32 { inputs.push(( constants::DW_OP_breg0.0 + i, Operation::RegisterOffset { register: Register(i.into()), offset: *value, base_type: UnitOffset(0), }, )); } for item in inputs.iter() { let (op, ref expect) = *item; check_op_parse(|s| s.D8(op).sleb(*value), expect, encoding); } } } #[test] fn test_op_parse_uleb() { // Doesn't matter for this test. let encoding = encoding4(); let values = [ 0, 1, 0x100, (!0u16).into(), 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, !0u64, ]; for value in values.iter() { let mut inputs = vec![ ( constants::DW_OP_constu, Operation::Literal { value: *value }, ), ( constants::DW_OP_plus_uconst, Operation::PlusConstant { value: *value }, ), ]; if *value <= (!0u16).into() { inputs.push(( constants::DW_OP_regx, Operation::Register { register: Register::from_u64(*value).unwrap(), }, )); } if *value <= (!0u32).into() { inputs.extend(&[ ( constants::DW_OP_addrx, Operation::AddressIndex { index: DebugAddrIndex(*value as usize), }, ), ( constants::DW_OP_constx, Operation::ConstantIndex { index: DebugAddrIndex(*value as usize), }, ), ]); } // FIXME if *value < !0u64 / 8 { inputs.push(( constants::DW_OP_piece, Operation::Piece { size_in_bits: 8 * value, bit_offset: None, }, )); } for item in inputs.iter() { let (op, ref expect) = *item; let input = Section::with_endian(Endian::Little) .D8(op.0) .uleb(*value) .get_contents() .unwrap(); check_op_parse_simple(&input, expect, encoding); } } } #[test] fn test_op_parse_bregx() { // Doesn't matter for this test. let encoding = encoding4(); let uvalues = [0, 1, 0x100, !0u16]; let svalues = [ -1i64, 0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, -0x100, -0x1eee_eeee, -0x7fff_ffff_ffff_ffff, ]; for v1 in uvalues.iter() { for v2 in svalues.iter() { check_op_parse( |s| s.D8(constants::DW_OP_bregx.0).uleb((*v1).into()).sleb(*v2), &Operation::RegisterOffset { register: Register(*v1), offset: *v2, base_type: UnitOffset(0), }, encoding, ); } } } #[test] fn test_op_parse_bit_piece() { // Doesn't matter for this test. let encoding = encoding4(); let values = [0, 1, 0x100, 0x1eee_eeee, 0x7fff_ffff_ffff_ffff, !0u64]; for v1 in values.iter() { for v2 in values.iter() { let input = Section::with_endian(Endian::Little) .D8(constants::DW_OP_bit_piece.0) .uleb(*v1) .uleb(*v2) .get_contents() .unwrap(); check_op_parse_simple( &input, &Operation::Piece { size_in_bits: *v1, bit_offset: Some(*v2), }, encoding, ); } } } #[test] fn test_op_parse_implicit_value() { // Doesn't matter for this test. let encoding = encoding4(); let data = b"hello"; check_op_parse( |s| { s.D8(constants::DW_OP_implicit_value.0) .uleb(data.len() as u64) .append_bytes(&data[..]) }, &Operation::ImplicitValue { data: EndianSlice::new(&data[..], LittleEndian), }, encoding, ); } #[test] fn test_op_parse_const_type() { // Doesn't matter for this test. let encoding = encoding4(); let data = b"hello"; check_op_parse( |s| { s.D8(constants::DW_OP_const_type.0) .uleb(100) .D8(data.len() as u8) .append_bytes(&data[..]) }, &Operation::TypedLiteral { base_type: UnitOffset(100), value: EndianSlice::new(&data[..], LittleEndian), }, encoding, ); check_op_parse( |s| { s.D8(constants::DW_OP_GNU_const_type.0) .uleb(100) .D8(data.len() as u8) .append_bytes(&data[..]) }, &Operation::TypedLiteral { base_type: UnitOffset(100), value: EndianSlice::new(&data[..], LittleEndian), }, encoding, ); } #[test] fn test_op_parse_regval_type() { // Doesn't matter for this test. let encoding = encoding4(); check_op_parse( |s| s.D8(constants::DW_OP_regval_type.0).uleb(1).uleb(100), &Operation::RegisterOffset { register: Register(1), offset: 0, base_type: UnitOffset(100), }, encoding, ); check_op_parse( |s| s.D8(constants::DW_OP_GNU_regval_type.0).uleb(1).uleb(100), &Operation::RegisterOffset { register: Register(1), offset: 0, base_type: UnitOffset(100), }, encoding, ); } #[test] fn test_op_parse_deref_type() { // Doesn't matter for this test. let encoding = encoding4(); check_op_parse( |s| s.D8(constants::DW_OP_deref_type.0).D8(8).uleb(100), &Operation::Deref { base_type: UnitOffset(100), size: 8, space: false, }, encoding, ); check_op_parse( |s| s.D8(constants::DW_OP_GNU_deref_type.0).D8(8).uleb(100), &Operation::Deref { base_type: UnitOffset(100), size: 8, space: false, }, encoding, ); check_op_parse( |s| s.D8(constants::DW_OP_xderef_type.0).D8(8).uleb(100), &Operation::Deref { base_type: UnitOffset(100), size: 8, space: true, }, encoding, ); } #[test] fn test_op_convert() { // Doesn't matter for this test. let encoding = encoding4(); check_op_parse( |s| s.D8(constants::DW_OP_convert.0).uleb(100), &Operation::Convert { base_type: UnitOffset(100), }, encoding, ); check_op_parse( |s| s.D8(constants::DW_OP_GNU_convert.0).uleb(100), &Operation::Convert { base_type: UnitOffset(100), }, encoding, ); } #[test] fn test_op_reinterpret() { // Doesn't matter for this test. let encoding = encoding4(); check_op_parse( |s| s.D8(constants::DW_OP_reinterpret.0).uleb(100), &Operation::Reinterpret { base_type: UnitOffset(100), }, encoding, ); check_op_parse( |s| s.D8(constants::DW_OP_GNU_reinterpret.0).uleb(100), &Operation::Reinterpret { base_type: UnitOffset(100), }, encoding, ); } #[test] fn test_op_parse_implicit_pointer() { for op in &[ constants::DW_OP_implicit_pointer, constants::DW_OP_GNU_implicit_pointer, ] { check_op_parse( |s| s.D8(op.0).D32(0x1234_5678).sleb(0x123), &Operation::ImplicitPointer { value: DebugInfoOffset(0x1234_5678), byte_offset: 0x123, }, encoding4(), ); check_op_parse( |s| s.D8(op.0).D64(0x1234_5678).sleb(0x123), &Operation::ImplicitPointer { value: DebugInfoOffset(0x1234_5678), byte_offset: 0x123, }, encoding8(), ); } } #[test] fn test_op_parse_entry_value() { for op in &[ constants::DW_OP_entry_value, constants::DW_OP_GNU_entry_value, ] { let data = b"hello"; check_op_parse( |s| s.D8(op.0).uleb(data.len() as u64).append_bytes(&data[..]), &Operation::EntryValue { expression: EndianSlice::new(&data[..], LittleEndian), }, encoding4(), ); } } #[test] fn test_op_parse_gnu_parameter_ref() { check_op_parse( |s| s.D8(constants::DW_OP_GNU_parameter_ref.0).D32(0x1234_5678), &Operation::ParameterRef { offset: UnitOffset(0x1234_5678), }, encoding4(), ) } enum AssemblerEntry { Op(constants::DwOp), Mark(u8), Branch(u8), U8(u8), U16(u16), U32(u32), U64(u64), Uleb(u64), Sleb(u64), } fn assemble(entries: &[AssemblerEntry]) -> Vec { let mut result = Vec::new(); struct Marker(Option, Vec); let mut markers = Vec::new(); for _ in 0..256 { markers.push(Marker(None, Vec::new())); } fn write(stack: &mut Vec, index: usize, mut num: u64, nbytes: u8) { for i in 0..nbytes as usize { stack[index + i] = (num & 0xff) as u8; num >>= 8; } } fn push(stack: &mut Vec, num: u64, nbytes: u8) { let index = stack.len(); for _ in 0..nbytes { stack.push(0); } write(stack, index, num, nbytes); } for item in entries { match *item { AssemblerEntry::Op(op) => result.push(op.0), AssemblerEntry::Mark(num) => { assert!(markers[num as usize].0.is_none()); markers[num as usize].0 = Some(result.len()); } AssemblerEntry::Branch(num) => { markers[num as usize].1.push(result.len()); push(&mut result, 0, 2); } AssemblerEntry::U8(num) => result.push(num), AssemblerEntry::U16(num) => push(&mut result, u64::from(num), 2), AssemblerEntry::U32(num) => push(&mut result, u64::from(num), 4), AssemblerEntry::U64(num) => push(&mut result, num, 8), AssemblerEntry::Uleb(num) => { leb128::write::unsigned(&mut result, num).unwrap(); } AssemblerEntry::Sleb(num) => { leb128::write::signed(&mut result, num as i64).unwrap(); } } } // Update all the branches. for marker in markers { if let Some(offset) = marker.0 { for branch_offset in marker.1 { let delta = offset.wrapping_sub(branch_offset + 2) as u64; write(&mut result, branch_offset, delta, 2); } } } result } #[allow(clippy::too_many_arguments)] fn check_eval_with_args( program: &[AssemblerEntry], expect: Result<&[Piece>]>, encoding: Encoding, object_address: Option, initial_value: Option, max_iterations: Option, f: F, ) where for<'a> F: Fn( &mut Evaluation>, EvaluationResult>, ) -> Result>>, { let bytes = assemble(program); let bytes = EndianSlice::new(&bytes, LittleEndian); let mut eval = Evaluation::new(bytes, encoding); if let Some(val) = object_address { eval.set_object_address(val); } if let Some(val) = initial_value { eval.set_initial_value(val); } if let Some(val) = max_iterations { eval.set_max_iterations(val); } let result = match eval.evaluate() { Err(e) => Err(e), Ok(r) => f(&mut eval, r), }; match (result, expect) { (Ok(EvaluationResult::Complete), Ok(pieces)) => { let vec = eval.result(); assert_eq!(vec.len(), pieces.len()); for i in 0..pieces.len() { assert_eq!(vec[i], pieces[i]); } } (Err(f1), Err(f2)) => { assert_eq!(f1, f2); } otherwise => panic!("Unexpected result: {:?}", otherwise), } } fn check_eval( program: &[AssemblerEntry], expect: Result<&[Piece>]>, encoding: Encoding, ) { check_eval_with_args(program, expect, encoding, None, None, None, |_, result| { Ok(result) }); } #[test] fn test_eval_arith() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Indices of marks in the assembly. let done = 0; let fail = 1; #[rustfmt::skip] let program = [ Op(DW_OP_const1u), U8(23), Op(DW_OP_const1s), U8((-23i8) as u8), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const2u), U16(23), Op(DW_OP_const2s), U16((-23i16) as u16), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4u), U32(0x1111_2222), Op(DW_OP_const4s), U32((-0x1111_2222i32) as u32), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), // Plus should overflow. Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1u), U8(1), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_plus_uconst), Uleb(1), Op(DW_OP_bra), Branch(fail), // Minus should underflow. Op(DW_OP_const1s), U8(0), Op(DW_OP_const1u), U8(1), Op(DW_OP_minus), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_abs), Op(DW_OP_const1u), U8(1), Op(DW_OP_minus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4u), U32(0xf078_fffe), Op(DW_OP_const4u), U32(0x0f87_0001), Op(DW_OP_and), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4u), U32(0xf078_fffe), Op(DW_OP_const4u), U32(0xf000_00fe), Op(DW_OP_and), Op(DW_OP_const4u), U32(0xf000_00fe), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), // Division is signed. Op(DW_OP_const1s), U8(0xfe), Op(DW_OP_const1s), U8(2), Op(DW_OP_div), Op(DW_OP_plus_uconst), Uleb(1), Op(DW_OP_bra), Branch(fail), // Mod is unsigned. Op(DW_OP_const1s), U8(0xfd), Op(DW_OP_const1s), U8(2), Op(DW_OP_mod), Op(DW_OP_neg), Op(DW_OP_plus_uconst), Uleb(1), Op(DW_OP_bra), Branch(fail), // Overflow is defined for multiplication. Op(DW_OP_const4u), U32(0x8000_0001), Op(DW_OP_lit2), Op(DW_OP_mul), Op(DW_OP_lit2), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4u), U32(0xf0f0_f0f0), Op(DW_OP_const4u), U32(0xf0f0_f0f0), Op(DW_OP_xor), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4u), U32(0xf0f0_f0f0), Op(DW_OP_const4u), U32(0x0f0f_0f0f), Op(DW_OP_or), Op(DW_OP_not), Op(DW_OP_bra), Branch(fail), // In 32 bit mode, values are truncated. Op(DW_OP_const8u), U64(0xffff_ffff_0000_0000), Op(DW_OP_lit2), Op(DW_OP_div), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1u), U8(0xff), Op(DW_OP_lit1), Op(DW_OP_shl), Op(DW_OP_const2u), U16(0x1fe), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1u), U8(0xff), Op(DW_OP_const1u), U8(50), Op(DW_OP_shl), Op(DW_OP_bra), Branch(fail), // Absurd shift. Op(DW_OP_const1u), U8(0xff), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_shl), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_lit1), Op(DW_OP_shr), Op(DW_OP_const4u), U32(0x7fff_ffff), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1u), U8(0xff), Op(DW_OP_shr), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_lit1), Op(DW_OP_shra), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1u), U8(0xff), Op(DW_OP_shra), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), // Success. Op(DW_OP_lit0), Op(DW_OP_nop), Op(DW_OP_skip), Branch(done), Mark(fail), Op(DW_OP_lit1), Mark(done), Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0), }, }]; check_eval(&program, Ok(&result), encoding4()); } #[test] fn test_eval_arith64() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Indices of marks in the assembly. let done = 0; let fail = 1; #[rustfmt::skip] let program = [ Op(DW_OP_const8u), U64(0x1111_2222_3333_4444), Op(DW_OP_const8s), U64((-0x1111_2222_3333_4444i64) as u64), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_constu), Uleb(0x1111_2222_3333_4444), Op(DW_OP_consts), Sleb((-0x1111_2222_3333_4444i64) as u64), Op(DW_OP_plus), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit1), Op(DW_OP_plus_uconst), Uleb(!0u64), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit1), Op(DW_OP_neg), Op(DW_OP_not), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), Op(DW_OP_const1u), U8(63), Op(DW_OP_shr), Op(DW_OP_lit1), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), Op(DW_OP_const1u), U8(62), Op(DW_OP_shra), Op(DW_OP_plus_uconst), Uleb(2), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit1), Op(DW_OP_const1u), U8(63), Op(DW_OP_shl), Op(DW_OP_const8u), U64(0x8000_0000_0000_0000), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), // Success. Op(DW_OP_lit0), Op(DW_OP_nop), Op(DW_OP_skip), Branch(done), Mark(fail), Op(DW_OP_lit1), Mark(done), Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0), }, }]; check_eval(&program, Ok(&result), encoding8()); } #[test] fn test_eval_compare() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Indices of marks in the assembly. let done = 0; let fail = 1; #[rustfmt::skip] let program = [ // Comparisons are signed. Op(DW_OP_const1s), U8(1), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_lt), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1s), U8(1), Op(DW_OP_gt), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(1), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_le), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1s), U8(1), Op(DW_OP_ge), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const1s), U8(0xff), Op(DW_OP_const1s), U8(1), Op(DW_OP_eq), Op(DW_OP_bra), Branch(fail), Op(DW_OP_const4s), U32(1), Op(DW_OP_const1s), U8(1), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), // Success. Op(DW_OP_lit0), Op(DW_OP_nop), Op(DW_OP_skip), Branch(done), Mark(fail), Op(DW_OP_lit1), Mark(done), Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0), }, }]; check_eval(&program, Ok(&result), encoding4()); } #[test] fn test_eval_stack() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; #[rustfmt::skip] let program = [ Op(DW_OP_lit17), // -- 17 Op(DW_OP_dup), // -- 17 17 Op(DW_OP_over), // -- 17 17 17 Op(DW_OP_minus), // -- 17 0 Op(DW_OP_swap), // -- 0 17 Op(DW_OP_dup), // -- 0 17 17 Op(DW_OP_plus_uconst), Uleb(1), // -- 0 17 18 Op(DW_OP_rot), // -- 18 0 17 Op(DW_OP_pick), U8(2), // -- 18 0 17 18 Op(DW_OP_pick), U8(3), // -- 18 0 17 18 18 Op(DW_OP_minus), // -- 18 0 17 0 Op(DW_OP_drop), // -- 18 0 17 Op(DW_OP_swap), // -- 18 17 0 Op(DW_OP_drop), // -- 18 17 Op(DW_OP_minus), // -- 1 Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(1), }, }]; check_eval(&program, Ok(&result), encoding4()); } #[test] fn test_eval_lit_and_reg() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; let mut program = Vec::new(); program.push(Op(DW_OP_lit0)); for i in 0..32 { program.push(Op(DwOp(DW_OP_lit0.0 + i))); program.push(Op(DwOp(DW_OP_breg0.0 + i))); program.push(Sleb(u64::from(i))); program.push(Op(DW_OP_plus)); program.push(Op(DW_OP_plus)); } program.push(Op(DW_OP_bregx)); program.push(Uleb(0x1234)); program.push(Sleb(0x1234)); program.push(Op(DW_OP_plus)); program.push(Op(DW_OP_stack_value)); let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(496), }, }]; check_eval_with_args( &program, Ok(&result), encoding4(), None, None, None, |eval, mut result| { while result != EvaluationResult::Complete { result = eval.resume_with_register(match result { EvaluationResult::RequiresRegister { register, base_type, } => { assert_eq!(base_type, UnitOffset(0)); Value::Generic(u64::from(register.0).wrapping_neg()) } _ => panic!(), })?; } Ok(result) }, ); } #[test] fn test_eval_memory() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Indices of marks in the assembly. let done = 0; let fail = 1; #[rustfmt::skip] let program = [ Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_deref), Op(DW_OP_const4u), U32(0xffff_fffc), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_deref_size), U8(2), Op(DW_OP_const4u), U32(0xfffc), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit1), Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_xderef), Op(DW_OP_const4u), U32(0xffff_fffd), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit1), Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_xderef_size), U8(2), Op(DW_OP_const4u), U32(0xfffd), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit17), Op(DW_OP_form_tls_address), Op(DW_OP_constu), Uleb(!17), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_lit17), Op(DW_OP_GNU_push_tls_address), Op(DW_OP_constu), Uleb(!17), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_addrx), Uleb(0x10), Op(DW_OP_deref), Op(DW_OP_const4u), U32(0x4040), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), Op(DW_OP_constx), Uleb(17), Op(DW_OP_form_tls_address), Op(DW_OP_constu), Uleb(!27), Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), // Success. Op(DW_OP_lit0), Op(DW_OP_nop), Op(DW_OP_skip), Branch(done), Mark(fail), Op(DW_OP_lit1), Mark(done), Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0), }, }]; check_eval_with_args( &program, Ok(&result), encoding4(), None, None, None, |eval, mut result| { while result != EvaluationResult::Complete { result = match result { EvaluationResult::RequiresMemory { address, size, space, base_type, } => { assert_eq!(base_type, UnitOffset(0)); let mut v = address << 2; if let Some(value) = space { v += value; } v &= (1u64 << (8 * size)) - 1; eval.resume_with_memory(Value::Generic(v))? } EvaluationResult::RequiresTls(slot) => eval.resume_with_tls(!slot)?, EvaluationResult::RequiresRelocatedAddress(address) => { eval.resume_with_relocated_address(address)? } EvaluationResult::RequiresIndexedAddress { index, relocate } => { if relocate { eval.resume_with_indexed_address(0x1000 + index.0 as u64)? } else { eval.resume_with_indexed_address(10 + index.0 as u64)? } } _ => panic!(), }; } Ok(result) }, ); } #[test] fn test_eval_register() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; for i in 0..32 { #[rustfmt::skip] let program = [ Op(DwOp(DW_OP_reg0.0 + i)), // Included only in the "bad" run. Op(DW_OP_lit23), ]; let ok_result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Register { register: Register(i.into()), }, }]; check_eval(&program[..1], Ok(&ok_result), encoding4()); check_eval( &program, Err(Error::InvalidExpressionTerminator(1)), encoding4(), ); } #[rustfmt::skip] let program = [ Op(DW_OP_regx), Uleb(0x1234) ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Register { register: Register(0x1234), }, }]; check_eval(&program, Ok(&result), encoding4()); } #[test] fn test_eval_context() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Test `frame_base` and `call_frame_cfa` callbacks. #[rustfmt::skip] let program = [ Op(DW_OP_fbreg), Sleb((-8i8) as u64), Op(DW_OP_call_frame_cfa), Op(DW_OP_plus), Op(DW_OP_neg), Op(DW_OP_stack_value) ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(9), }, }]; check_eval_with_args( &program, Ok(&result), encoding8(), None, None, None, |eval, result| { match result { EvaluationResult::RequiresFrameBase => {} _ => panic!(), }; match eval.resume_with_frame_base(0x0123_4567_89ab_cdef)? { EvaluationResult::RequiresCallFrameCfa => {} _ => panic!(), }; eval.resume_with_call_frame_cfa(0xfedc_ba98_7654_3210) }, ); // Test `evaluate_entry_value` callback. #[rustfmt::skip] let program = [ Op(DW_OP_entry_value), Uleb(8), U64(0x1234_5678), Op(DW_OP_stack_value) ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0x1234_5678), }, }]; check_eval_with_args( &program, Ok(&result), encoding8(), None, None, None, |eval, result| { let entry_value = match result { EvaluationResult::RequiresEntryValue(mut expression) => { expression.0.read_u64()? } _ => panic!(), }; eval.resume_with_entry_value(Value::Generic(entry_value)) }, ); // Test missing `object_address` field. #[rustfmt::skip] let program = [ Op(DW_OP_push_object_address), ]; check_eval_with_args( &program, Err(Error::InvalidPushObjectAddress), encoding4(), None, None, None, |_, _| panic!(), ); // Test `object_address` field. #[rustfmt::skip] let program = [ Op(DW_OP_push_object_address), Op(DW_OP_stack_value), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(0xff), }, }]; check_eval_with_args( &program, Ok(&result), encoding8(), Some(0xff), None, None, |_, result| Ok(result), ); // Test `initial_value` field. #[rustfmt::skip] let program = [ ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Address { address: 0x1234_5678, }, }]; check_eval_with_args( &program, Ok(&result), encoding8(), None, Some(0x1234_5678), None, |_, result| Ok(result), ); } #[test] fn test_eval_empty_stack() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; #[rustfmt::skip] let program = [ Op(DW_OP_stack_value) ]; check_eval(&program, Err(Error::NotEnoughStackItems), encoding4()); } #[test] fn test_eval_call() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; #[rustfmt::skip] let program = [ Op(DW_OP_lit23), Op(DW_OP_call2), U16(0x7755), Op(DW_OP_call4), U32(0x7755_aaee), Op(DW_OP_call_ref), U32(0x7755_aaee), Op(DW_OP_stack_value) ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(23), }, }]; check_eval_with_args( &program, Ok(&result), encoding4(), None, None, None, |eval, result| { let buf = EndianSlice::new(&[], LittleEndian); match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf)?; match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf)?; match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf) }, ); // DW_OP_lit2 DW_OP_mul const SUBR: &[u8] = &[0x32, 0x1e]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value: Value::Generic(184), }, }]; check_eval_with_args( &program, Ok(&result), encoding4(), None, None, None, |eval, result| { let buf = EndianSlice::new(SUBR, LittleEndian); match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf)?; match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf)?; match result { EvaluationResult::RequiresAtLocation(_) => {} _ => panic!(), }; eval.resume_with_at_location(buf) }, ); } #[test] fn test_eval_pieces() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; // Example from DWARF 2.6.1.3. #[rustfmt::skip] let program = [ Op(DW_OP_reg3), Op(DW_OP_piece), Uleb(4), Op(DW_OP_reg4), Op(DW_OP_piece), Uleb(2), ]; let result = [ Piece { size_in_bits: Some(32), bit_offset: None, location: Location::Register { register: Register(3), }, }, Piece { size_in_bits: Some(16), bit_offset: None, location: Location::Register { register: Register(4), }, }, ]; check_eval(&program, Ok(&result), encoding4()); // Example from DWARF 2.6.1.3 (but hacked since dealing with fbreg // in the tests is a pain). #[rustfmt::skip] let program = [ Op(DW_OP_reg0), Op(DW_OP_piece), Uleb(4), Op(DW_OP_piece), Uleb(4), Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_piece), Uleb(4), ]; let result = [ Piece { size_in_bits: Some(32), bit_offset: None, location: Location::Register { register: Register(0), }, }, Piece { size_in_bits: Some(32), bit_offset: None, location: Location::Empty, }, Piece { size_in_bits: Some(32), bit_offset: None, location: Location::Address { address: 0x7fff_ffff, }, }, ]; check_eval_with_args( &program, Ok(&result), encoding4(), None, None, None, |eval, mut result| { while result != EvaluationResult::Complete { result = match result { EvaluationResult::RequiresRelocatedAddress(address) => { eval.resume_with_relocated_address(address)? } _ => panic!(), }; } Ok(result) }, ); #[rustfmt::skip] let program = [ Op(DW_OP_implicit_value), Uleb(5), U8(23), U8(24), U8(25), U8(26), U8(0), ]; const BYTES: &[u8] = &[23, 24, 25, 26, 0]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Bytes { value: EndianSlice::new(BYTES, LittleEndian), }, }]; check_eval(&program, Ok(&result), encoding4()); #[rustfmt::skip] let program = [ Op(DW_OP_lit7), Op(DW_OP_stack_value), Op(DW_OP_bit_piece), Uleb(5), Uleb(0), Op(DW_OP_bit_piece), Uleb(3), Uleb(0), ]; let result = [ Piece { size_in_bits: Some(5), bit_offset: Some(0), location: Location::Value { value: Value::Generic(7), }, }, Piece { size_in_bits: Some(3), bit_offset: Some(0), location: Location::Empty, }, ]; check_eval(&program, Ok(&result), encoding4()); #[rustfmt::skip] let program = [ Op(DW_OP_lit7), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Address { address: 7 }, }]; check_eval(&program, Ok(&result), encoding4()); #[rustfmt::skip] let program = [ Op(DW_OP_implicit_pointer), U32(0x1234_5678), Sleb(0x123), ]; let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::ImplicitPointer { value: DebugInfoOffset(0x1234_5678), byte_offset: 0x123, }, }]; check_eval(&program, Ok(&result), encoding4()); #[rustfmt::skip] let program = [ Op(DW_OP_reg3), Op(DW_OP_piece), Uleb(4), Op(DW_OP_reg4), ]; check_eval(&program, Err(Error::InvalidPiece), encoding4()); #[rustfmt::skip] let program = [ Op(DW_OP_reg3), Op(DW_OP_piece), Uleb(4), Op(DW_OP_lit0), ]; check_eval(&program, Err(Error::InvalidPiece), encoding4()); } #[test] fn test_eval_max_iterations() { // It's nice if an operation and its arguments can fit on a single // line in the test program. use self::AssemblerEntry::*; use crate::constants::*; #[rustfmt::skip] let program = [ Mark(1), Op(DW_OP_skip), Branch(1), ]; check_eval_with_args( &program, Err(Error::TooManyIterations), encoding4(), None, None, Some(150), |_, _| panic!(), ); } #[test] fn test_eval_typed_stack() { use self::AssemblerEntry::*; use crate::constants::*; let base_types = [ ValueType::Generic, ValueType::U16, ValueType::U32, ValueType::F32, ]; // TODO: convert, reinterpret #[rustfmt::skip] let tests = [ ( &[ Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), Op(DW_OP_stack_value), ][..], Value::U16(0x1234), ), ( &[ Op(DW_OP_regval_type), Uleb(0x1234), Uleb(1), Op(DW_OP_stack_value), ][..], Value::U16(0x2340), ), ( &[ Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_deref_type), U8(2), Uleb(1), Op(DW_OP_stack_value), ][..], Value::U16(0xfff0), ), ( &[ Op(DW_OP_lit1), Op(DW_OP_addr), U32(0x7fff_ffff), Op(DW_OP_xderef_type), U8(2), Uleb(1), Op(DW_OP_stack_value), ][..], Value::U16(0xfff1), ), ( &[ Op(DW_OP_const_type), Uleb(1), U8(2), U16(0x1234), Op(DW_OP_convert), Uleb(2), Op(DW_OP_stack_value), ][..], Value::U32(0x1234), ), ( &[ Op(DW_OP_const_type), Uleb(2), U8(4), U32(0x3f80_0000), Op(DW_OP_reinterpret), Uleb(3), Op(DW_OP_stack_value), ][..], Value::F32(1.0), ), ]; for &(program, value) in &tests { let result = [Piece { size_in_bits: None, bit_offset: None, location: Location::Value { value }, }]; check_eval_with_args( program, Ok(&result), encoding4(), None, None, None, |eval, mut result| { while result != EvaluationResult::Complete { result = match result { EvaluationResult::RequiresMemory { address, size, space, base_type, } => { let mut v = address << 4; if let Some(value) = space { v += value; } v &= (1u64 << (8 * size)) - 1; let v = Value::from_u64(base_types[base_type.0], v)?; eval.resume_with_memory(v)? } EvaluationResult::RequiresRegister { register, base_type, } => { let v = Value::from_u64( base_types[base_type.0], u64::from(register.0) << 4, )?; eval.resume_with_register(v)? } EvaluationResult::RequiresBaseType(offset) => { eval.resume_with_base_type(base_types[offset.0])? } EvaluationResult::RequiresRelocatedAddress(address) => { eval.resume_with_relocated_address(address)? } _ => panic!("Unexpected result {:?}", result), } } Ok(result) }, ); } } } gimli-0.19.0/src/read/pubnames.rs010066400017500001750000000107421346020377600150230ustar0000000000000000use fallible_iterator::FallibleIterator; use crate::common::{DebugInfoOffset, SectionId}; use crate::endianity::Endianity; use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; use crate::read::{EndianSlice, Error, Reader, Result, Section, UnitOffset}; /// A single parsed pubname. #[derive(Debug, Clone)] pub struct PubNamesEntry { unit_header_offset: DebugInfoOffset, die_offset: UnitOffset, name: R, } impl PubNamesEntry { /// Returns the name this entry refers to. pub fn name(&self) -> &R { &self.name } /// Returns the offset into the .debug_info section for the header of the compilation unit /// which contains this name. pub fn unit_header_offset(&self) -> DebugInfoOffset { self.unit_header_offset } /// Returns the offset into the compilation unit for the debugging information entry which /// has this name. pub fn die_offset(&self) -> UnitOffset { self.die_offset } } impl PubStuffEntry for PubNamesEntry { fn new( die_offset: UnitOffset, name: R, unit_header_offset: DebugInfoOffset, ) -> Self { PubNamesEntry { unit_header_offset, die_offset, name, } } } /// The `DebugPubNames` struct represents the DWARF public names information /// found in the `.debug_pubnames` section. #[derive(Debug, Clone)] pub struct DebugPubNames(DebugLookup>>); impl<'input, Endian> DebugPubNames> where Endian: Endianity, { /// Construct a new `DebugPubNames` instance from the data in the `.debug_pubnames` /// section. /// /// It is the caller's responsibility to read the `.debug_pubnames` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugPubNames, LittleEndian}; /// /// # let buf = []; /// # let read_debug_pubnames_section_somehow = || &buf; /// let debug_pubnames = /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); /// ``` pub fn new(debug_pubnames_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_pubnames_section, endian)) } } impl DebugPubNames { /// Iterate the pubnames in the `.debug_pubnames` section. /// /// ``` /// use gimli::{DebugPubNames, EndianSlice, LittleEndian}; /// /// # let buf = []; /// # let read_debug_pubnames_section_somehow = || &buf; /// let debug_pubnames = /// DebugPubNames::new(read_debug_pubnames_section_somehow(), LittleEndian); /// /// let mut iter = debug_pubnames.items(); /// while let Some(pubname) = iter.next().unwrap() { /// println!("pubname {} found!", pubname.name().to_string_lossy()); /// } /// ``` pub fn items(&self) -> PubNamesEntryIter { PubNamesEntryIter(self.0.items()) } } impl Section for DebugPubNames { fn id() -> SectionId { SectionId::DebugPubNames } fn reader(&self) -> &R { self.0.reader() } } impl From for DebugPubNames { fn from(debug_pubnames_section: R) -> Self { DebugPubNames(DebugLookup::from(debug_pubnames_section)) } } /// An iterator over the pubnames from a `.debug_pubnames` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[derive(Debug, Clone)] pub struct PubNamesEntryIter(LookupEntryIter>>); impl PubNamesEntryIter { /// Advance the iterator and return the next pubname. /// /// Returns the newly parsed pubname as `Ok(Some(pubname))`. Returns /// `Ok(None)` when iteration is complete and all pubnames have already been /// parsed and yielded. If an error occurs while parsing the next pubname, /// then this error is returned as `Err(e)`, and all subsequent calls return /// `Ok(None)`. pub fn next(&mut self) -> Result>> { self.0.next() } } impl FallibleIterator for PubNamesEntryIter { type Item = PubNamesEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { self.0.next() } } gimli-0.19.0/src/read/pubtypes.rs010066400017500001750000000107621346020377600150660ustar0000000000000000use fallible_iterator::FallibleIterator; use crate::common::{DebugInfoOffset, SectionId}; use crate::endianity::Endianity; use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser}; use crate::read::{EndianSlice, Error, Reader, Result, Section, UnitOffset}; /// A single parsed pubtype. #[derive(Debug, Clone)] pub struct PubTypesEntry { unit_header_offset: DebugInfoOffset, die_offset: UnitOffset, name: R, } impl PubTypesEntry { /// Returns the name of the type this entry refers to. pub fn name(&self) -> &R { &self.name } /// Returns the offset into the .debug_info section for the header of the compilation unit /// which contains the type with this name. pub fn unit_header_offset(&self) -> DebugInfoOffset { self.unit_header_offset } /// Returns the offset into the compilation unit for the debugging information entry which /// the type with this name. pub fn die_offset(&self) -> UnitOffset { self.die_offset } } impl PubStuffEntry for PubTypesEntry { fn new( die_offset: UnitOffset, name: R, unit_header_offset: DebugInfoOffset, ) -> Self { PubTypesEntry { unit_header_offset, die_offset, name, } } } /// The `DebugPubTypes` struct represents the DWARF public types information /// found in the `.debug_info` section. #[derive(Debug, Clone)] pub struct DebugPubTypes(DebugLookup>>); impl<'input, Endian> DebugPubTypes> where Endian: Endianity, { /// Construct a new `DebugPubTypes` instance from the data in the `.debug_pubtypes` /// section. /// /// It is the caller's responsibility to read the `.debug_pubtypes` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugPubTypes, LittleEndian}; /// /// # let buf = []; /// # let read_debug_pubtypes_somehow = || &buf; /// let debug_pubtypes = /// DebugPubTypes::new(read_debug_pubtypes_somehow(), LittleEndian); /// ``` pub fn new(debug_pubtypes_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_pubtypes_section, endian)) } } impl DebugPubTypes { /// Iterate the pubtypes in the `.debug_pubtypes` section. /// /// ``` /// use gimli::{DebugPubTypes, EndianSlice, LittleEndian}; /// /// # let buf = []; /// # let read_debug_pubtypes_section_somehow = || &buf; /// let debug_pubtypes = /// DebugPubTypes::new(read_debug_pubtypes_section_somehow(), LittleEndian); /// /// let mut iter = debug_pubtypes.items(); /// while let Some(pubtype) = iter.next().unwrap() { /// println!("pubtype {} found!", pubtype.name().to_string_lossy()); /// } /// ``` pub fn items(&self) -> PubTypesEntryIter { PubTypesEntryIter(self.0.items()) } } impl Section for DebugPubTypes { fn id() -> SectionId { SectionId::DebugPubTypes } fn reader(&self) -> &R { self.0.reader() } } impl From for DebugPubTypes { fn from(debug_pubtypes_section: R) -> Self { DebugPubTypes(DebugLookup::from(debug_pubtypes_section)) } } /// An iterator over the pubtypes from a `.debug_pubtypes` section. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[derive(Debug, Clone)] pub struct PubTypesEntryIter(LookupEntryIter>>); impl PubTypesEntryIter { /// Advance the iterator and return the next pubtype. /// /// Returns the newly parsed pubtype as `Ok(Some(pubtype))`. Returns /// `Ok(None)` when iteration is complete and all pubtypes have already been /// parsed and yielded. If an error occurs while parsing the next pubtype, /// then this error is returned as `Err(e)`, and all subsequent calls return /// `Ok(None)`. pub fn next(&mut self) -> Result>> { self.0.next() } } impl FallibleIterator for PubTypesEntryIter { type Item = PubTypesEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { self.0.next() } } gimli-0.19.0/src/read/reader.rs010066400017500001750000000331771346020377600144620ustar0000000000000000use crate::borrow::Cow; use std::fmt::Debug; use std::hash::Hash; use std::ops::{Add, AddAssign, Sub}; use crate::common::Format; use crate::endianity::Endianity; use crate::leb128; use crate::read::{Error, Result}; /// An identifier for an offset within a section reader. /// /// This is used for error reporting. The meaning of this value is specific to /// each reader implementation. The values should be chosen to be unique amongst /// all readers. If values are not unique then errors may point to the wrong reader. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ReaderOffsetId(pub u64); /// A trait for offsets with a DWARF section. /// /// This allows consumers to choose a size that is appropriate for their address space. pub trait ReaderOffset: Debug + Copy + Eq + Ord + Hash + Add + AddAssign + Sub { /// Convert a u8 to an offset. fn from_u8(offset: u8) -> Self; /// Convert a u16 to an offset. fn from_u16(offset: u16) -> Self; /// Convert an i16 to an offset. fn from_i16(offset: i16) -> Self; /// Convert a u32 to an offset. fn from_u32(offset: u32) -> Self; /// Convert a u64 to an offset. /// /// Returns `Error::UnsupportedOffset` if the value is too large. fn from_u64(offset: u64) -> Result; /// Convert an offset to a u64. fn into_u64(self) -> u64; /// Wrapping (modular) addition. Computes `self + other`. fn wrapping_add(self, other: Self) -> Self; /// Checked subtraction. Computes `self - other`. fn checked_sub(self, other: Self) -> Option; } impl ReaderOffset for u64 { #[inline] fn from_u8(offset: u8) -> Self { u64::from(offset) } #[inline] fn from_u16(offset: u16) -> Self { u64::from(offset) } #[inline] fn from_i16(offset: i16) -> Self { offset as u64 } #[inline] fn from_u32(offset: u32) -> Self { u64::from(offset) } #[inline] fn from_u64(offset: u64) -> Result { Ok(offset) } #[inline] fn into_u64(self) -> u64 { self } #[inline] fn wrapping_add(self, other: Self) -> Self { self.wrapping_add(other) } #[inline] fn checked_sub(self, other: Self) -> Option { self.checked_sub(other) } } impl ReaderOffset for u32 { #[inline] fn from_u8(offset: u8) -> Self { u32::from(offset) } #[inline] fn from_u16(offset: u16) -> Self { u32::from(offset) } #[inline] fn from_i16(offset: i16) -> Self { offset as u32 } #[inline] fn from_u32(offset: u32) -> Self { offset } #[inline] fn from_u64(offset64: u64) -> Result { let offset = offset64 as u32; if u64::from(offset) == offset64 { Ok(offset) } else { Err(Error::UnsupportedOffset) } } #[inline] fn into_u64(self) -> u64 { u64::from(self) } #[inline] fn wrapping_add(self, other: Self) -> Self { self.wrapping_add(other) } #[inline] fn checked_sub(self, other: Self) -> Option { self.checked_sub(other) } } impl ReaderOffset for usize { #[inline] fn from_u8(offset: u8) -> Self { offset as usize } #[inline] fn from_u16(offset: u16) -> Self { offset as usize } #[inline] fn from_i16(offset: i16) -> Self { offset as usize } #[inline] fn from_u32(offset: u32) -> Self { offset as usize } #[inline] fn from_u64(offset64: u64) -> Result { let offset = offset64 as usize; if offset as u64 == offset64 { Ok(offset) } else { Err(Error::UnsupportedOffset) } } #[inline] fn into_u64(self) -> u64 { self as u64 } #[inline] fn wrapping_add(self, other: Self) -> Self { self.wrapping_add(other) } #[inline] fn checked_sub(self, other: Self) -> Option { self.checked_sub(other) } } /// A trait for reading the data from a DWARF section. /// /// All read operations advance the section offset of the reader /// unless specified otherwise. /// /// ## Choosing a `Reader` Implementation /// /// `gimli` comes with a few different `Reader` implementations and lets you /// choose the one that is right for your use case. A `Reader` is essentially a /// view into the raw bytes that make up some DWARF, but this view might borrow /// the underlying data or use reference counting ownership, and it might be /// thread safe or not. /// /// | Implementation | Ownership | Thread Safe | Notes | /// |:------------------|:------------------|:------------|:------| /// | [`EndianSlice`](./struct.EndianSlice.html) | Borrowed | Yes | Fastest, but requires that all of your code work with borrows. | /// | [`EndianRcSlice`](./struct.EndianRcSlice.html) | Reference counted | No | Shared ownership via reference counting, which alleviates the borrow restrictions of `EndianSlice` but imposes reference counting increments and decrements. Cannot be sent across threads, because the reference count is not atomic. | /// | [`EndianArcSlice`](./struct.EndianArcSlice.html) | Reference counted | Yes | The same as `EndianRcSlice`, but uses atomic reference counting, and therefore reference counting operations are slower but `EndianArcSlice`s may be sent across threads. | /// | [`EndianReader`](./struct.EndianReader.html) | Same as `T` | Same as `T` | Escape hatch for easily defining your own type of `Reader`. | pub trait Reader: Debug + Clone { /// The endianity of bytes that are read. type Endian: Endianity; /// The type used for offsets and lengths. type Offset: ReaderOffset; /// Return the endianity of bytes that are read. fn endian(&self) -> Self::Endian; /// Return the number of bytes remaining. fn len(&self) -> Self::Offset; /// Set the number of bytes remaining to zero. fn empty(&mut self); /// Set the number of bytes remaining to the specified length. fn truncate(&mut self, len: Self::Offset) -> Result<()>; /// Return the offset of this reader's data relative to the start of /// the given base reader's data. /// /// May panic if this reader's data is not contained within the given /// base reader's data. fn offset_from(&self, base: &Self) -> Self::Offset; /// Return an identifier for the current reader offset. fn offset_id(&self) -> ReaderOffsetId; /// Return the offset corresponding to the given `id` if /// it is associated with this reader. fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option; /// Find the index of the first occurence of the given byte. /// The offset of the reader is not changed. fn find(&self, byte: u8) -> Result; /// Discard the specified number of bytes. fn skip(&mut self, len: Self::Offset) -> Result<()>; /// Split a reader in two. /// /// A new reader is returned that can be used to read the next /// `len` bytes, and `self` is advanced so that it reads the remainder. fn split(&mut self, len: Self::Offset) -> Result; /// Return all remaining data as a clone-on-write slice. /// /// The slice will be borrowed where possible, but some readers may /// always return an owned vector. /// /// Does not advance the reader. fn to_slice(&self) -> Result>; /// Convert all remaining data to a clone-on-write string. /// /// The string will be borrowed where possible, but some readers may /// always return an owned string. /// /// Does not advance the reader. /// /// Returns an error if the data contains invalid characters. fn to_string(&self) -> Result>; /// Convert all remaining data to a clone-on-write string, including invalid characters. /// /// The string will be borrowed where possible, but some readers may /// always return an owned string. /// /// Does not advance the reader. fn to_string_lossy(&self) -> Result>; /// Read exactly `buf.len()` bytes into `buf`. fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>; /// Read a u8 array. #[inline] fn read_u8_array(&mut self) -> Result where A: Sized + Default + AsMut<[u8]>, { let mut val = Default::default(); self.read_slice(>::as_mut(&mut val))?; Ok(val) } /// Return true if the number of bytes remaining is zero. #[inline] fn is_empty(&self) -> bool { self.len() == Self::Offset::from_u8(0) } /// Read a u8. #[inline] fn read_u8(&mut self) -> Result { let a: [u8; 1] = self.read_u8_array()?; Ok(a[0]) } /// Read an i8. #[inline] fn read_i8(&mut self) -> Result { let a: [u8; 1] = self.read_u8_array()?; Ok(a[0] as i8) } /// Read a u16. #[inline] fn read_u16(&mut self) -> Result { let a: [u8; 2] = self.read_u8_array()?; Ok(self.endian().read_u16(&a)) } /// Read an i16. #[inline] fn read_i16(&mut self) -> Result { let a: [u8; 2] = self.read_u8_array()?; Ok(self.endian().read_i16(&a)) } /// Read a u32. #[inline] fn read_u32(&mut self) -> Result { let a: [u8; 4] = self.read_u8_array()?; Ok(self.endian().read_u32(&a)) } /// Read an i32. #[inline] fn read_i32(&mut self) -> Result { let a: [u8; 4] = self.read_u8_array()?; Ok(self.endian().read_i32(&a)) } /// Read a u64. #[inline] fn read_u64(&mut self) -> Result { let a: [u8; 8] = self.read_u8_array()?; Ok(self.endian().read_u64(&a)) } /// Read an i64. #[inline] fn read_i64(&mut self) -> Result { let a: [u8; 8] = self.read_u8_array()?; Ok(self.endian().read_i64(&a)) } /// Read a f32. #[inline] fn read_f32(&mut self) -> Result { let a: [u8; 4] = self.read_u8_array()?; Ok(self.endian().read_f32(&a)) } /// Read a f64. #[inline] fn read_f64(&mut self) -> Result { let a: [u8; 8] = self.read_u8_array()?; Ok(self.endian().read_f64(&a)) } /// Read an unsigned n-bytes integer u64. /// /// # Panics /// /// Panics when nbytes < 1 or nbytes > 8 #[inline] fn read_uint(&mut self, n: usize) -> Result { let mut buf = [0; 8]; self.read_slice(&mut buf[..n])?; Ok(self.endian().read_uint(&buf[..n])) } /// Read a null-terminated slice, and return it (excluding the null). fn read_null_terminated_slice(&mut self) -> Result { let idx = self.find(0)?; let val = self.split(idx)?; self.skip(Self::Offset::from_u8(1))?; Ok(val) } /// Read an unsigned LEB128 encoded integer. fn read_uleb128(&mut self) -> Result { leb128::read::unsigned(self) } /// Read a signed LEB128 encoded integer. fn read_sleb128(&mut self) -> Result { leb128::read::signed(self) } /// Read an initial length field. /// /// This field is encoded as either a 32-bit length or /// a 64-bit length, and the returned `Format` indicates which. fn read_initial_length(&mut self) -> Result<(Self::Offset, Format)> { const MAX_DWARF_32_UNIT_LENGTH: u32 = 0xffff_fff0; const DWARF_64_INITIAL_UNIT_LENGTH: u32 = 0xffff_ffff; let val = self.read_u32()?; if val < MAX_DWARF_32_UNIT_LENGTH { Ok((Self::Offset::from_u32(val), Format::Dwarf32)) } else if val == DWARF_64_INITIAL_UNIT_LENGTH { let val = self.read_u64().and_then(Self::Offset::from_u64)?; Ok((val, Format::Dwarf64)) } else { Err(Error::UnknownReservedLength) } } /// Read an address-sized integer, and return it as a `u64`. fn read_address(&mut self, address_size: u8) -> Result { match address_size { 1 => self.read_u8().map(u64::from), 2 => self.read_u16().map(u64::from), 4 => self.read_u32().map(u64::from), 8 => self.read_u64(), otherwise => Err(Error::UnsupportedAddressSize(otherwise)), } } /// Parse a word-sized integer according to the DWARF format. /// /// These are always used to encode section offsets or lengths, /// and so have a type of `Self::Offset`. fn read_word(&mut self, format: Format) -> Result { match format { Format::Dwarf32 => self.read_u32().map(Self::Offset::from_u32), Format::Dwarf64 => self.read_u64().and_then(Self::Offset::from_u64), } } /// Parse a word-sized section length according to the DWARF format. #[inline] fn read_length(&mut self, format: Format) -> Result { self.read_word(format) } /// Parse a word-sized section offset according to the DWARF format. #[inline] fn read_offset(&mut self, format: Format) -> Result { self.read_word(format) } /// Parse a section offset of the given size. /// /// This is used for `DW_FORM_ref_addr` values in DWARF version 2. fn read_sized_offset(&mut self, size: u8) -> Result { match size { 1 => self.read_u8().map(u64::from), 2 => self.read_u16().map(u64::from), 4 => self.read_u32().map(u64::from), 8 => self.read_u64(), otherwise => Err(Error::UnsupportedOffsetSize(otherwise)), } .and_then(Self::Offset::from_u64) } } gimli-0.19.0/src/read/rnglists.rs010066400017500001750000001210231346020377600150510ustar0000000000000000use fallible_iterator::FallibleIterator; use crate::common::{ DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, Encoding, Format, RangeListsOffset, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{ DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId, Result, Section, }; /// The raw contents of the `.debug_ranges` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugRanges { pub(crate) section: R, } impl<'input, Endian> DebugRanges> where Endian: Endianity, { /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges` /// section. /// /// It is the caller's responsibility to read the `.debug_ranges` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugRanges, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_ranges_section_somehow = || &buf; /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for DebugRanges { fn id() -> SectionId { SectionId::DebugRanges } fn reader(&self) -> &R { &self.section } } impl From for DebugRanges { fn from(section: R) -> Self { DebugRanges { section } } } /// The `DebugRngLists` struct represents the contents of the /// `.debug_rnglists` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugRngLists { section: R, } impl<'input, Endian> DebugRngLists> where Endian: Endianity, { /// Construct a new `DebugRngLists` instance from the data in the /// `.debug_rnglists` section. /// /// It is the caller's responsibility to read the `.debug_rnglists` /// section and present it as a `&[u8]` slice. That means using some ELF /// loader on Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugRngLists, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_rnglists_section_somehow = || &buf; /// let debug_rnglists = /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian); /// ``` pub fn new(section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(section, endian)) } } impl Section for DebugRngLists { fn id() -> SectionId { SectionId::DebugRngLists } fn reader(&self) -> &R { &self.section } } impl From for DebugRngLists { fn from(section: R) -> Self { DebugRngLists { section } } } #[derive(Debug, Clone, Copy)] struct RngListsHeader { encoding: Encoding, offset_entry_count: u32, } impl Default for RngListsHeader { fn default() -> Self { RngListsHeader { encoding: Encoding { format: Format::Dwarf32, version: 5, address_size: 0, }, offset_entry_count: 0, } } } impl RngListsHeader { /// Return the serialized size of the table header. #[allow(dead_code)] #[inline] fn size(self) -> u8 { // initial_length + version + address_size + segment_selector_size + offset_entry_count self.encoding.format.initial_length_size() + 2 + 1 + 1 + 4 } } // TODO: add an iterator over headers in the .debug_rnglists section #[allow(dead_code)] fn parse_header(input: &mut R) -> Result { let (length, format) = input.read_initial_length()?; input.truncate(length)?; let version = input.read_u16()?; if version != 5 { return Err(Error::UnknownVersion(u64::from(version))); } let address_size = input.read_u8()?; let segment_selector_size = input.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); } let offset_entry_count = input.read_u32()?; let encoding = Encoding { format, version, address_size, }; Ok(RngListsHeader { encoding, offset_entry_count, }) } /// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections. #[derive(Debug, Default, Clone, Copy)] pub struct RangeLists { debug_ranges: DebugRanges, debug_rnglists: DebugRngLists, } impl RangeLists { /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and /// `.debug_rnglists` sections. pub fn new(debug_ranges: DebugRanges, debug_rnglists: DebugRngLists) -> RangeLists { RangeLists { debug_ranges, debug_rnglists, } } } impl RangeLists { /// Create a `RangeLists` that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::RangeLists> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> RangeLists where F: FnMut(&'a T) -> R, { RangeLists { debug_ranges: borrow(&self.debug_ranges.section).into(), debug_rnglists: borrow(&self.debug_rnglists.section).into(), } } } impl RangeLists { /// Iterate over the `Range` list entries starting at the given offset. /// /// The `unit_version` and `address_size` must match the compilation unit that the /// offset was contained in. /// /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn ranges( &self, offset: RangeListsOffset, unit_encoding: Encoding, base_address: u64, debug_addr: &DebugAddr, debug_addr_base: DebugAddrBase, ) -> Result> { Ok(RngListIter::new( self.raw_ranges(offset, unit_encoding)?, base_address, debug_addr.clone(), debug_addr_base, )) } /// Iterate over the `RawRngListEntry`ies starting at the given offset. /// /// The `unit_encoding` must match the compilation unit that the /// offset was contained in. /// /// This iterator does not perform any processing of the range entries, /// such as handling base addresses. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn raw_ranges( &self, offset: RangeListsOffset, unit_encoding: Encoding, ) -> Result> { let mut input = if unit_encoding.version <= 4 { self.debug_ranges.section.clone() } else { self.debug_rnglists.section.clone() }; input.skip(offset.0)?; Ok(RawRngListIter::new(input, unit_encoding)) } /// Returns the `.debug_rnglists` offset at the given `base` and `index`. /// /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE. /// This is an offset that points to the first entry following the header. /// /// The `index` is the value of a `DW_FORM_rnglistx` attribute. /// /// The `unit_encoding` must match the compilation unit that the /// index was contained in. pub fn get_offset( &self, unit_encoding: Encoding, base: DebugRngListsBase, index: DebugRngListsIndex, ) -> Result> { let format = unit_encoding.format; let input = &mut self.debug_rnglists.section.clone(); input.skip(base.0)?; input.skip(R::Offset::from_u64( index.0.into_u64() * u64::from(format.word_size()), )?)?; input .read_offset(format) .map(|x| RangeListsOffset(base.0 + x)) } /// Call `Reader::lookup_offset_id` for each section, and return the first match. pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> { self.debug_ranges .lookup_offset_id(id) .or_else(|| self.debug_rnglists.lookup_offset_id(id)) } } /// A raw iterator over an address range list. /// /// This iterator does not perform any processing of the range entries, /// such as handling base addresses. #[derive(Debug)] pub struct RawRngListIter { input: R, encoding: Encoding, } /// A raw entry in .debug_rnglists #[derive(Clone, Debug)] pub enum RawRngListEntry { /// A range from DWARF version <= 4. AddressOrOffsetPair { /// Start of range. May be an address or an offset. begin: u64, /// End of range. May be an address or an offset. end: u64, }, /// DW_RLE_base_address BaseAddress { /// base address addr: u64, }, /// DW_RLE_base_addressx BaseAddressx { /// base address addr: DebugAddrIndex, }, /// DW_RLE_startx_endx StartxEndx { /// start of range begin: DebugAddrIndex, /// end of range end: DebugAddrIndex, }, /// DW_RLE_startx_length StartxLength { /// start of range begin: DebugAddrIndex, /// length of range length: u64, }, /// DW_RLE_offset_pair OffsetPair { /// start of range begin: u64, /// end of range end: u64, }, /// DW_RLE_start_end StartEnd { /// start of range begin: u64, /// end of range end: u64, }, /// DW_RLE_start_length StartLength { /// start of range begin: u64, /// length of range length: u64, }, } impl RawRngListEntry { /// Parse a range entry from `.debug_rnglists` fn parse>(input: &mut R, encoding: Encoding) -> Result> { if encoding.version < 5 { let range = RawRange::parse(input, encoding.address_size)?; return Ok(if range.is_end() { None } else if range.is_base_address(encoding.address_size) { Some(RawRngListEntry::BaseAddress { addr: range.end }) } else { Some(RawRngListEntry::AddressOrOffsetPair { begin: range.begin, end: range.end, }) }); } Ok(match constants::DwRle(input.read_u8()?) { constants::DW_RLE_end_of_list => None, constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), length: input.read_uleb128()?, }), constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { begin: input.read_uleb128()?, end: input.read_uleb128()?, }), constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { addr: input.read_address(encoding.address_size)?, }), constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { begin: input.read_address(encoding.address_size)?, end: input.read_address(encoding.address_size)?, }), constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { begin: input.read_address(encoding.address_size)?, length: input.read_uleb128()?, }), _ => { return Err(Error::InvalidAddressRange); } }) } } impl RawRngListIter { /// Construct a `RawRngListIter`. fn new(input: R, encoding: Encoding) -> RawRngListIter { RawRngListIter { input, encoding } } /// Advance the iterator to the next range. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } match RawRngListEntry::parse(&mut self.input, self.encoding) { Ok(range) => { if range.is_none() { self.input.empty(); } Ok(range) } Err(e) => { self.input.empty(); Err(e) } } } } impl FallibleIterator for RawRngListIter { type Item = RawRngListEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { RawRngListIter::next(self) } } /// An iterator over an address range list. /// /// This iterator internally handles processing of base addresses and different /// entry types. Thus, it only returns range entries that are valid /// and already adjusted for the base address. #[derive(Debug)] pub struct RngListIter { raw: RawRngListIter, base_address: u64, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, } impl RngListIter { /// Construct a `RngListIter`. fn new( raw: RawRngListIter, base_address: u64, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, ) -> RngListIter { RngListIter { raw, base_address, debug_addr, debug_addr_base, } } #[inline] fn get_address(&self, index: DebugAddrIndex) -> Result { self.debug_addr .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) } /// Advance the iterator to the next range. pub fn next(&mut self) -> Result> { loop { let raw_range = match self.raw.next()? { Some(range) => range, None => return Ok(None), }; let range = match raw_range { RawRngListEntry::BaseAddress { addr } => { self.base_address = addr; continue; } RawRngListEntry::BaseAddressx { addr } => { self.base_address = self.get_address(addr)?; continue; } RawRngListEntry::StartxEndx { begin, end } => { let begin = self.get_address(begin)?; let end = self.get_address(end)?; Range { begin, end } } RawRngListEntry::StartxLength { begin, length } => { let begin = self.get_address(begin)?; let end = begin + length; Range { begin, end } } RawRngListEntry::AddressOrOffsetPair { begin, end } | RawRngListEntry::OffsetPair { begin, end } => { let mut range = Range { begin, end }; range.add_base_address(self.base_address, self.raw.encoding.address_size); range } RawRngListEntry::StartEnd { begin, end } => Range { begin, end }, RawRngListEntry::StartLength { begin, length } => Range { begin, end: begin + length, }, }; if range.begin > range.end { self.raw.input.empty(); return Err(Error::InvalidAddressRange); } return Ok(Some(range)); } } } impl FallibleIterator for RngListIter { type Item = Range; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { RngListIter::next(self) } } /// A raw address range from the `.debug_ranges` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct RawRange { /// The beginning address of the range. pub begin: u64, /// The first address past the end of the range. pub end: u64, } impl RawRange { /// Check if this is a range end entry. /// /// This will only occur for raw ranges. #[inline] pub fn is_end(&self) -> bool { self.begin == 0 && self.end == 0 } /// Check if this is a base address selection entry. /// /// A base address selection entry changes the base address that subsequent /// range entries are relative to. This will only occur for raw ranges. #[inline] pub fn is_base_address(&self, address_size: u8) -> bool { self.begin == !0 >> (64 - address_size * 8) } /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. #[doc(hidden)] #[inline] pub fn parse(input: &mut R, address_size: u8) -> Result { let begin = input.read_address(address_size)?; let end = input.read_address(address_size)?; let range = RawRange { begin, end }; Ok(range) } } /// An address range from the `.debug_ranges` or `.debug_rnglists` sections. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Range { /// The beginning address of the range. pub begin: u64, /// The first address past the end of the range. pub end: u64, } impl Range { /// Add a base address to this range. #[inline] pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) { let mask = !0 >> (64 - address_size * 8); self.begin = base_address.wrapping_add(self.begin) & mask; self.end = base_address.wrapping_add(self.end) & mask; } } #[cfg(test)] mod tests { use super::*; use crate::endianity::LittleEndian; use crate::test_util::GimliSectionMethods; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] fn test_rnglists_32() { let encoding = Encoding { format: Format::Dwarf32, version: 5, address_size: 4, }; let section = Section::with_endian(Endian::Little) .L32(0x0300_0000) .L32(0x0301_0300) .L32(0x0301_0400) .L32(0x0301_0500); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); let start = Label::new(); let first = Label::new(); let size = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // Header .mark(&start) .L32(&size) .L16(encoding.version) .L8(encoding.address_size) .L8(0) .L32(0) .mark(&first) // OffsetPair .L8(4).uleb(0x10200).uleb(0x10300) // A base address selection followed by an OffsetPair. .L8(5).L32(0x0200_0000) .L8(4).uleb(0x10400).uleb(0x10500) // An empty OffsetPair followed by a normal OffsetPair. .L8(4).uleb(0x10600).uleb(0x10600) .L8(4).uleb(0x10800).uleb(0x10900) // A StartEnd .L8(6).L32(0x201_0a00).L32(0x201_0b00) // A StartLength .L8(7).L32(0x201_0c00).uleb(0x100) // An OffsetPair that starts at 0. .L8(4).uleb(0).uleb(1) // An OffsetPair that starts and ends at 0. .L8(4).uleb(0).uleb(0) // An OffsetPair that ends at -1. .L8(5).L32(0) .L8(4).uleb(0).uleb(0xffff_ffff) // A BaseAddressx + OffsetPair .L8(1).uleb(0) .L8(4).uleb(0x10100).uleb(0x10200) // A StartxEndx .L8(2).uleb(1).uleb(2) // A StartxLength .L8(3).uleb(3).uleb(0x100) // A range end. .L8(0) // Some extra data. .L32(0xffff_ffff); size.set_const((§ion.here() - &start - 4) as u64); let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&[], LittleEndian); let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let offset = RangeListsOffset((&first - &start) as usize); let mut ranges = rnglists .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0101_0200, end: 0x0101_0300, })) ); // A base address selection followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0400, end: 0x0201_0500, })) ); // An empty range followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0600, end: 0x0201_0600, })) ); assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0800, end: 0x0201_0900, })) ); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0a00, end: 0x0201_0b00, })) ); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0c00, end: 0x0201_0d00, })) ); // A range that starts at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0001, })) ); // A range that starts and ends at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0000, })) ); // A range that ends at -1. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0000_0000, end: 0xffff_ffff, })) ); // A BaseAddressx + OffsetPair assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0100, end: 0x0301_0200, })) ); // A StartxEndx assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0300, end: 0x0301_0400, })) ); // A StartxLength assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0500, end: 0x0301_0600, })) ); // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists .ranges( RangeListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } #[test] fn test_rnglists_64() { let encoding = Encoding { format: Format::Dwarf64, version: 5, address_size: 8, }; let section = Section::with_endian(Endian::Little) .L64(0x0300_0000) .L64(0x0301_0300) .L64(0x0301_0400) .L64(0x0301_0500); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); let start = Label::new(); let first = Label::new(); let size = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // Header .mark(&start) .L32(0xffff_ffff) .L64(&size) .L16(encoding.version) .L8(encoding.address_size) .L8(0) .L32(0) .mark(&first) // OffsetPair .L8(4).uleb(0x10200).uleb(0x10300) // A base address selection followed by an OffsetPair. .L8(5).L64(0x0200_0000) .L8(4).uleb(0x10400).uleb(0x10500) // An empty OffsetPair followed by a normal OffsetPair. .L8(4).uleb(0x10600).uleb(0x10600) .L8(4).uleb(0x10800).uleb(0x10900) // A StartEnd .L8(6).L64(0x201_0a00).L64(0x201_0b00) // A StartLength .L8(7).L64(0x201_0c00).uleb(0x100) // An OffsetPair that starts at 0. .L8(4).uleb(0).uleb(1) // An OffsetPair that starts and ends at 0. .L8(4).uleb(0).uleb(0) // An OffsetPair that ends at -1. .L8(5).L64(0) .L8(4).uleb(0).uleb(0xffff_ffff) // A BaseAddressx + OffsetPair .L8(1).uleb(0) .L8(4).uleb(0x10100).uleb(0x10200) // A StartxEndx .L8(2).uleb(1).uleb(2) // A StartxLength .L8(3).uleb(3).uleb(0x100) // A range end. .L8(0) // Some extra data. .L32(0xffff_ffff); size.set_const((§ion.here() - &start - 12) as u64); let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&[], LittleEndian); let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let offset = RangeListsOffset((&first - &start) as usize); let mut ranges = rnglists .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0101_0200, end: 0x0101_0300, })) ); // A base address selection followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0400, end: 0x0201_0500, })) ); // An empty range followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0600, end: 0x0201_0600, })) ); assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0800, end: 0x0201_0900, })) ); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0a00, end: 0x0201_0b00, })) ); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0c00, end: 0x0201_0d00, })) ); // A range that starts at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0001, })) ); // A range that starts and ends at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0000, })) ); // A range that ends at -1. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0000_0000, end: 0xffff_ffff, })) ); // A BaseAddressx + OffsetPair assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0100, end: 0x0301_0200, })) ); // A StartxEndx assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0300, end: 0x0301_0400, })) ); // A StartxLength assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0301_0500, end: 0x0301_0600, })) ); // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists .ranges( RangeListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } #[test] fn test_raw_range() { let range = RawRange { begin: 0, end: 0xffff_ffff, }; assert!(!range.is_end()); assert!(!range.is_base_address(4)); assert!(!range.is_base_address(8)); let range = RawRange { begin: 0, end: 0 }; assert!(range.is_end()); assert!(!range.is_base_address(4)); assert!(!range.is_base_address(8)); let range = RawRange { begin: 0xffff_ffff, end: 0, }; assert!(!range.is_end()); assert!(range.is_base_address(4)); assert!(!range.is_base_address(8)); let range = RawRange { begin: 0xffff_ffff_ffff_ffff, end: 0, }; assert!(!range.is_end()); assert!(!range.is_base_address(4)); assert!(range.is_base_address(8)); } #[test] fn test_ranges_32() { let start = Label::new(); let first = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // A range before the offset. .mark(&start) .L32(0x10000).L32(0x10100) .mark(&first) // A normal range. .L32(0x10200).L32(0x10300) // A base address selection followed by a normal range. .L32(0xffff_ffff).L32(0x0200_0000) .L32(0x10400).L32(0x10500) // An empty range followed by a normal range. .L32(0x10600).L32(0x10600) .L32(0x10800).L32(0x10900) // A range that starts at 0. .L32(0).L32(1) // A range that ends at -1. .L32(0xffff_ffff).L32(0x0000_0000) .L32(0).L32(0xffff_ffff) // A range end. .L32(0).L32(0) // Some extra data. .L32(0); let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let offset = RangeListsOffset((&first - &start) as usize); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut ranges = rnglists .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0101_0200, end: 0x0101_0300, })) ); // A base address selection followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0400, end: 0x0201_0500, })) ); // An empty range followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0600, end: 0x0201_0600, })) ); assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0800, end: 0x0201_0900, })) ); // A range that starts at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0001, })) ); // A range that ends at -1. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0000_0000, end: 0xffff_ffff, })) ); // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists .ranges( RangeListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } #[test] fn test_ranges_64() { let start = Label::new(); let first = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // A range before the offset. .mark(&start) .L64(0x10000).L64(0x10100) .mark(&first) // A normal range. .L64(0x10200).L64(0x10300) // A base address selection followed by a normal range. .L64(0xffff_ffff_ffff_ffff).L64(0x0200_0000) .L64(0x10400).L64(0x10500) // An empty range followed by a normal range. .L64(0x10600).L64(0x10600) .L64(0x10800).L64(0x10900) // A range that starts at 0. .L64(0).L64(1) // A range that ends at -1. .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) .L64(0).L64(0xffff_ffff_ffff_ffff) // A range end. .L64(0).L64(0) // Some extra data. .L64(0); let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let offset = RangeListsOffset((&first - &start) as usize); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf64, version: 4, address_size: 8, }; let mut ranges = rnglists .ranges(offset, encoding, 0x0100_0000, debug_addr, debug_addr_base) .unwrap(); // A normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0101_0200, end: 0x0101_0300, })) ); // A base address selection followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0400, end: 0x0201_0500, })) ); // An empty range followed by a normal range. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0600, end: 0x0201_0600, })) ); assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0201_0800, end: 0x0201_0900, })) ); // A range that starts at 0. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0200_0000, end: 0x0200_0001, })) ); // A range that ends at -1. assert_eq!( ranges.next(), Ok(Some(Range { begin: 0x0, end: 0xffff_ffff_ffff_ffff, })) ); // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists .ranges( RangeListsOffset(buf.len()), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } #[test] fn test_ranges_invalid() { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) // An invalid range. .L32(0x20000).L32(0x10000) // An invalid range after wrapping. .L32(0x20000).L32(0xff01_0000); let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; // An invalid range. let mut ranges = rnglists .ranges( RangeListsOffset(0x0), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid range after wrapping. let mut ranges = rnglists .ranges( RangeListsOffset(0x8), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid offset. match rnglists.ranges( RangeListsOffset(buf.len() + 1), encoding, 0x0100_0000, debug_addr, debug_addr_base, ) { Err(Error::UnexpectedEof(_)) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_get_offset() { for format in vec![Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version: 5, address_size: 4, }; let zero = Label::new(); let length = Label::new(); let start = Label::new(); let first = Label::new(); let end = Label::new(); let mut section = Section::with_endian(Endian::Little) .mark(&zero) .initial_length(format, &length, &start) .D16(encoding.version) .D8(encoding.address_size) .D8(0) .D32(20) .mark(&first); for i in 0..20 { section = section.word(format.word_size(), 1000 + i); } section = section.mark(&end); length.set_const((&end - &start) as u64); let section = section.get_contents().unwrap(); let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian)); let debug_rnglists = DebugRngLists::from(EndianSlice::new(§ion, LittleEndian)); let ranges = RangeLists::new(debug_ranges, debug_rnglists); let base = DebugRngListsBase((&first - &zero) as usize); assert_eq!( ranges.get_offset(encoding, base, DebugRngListsIndex(0)), Ok(RangeListsOffset(base.0 + 1000)) ); assert_eq!( ranges.get_offset(encoding, base, DebugRngListsIndex(19)), Ok(RangeListsOffset(base.0 + 1019)) ); } } } gimli-0.19.0/src/read/str.rs010066400017500001750000000213121346020377600140140ustar0000000000000000use crate::common::{ DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, SectionId, }; use crate::endianity::Endianity; use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section}; use crate::Format; /// The `DebugStr` struct represents the DWARF strings /// found in the `.debug_str` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugStr { debug_str_section: R, } impl<'input, Endian> DebugStr> where Endian: Endianity, { /// Construct a new `DebugStr` instance from the data in the `.debug_str` /// section. /// /// It is the caller's responsibility to read the `.debug_str` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugStr, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_str_section_somehow = || &buf; /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); /// ``` pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_str_section, endian)) } } impl DebugStr { /// Lookup a string from the `.debug_str` section by DebugStrOffset. /// /// ``` /// use gimli::{DebugStr, DebugStrOffset, LittleEndian}; /// /// # let buf = [0x01, 0x02, 0x00]; /// # let offset = DebugStrOffset(0); /// # let read_debug_str_section_somehow = || &buf; /// # let debug_str_offset_somehow = || offset; /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow())); /// ``` pub fn get_str(&self, offset: DebugStrOffset) -> Result { let input = &mut self.debug_str_section.clone(); input.skip(offset.0)?; input.read_null_terminated_slice() } } impl DebugStr { /// Create a `DebugStr` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugStr> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr where F: FnMut(&'a T) -> R, { borrow(&self.debug_str_section).into() } } impl Section for DebugStr { fn id() -> SectionId { SectionId::DebugStr } fn reader(&self) -> &R { &self.debug_str_section } } impl From for DebugStr { fn from(debug_str_section: R) -> Self { DebugStr { debug_str_section } } } /// The raw contents of the `.debug_str_offsets` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugStrOffsets { section: R, } impl DebugStrOffsets { // TODO: add an iterator over the sets of entries in the section. // This is not needed for common usage of the section though. /// Returns the `.debug_str` offset at the given `base` and `index`. /// /// A set of entries in the `.debug_str_offsets` section consists of a header /// followed by a series of string table offsets. /// /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. /// This is an offset that points to the first entry following the header. /// /// The `index` is the value of a `DW_FORM_strx` attribute. /// /// The `format` must be the DWARF format of the compilation unit. This format must /// match the header. However, note that we do not parse the header to validate this, /// since locating the header is unreliable, and the GNU extensions do not emit it. pub fn get_str_offset( &self, format: Format, base: DebugStrOffsetsBase, index: DebugStrOffsetsIndex, ) -> Result> { let input = &mut self.section.clone(); input.skip(base.0)?; input.skip(R::Offset::from_u64( index.0.into_u64() * u64::from(format.word_size()), )?)?; input.read_offset(format).map(DebugStrOffset) } } impl DebugStrOffsets { /// Create a `DebugStrOffsets` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugStrOffsets> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets where F: FnMut(&'a T) -> R, { borrow(&self.section).into() } } impl Section for DebugStrOffsets { fn id() -> SectionId { SectionId::DebugStrOffsets } fn reader(&self) -> &R { &self.section } } impl From for DebugStrOffsets { fn from(section: R) -> Self { DebugStrOffsets { section } } } /// The `DebugLineStr` struct represents the DWARF strings /// found in the `.debug_line_str` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLineStr { section: R, } impl DebugLineStr { /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. pub fn get_str(&self, offset: DebugLineStrOffset) -> Result { let input = &mut self.section.clone(); input.skip(offset.0)?; input.read_null_terminated_slice() } } impl DebugLineStr { /// Create a `DebugLineStr` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugLineStr> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr where F: FnMut(&'a T) -> R, { borrow(&self.section).into() } } impl Section for DebugLineStr { fn id() -> SectionId { SectionId::DebugLineStr } fn reader(&self) -> &R { &self.section } } impl From for DebugLineStr { fn from(section: R) -> Self { DebugLineStr { section } } } #[cfg(test)] mod tests { use super::*; use crate::test_util::GimliSectionMethods; use crate::LittleEndian; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] fn test_get_str_offset() { for format in vec![Format::Dwarf32, Format::Dwarf64] { let zero = Label::new(); let length = Label::new(); let start = Label::new(); let first = Label::new(); let end = Label::new(); let mut section = Section::with_endian(Endian::Little) .mark(&zero) .initial_length(format, &length, &start) .D16(5) .D16(0) .mark(&first); for i in 0..20 { section = section.word(format.word_size(), 1000 + i); } section = section.mark(&end); length.set_const((&end - &start) as u64); let section = section.get_contents().unwrap(); let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); let base = DebugStrOffsetsBase((&first - &zero) as usize); assert_eq!( debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), Ok(DebugStrOffset(1000)) ); assert_eq!( debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), Ok(DebugStrOffset(1019)) ); } } } gimli-0.19.0/src/read/unit.rs010066400017500001750000005726761351057326000142050ustar0000000000000000//! Functions for parsing DWARF `.debug_info` and `.debug_types` sections. use fallible_iterator::FallibleIterator; use std::cell::Cell; use std::ops::{Range, RangeFrom, RangeTo}; use std::{u16, u8}; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, Encoding, Format, LocationListsOffset, RangeListsOffset, SectionId, }; use crate::constants; use crate::endianity::Endianity; use crate::read::{ Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, }; impl DebugTypesOffset { /// Convert an offset to be relative to the start of the given unit, /// instead of relative to the start of the .debug_types section. /// Returns `None` if the offset is not within the unit entries. pub fn to_unit_offset(&self, unit: &TypeUnitHeader) -> Option> where R: Reader, { let offset = match self.0.checked_sub(unit.offset.0) { Some(offset) => UnitOffset(offset), None => return None, }; if !unit.header.is_valid_offset(offset) { return None; } Some(offset) } } impl DebugInfoOffset { /// Convert an offset to be relative to the start of the given unit, /// instead of relative to the start of the .debug_info section. /// Returns `None` if the offset is not within this unit entries. pub fn to_unit_offset(&self, unit: &CompilationUnitHeader) -> Option> where R: Reader, { let offset = match self.0.checked_sub(unit.offset.0) { Some(offset) => UnitOffset(offset), None => return None, }; if !unit.header.is_valid_offset(offset) { return None; } Some(offset) } } /// An offset into the current compilation or type unit. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct UnitOffset(pub T); impl UnitOffset { /// Convert an offset to be relative to the start of the .debug_info section, /// instead of relative to the start of the given compilation unit. pub fn to_debug_info_offset(&self, unit: &CompilationUnitHeader) -> DebugInfoOffset where R: Reader, { DebugInfoOffset(unit.offset.0 + self.0) } /// Convert an offset to be relative to the start of the .debug_types section, /// instead of relative to the start of the given type unit. pub fn to_debug_types_offset(&self, unit: &TypeUnitHeader) -> DebugTypesOffset where R: Reader, { DebugTypesOffset(unit.offset.0 + self.0) } } /// The `DebugInfo` struct represents the DWARF debugging information found in /// the `.debug_info` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugInfo { debug_info_section: R, } impl<'input, Endian> DebugInfo> where Endian: Endianity, { /// Construct a new `DebugInfo` instance from the data in the `.debug_info` /// section. /// /// It is the caller's responsibility to read the `.debug_info` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugInfo, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_info_section_somehow = || &buf; /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); /// ``` pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_info_section, endian)) } } impl DebugInfo { /// Iterate the compilation- and partial-units in this /// `.debug_info` section. /// /// ``` /// use gimli::{DebugInfo, LittleEndian}; /// /// # let buf = []; /// # let read_debug_info_section_somehow = || &buf; /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); /// /// let mut iter = debug_info.units(); /// while let Some(unit) = iter.next().unwrap() { /// println!("unit's length is {}", unit.unit_length()); /// } /// ``` /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn units(&self) -> CompilationUnitHeadersIter { CompilationUnitHeadersIter { input: self.debug_info_section.clone(), offset: DebugInfoOffset(R::Offset::from_u8(0)), } } /// Get the CompilationUnitHeader located at offset from this .debug_info section. /// /// pub fn header_from_offset( &self, offset: DebugInfoOffset, ) -> Result> { let input = &mut self.debug_info_section.clone(); input.skip(offset.0)?; CompilationUnitHeader::parse(input, offset) } } impl DebugInfo { /// Create a `DebugInfo` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugInfo> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo where F: FnMut(&'a T) -> R, { borrow(&self.debug_info_section).into() } } impl Section for DebugInfo { fn id() -> SectionId { SectionId::DebugInfo } fn reader(&self) -> &R { &self.debug_info_section } } impl From for DebugInfo { fn from(debug_info_section: R) -> Self { DebugInfo { debug_info_section } } } /// An iterator over the compilation- and partial-units of a section. /// /// See the [documentation on /// `DebugInfo::units`](./struct.DebugInfo.html#method.units) for more detail. #[derive(Clone, Debug)] pub struct CompilationUnitHeadersIter { input: R, offset: DebugInfoOffset, } impl CompilationUnitHeadersIter { /// Advance the iterator to the next unit header. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { Ok(None) } else { let len = self.input.len(); match CompilationUnitHeader::parse(&mut self.input, self.offset) { Ok(header) => { self.offset.0 += len - self.input.len(); Ok(Some(header)) } Err(e) => { self.input.empty(); Err(e) } } } } } impl FallibleIterator for CompilationUnitHeadersIter { type Item = CompilationUnitHeader; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { CompilationUnitHeadersIter::next(self) } } /// The header of a compilation unit's debugging information. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct CompilationUnitHeader::Offset> where R: Reader, Offset: ReaderOffset, { header: UnitHeader, offset: DebugInfoOffset, } impl CompilationUnitHeader where R: Reader, Offset: ReaderOffset, { /// Construct a new `CompilationUnitHeader`. pub fn new(header: UnitHeader, offset: DebugInfoOffset) -> Self { CompilationUnitHeader { header, offset } } /// Return the `UnitHeader` containing common unit header fields. pub fn header(self) -> UnitHeader { self.header } /// Return the serialized size of the compilation unit header for the given /// DWARF format. pub fn size_of_header(format: Format) -> usize { UnitHeader::::size_of_header(format) } /// Get the offset of this compilation unit within the .debug_info section. pub fn offset(&self) -> DebugInfoOffset { self.offset } /// Get the length of the debugging info for this compilation unit, not /// including the byte length of the encoded length itself. pub fn unit_length(&self) -> R::Offset { self.header.unit_length } /// Get the length of the debugging info for this compilation unit, /// including the byte length of the encoded length itself. pub fn length_including_self(&self) -> R::Offset { self.header.length_including_self() } /// Return the encoding parameters for this unit. pub fn encoding(&self) -> Encoding { self.header.encoding } /// Get the DWARF version of the debugging info for this compilation unit. pub fn version(&self) -> u16 { self.header.version() } /// The offset into the `.debug_abbrev` section for this compilation unit's /// debugging information entries' abbreviations. pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { self.header.debug_abbrev_offset } /// The size of addresses (in bytes) in this type-unit. pub fn address_size(&self) -> u8 { self.header.address_size() } /// Whether this type unit is encoded in 64- or 32-bit DWARF. pub fn format(&self) -> Format { self.header.format() } /// The serialized size of the header for this compilation unit. pub fn header_size(&self) -> R::Offset { self.header.header_size() } /// Navigate this compilation unit's `DebuggingInformationEntry`s. pub fn entries<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, ) -> EntriesCursor<'abbrev, 'me, R> { self.header.entries(abbreviations) } /// Navigate this compilation unit's `DebuggingInformationEntry`s /// starting at the given offset. pub fn entries_at_offset<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: UnitOffset, ) -> Result> { self.header.entries_at_offset(abbreviations, offset) } /// Navigate this compilation unit's `DebuggingInformationEntry`s as a tree /// starting at the given offset. pub fn entries_tree<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: Option>, ) -> Result> { self.header.entries_tree(abbreviations, offset) } /// Parse this compilation unit's abbreviations. /// /// ``` /// use gimli::DebugAbbrev; /// # use gimli::{DebugInfo, LittleEndian}; /// # let info_buf = [ /// # // Comilation unit header /// # /// # // 32-bit unit length = 25 /// # 0x19, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # ]; /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); /// # /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_yes /// # 0x01, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); /// /// let unit = get_some_unit(); /// /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// let abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); /// ``` pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { self.header.abbreviations(debug_abbrev) } /// Parse a compilation unit header. fn parse( input: &mut R, offset: DebugInfoOffset, ) -> Result> { let header = parse_unit_header(input)?; Ok(CompilationUnitHeader { header, offset }) } } /// Parse the unit type from the compilation unit header. fn parse_compilation_unit_type(input: &mut R) -> Result { let val = input.read_u8()?; Ok(constants::DwUt(val)) } /// Parse the `debug_abbrev_offset` in the compilation unit header. fn parse_debug_abbrev_offset( input: &mut R, format: Format, ) -> Result> { input.read_offset(format).map(DebugAbbrevOffset) } /// Parse the `debug_info_offset` in the arange header. pub(crate) fn parse_debug_info_offset( input: &mut R, format: Format, ) -> Result> { input.read_offset(format).map(DebugInfoOffset) } /// The common fields for the headers of compilation units and /// type units. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct UnitHeader::Offset> where R: Reader, Offset: ReaderOffset, { encoding: Encoding, unit_length: Offset, debug_abbrev_offset: DebugAbbrevOffset, entries_buf: R, } /// Static methods. impl UnitHeader where R: Reader, Offset: ReaderOffset, { /// Construct a new `UnitHeader`. pub fn new( encoding: Encoding, unit_length: R::Offset, debug_abbrev_offset: DebugAbbrevOffset, entries_buf: R, ) -> Self { UnitHeader { encoding, unit_length, debug_abbrev_offset, entries_buf, } } /// Return the serialized size of the common unit header for the given /// DWARF format. pub fn size_of_header(format: Format) -> usize { let unit_length_size = format.initial_length_size() as usize; let version_size = 2; let debug_abbrev_offset_size = format.word_size() as usize; let address_size_size = 1; unit_length_size + version_size + debug_abbrev_offset_size + address_size_size } } /// Instance methods. impl UnitHeader where R: Reader, Offset: ReaderOffset, { /// Get the length of the debugging info for this compilation unit, not /// including the byte length of the encoded length itself. pub fn unit_length(&self) -> R::Offset { self.unit_length } /// Get the length of the debugging info for this compilation unit, /// including the byte length of the encoded length itself. pub fn length_including_self(&self) -> R::Offset { R::Offset::from_u8(self.format().initial_length_size()) + self.unit_length } /// Return the encoding parameters for this unit. pub fn encoding(&self) -> Encoding { self.encoding } /// Get the DWARF version of the debugging info for this compilation unit. pub fn version(&self) -> u16 { self.encoding.version } /// The offset into the `.debug_abbrev` section for this compilation unit's /// debugging information entries' abbreviations. pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { self.debug_abbrev_offset } /// The size of addresses (in bytes) in this compilation unit. pub fn address_size(&self) -> u8 { self.encoding.address_size } /// Whether this compilation unit is encoded in 64- or 32-bit DWARF. pub fn format(&self) -> Format { self.encoding.format } /// The serialized size of the header for this compilation unit. pub fn header_size(&self) -> R::Offset { self.length_including_self() - self.entries_buf.len() } pub(crate) fn is_valid_offset(&self, offset: UnitOffset) -> bool { let size_of_header = self.header_size(); if offset.0 < size_of_header { return false; } let relative_to_entries_buf = offset.0 - size_of_header; relative_to_entries_buf < self.entries_buf.len() } /// Get the underlying bytes for the supplied range. pub fn range(&self, idx: Range>) -> Result { if !self.is_valid_offset(idx.start) { return Err(Error::OffsetOutOfBounds); } if !self.is_valid_offset(idx.end) { return Err(Error::OffsetOutOfBounds); } assert!(idx.start <= idx.end); let size_of_header = self.header_size(); let start = idx.start.0 - size_of_header; let end = idx.end.0 - size_of_header; let mut input = self.entries_buf.clone(); input.skip(start)?; input.truncate(end - start)?; Ok(input) } /// Get the underlying bytes for the supplied range. pub fn range_from(&self, idx: RangeFrom>) -> Result { if !self.is_valid_offset(idx.start) { return Err(Error::OffsetOutOfBounds); } let start = idx.start.0 - self.header_size(); let mut input = self.entries_buf.clone(); input.skip(start)?; Ok(input) } /// Get the underlying bytes for the supplied range. pub fn range_to(&self, idx: RangeTo>) -> Result { if !self.is_valid_offset(idx.end) { return Err(Error::OffsetOutOfBounds); } let end = idx.end.0 - self.header_size(); let mut input = self.entries_buf.clone(); input.truncate(end)?; Ok(input) } /// Navigate this unit's `DebuggingInformationEntry`s. pub fn entries<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, ) -> EntriesCursor<'abbrev, 'me, R> { EntriesCursor { unit: self, input: self.entries_buf.clone(), abbreviations, cached_current: None, delta_depth: 0, } } /// Navigate this compilation unit's `DebuggingInformationEntry`s /// starting at the given offset. pub fn entries_at_offset<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: UnitOffset, ) -> Result> { let input = self.range_from(offset..)?; Ok(EntriesCursor { unit: self, input, abbreviations, cached_current: None, delta_depth: 0, }) } /// Navigate this unit's `DebuggingInformationEntry`s as a tree /// starting at the given offset. pub fn entries_tree<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: Option>, ) -> Result> { let input = match offset { Some(offset) => self.range_from(offset..)?, None => self.entries_buf.clone(), }; Ok(EntriesTree::new(input, self, abbreviations)) } /// Parse this unit's abbreviations. pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { debug_abbrev.abbreviations(self.debug_abbrev_offset()) } } /// Parse a compilation unit header. fn parse_unit_header(input: &mut R) -> Result> { let (unit_length, format) = input.read_initial_length()?; let mut rest = input.split(unit_length)?; let version = rest.read_u16()?; let offset; let address_size; // DWARF 1 was very different, and is obsolete, so isn't supported by this // reader. if 2 <= version && version <= 4 { offset = parse_debug_abbrev_offset(&mut rest, format)?; address_size = rest.read_u8()?; } else if version == 5 { let unit_type = parse_compilation_unit_type(&mut rest)?; if unit_type != constants::DW_UT_compile { return Err(Error::UnsupportedUnitType); } address_size = rest.read_u8()?; offset = parse_debug_abbrev_offset(&mut rest, format)?; } else { return Err(Error::UnknownVersion(u64::from(version))); } let encoding = Encoding { format, version, address_size, }; Ok(UnitHeader::new(encoding, unit_length, offset, rest)) } /// A Debugging Information Entry (DIE). /// /// DIEs have a set of attributes and optionally have children DIEs as well. #[derive(Clone, Debug)] pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = ::Offset> where R: Reader, Offset: ReaderOffset, { offset: UnitOffset, attrs_slice: R, attrs_len: Cell>, abbrev: &'abbrev Abbreviation, unit: &'unit UnitHeader, } impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset> where R: Reader, Offset: ReaderOffset, { /// Construct a new `DebuggingInformationEntry`. pub fn new( offset: UnitOffset, attrs_slice: R, abbrev: &'abbrev Abbreviation, unit: &'unit UnitHeader, ) -> Self { DebuggingInformationEntry { offset, attrs_slice, attrs_len: Cell::new(None), abbrev, unit, } } /// Get this entry's code. pub fn code(&self) -> u64 { self.abbrev.code() } /// Get this entry's offset. pub fn offset(&self) -> UnitOffset { self.offset } /// Get this entry's `DW_TAG_whatever` tag. /// /// ``` /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; /// # let info_buf = [ /// # // Comilation unit header /// # /// # // 32-bit unit length = 12 /// # 0x0c, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # ]; /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_no /// # 0x00, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); /// # let unit = debug_info.units().next().unwrap().unwrap(); /// # let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); /// # let mut cursor = unit.entries(&abbrevs); /// # let (_, entry) = cursor.next_dfs().unwrap().unwrap(); /// # let mut get_some_entry = || entry; /// let entry = get_some_entry(); /// /// match entry.tag() { /// gimli::DW_TAG_subprogram => /// println!("this entry contains debug info about a function"), /// gimli::DW_TAG_inlined_subroutine => /// println!("this entry contains debug info about a particular instance of inlining"), /// gimli::DW_TAG_variable => /// println!("this entry contains debug info about a local variable"), /// gimli::DW_TAG_formal_parameter => /// println!("this entry contains debug info about a function parameter"), /// otherwise => /// println!("this entry is some other kind of data: {:?}", otherwise), /// }; /// ``` pub fn tag(&self) -> constants::DwTag { self.abbrev.tag() } /// Return true if this entry's type can have children, false otherwise. pub fn has_children(&self) -> bool { self.abbrev.has_children() } /// Iterate over this entry's set of attributes. /// /// ``` /// use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; /// /// // Read the `.debug_info` section. /// /// # let info_buf = [ /// # // Comilation unit header /// # /// # // 32-bit unit length = 12 /// # 0x0c, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # ]; /// # let read_debug_info_section_somehow = || &info_buf; /// let debug_info = DebugInfo::new(read_debug_info_section_somehow(), LittleEndian); /// /// // Get the data about the first compilation unit out of the `.debug_info`. /// /// let unit = debug_info.units().next() /// .expect("Should have at least one compilation unit") /// .expect("and it should parse ok"); /// /// // Read the `.debug_abbrev` section and parse the /// // abbreviations for our compilation unit. /// /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_no /// # 0x00, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// let abbrevs = unit.abbreviations(&debug_abbrev).unwrap(); /// /// // Get the first entry from that compilation unit. /// /// let mut cursor = unit.entries(&abbrevs); /// let (_, entry) = cursor.next_dfs() /// .expect("Should parse next entry") /// .expect("Should have at least one entry"); /// /// // Finally, print the first entry's attributes. /// /// let mut attrs = entry.attrs(); /// while let Some(attr) = attrs.next().unwrap() { /// println!("Attribute name = {:?}", attr.name()); /// println!("Attribute value = {:?}", attr.value()); /// } /// ``` /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> { AttrsIter { input: self.attrs_slice.clone(), attributes: self.abbrev.attributes(), entry: self, } } /// Find the first attribute in this entry which has the given name, /// and return it. Returns `Ok(None)` if no attribute is found. pub fn attr(&self, name: constants::DwAt) -> Result>> { let mut attrs = self.attrs(); while let Some(attr) = attrs.next()? { if attr.name() == name { return Ok(Some(attr)); } } Ok(None) } /// Find the first attribute in this entry which has the given name, /// and return its raw value. Returns `Ok(None)` if no attribute is found. pub fn attr_value_raw(&self, name: constants::DwAt) -> Result>> { self.attr(name) .map(|attr| attr.map(|attr| attr.raw_value())) } /// Find the first attribute in this entry which has the given name, /// and return its normalized value. Returns `Ok(None)` if no /// attribute is found. pub fn attr_value(&self, name: constants::DwAt) -> Result>> { self.attr(name).map(|attr| attr.map(|attr| attr.value())) } /// Return the input buffer after the last attribute. #[allow(clippy::inline_always)] #[inline(always)] fn after_attrs(&self) -> Result { if let Some(attrs_len) = self.attrs_len.get() { let mut input = self.attrs_slice.clone(); input.skip(attrs_len)?; Ok(input) } else { let mut attrs = self.attrs(); while let Some(_) = attrs.next()? {} Ok(attrs.input) } } /// Use the `DW_AT_sibling` attribute to find the input buffer for the /// next sibling. Returns `None` if the attribute is missing or invalid. fn sibling(&self) -> Option { let attr = self.attr_value(constants::DW_AT_sibling); if let Ok(Some(AttributeValue::UnitRef(offset))) = attr { if offset.0 > self.offset.0 { if let Ok(input) = self.unit.range_from(offset..) { return Some(input); } } } None } /// Parse an entry. Returns `Ok(None)` for null entries. #[allow(clippy::inline_always)] #[inline(always)] fn parse( input: &mut R, unit: &'unit UnitHeader, abbreviations: &'abbrev Abbreviations, ) -> Result> { let offset = unit.header_size() + input.offset_from(&unit.entries_buf); let code = input.read_uleb128()?; if code == 0 { return Ok(None); }; let abbrev = abbreviations.get(code).ok_or(Error::UnknownAbbreviation)?; Ok(Some(DebuggingInformationEntry { offset: UnitOffset(offset), attrs_slice: input.clone(), attrs_len: Cell::new(None), abbrev, unit, })) } } /// The value of an attribute in a `DebuggingInformationEntry`. // // Set the discriminant size so that all variants use the same alignment // for their data. This gives better code generation in `parse_attribute`. #[repr(u64)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AttributeValue::Offset> where R: Reader, Offset: ReaderOffset, { /// "Refers to some location in the address space of the described program." Addr(u64), /// A slice of an arbitrary number of bytes. Block(R), /// A one byte constant data value. How to interpret the byte depends on context. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data1(u8), /// A two byte constant data value. How to interpret the bytes depends on context. /// /// These bytes have been converted from `R::Endian`. This may need to be reversed /// if this was not required. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data2(u16), /// A four byte constant data value. How to interpret the bytes depends on context. /// /// These bytes have been converted from `R::Endian`. This may need to be reversed /// if this was not required. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data4(u32), /// An eight byte constant data value. How to interpret the bytes depends on context. /// /// These bytes have been converted from `R::Endian`. This may need to be reversed /// if this was not required. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data8(u64), /// A signed integer constant. Sdata(i64), /// An unsigned integer constant. Udata(u64), /// "The information bytes contain a DWARF expression (see Section 2.5) or /// location description (see Section 2.6)." Exprloc(Expression), /// A boolean that indicates presence or absence of the attribute. Flag(bool), /// An offset into another section. Which section this is an offset into /// depends on context. SecOffset(Offset), /// An offset to a set of addresses in the `.debug_addr` section. DebugAddrBase(DebugAddrBase), /// An index into a set of addresses in the `.debug_addr` section. DebugAddrIndex(DebugAddrIndex), /// An offset into the current compilation unit. UnitRef(UnitOffset), /// An offset into the current `.debug_info` section, but possibly a /// different compilation unit from the current one. DebugInfoRef(DebugInfoOffset), /// An offset into the `.debug_info` section of the supplementary object file. DebugInfoRefSup(DebugInfoOffset), /// An offset into the `.debug_line` section. DebugLineRef(DebugLineOffset), /// An offset into either the `.debug_loc` section or the `.debug_loclists` section. LocationListsRef(LocationListsOffset), /// An offset to a set of offsets in the `.debug_loclists` section. DebugLocListsBase(DebugLocListsBase), /// An index into a set of offsets in the `.debug_loclists` section. DebugLocListsIndex(DebugLocListsIndex), /// An offset into the `.debug_macinfo` section. DebugMacinfoRef(DebugMacinfoOffset), /// An offset into the `.debug_ranges` section. RangeListsRef(RangeListsOffset), /// An offset to a set of offsets in the `.debug_rnglists` section. DebugRngListsBase(DebugRngListsBase), /// An index into a set of offsets in the `.debug_rnglists` section. DebugRngListsIndex(DebugRngListsIndex), /// A type signature. DebugTypesRef(DebugTypeSignature), /// An offset into the `.debug_str` section. DebugStrRef(DebugStrOffset), /// An offset into the `.debug_str` section of the supplementary object file. DebugStrRefSup(DebugStrOffset), /// An offset to a set of entries in the `.debug_str_offsets` section. DebugStrOffsetsBase(DebugStrOffsetsBase), /// An index into a set of entries in the `.debug_str_offsets` section. DebugStrOffsetsIndex(DebugStrOffsetsIndex), /// An offset into the `.debug_line_str` section. DebugLineStrRef(DebugLineStrOffset), /// A slice of bytes representing a string. Does not include a final null byte. /// Not guaranteed to be UTF-8 or anything like that. String(R), /// The value of a `DW_AT_encoding` attribute. Encoding(constants::DwAte), /// The value of a `DW_AT_decimal_sign` attribute. DecimalSign(constants::DwDs), /// The value of a `DW_AT_endianity` attribute. Endianity(constants::DwEnd), /// The value of a `DW_AT_accessibility` attribute. Accessibility(constants::DwAccess), /// The value of a `DW_AT_visibility` attribute. Visibility(constants::DwVis), /// The value of a `DW_AT_virtuality` attribute. Virtuality(constants::DwVirtuality), /// The value of a `DW_AT_language` attribute. Language(constants::DwLang), /// The value of a `DW_AT_address_class` attribute. AddressClass(constants::DwAddr), /// The value of a `DW_AT_identifier_case` attribute. IdentifierCase(constants::DwId), /// The value of a `DW_AT_calling_convention` attribute. CallingConvention(constants::DwCc), /// The value of a `DW_AT_inline` attribute. Inline(constants::DwInl), /// The value of a `DW_AT_ordering` attribute. Ordering(constants::DwOrd), /// An index into the filename entries from the line number information /// table for the compilation unit containing this value. FileIndex(u64), } /// An attribute in a `DebuggingInformationEntry`, consisting of a name and /// associated value. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Attribute { name: constants::DwAt, value: AttributeValue, } impl Attribute { /// Get this attribute's name. pub fn name(&self) -> constants::DwAt { self.name } /// Get this attribute's raw value. pub fn raw_value(&self) -> AttributeValue { self.value.clone() } /// Get this attribute's normalized value. /// /// Attribute values can potentially be encoded in multiple equivalent forms, /// and may have special meaning depending on the attribute name. This method /// converts the attribute value to a normalized form based on the attribute /// name. /// /// See "Figure 20. Attribute encodings" and "Figure 21. Attribute form encodings". #[allow(clippy::cyclomatic_complexity)] #[allow(clippy::match_same_arms)] pub fn value(&self) -> AttributeValue { // Figure 20 shows the possible attribute classes for each name. // Figure 21 shows the possible attribute classes for each form. // For each attribute name, we need to match on the form, and // convert it to one of the classes that is allowed for both // the name and the form. // // The individual class conversions rarely vary for each name, // so for each class conversion we define a macro that matches // on the allowed forms for that class. // // For some classes, we don't need to do any conversion, so their // macro is empty. In the future we may want to fill them in to // provide strict checking of the forms for each class. For now, // they simply provide a way to document the allowed classes for // each name. macro_rules! address { () => {}; } macro_rules! addrptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugAddrBase(DebugAddrBase(offset)); } }; } macro_rules! block { () => {}; } macro_rules! constant { ($value:ident, $variant:ident) => { if let Some(value) = self.$value() { return AttributeValue::$variant(value); } }; ($value:ident, $variant:ident, $constant:ident) => { if let Some(value) = self.$value() { return AttributeValue::$variant(constants::$constant(value)); } }; } macro_rules! exprloc { () => { if let Some(value) = self.exprloc_value() { return AttributeValue::Exprloc(value); } }; } macro_rules! flag { () => {}; } macro_rules! lineptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugLineRef(DebugLineOffset(offset)); } }; } // This also covers `loclist` in DWARF version 5. macro_rules! loclistptr { () => { // DebugLocListsIndex is also an allowed form in DWARF version 5. if let Some(offset) = self.offset_value() { return AttributeValue::LocationListsRef(LocationListsOffset(offset)); } }; } macro_rules! loclistsptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset)); } }; } macro_rules! macptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset)); } }; } macro_rules! reference { () => {}; } // This also covers `rnglist` in DWARF version 5. macro_rules! rangelistptr { () => { // DebugRngListsIndex is also an allowed form in DWARF version 5. if let Some(offset) = self.offset_value() { return AttributeValue::RangeListsRef(RangeListsOffset(offset)); } }; } macro_rules! rnglistsptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset)); } }; } macro_rules! string { () => {}; } macro_rules! stroffsetsptr { () => { if let Some(offset) = self.offset_value() { return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset)); } }; } // Perform the allowed class conversions for each attribute name. match self.name { constants::DW_AT_sibling => { reference!(); } constants::DW_AT_location => { exprloc!(); loclistptr!(); } constants::DW_AT_name => { string!(); } constants::DW_AT_ordering => { constant!(u8_value, Ordering, DwOrd); } constants::DW_AT_byte_size | constants::DW_AT_bit_offset | constants::DW_AT_bit_size => { constant!(udata_value, Udata); exprloc!(); reference!(); } constants::DW_AT_stmt_list => { lineptr!(); } constants::DW_AT_low_pc => { address!(); } constants::DW_AT_high_pc => { address!(); constant!(udata_value, Udata); } constants::DW_AT_language => { constant!(u16_value, Language, DwLang); } constants::DW_AT_discr => { reference!(); } constants::DW_AT_discr_value => { // constant: depends on type of DW_TAG_variant_part, // so caller must normalize. } constants::DW_AT_visibility => { constant!(u8_value, Visibility, DwVis); } constants::DW_AT_import => { reference!(); } constants::DW_AT_string_length => { exprloc!(); loclistptr!(); } constants::DW_AT_common_reference => { reference!(); } constants::DW_AT_comp_dir => { string!(); } constants::DW_AT_const_value => { // TODO: constant: sign depends on DW_AT_type. block!(); string!(); } constants::DW_AT_containing_type => { reference!(); } constants::DW_AT_default_value => { reference!(); } constants::DW_AT_inline => { constant!(u8_value, Inline, DwInl); } constants::DW_AT_is_optional => { flag!(); } constants::DW_AT_lower_bound => { // TODO: constant: sign depends on DW_AT_type. exprloc!(); reference!(); } constants::DW_AT_producer => { string!(); } constants::DW_AT_prototyped => { flag!(); } constants::DW_AT_return_addr => { exprloc!(); loclistptr!(); } constants::DW_AT_start_scope => { // TODO: constant rangelistptr!(); } constants::DW_AT_bit_stride => { constant!(udata_value, Udata); exprloc!(); reference!(); } constants::DW_AT_upper_bound => { // TODO: constant: sign depends on DW_AT_type. exprloc!(); reference!(); } constants::DW_AT_abstract_origin => { reference!(); } constants::DW_AT_accessibility => { constant!(u8_value, Accessibility, DwAccess); } constants::DW_AT_address_class => { constant!(udata_value, AddressClass, DwAddr); } constants::DW_AT_artificial => { flag!(); } constants::DW_AT_base_types => { reference!(); } constants::DW_AT_calling_convention => { constant!(u8_value, CallingConvention, DwCc); } constants::DW_AT_count => { // TODO: constant exprloc!(); reference!(); } constants::DW_AT_data_member_location => { // Constants must be handled before loclistptr so that DW_FORM_data4/8 // are correctly interpreted for DWARF version 4+. constant!(udata_value, Udata); exprloc!(); loclistptr!(); } constants::DW_AT_decl_column => { constant!(udata_value, Udata); } constants::DW_AT_decl_file => { constant!(udata_value, FileIndex); } constants::DW_AT_decl_line => { constant!(udata_value, Udata); } constants::DW_AT_declaration => { flag!(); } constants::DW_AT_discr_list => { block!(); } constants::DW_AT_encoding => { constant!(u8_value, Encoding, DwAte); } constants::DW_AT_external => { flag!(); } constants::DW_AT_frame_base => { exprloc!(); loclistptr!(); } constants::DW_AT_friend => { reference!(); } constants::DW_AT_identifier_case => { constant!(u8_value, IdentifierCase, DwId); } constants::DW_AT_macro_info => { macptr!(); } constants::DW_AT_namelist_item => { reference!(); } constants::DW_AT_priority => { reference!(); } constants::DW_AT_segment => { exprloc!(); loclistptr!(); } constants::DW_AT_specification => { reference!(); } constants::DW_AT_static_link => { exprloc!(); loclistptr!(); } constants::DW_AT_type => { reference!(); } constants::DW_AT_use_location => { exprloc!(); loclistptr!(); } constants::DW_AT_variable_parameter => { flag!(); } constants::DW_AT_virtuality => { constant!(u8_value, Virtuality, DwVirtuality); } constants::DW_AT_vtable_elem_location => { exprloc!(); loclistptr!(); } constants::DW_AT_allocated => { // TODO: constant exprloc!(); reference!(); } constants::DW_AT_associated => { // TODO: constant exprloc!(); reference!(); } constants::DW_AT_data_location => { exprloc!(); } constants::DW_AT_byte_stride => { constant!(udata_value, Udata); exprloc!(); reference!(); } constants::DW_AT_entry_pc => { address!(); } constants::DW_AT_use_UTF8 => { flag!(); } constants::DW_AT_extension => { reference!(); } constants::DW_AT_ranges => { rangelistptr!(); } constants::DW_AT_trampoline => { address!(); flag!(); reference!(); string!(); } constants::DW_AT_call_column => { constant!(udata_value, Udata); } constants::DW_AT_call_file => { constant!(udata_value, FileIndex); } constants::DW_AT_call_line => { constant!(udata_value, Udata); } constants::DW_AT_description => { string!(); } constants::DW_AT_binary_scale => { // TODO: constant } constants::DW_AT_decimal_scale => { // TODO: constant } constants::DW_AT_small => { reference!(); } constants::DW_AT_decimal_sign => { constant!(u8_value, DecimalSign, DwDs); } constants::DW_AT_digit_count => { // TODO: constant } constants::DW_AT_picture_string => { string!(); } constants::DW_AT_mutable => { flag!(); } constants::DW_AT_threads_scaled => { flag!(); } constants::DW_AT_explicit => { flag!(); } constants::DW_AT_object_pointer => { reference!(); } constants::DW_AT_endianity => { constant!(u8_value, Endianity, DwEnd); } constants::DW_AT_elemental => { flag!(); } constants::DW_AT_pure => { flag!(); } constants::DW_AT_recursive => { flag!(); } constants::DW_AT_signature => { reference!(); } constants::DW_AT_main_subprogram => { flag!(); } constants::DW_AT_data_bit_offset => { // TODO: constant } constants::DW_AT_const_expr => { flag!(); } constants::DW_AT_enum_class => { flag!(); } constants::DW_AT_linkage_name => { string!(); } constants::DW_AT_str_offsets_base => { stroffsetsptr!(); } constants::DW_AT_addr_base => { addrptr!(); } constants::DW_AT_rnglists_base => { rnglistsptr!(); } constants::DW_AT_loclists_base => { loclistsptr!(); } _ => {} } self.value.clone() } /// Try to convert this attribute's value to a u8. #[inline] pub fn u8_value(&self) -> Option { self.value.u8_value() } /// Try to convert this attribute's value to a u16. #[inline] pub fn u16_value(&self) -> Option { self.value.u16_value() } /// Try to convert this attribute's value to an unsigned integer. #[inline] pub fn udata_value(&self) -> Option { self.value.udata_value() } /// Try to convert this attribute's value to a signed integer. #[inline] pub fn sdata_value(&self) -> Option { self.value.sdata_value() } /// Try to convert this attribute's value to an offset. #[inline] pub fn offset_value(&self) -> Option { self.value.offset_value() } /// Try to convert this attribute's value to an expression or location buffer. /// /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. /// The standard doesn't mention `DW_FORM_block*` as a possible form, but /// it is encountered in practice. #[inline] pub fn exprloc_value(&self) -> Option> { self.value.exprloc_value() } /// Try to return this attribute's value as a string slice. /// /// If this attribute's value is either an inline `DW_FORM_string` string, /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` /// section, return the attribute's string value as `Some`. Other attribute /// value forms are returned as `None`. /// /// Warning: this function does not handle all possible string forms. /// Use `Dwarf::attr_string` instead. #[inline] pub fn string_value(&self, debug_str: &DebugStr) -> Option { self.value.string_value(debug_str) } /// Try to return this attribute's value as a string slice. /// /// If this attribute's value is either an inline `DW_FORM_string` string, /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary /// object file, return the attribute's string value as `Some`. Other attribute /// value forms are returned as `None`. /// /// Warning: this function does not handle all possible string forms. /// Use `Dwarf::attr_string` instead. #[inline] pub fn string_value_sup( &self, debug_str: &DebugStr, debug_str_sup: Option<&DebugStr>, ) -> Option { self.value.string_value_sup(debug_str, debug_str_sup) } } impl AttributeValue where R: Reader, Offset: ReaderOffset, { /// Try to convert this attribute's value to a u8. pub fn u8_value(&self) -> Option { if let Some(value) = self.udata_value() { if value <= u64::from(u8::MAX) { return Some(value as u8); } } None } /// Try to convert this attribute's value to a u16. pub fn u16_value(&self) -> Option { if let Some(value) = self.udata_value() { if value <= u64::from(u16::MAX) { return Some(value as u16); } } None } /// Try to convert this attribute's value to an unsigned integer. pub fn udata_value(&self) -> Option { Some(match *self { AttributeValue::Data1(data) => u64::from(data), AttributeValue::Data2(data) => u64::from(data), AttributeValue::Data4(data) => u64::from(data), AttributeValue::Data8(data) => data, AttributeValue::Udata(data) => data, AttributeValue::Sdata(data) => { if data < 0 { // Maybe we should emit a warning here return None; } data as u64 } _ => return None, }) } /// Try to convert this attribute's value to a signed integer. pub fn sdata_value(&self) -> Option { Some(match *self { AttributeValue::Data1(data) => i64::from(data as i8), AttributeValue::Data2(data) => i64::from(data as i16), AttributeValue::Data4(data) => i64::from(data as i32), AttributeValue::Data8(data) => data as i64, AttributeValue::Sdata(data) => data, AttributeValue::Udata(data) => { if data > i64::max_value() as u64 { // Maybe we should emit a warning here return None; } data as i64 } _ => return None, }) } /// Try to convert this attribute's value to an offset. pub fn offset_value(&self) -> Option { // While offsets will be DW_FORM_data4/8 in DWARF version 2/3, // these have already been converted to `SecOffset. if let AttributeValue::SecOffset(offset) = *self { Some(offset) } else { None } } /// Try to convert this attribute's value to an expression or location buffer. /// /// Expressions and locations may be `DW_FORM_block*` or `DW_FORM_exprloc`. /// The standard doesn't mention `DW_FORM_block*` as a possible form, but /// it is encountered in practice. pub fn exprloc_value(&self) -> Option> { Some(match *self { AttributeValue::Block(ref data) => Expression(data.clone()), AttributeValue::Exprloc(ref data) => data.clone(), _ => return None, }) } /// Try to return this attribute's value as a string slice. /// /// If this attribute's value is either an inline `DW_FORM_string` string, /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` /// section, return the attribute's string value as `Some`. Other attribute /// value forms are returned as `None`. /// /// Warning: this function does not handle all possible string forms. /// Use `Dwarf::attr_string` instead. pub fn string_value(&self, debug_str: &DebugStr) -> Option { match *self { AttributeValue::String(ref string) => Some(string.clone()), AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), _ => None, } } /// Try to return this attribute's value as a string slice. /// /// If this attribute's value is either an inline `DW_FORM_string` string, /// or a `DW_FORM_strp` reference to an offset into the `.debug_str` /// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary /// object file, return the attribute's string value as `Some`. Other attribute /// value forms are returned as `None`. /// /// Warning: this function does not handle all possible string forms. /// Use `Dwarf::attr_string` instead. pub fn string_value_sup( &self, debug_str: &DebugStr, debug_str_sup: Option<&DebugStr>, ) -> Option { match *self { AttributeValue::String(ref string) => Some(string.clone()), AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(), AttributeValue::DebugStrRefSup(offset) => { debug_str_sup.and_then(|s| s.get_str(offset).ok()) } _ => None, } } } fn length_u8_value(input: &mut R) -> Result { let len = input.read_u8().map(R::Offset::from_u8)?; input.split(len) } fn length_u16_value(input: &mut R) -> Result { let len = input.read_u16().map(R::Offset::from_u16)?; input.split(len) } fn length_u32_value(input: &mut R) -> Result { let len = input.read_u32().map(R::Offset::from_u32)?; input.split(len) } fn length_uleb128_value(input: &mut R) -> Result { let len = input.read_uleb128().and_then(R::Offset::from_u64)?; input.split(len) } // Return true if the given `name` can be a section offset in DWARF version 2/3. // This is required to correctly handle relocations. fn allow_section_offset(name: constants::DwAt, version: u16) -> bool { match name { constants::DW_AT_location | constants::DW_AT_stmt_list | constants::DW_AT_string_length | constants::DW_AT_return_addr | constants::DW_AT_start_scope | constants::DW_AT_frame_base | constants::DW_AT_macro_info | constants::DW_AT_segment | constants::DW_AT_static_link | constants::DW_AT_use_location | constants::DW_AT_vtable_elem_location | constants::DW_AT_ranges => true, constants::DW_AT_data_member_location => version == 2 || version == 3, _ => false, } } pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( input: &mut R, unit: &'unit UnitHeader, mut specs: &'abbrev [AttributeSpecification], ) -> Result<(Attribute, &'abbrev [AttributeSpecification])> { let spec = specs[0]; specs = &specs[1..]; let mut form = spec.form(); loop { let value = match form { constants::DW_FORM_indirect => { let dynamic_form = input.read_uleb128()?; form = constants::DwForm(dynamic_form); continue; } constants::DW_FORM_addr => { let addr = input.read_address(unit.address_size())?; AttributeValue::Addr(addr) } constants::DW_FORM_block1 => { let block = length_u8_value(input)?; AttributeValue::Block(block) } constants::DW_FORM_block2 => { let block = length_u16_value(input)?; AttributeValue::Block(block) } constants::DW_FORM_block4 => { let block = length_u32_value(input)?; AttributeValue::Block(block) } constants::DW_FORM_block => { let block = length_uleb128_value(input)?; AttributeValue::Block(block) } constants::DW_FORM_data1 => { let data = input.read_u8()?; AttributeValue::Data1(data) } constants::DW_FORM_data2 => { let data = input.read_u16()?; AttributeValue::Data2(data) } constants::DW_FORM_data4 => { // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. // Ensure we handle relocations here. if unit.format() == Format::Dwarf32 && allow_section_offset(spec.name(), unit.version()) { let offset = input.read_offset(Format::Dwarf32)?; AttributeValue::SecOffset(offset) } else { let data = input.read_u32()?; AttributeValue::Data4(data) } } constants::DW_FORM_data8 => { // DWARF version 2/3 may use DW_FORM_data4/8 for section offsets. // Ensure we handle relocations here. if unit.format() == Format::Dwarf64 && allow_section_offset(spec.name(), unit.version()) { let offset = input.read_offset(Format::Dwarf64)?; AttributeValue::SecOffset(offset) } else { let data = input.read_u64()?; AttributeValue::Data8(data) } } constants::DW_FORM_data16 => { let block = input.split(R::Offset::from_u8(16))?; AttributeValue::Block(block) } constants::DW_FORM_udata => { let data = input.read_uleb128()?; AttributeValue::Udata(data) } constants::DW_FORM_sdata => { let data = input.read_sleb128()?; AttributeValue::Sdata(data) } constants::DW_FORM_exprloc => { let block = length_uleb128_value(input)?; AttributeValue::Exprloc(Expression(block)) } constants::DW_FORM_flag => { let present = input.read_u8()?; AttributeValue::Flag(present != 0) } constants::DW_FORM_flag_present => { // FlagPresent is this weird compile time always true thing that // isn't actually present in the serialized DIEs, only in the abbreviation. AttributeValue::Flag(true) } constants::DW_FORM_sec_offset => { let offset = input.read_offset(unit.format())?; AttributeValue::SecOffset(offset) } constants::DW_FORM_ref1 => { let reference = input.read_u8().map(R::Offset::from_u8)?; AttributeValue::UnitRef(UnitOffset(reference)) } constants::DW_FORM_ref2 => { let reference = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::UnitRef(UnitOffset(reference)) } constants::DW_FORM_ref4 => { let reference = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::UnitRef(UnitOffset(reference)) } constants::DW_FORM_ref8 => { let reference = input.read_u64().and_then(R::Offset::from_u64)?; AttributeValue::UnitRef(UnitOffset(reference)) } constants::DW_FORM_ref_udata => { let reference = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::UnitRef(UnitOffset(reference)) } constants::DW_FORM_ref_addr => { // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr // has the same size as an address on the target system. This was changed // in DWARF version 3. let offset = if unit.version() == 2 { input.read_sized_offset(unit.address_size())? } else { input.read_offset(unit.format())? }; AttributeValue::DebugInfoRef(DebugInfoOffset(offset)) } constants::DW_FORM_ref_sig8 => { let signature = input.read_u64()?; AttributeValue::DebugTypesRef(DebugTypeSignature(signature)) } constants::DW_FORM_ref_sup4 => { let offset = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) } constants::DW_FORM_ref_sup8 => { let offset = input.read_u64().and_then(R::Offset::from_u64)?; AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) } constants::DW_FORM_GNU_ref_alt => { let offset = input.read_offset(unit.format())?; AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset)) } constants::DW_FORM_string => { let string = input.read_null_terminated_slice()?; AttributeValue::String(string) } constants::DW_FORM_strp => { let offset = input.read_offset(unit.format())?; AttributeValue::DebugStrRef(DebugStrOffset(offset)) } constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => { let offset = input.read_offset(unit.format())?; AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) } constants::DW_FORM_line_strp => { let offset = input.read_offset(unit.format())?; AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset)) } constants::DW_FORM_implicit_const => AttributeValue::Sdata(spec.implicit_const_value()), constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { let index = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx1 => { let index = input.read_u8().map(R::Offset::from_u8)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx2 => { let index = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx3 => { let index = input.read_uint(3).and_then(R::Offset::from_u64)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_strx4 => { let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => { let index = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } constants::DW_FORM_addrx1 => { let index = input.read_u8().map(R::Offset::from_u8)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } constants::DW_FORM_addrx2 => { let index = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } constants::DW_FORM_addrx3 => { let index = input.read_uint(3).and_then(R::Offset::from_u64)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } constants::DW_FORM_addrx4 => { let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } constants::DW_FORM_loclistx => { let index = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index)) } constants::DW_FORM_rnglistx => { let index = input.read_uleb128().and_then(R::Offset::from_u64)?; AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index)) } _ => { return Err(Error::UnknownForm); } }; let attr = Attribute { name: spec.name(), value, }; return Ok((attr, specs)); } } /// An iterator over a particular entry's attributes. /// /// See [the documentation for /// `DebuggingInformationEntry::attrs()`](./struct.DebuggingInformationEntry.html#method.attrs) /// for details. /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). #[derive(Clone, Copy, Debug)] pub struct AttrsIter<'abbrev, 'entry, 'unit, R> where 'abbrev: 'entry, 'unit: 'entry, R: Reader, { input: R, attributes: &'abbrev [AttributeSpecification], entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>, } impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> { /// Advance the iterator and return the next attribute. /// /// Returns `None` when iteration is finished. If an error /// occurs while parsing the next attribute, then this error /// is returned, and all subsequent calls return `None`. #[allow(clippy::inline_always)] #[inline(always)] pub fn next(&mut self) -> Result>> { if self.attributes.is_empty() { // Now that we have parsed all of the attributes, we know where // either (1) this entry's children start, if the abbreviation says // this entry has children; or (2) where this entry's siblings // begin. if let Some(end) = self.entry.attrs_len.get() { debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice)); } else { self.entry .attrs_len .set(Some(self.input.offset_from(&self.entry.attrs_slice))); } return Ok(None); } match parse_attribute(&mut self.input, self.entry.unit, &self.attributes[..]) { Ok((attr, rest_attr)) => { self.attributes = rest_attr; Ok(Some(attr)) } Err(e) => { self.input.empty(); Err(e) } } } } impl<'abbrev, 'entry, 'unit, R: Reader> FallibleIterator for AttrsIter<'abbrev, 'entry, 'unit, R> { type Item = Attribute; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { AttrsIter::next(self) } } /// A cursor into the Debugging Information Entries tree for a compilation unit. /// /// The `EntriesCursor` can traverse the DIE tree in DFS order using `next_dfs()`, /// or skip to the next sibling of the entry the cursor is currently pointing to /// using `next_sibling()`. /// /// It is also possible to traverse the DIE tree at a lower abstraction level /// using `next_entry()`. This method does not skip over null entries, or provide /// any indication of the current tree depth. In this case, you must use `current()` /// to obtain the current entry, and `current().has_children()` to determine if /// the entry following the current entry will be a sibling or child. `current()` /// will return `None` if the current entry is a null entry, which signifies the /// end of the current tree depth. #[derive(Clone, Debug)] pub struct EntriesCursor<'abbrev, 'unit, R> where R: Reader, { input: R, unit: &'unit UnitHeader, abbreviations: &'abbrev Abbreviations, cached_current: Option>, delta_depth: isize, } impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> { /// Get a reference to the entry that the cursor is currently pointing to. /// /// If the cursor is not pointing at an entry, or if the current entry is a /// null entry, then `None` is returned. #[inline] pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> { self.cached_current.as_ref() } /// Move the cursor to the next DIE in the tree. /// /// Returns `Some` if there is a next entry, even if this entry is null. /// If there is no next entry, then `None` is returned. pub fn next_entry(&mut self) -> Result> { if let Some(ref current) = self.cached_current { self.input = current.after_attrs()?; } if self.input.is_empty() { self.cached_current = None; self.delta_depth = 0; return Ok(None); } match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { Ok(Some(entry)) => { self.delta_depth = entry.has_children() as isize; self.cached_current = Some(entry); Ok(Some(())) } Ok(None) => { self.delta_depth = -1; self.cached_current = None; Ok(Some(())) } Err(e) => { self.input.empty(); self.delta_depth = 0; self.cached_current = None; Err(e) } } } /// Move the cursor to the next DIE in the tree in DFS order. /// /// Upon successful movement of the cursor, return the delta traversal /// depth and the entry: /// /// * If we moved down into the previous current entry's children, we get /// `Some((1, entry))`. /// /// * If we moved to the previous current entry's sibling, we get /// `Some((0, entry))`. /// /// * If the previous entry does not have any siblings and we move up to /// its parent's next sibling, then we get `Some((-1, entry))`. Note that /// if the parent doesn't have a next sibling, then it could go up to the /// parent's parent's next sibling and return `Some((-2, entry))`, etc. /// /// If there is no next entry, then `None` is returned. /// /// Here is an example that finds the first entry in a compilation unit that /// does not have any children. /// /// ``` /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; /// # let info_buf = [ /// # // Comilation unit header /// # /// # // 32-bit unit length = 25 /// # 0x19, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # ]; /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); /// # /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_yes /// # 0x01, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); /// # /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); /// /// let unit = get_some_unit(); /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); /// let abbrevs = get_abbrevs_for_unit(&unit); /// /// let mut first_entry_with_no_children = None; /// let mut cursor = unit.entries(&abbrevs); /// /// // Move the cursor to the root. /// assert!(cursor.next_dfs().unwrap().is_some()); /// /// // Traverse the DIE tree in depth-first search order. /// let mut depth = 0; /// while let Some((delta_depth, current)) = cursor.next_dfs().expect("Should parse next dfs") { /// // Update depth value, and break out of the loop when we /// // return to the original starting position. /// depth += delta_depth; /// if depth <= 0 { /// break; /// } /// /// first_entry_with_no_children = Some(current.clone()); /// } /// /// println!("The first entry with no children is {:?}", /// first_entry_with_no_children.unwrap()); /// ``` #[allow(clippy::type_complexity)] pub fn next_dfs( &mut self, ) -> Result)>> { let mut delta_depth = self.delta_depth; loop { // The next entry should be the one we want. if self.next_entry()?.is_some() { if let Some(ref entry) = self.cached_current { return Ok(Some((delta_depth, entry))); } // next_entry() read a null entry. delta_depth += self.delta_depth; } else { return Ok(None); } } } /// Move the cursor to the next sibling DIE of the current one. /// /// Returns `Ok(Some(entry))` when the cursor has been moved to /// the next sibling, `Ok(None)` when there is no next sibling. /// /// The depth of the cursor is never changed if this method returns `Ok`. /// Once `Ok(None)` is returned, this method will continue to return /// `Ok(None)` until either `next_entry` or `next_dfs` is called. /// /// Here is an example that iterates over all of the direct children of the /// root entry: /// /// ``` /// # use gimli::{DebugAbbrev, DebugInfo, LittleEndian}; /// # let info_buf = [ /// # // Comilation unit header /// # /// # // 32-bit unit length = 25 /// # 0x19, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # ]; /// # let debug_info = DebugInfo::new(&info_buf, LittleEndian); /// # /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); /// /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_yes /// # 0x01, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); /// # /// let unit = get_some_unit(); /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); /// let abbrevs = get_abbrevs_for_unit(&unit); /// /// let mut cursor = unit.entries(&abbrevs); /// /// // Move the cursor to the root. /// assert!(cursor.next_dfs().unwrap().is_some()); /// /// // Move the cursor to the root's first child. /// assert!(cursor.next_dfs().unwrap().is_some()); /// /// // Iterate the root's children. /// loop { /// { /// let current = cursor.current().expect("Should be at an entry"); /// println!("{:?} is a child of the root", current); /// } /// /// if cursor.next_sibling().expect("Should parse next sibling").is_none() { /// break; /// } /// } /// ``` pub fn next_sibling( &mut self, ) -> Result)>> { if self.current().is_none() { // We're already at the null for the end of the sibling list. return Ok(None); } // Loop until we find an entry at the current level. let mut depth = 0; loop { // Use is_some() and unwrap() to keep borrow checker happy. if self.current().is_some() && self.current().unwrap().has_children() { if let Some(sibling_input) = self.current().unwrap().sibling() { // Fast path: this entry has a DW_AT_sibling // attribute pointing to its sibling, so jump // to it (which keeps us at the same depth). self.input = sibling_input; self.cached_current = None; } else { // This entry has children, so the next entry is // down one level. depth += 1; } } if self.next_entry()?.is_none() { // End of input. return Ok(None); } if depth == 0 { // Found an entry at the current level. return Ok(self.current()); } if self.current().is_none() { // A null entry means the end of a child list, so we're // back up a level. depth -= 1; } } } } /// The state information for a tree view of the Debugging Information Entries. /// /// The `EntriesTree` can be used to recursively iterate through the DIE /// tree, following the parent/child relationships. The `EntriesTree` contains /// shared state for all nodes in the tree, avoiding any duplicate parsing of /// entries during the traversal. /// /// ## Example Usage /// ```rust,no_run /// # fn example() -> Result<(), gimli::Error> { /// # let debug_info = gimli::DebugInfo::new(&[], gimli::LittleEndian); /// # let get_some_unit = || debug_info.units().next().unwrap().unwrap(); /// let unit = get_some_unit(); /// # let debug_abbrev = gimli::DebugAbbrev::new(&[], gimli::LittleEndian); /// # let get_abbrevs_for_unit = |_| unit.abbreviations(&debug_abbrev).unwrap(); /// let abbrevs = get_abbrevs_for_unit(&unit); /// /// let mut tree = unit.entries_tree(&abbrevs, None)?; /// let root = tree.root()?; /// process_tree(root)?; /// # unreachable!() /// # } /// /// fn process_tree(mut node: gimli::EntriesTreeNode) -> gimli::Result<()> /// where R: gimli::Reader /// { /// { /// // Examine the entry attributes. /// let mut attrs = node.entry().attrs(); /// while let Some(attr) = attrs.next()? { /// } /// } /// let mut children = node.children(); /// while let Some(child) = children.next()? { /// // Recursively process a child. /// process_tree(child); /// } /// Ok(()) /// } /// ``` #[derive(Clone, Debug)] pub struct EntriesTree<'abbrev, 'unit, R> where R: Reader, { root: R, unit: &'unit UnitHeader, abbreviations: &'abbrev Abbreviations, input: R, entry: Option>, depth: isize, } impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> { fn new(root: R, unit: &'unit UnitHeader, abbreviations: &'abbrev Abbreviations) -> Self { let input = root.clone(); EntriesTree { root, unit, abbreviations, input, entry: None, depth: 0, } } /// Returns the root node of the tree. pub fn root<'me>(&'me mut self) -> Result> { self.input = self.root.clone(); self.entry = DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?; if self.entry.is_none() { return Err(Error::UnexpectedNull); } self.depth = 0; Ok(EntriesTreeNode::new(self, 1)) } /// Move the cursor to the next entry at the specified depth. /// /// Requires `depth <= self.depth + 1`. /// /// Returns `true` if successful. fn next(&mut self, depth: isize) -> Result { if self.depth < depth { debug_assert_eq!(self.depth + 1, depth); match self.entry { Some(ref entry) => { if !entry.has_children() { return Ok(false); } self.depth += 1; self.input = entry.after_attrs()?; } None => return Ok(false), } if self.input.is_empty() { self.entry = None; return Ok(false); } return match DebuggingInformationEntry::parse( &mut self.input, self.unit, self.abbreviations, ) { Ok(entry) => { self.entry = entry; Ok(self.entry.is_some()) } Err(e) => { self.input.empty(); self.entry = None; Err(e) } }; } loop { match self.entry { Some(ref entry) => { if entry.has_children() { if let Some(sibling_input) = entry.sibling() { // Fast path: this entry has a DW_AT_sibling // attribute pointing to its sibling, so jump // to it (which keeps us at the same depth). self.input = sibling_input; } else { // This entry has children, so the next entry is // down one level. self.depth += 1; self.input = entry.after_attrs()?; } } else { // This entry has no children, so next entry is at same depth. self.input = entry.after_attrs()?; } } None => { // This entry is a null, so next entry is up one level. self.depth -= 1; } } if self.input.is_empty() { self.entry = None; return Ok(false); } match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) { Ok(entry) => { self.entry = entry; if self.depth == depth { return Ok(self.entry.is_some()); } } Err(e) => { self.input.empty(); self.entry = None; return Err(e); } } } } } /// A node in the Debugging Information Entry tree. /// /// The root node of a tree can be obtained /// via [`EntriesTree::root`](./struct.EntriesTree.html#method.root). #[derive(Debug)] pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R> where 'abbrev: 'tree, 'unit: 'tree, R: Reader, { tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, depth: isize, } impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { fn new( tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, depth: isize, ) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> { debug_assert!(tree.entry.is_some()); EntriesTreeNode { tree, depth } } /// Returns the current entry in the tree. pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> { // We never create a node without an entry. self.tree.entry.as_ref().unwrap() } /// Create an iterator for the children of the current entry. /// /// The current entry can no longer be accessed after creating the /// iterator. pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { EntriesTreeIter::new(self.tree, self.depth) } } /// An iterator that allows traversal of the children of an /// `EntriesTreeNode`. /// /// The items returned by this iterator are also `EntriesTreeNode`s, /// which allow recursive traversal of grandchildren, etc. #[derive(Debug)] pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R> where 'abbrev: 'tree, 'unit: 'tree, R: Reader, { tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, depth: isize, empty: bool, } impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { fn new( tree: &'tree mut EntriesTree<'abbrev, 'unit, R>, depth: isize, ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> { EntriesTreeIter { tree, depth, empty: false, } } /// Returns an `EntriesTreeNode` for the next child entry. /// /// Returns `None` if there are no more children. pub fn next<'me>(&'me mut self) -> Result>> { if self.empty { Ok(None) } else if self.tree.next(self.depth)? { Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1))) } else { self.empty = true; Ok(None) } } } /// Parse a type unit header's unique type signature. Callers should handle /// unique-ness checking. fn parse_type_signature(input: &mut R) -> Result { input.read_u64().map(DebugTypeSignature) } /// Parse a type unit header's type offset. fn parse_type_offset(input: &mut R, format: Format) -> Result> { input.read_offset(format).map(UnitOffset) } /// The `DebugTypes` struct represents the DWARF type information /// found in the `.debug_types` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugTypes { debug_types_section: R, } impl<'input, Endian> DebugTypes> where Endian: Endianity, { /// Construct a new `DebugTypes` instance from the data in the `.debug_types` /// section. /// /// It is the caller's responsibility to read the `.debug_types` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on OSX, etc. /// /// ``` /// use gimli::{DebugTypes, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_types_section_somehow = || &buf; /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); /// ``` pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_types_section, endian)) } } impl DebugTypes { /// Create a `DebugTypes` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugTypes> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes where F: FnMut(&'a T) -> R, { borrow(&self.debug_types_section).into() } } impl Section for DebugTypes { fn id() -> SectionId { SectionId::DebugTypes } fn reader(&self) -> &R { &self.debug_types_section } } impl From for DebugTypes { fn from(debug_types_section: R) -> Self { DebugTypes { debug_types_section, } } } impl DebugTypes { /// Iterate the type-units in this `.debug_types` section. /// /// ``` /// use gimli::{DebugTypes, LittleEndian}; /// /// # let buf = []; /// # let read_debug_types_section_somehow = || &buf; /// let debug_types = DebugTypes::new(read_debug_types_section_somehow(), LittleEndian); /// /// let mut iter = debug_types.units(); /// while let Some(unit) = iter.next().unwrap() { /// println!("unit's length is {}", unit.unit_length()); /// } /// ``` /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn units(&self) -> TypeUnitHeadersIter { TypeUnitHeadersIter { input: self.debug_types_section.clone(), offset: DebugTypesOffset(R::Offset::from_u8(0)), } } } /// An iterator over the type-units of this `.debug_types` section. /// /// See the [documentation on /// `DebugTypes::units`](./struct.DebugTypes.html#method.units) for /// more detail. #[derive(Clone, Debug)] pub struct TypeUnitHeadersIter { input: R, offset: DebugTypesOffset, } impl TypeUnitHeadersIter { /// Advance the iterator to the next type unit header. pub fn next(&mut self) -> Result>> { if self.input.is_empty() { Ok(None) } else { let len = self.input.len(); match parse_type_unit_header(&mut self.input, self.offset) { Ok(header) => { self.offset.0 += len - self.input.len(); Ok(Some(header)) } Err(e) => { self.input.empty(); Err(e) } } } } } impl FallibleIterator for TypeUnitHeadersIter { type Item = TypeUnitHeader; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { TypeUnitHeadersIter::next(self) } } /// The header of a type unit's debugging information. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct TypeUnitHeader::Offset> where R: Reader, Offset: ReaderOffset, { header: UnitHeader, offset: DebugTypesOffset, type_signature: DebugTypeSignature, type_offset: UnitOffset, } impl TypeUnitHeader where R: Reader, Offset: ReaderOffset, { /// Construct a new `TypeUnitHeader`. fn new( header: UnitHeader, offset: DebugTypesOffset, type_signature: DebugTypeSignature, type_offset: UnitOffset, ) -> Self { TypeUnitHeader { header, offset, type_signature, type_offset, } } /// Return the `UnitHeader` containing common unit fields. pub fn header(self) -> UnitHeader { self.header } /// Return the serialized size of the type-unit header for the given /// DWARF format. pub fn size_of_header(format: Format) -> usize { let unit_header_size = UnitHeader::::size_of_header(format); let type_signature_size = 8; let type_offset_size = format.word_size() as usize; unit_header_size + type_signature_size + type_offset_size } /// Get the offset of this compilation unit within the .debug_info section. pub fn offset(&self) -> DebugTypesOffset { self.offset } /// Get the length of the debugging info for this type-unit. pub fn unit_length(&self) -> R::Offset { self.header.unit_length } /// Get the length of the debugging info for this type-unit, /// including the byte length of the encoded length itself. pub fn length_including_self(&self) -> R::Offset { self.header.length_including_self() } /// Return the encoding parameters for this unit. pub fn encoding(&self) -> Encoding { self.header.encoding } /// Get the DWARF version of the debugging info for this type-unit. pub fn version(&self) -> u16 { self.header.version() } /// The offset into the `.debug_abbrev` section for this type-unit's /// debugging information entries. pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset { self.header.debug_abbrev_offset } /// The size of addresses (in bytes) in this type-unit. pub fn address_size(&self) -> u8 { self.header.address_size() } /// Whether this type unit is encoded in 64- or 32-bit DWARF. pub fn format(&self) -> Format { self.header.format() } /// The serialized size of the header for this type-unit. pub fn header_size(&self) -> R::Offset { self.header.header_size() } /// Get the unique type signature for this type unit. pub fn type_signature(&self) -> DebugTypeSignature { self.type_signature } /// Get the offset within this type unit where the type is defined. pub fn type_offset(&self) -> UnitOffset { self.type_offset } /// Navigate this type unit's `DebuggingInformationEntry`s. pub fn entries<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, ) -> EntriesCursor<'abbrev, 'me, R> { self.header.entries(abbreviations) } /// Navigate this type unit's `DebuggingInformationEntry`s /// starting at the given offset. pub fn entries_at_offset<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: UnitOffset, ) -> Result> { self.header.entries_at_offset(abbreviations, offset) } /// Navigate this type unit's `DebuggingInformationEntry`s as a tree /// starting at the given offset. pub fn entries_tree<'me, 'abbrev>( &'me self, abbreviations: &'abbrev Abbreviations, offset: Option>, ) -> Result> { self.header.entries_tree(abbreviations, offset) } /// Parse this type unit's abbreviations. /// /// ``` /// use gimli::DebugAbbrev; /// # use gimli::{DebugTypes, LittleEndian}; /// # let types_buf = [ /// # // Type unit header /// # /// # // 32-bit unit length = 37 /// # 0x25, 0x00, 0x00, 0x00, /// # // Version 4 /// # 0x04, 0x00, /// # // debug_abbrev_offset /// # 0x00, 0x00, 0x00, 0x00, /// # // Address size /// # 0x04, /// # // Type signature /// # 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, /// # // Type offset /// # 0x01, 0x02, 0x03, 0x04, /// # /// # // DIEs /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // Abbreviation code /// # 0x01, /// # // Attribute of form DW_FORM_string = "foo\0" /// # 0x66, 0x6f, 0x6f, 0x00, /// # /// # // Children /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # /// # // End of children /// # 0x00, /// # ]; /// # let debug_types = DebugTypes::new(&types_buf, LittleEndian); /// # /// # let abbrev_buf = [ /// # // Code /// # 0x01, /// # // DW_TAG_subprogram /// # 0x2e, /// # // DW_CHILDREN_yes /// # 0x01, /// # // Begin attributes /// # // Attribute name = DW_AT_name /// # 0x03, /// # // Attribute form = DW_FORM_string /// # 0x08, /// # // End attributes /// # 0x00, /// # 0x00, /// # // Null terminator /// # 0x00 /// # ]; /// # /// # let get_some_type_unit = || debug_types.units().next().unwrap().unwrap(); /// /// let unit = get_some_type_unit(); /// /// # let read_debug_abbrev_section_somehow = || &abbrev_buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// let abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap(); /// ``` pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev) -> Result { self.header.abbreviations(debug_abbrev) } } /// Parse a type unit header. fn parse_type_unit_header( input: &mut R, offset: DebugTypesOffset, ) -> Result> { let mut header = parse_unit_header(input)?; let format = header.format(); let signature = parse_type_signature(&mut header.entries_buf)?; let type_offset = parse_type_offset(&mut header.entries_buf, format)?; Ok(TypeUnitHeader::new(header, offset, signature, type_offset)) } #[cfg(test)] mod tests { use super::*; use crate::constants; use crate::constants::*; use crate::endianity::{Endianity, LittleEndian}; use crate::leb128; use crate::read::abbrev::tests::AbbrevSectionMethods; use crate::read::{ Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result, }; use crate::test_util::GimliSectionMethods; use crate::vec::Vec; use std; use std::cell::Cell; use test_assembler::{Endian, Label, LabelMaker, Section}; // Mixin methods for `Section` to help define binary test data. trait UnitSectionMethods { fn comp_unit<'input, E>( self, unit: &mut CompilationUnitHeader>, ) -> Self where E: Endianity; fn type_unit<'input, E>(self, unit: &mut TypeUnitHeader>) -> Self where E: Endianity; fn unit<'input, E>( self, unit: &mut UnitHeader>, extra_header: &[u8], ) -> Self where E: Endianity; fn die(self, code: u64, attr: F) -> Self where F: Fn(Section) -> Section; fn die_null(self) -> Self; fn attr_string(self, s: &str) -> Self; fn attr_ref1(self, o: u8) -> Self; fn offset(self, offset: usize, format: Format) -> Self; } impl UnitSectionMethods for Section { fn comp_unit<'input, E>( self, unit: &mut CompilationUnitHeader>, ) -> Self where E: Endianity, { unit.offset = DebugInfoOffset(self.size() as usize); self.unit(&mut unit.header, &[]) } fn type_unit<'input, E>(self, unit: &mut TypeUnitHeader>) -> Self where E: Endianity, { unit.offset = DebugTypesOffset(self.size() as usize); let section = Section::with_endian(Endian::Little) .L64(unit.type_signature.0) .offset(unit.type_offset.0, unit.header.format()); let extra_header = section.get_contents().unwrap(); self.unit(&mut unit.header, &extra_header) } fn unit<'input, E>( self, unit: &mut UnitHeader>, extra_header: &[u8], ) -> Self where E: Endianity, { let length = Label::new(); let start = Label::new(); let end = Label::new(); let section = match unit.format() { Format::Dwarf32 => self.L32(&length), Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length), }; let section = match unit.version() { 2 | 3 | 4 => section .mark(&start) .L16(unit.version()) .offset(unit.debug_abbrev_offset.0, unit.format()) .D8(unit.address_size()) .append_bytes(extra_header) .append_bytes(unit.entries_buf.into()) .mark(&end), 5 => section .mark(&start) .L16(unit.version()) .D8(constants::DW_UT_compile.0) .D8(unit.address_size()) .offset(unit.debug_abbrev_offset.0, unit.format()) .append_bytes(extra_header) .append_bytes(unit.entries_buf.into()) .mark(&end), _ => unreachable!(), }; unit.unit_length = (&end - &start) as usize; length.set_const(unit.unit_length as u64); section } fn die(self, code: u64, attr: F) -> Self where F: Fn(Section) -> Section, { let section = self.uleb(code); attr(section) } fn die_null(self) -> Self { self.D8(0) } fn attr_string(self, attr: &str) -> Self { self.append_bytes(attr.as_bytes()).D8(0) } fn attr_ref1(self, attr: u8) -> Self { self.D8(attr) } fn offset(self, offset: usize, format: Format) -> Self { match format { Format::Dwarf32 => self.L32(offset as u32), Format::Dwarf64 => self.L64(offset as u64), } } } #[test] fn test_parse_debug_abbrev_offset_32() { let section = Section::with_endian(Endian::Little).L32(0x0403_0201); let buf = section.get_contents().unwrap(); let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_abbrev_offset(buf, Format::Dwarf32) { Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_debug_abbrev_offset_32_incomplete() { let buf = [0x01, 0x02]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_abbrev_offset(buf, Format::Dwarf32) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_debug_abbrev_offset_64() { let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); let buf = section.get_contents().unwrap(); let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_abbrev_offset(buf, Format::Dwarf64) { Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_debug_abbrev_offset_64_incomplete() { let buf = [0x01, 0x02]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_abbrev_offset(buf, Format::Dwarf64) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_debug_info_offset_32() { let section = Section::with_endian(Endian::Little).L32(0x0403_0201); let buf = section.get_contents().unwrap(); let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_info_offset(buf, Format::Dwarf32) { Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_debug_info_offset_32_incomplete() { let buf = [0x01, 0x02]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_info_offset(buf, Format::Dwarf32) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_debug_info_offset_64() { let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201); let buf = section.get_contents().unwrap(); let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_info_offset(buf, Format::Dwarf64) { Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_debug_info_offset_64_incomplete() { let buf = [0x01, 0x02]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match parse_debug_info_offset(buf, Format::Dwarf64) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] #[cfg(target_pointer_width = "64")] fn test_units() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let mut unit64 = CompilationUnitHeader { header: UnitHeader { encoding: Encoding { format: Format::Dwarf64, version: 4, address_size: 8, }, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }, offset: DebugInfoOffset(0), }; let mut unit32 = CompilationUnitHeader { header: UnitHeader { encoding: Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }, offset: DebugInfoOffset(0), }; let section = Section::with_endian(Endian::Little) .comp_unit(&mut unit64) .comp_unit(&mut unit32); let buf = section.get_contents().unwrap(); let debug_info = DebugInfo::new(&buf, LittleEndian); let mut units = debug_info.units(); assert_eq!(units.next(), Ok(Some(unit64))); assert_eq!(units.next(), Ok(Some(unit32))); assert_eq!(units.next(), Ok(None)); } #[test] fn test_unit_version_unknown_version() { let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_unit_header(rest) { Err(Error::UnknownVersion(0xcdab)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_unit_header(rest) { Err(Error::UnknownVersion(1)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_unit_version_incomplete() { let buf = [0x01, 0x00, 0x00, 0x00, 0x04]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_unit_header(rest) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) .unit(&mut expected_unit, &[]) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!(parse_unit_header(rest), Ok(expected_unit)); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_unit_header_64_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf64, version: 4, address_size: 8, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) .unit(&mut expected_unit, &[]) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!(parse_unit_header(rest), Ok(expected_unit)); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] fn test_parse_v5_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf32, version: 5, address_size: 4, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) .unit(&mut expected_unit, &[]) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!(parse_unit_header(rest), Ok(expected_unit)); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_v5_unit_header_64_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf64, version: 5, address_size: 8, }; let mut expected_unit = UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }; let section = Section::with_endian(Endian::Little) .unit(&mut expected_unit, &[]) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!(parse_unit_header(rest), Ok(expected_unit)); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] fn test_parse_type_offset_32_ok() { let buf = [0x12, 0x34, 0x56, 0x78, 0x00]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_type_offset(rest, Format::Dwarf32) { Ok(offset) => { assert_eq!(rest.len(), 1); assert_eq!(UnitOffset(0x7856_3412), offset); } otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_type_offset_64_ok() { let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_type_offset(rest, Format::Dwarf64) { Ok(offset) => { assert_eq!(rest.len(), 1); assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset); } otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_parse_type_offset_incomplete() { // Need at least 4 bytes. let buf = [0xff, 0xff, 0xff]; let rest = &mut EndianSlice::new(&buf, LittleEndian); match parse_type_offset(rest, Format::Dwarf32) { Err(Error::UnexpectedEof(_)) => assert!(true), otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_type_unit_header_32_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 8, }; let mut expected_unit = TypeUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }, offset: DebugTypesOffset(0), type_signature: DebugTypeSignature(0xdead_beef_dead_beef), type_offset: UnitOffset(0x7856_3412), }; let section = Section::with_endian(Endian::Little) .type_unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!( parse_type_unit_header(rest, DebugTypesOffset(0)), Ok(expected_unit) ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_type_unit_header_64_ok() { let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9]; let encoding = Encoding { format: Format::Dwarf64, version: 4, address_size: 8, }; let mut expected_unit = TypeUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605), entries_buf: EndianSlice::new(expected_rest, LittleEndian), }, offset: DebugTypesOffset(0), type_signature: DebugTypeSignature(0xdead_beef_dead_beef), type_offset: UnitOffset(0x7856_3412_7856_3412), }; let section = Section::with_endian(Endian::Little) .type_unit(&mut expected_unit) .append_bytes(expected_rest); let buf = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(&buf, LittleEndian); assert_eq!( parse_type_unit_header(rest, DebugTypesOffset(0)), Ok(expected_unit) ); assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian)); } fn section_contents(f: F) -> Vec where F: Fn(Section) -> Section, { f(Section::with_endian(Endian::Little)) .get_contents() .unwrap() } #[test] fn test_attribute_value() { let mut unit = test_parse_attribute_unit_default(); let endian = unit.entries_buf.endian(); let block_data = &[1, 2, 3, 4]; let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data)); let block = EndianSlice::new(&buf, endian); let buf = section_contents(|s| s.L32(0x0102_0304)); let data4 = EndianSlice::new(&buf, endian); let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708)); let data8 = EndianSlice::new(&buf, endian); let tests = [ ( Format::Dwarf32, 2, constants::DW_AT_data_member_location, constants::DW_FORM_block, block, AttributeValue::Block(EndianSlice::new(block_data, endian)), AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))), ), ( Format::Dwarf32, 2, constants::DW_AT_data_member_location, constants::DW_FORM_data4, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), ), ( Format::Dwarf64, 2, constants::DW_AT_data_member_location, constants::DW_FORM_data4, data4, AttributeValue::Data4(0x0102_0304), AttributeValue::Udata(0x0102_0304), ), ( Format::Dwarf32, 4, constants::DW_AT_data_member_location, constants::DW_FORM_data4, data4, AttributeValue::Data4(0x0102_0304), AttributeValue::Udata(0x0102_0304), ), ( Format::Dwarf32, 2, constants::DW_AT_data_member_location, constants::DW_FORM_data8, data8, AttributeValue::Data8(0x0102_0304_0506_0708), AttributeValue::Udata(0x0102_0304_0506_0708), ), #[cfg(target_pointer_width = "64")] ( Format::Dwarf64, 2, constants::DW_AT_data_member_location, constants::DW_FORM_data8, data8, AttributeValue::SecOffset(0x0102_0304_0506_0708), AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), ), ( Format::Dwarf64, 4, constants::DW_AT_data_member_location, constants::DW_FORM_data8, data8, AttributeValue::Data8(0x0102_0304_0506_0708), AttributeValue::Udata(0x0102_0304_0506_0708), ), ( Format::Dwarf32, 4, constants::DW_AT_location, constants::DW_FORM_data4, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)), ), #[cfg(target_pointer_width = "64")] ( Format::Dwarf64, 4, constants::DW_AT_location, constants::DW_FORM_data8, data8, AttributeValue::SecOffset(0x0102_0304_0506_0708), AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)), ), ( Format::Dwarf32, 4, constants::DW_AT_str_offsets_base, constants::DW_FORM_sec_offset, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)), ), ( Format::Dwarf32, 4, constants::DW_AT_addr_base, constants::DW_FORM_sec_offset, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)), ), ( Format::Dwarf32, 4, constants::DW_AT_rnglists_base, constants::DW_FORM_sec_offset, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)), ), ( Format::Dwarf32, 4, constants::DW_AT_loclists_base, constants::DW_FORM_sec_offset, data4, AttributeValue::SecOffset(0x0102_0304), AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)), ), ]; for test in tests.iter() { let (format, version, name, form, mut input, expect_raw, expect_value) = *test; unit.encoding.format = format; unit.encoding.version = version; let spec = vec![AttributeSpecification::new(name, form, None)]; let attribute = parse_attribute(&mut input, &unit, &spec[..]) .expect("Should parse attribute") .0; assert_eq!(attribute.raw_value(), expect_raw); assert_eq!(attribute.value(), expect_value); } } #[test] fn test_attribute_udata_sdata_value() { #[allow(clippy::type_complexity)] let tests: &[( AttributeValue>, Option, Option, )] = &[ (AttributeValue::Data1(1), Some(1), Some(1)), ( AttributeValue::Data1(std::u8::MAX), Some(u64::from(std::u8::MAX)), Some(-1), ), (AttributeValue::Data2(1), Some(1), Some(1)), ( AttributeValue::Data2(std::u16::MAX), Some(u64::from(std::u16::MAX)), Some(-1), ), (AttributeValue::Data4(1), Some(1), Some(1)), ( AttributeValue::Data4(std::u32::MAX), Some(u64::from(std::u32::MAX)), Some(-1), ), (AttributeValue::Data8(1), Some(1), Some(1)), ( AttributeValue::Data8(std::u64::MAX), Some(std::u64::MAX), Some(-1), ), (AttributeValue::Sdata(1), Some(1), Some(1)), (AttributeValue::Sdata(-1), None, Some(-1)), (AttributeValue::Udata(1), Some(1), Some(1)), (AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None), ]; for test in tests.iter() { let (value, expect_udata, expect_sdata) = *test; let attribute = Attribute { name: DW_AT_data_member_location, value, }; assert_eq!(attribute.udata_value(), expect_udata); assert_eq!(attribute.sdata_value(), expect_sdata); } } fn test_parse_attribute_unit( address_size: u8, format: Format, endian: Endian, ) -> UnitHeader> where Endian: Endianity, { let encoding = Encoding { format, version: 4, address_size, }; UnitHeader::new( encoding, 7, DebugAbbrevOffset(0x0807_0605), EndianSlice::new(&[], endian), ) } fn test_parse_attribute_unit_default() -> UnitHeader> { test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian) } fn test_parse_attribute<'input, Endian>( buf: &'input [u8], len: usize, unit: &UnitHeader>, form: constants::DwForm, value: AttributeValue>, ) where Endian: Endianity, { let spec = vec![AttributeSpecification::new( constants::DW_AT_low_pc, form, None, )]; let expect = Attribute { name: constants::DW_AT_low_pc, value, }; let rest = &mut EndianSlice::new(buf, Endian::default()); match parse_attribute(rest, unit, &spec[..]) { Ok((attr, _)) => { assert_eq!(attr, expect); assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default())); } otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } }; } #[test] fn test_parse_attribute_addr() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_addr; let value = AttributeValue::Addr(0x0403_0201); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_addr8() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_addr; let value = AttributeValue::Addr(0x0807_0605_0403_0201); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_block1() { // Length of data (3), three bytes of data, two bytes of left over input. let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_block1; let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_block2() { // Two byte length of data (2), two bytes of data, two bytes of left over input. let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_block2; let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_block4() { // Four byte length of data (2), two bytes of data, no left over input. let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_block4; let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian)); test_parse_attribute(&buf, 6, &unit, form, value); } #[test] fn test_parse_attribute_block() { // LEB length of data (2, one byte), two bytes of data, no left over input. let buf = [0x02, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_block; let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian)); test_parse_attribute(&buf, 3, &unit, form, value); } #[test] fn test_parse_attribute_data1() { let buf = [0x03]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_data1; let value = AttributeValue::Data1(0x03); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_data2() { let buf = [0x02, 0x01, 0x0]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_data2; let value = AttributeValue::Data2(0x0102); test_parse_attribute(&buf, 2, &unit, form, value); } #[test] fn test_parse_attribute_data4() { let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_data4; let value = AttributeValue::Data4(0x0403_0201); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_data8() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_data8; let value = AttributeValue::Data8(0x0807_0605_0403_0201); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_udata() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_udata; let value = AttributeValue::Udata(4097); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_sdata() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::signed(&mut writable, -4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_sdata; let value = AttributeValue::Sdata(-4097); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_exprloc() { // LEB length of data (2, one byte), two bytes of data, one byte left over input. let buf = [0x02, 0x99, 0x99, 0x11]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_exprloc; let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian))); test_parse_attribute(&buf, 3, &unit, form, value); } #[test] fn test_parse_attribute_flag_true() { let buf = [0x42]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_flag; let value = AttributeValue::Flag(true); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_flag_false() { let buf = [0x00]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_flag; let value = AttributeValue::Flag(false); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_flag_present() { let buf = [0x01, 0x02, 0x03, 0x04]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_flag_present; let value = AttributeValue::Flag(true); // DW_FORM_flag_present does not consume any bytes of the input stream. test_parse_attribute(&buf, 0, &unit, form, value); } #[test] fn test_parse_attribute_sec_offset_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_sec_offset; let value = AttributeValue::SecOffset(0x0403_0201); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_sec_offset_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_sec_offset; let value = AttributeValue::SecOffset(0x0807_0605_0403_0201); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_ref1() { let buf = [0x03]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref1; let value = AttributeValue::UnitRef(UnitOffset(3)); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_ref2() { let buf = [0x02, 0x01, 0x0]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref2; let value = AttributeValue::UnitRef(UnitOffset(258)); test_parse_attribute(&buf, 2, &unit, form, value); } #[test] fn test_parse_attribute_ref4() { let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref4; let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_ref8() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref8; let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_ref_sup4() { let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref_sup4; let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_ref_sup8() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref_sup8; let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_refudata() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref_udata; let value = AttributeValue::UnitRef(UnitOffset(4097)); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_refaddr_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_ref_addr; let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_refaddr_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_ref_addr; let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_refaddr_version2() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); unit.encoding.version = 2; let form = constants::DW_FORM_ref_addr; let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_refaddr8_version2() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian); unit.encoding.version = 2; let form = constants::DW_FORM_ref_addr; let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_gnu_ref_alt_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_GNU_ref_alt; let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_gnu_ref_alt_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_GNU_ref_alt; let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_refsig8() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_ref_sig8; let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_string() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_string; let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian)); test_parse_attribute(&buf, 6, &unit, form, value); } #[test] fn test_parse_attribute_strp_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_strp; let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_strp_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strp; let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_strp_sup_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_strp_sup; let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_strp_sup_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strp_sup; let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_gnu_strp_alt_32() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian); let form = constants::DW_FORM_GNU_strp_alt; let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] #[cfg(target_pointer_width = "64")] fn test_parse_attribute_gnu_strp_alt_64() { let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_GNU_strp_alt; let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201)); test_parse_attribute(&buf, 8, &unit, form, value); } #[test] fn test_parse_attribute_strx() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_strx; let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097)); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_strx1() { let buf = [0x01, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strx1; let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01)); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_strx2() { let buf = [0x01, 0x02, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strx2; let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201)); test_parse_attribute(&buf, 2, &unit, form, value); } #[test] fn test_parse_attribute_strx3() { let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strx3; let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201)); test_parse_attribute(&buf, 3, &unit, form, value); } #[test] fn test_parse_attribute_strx4() { let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_strx4; let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_addrx() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_addrx; let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097)); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_addrx1() { let buf = [0x01, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_addrx1; let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01)); test_parse_attribute(&buf, 1, &unit, form, value); } #[test] fn test_parse_attribute_addrx2() { let buf = [0x01, 0x02, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_addrx2; let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201)); test_parse_attribute(&buf, 2, &unit, form, value); } #[test] fn test_parse_attribute_addrx3() { let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_addrx3; let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201)); test_parse_attribute(&buf, 3, &unit, form, value); } #[test] fn test_parse_attribute_addrx4() { let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); let form = constants::DW_FORM_addrx4; let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201)); test_parse_attribute(&buf, 4, &unit, form, value); } #[test] fn test_parse_attribute_loclistx() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_loclistx; let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097)); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_rnglistx() { let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, 4097).expect("should write ok") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_rnglistx; let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097)); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_parse_attribute_indirect() { let mut buf = [0; 100]; let bytes_written = { let mut writable = &mut buf[..]; leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0) .expect("should write udata") + leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value") }; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_indirect; let value = AttributeValue::Udata(9_999_999); test_parse_attribute(&buf, bytes_written, &unit, form, value); } #[test] fn test_attrs_iter() { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let unit = UnitHeader::new( encoding, 7, DebugAbbrevOffset(0x0807_0605), EndianSlice::new(&[], LittleEndian), ); let abbrev = Abbreviation::new( 42, constants::DW_TAG_subprogram, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), AttributeSpecification::new( constants::DW_AT_high_pc, constants::DW_FORM_addr, None, ), ], ); // "foo", 42, 1337, 4 dangling bytes of 0xaa where children would be let buf = [ 0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, ]; let entry = DebuggingInformationEntry { offset: UnitOffset(0), attrs_slice: EndianSlice::new(&buf, LittleEndian), attrs_len: Cell::new(None), abbrev: &abbrev, unit: &unit, }; let mut attrs = AttrsIter { input: EndianSlice::new(&buf, LittleEndian), attributes: abbrev.attributes(), entry: &entry, }; match attrs.next() { Ok(Some(attr)) => { assert_eq!( attr, Attribute { name: constants::DW_AT_name, value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), } ); } otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } } assert!(entry.attrs_len.get().is_none()); match attrs.next() { Ok(Some(attr)) => { assert_eq!( attr, Attribute { name: constants::DW_AT_low_pc, value: AttributeValue::Addr(0x2a), } ); } otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } } assert!(entry.attrs_len.get().is_none()); match attrs.next() { Ok(Some(attr)) => { assert_eq!( attr, Attribute { name: constants::DW_AT_high_pc, value: AttributeValue::Addr(0x539), } ); } otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } } assert!(entry.attrs_len.get().is_none()); assert!(attrs.next().expect("should parse next").is_none()); assert!(entry.attrs_len.get().is_some()); assert_eq!( entry.attrs_len.get().expect("should have entry.attrs_len"), buf.len() - 4 ) } #[test] fn test_attrs_iter_incomplete() { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let unit = UnitHeader::new( encoding, 7, DebugAbbrevOffset(0x0807_0605), EndianSlice::new(&[], LittleEndian), ); let abbrev = Abbreviation::new( 42, constants::DW_TAG_subprogram, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None), AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None), AttributeSpecification::new( constants::DW_AT_high_pc, constants::DW_FORM_addr, None, ), ], ); // "foo" let buf = [0x66, 0x6f, 0x6f, 0x00]; let entry = DebuggingInformationEntry { offset: UnitOffset(0), attrs_slice: EndianSlice::new(&buf, LittleEndian), attrs_len: Cell::new(None), abbrev: &abbrev, unit: &unit, }; let mut attrs = AttrsIter { input: EndianSlice::new(&buf, LittleEndian), attributes: abbrev.attributes(), entry: &entry, }; match attrs.next() { Ok(Some(attr)) => { assert_eq!( attr, Attribute { name: constants::DW_AT_name, value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)), } ); } otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } } assert!(entry.attrs_len.get().is_none()); // Return error for incomplete attribute. assert!(attrs.next().is_err()); assert!(entry.attrs_len.get().is_none()); // Return error for all subsequent calls. assert!(attrs.next().is_err()); assert!(attrs.next().is_err()); assert!(attrs.next().is_err()); assert!(attrs.next().is_err()); assert!(entry.attrs_len.get().is_none()); } fn assert_entry_name(entry: &DebuggingInformationEntry>, name: &str) where Endian: Endianity, { let value = entry .attr_value(constants::DW_AT_name) .expect("Should have parsed the name attribute") .expect("Should have found the name attribute"); assert_eq!( value, AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default())) ); } fn assert_current_name(cursor: &EntriesCursor>, name: &str) where Endian: Endianity, { let entry = cursor.current().expect("Should have an entry result"); assert_entry_name(entry, name); } fn assert_next_entry(cursor: &mut EntriesCursor>, name: &str) where Endian: Endianity, { cursor .next_entry() .expect("Should parse next entry") .expect("Should have an entry"); assert_current_name(cursor, name); } fn assert_next_entry_null(cursor: &mut EntriesCursor>) where Endian: Endianity, { cursor .next_entry() .expect("Should parse next entry") .expect("Should have an entry"); assert!(cursor.current().is_none()); } fn assert_next_dfs( cursor: &mut EntriesCursor>, name: &str, depth: isize, ) where Endian: Endianity, { { let (val, entry) = cursor .next_dfs() .expect("Should parse next dfs") .expect("Should not be done with traversal"); assert_eq!(val, depth); assert_entry_name(entry, name); } assert_current_name(cursor, name); } fn assert_next_sibling(cursor: &mut EntriesCursor>, name: &str) where Endian: Endianity, { { let entry = cursor .next_sibling() .expect("Should parse next sibling") .expect("Should not be done with traversal"); assert_entry_name(entry, name); } assert_current_name(cursor, name); } fn assert_valid_sibling_ptr(cursor: &EntriesCursor>) where Endian: Endianity, { let sibling_ptr = cursor .current() .expect("Should have current entry") .attr_value(constants::DW_AT_sibling); match sibling_ptr { Ok(Some(AttributeValue::UnitRef(offset))) => { cursor .unit .range_from(offset..) .expect("Sibling offset should be valid"); } _ => panic!("Invalid sibling pointer {:?}", sibling_ptr), } } fn entries_cursor_tests_abbrev_buf() -> Vec { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) .abbrev_attr(DW_AT_name, DW_FORM_string) .abbrev_attr_null() .abbrev_null(); section.get_contents().unwrap() } fn entries_cursor_tests_debug_info_buf() -> Vec { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .die(1, |s| s.attr_string("001")) .die(1, |s| s.attr_string("002")) .die(1, |s| s.attr_string("003")) .die_null() .die_null() .die(1, |s| s.attr_string("004")) .die(1, |s| s.attr_string("005")) .die_null() .die(1, |s| s.attr_string("006")) .die_null() .die_null() .die(1, |s| s.attr_string("007")) .die(1, |s| s.attr_string("008")) .die(1, |s| s.attr_string("009")) .die_null() .die_null() .die_null() .die(1, |s| s.attr_string("010")) .die_null() .die_null(); let entries_buf = section.get_contents().unwrap(); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut unit = CompilationUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }, offset: DebugInfoOffset(0), }; let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); section.get_contents().unwrap() } #[test] fn test_cursor_next_entry_incomplete() { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .die(1, |s| s.attr_string("001")) .die(1, |s| s.attr_string("002")) .die(1, |s| s); let entries_buf = section.get_contents().unwrap(); let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut unit = CompilationUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }, offset: DebugInfoOffset(0), }; let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); let info_buf = §ion.get_contents().unwrap(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); assert_next_entry(&mut cursor, "001"); assert_next_entry(&mut cursor, "002"); { // Entry code is present, but none of the attributes. cursor .next_entry() .expect("Should parse next entry") .expect("Should have an entry"); let entry = cursor.current().expect("Should have an entry result"); assert!(entry.attrs().next().is_err()); } assert!(cursor.next_entry().is_err()); assert!(cursor.next_entry().is_err()); } #[test] fn test_cursor_next_entry() { let info_buf = &entries_cursor_tests_debug_info_buf(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); assert_next_entry(&mut cursor, "001"); assert_next_entry(&mut cursor, "002"); assert_next_entry(&mut cursor, "003"); assert_next_entry_null(&mut cursor); assert_next_entry_null(&mut cursor); assert_next_entry(&mut cursor, "004"); assert_next_entry(&mut cursor, "005"); assert_next_entry_null(&mut cursor); assert_next_entry(&mut cursor, "006"); assert_next_entry_null(&mut cursor); assert_next_entry_null(&mut cursor); assert_next_entry(&mut cursor, "007"); assert_next_entry(&mut cursor, "008"); assert_next_entry(&mut cursor, "009"); assert_next_entry_null(&mut cursor); assert_next_entry_null(&mut cursor); assert_next_entry_null(&mut cursor); assert_next_entry(&mut cursor, "010"); assert_next_entry_null(&mut cursor); assert_next_entry_null(&mut cursor); assert!(cursor .next_entry() .expect("Should parse next entry") .is_none()); assert!(cursor.current().is_none()); } #[test] fn test_cursor_next_dfs() { let info_buf = &entries_cursor_tests_debug_info_buf(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); assert_next_dfs(&mut cursor, "001", 0); assert_next_dfs(&mut cursor, "002", 1); assert_next_dfs(&mut cursor, "003", 1); assert_next_dfs(&mut cursor, "004", -1); assert_next_dfs(&mut cursor, "005", 1); assert_next_dfs(&mut cursor, "006", 0); assert_next_dfs(&mut cursor, "007", -1); assert_next_dfs(&mut cursor, "008", 1); assert_next_dfs(&mut cursor, "009", 1); assert_next_dfs(&mut cursor, "010", -2); assert!(cursor.next_dfs().expect("Should parse next dfs").is_none()); assert!(cursor.current().is_none()); } #[test] fn test_cursor_next_sibling_no_sibling_ptr() { let info_buf = &entries_cursor_tests_debug_info_buf(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); assert_next_dfs(&mut cursor, "001", 0); // Down to the first child of the root entry. assert_next_dfs(&mut cursor, "002", 1); // Now iterate all children of the root via `next_sibling`. assert_next_sibling(&mut cursor, "004"); assert_next_sibling(&mut cursor, "007"); assert_next_sibling(&mut cursor, "010"); // There should be no more siblings. assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor.current().is_none()); } #[test] fn test_cursor_next_sibling_continuation() { let info_buf = &entries_cursor_tests_debug_info_buf(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); assert_next_dfs(&mut cursor, "001", 0); // Down to the first child of the root entry. assert_next_dfs(&mut cursor, "002", 1); // Get the next sibling, then iterate its children assert_next_sibling(&mut cursor, "004"); assert_next_dfs(&mut cursor, "005", 1); assert_next_sibling(&mut cursor, "006"); assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); // And we should be able to continue with the children of the root entry. assert_next_dfs(&mut cursor, "007", -1); assert_next_sibling(&mut cursor, "010"); // There should be no more siblings. assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor.current().is_none()); } fn entries_cursor_sibling_abbrev_buf() -> Vec { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) .abbrev_attr(DW_AT_name, DW_FORM_string) .abbrev_attr(DW_AT_sibling, DW_FORM_ref1) .abbrev_attr_null() .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes) .abbrev_attr(DW_AT_name, DW_FORM_string) .abbrev_attr_null() .abbrev_null(); section.get_contents().unwrap() } fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec { let start = Label::new(); let sibling004_ref = Label::new(); let sibling004 = Label::new(); let sibling009_ref = Label::new(); let sibling009 = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .mark(&start) .die(2, |s| s.attr_string("001")) // Valid sibling attribute. .die(1, |s| s.attr_string("002").D8(&sibling004_ref)) // Invalid code to ensure the sibling attribute was used. .die(10, |s| s.attr_string("003")) .die_null() .die_null() .mark(&sibling004) // Invalid sibling attribute. .die(1, |s| s.attr_string("004").attr_ref1(255)) .die(2, |s| s.attr_string("005")) .die_null() .die_null() // Sibling attribute in child only. .die(2, |s| s.attr_string("006")) // Valid sibling attribute. .die(1, |s| s.attr_string("007").D8(&sibling009_ref)) // Invalid code to ensure the sibling attribute was used. .die(10, |s| s.attr_string("008")) .die_null() .die_null() .mark(&sibling009) .die(2, |s| s.attr_string("009")) .die_null() .die_null() // No sibling attribute. .die(2, |s| s.attr_string("010")) .die(2, |s| s.attr_string("011")) .die_null() .die_null() .die_null(); let offset = header_size as u64 + (&sibling004 - &start) as u64; sibling004_ref.set_const(offset); let offset = header_size as u64 + (&sibling009 - &start) as u64; sibling009_ref.set_const(offset); section.get_contents().unwrap() } fn test_cursor_next_sibling_with_ptr(cursor: &mut EntriesCursor>) { assert_next_dfs(cursor, "001", 0); // Down to the first child of the root. assert_next_dfs(cursor, "002", 1); // Now iterate all children of the root via `next_sibling`. assert_valid_sibling_ptr(&cursor); assert_next_sibling(cursor, "004"); assert_next_sibling(cursor, "006"); assert_next_sibling(cursor, "010"); // There should be no more siblings. assert!(cursor .next_sibling() .expect("Should parse next sibling") .is_none()); assert!(cursor.current().is_none()); } #[test] fn test_debug_info_next_sibling_with_ptr() { let format = Format::Dwarf32; let header_size = CompilationUnitHeader::, _>::size_of_header(format); let entries_buf = entries_cursor_sibling_entries_buf(header_size); let encoding = Encoding { format, version: 4, address_size: 4, }; let mut unit = CompilationUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }, offset: DebugInfoOffset(0), }; let section = Section::with_endian(Endian::Little).comp_unit(&mut unit); let info_buf = section.get_contents().unwrap(); let debug_info = DebugInfo::new(&info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrev_buf = entries_cursor_sibling_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); test_cursor_next_sibling_with_ptr(&mut cursor); } #[test] fn test_debug_types_next_sibling_with_ptr() { let format = Format::Dwarf32; let header_size = TypeUnitHeader::, _>::size_of_header(format); let entries_buf = entries_cursor_sibling_entries_buf(header_size); let encoding = Encoding { format, version: 4, address_size: 4, }; let mut unit = TypeUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }, type_signature: DebugTypeSignature(0), type_offset: UnitOffset(0), offset: DebugTypesOffset(0), }; let section = Section::with_endian(Endian::Little).type_unit(&mut unit); let info_buf = section.get_contents().unwrap(); let debug_types = DebugTypes::new(&info_buf, LittleEndian); let unit = debug_types .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrev_buf = entries_cursor_sibling_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); test_cursor_next_sibling_with_ptr(&mut cursor); } #[test] fn test_entries_at_offset() { let info_buf = &entries_cursor_tests_debug_info_buf(); let debug_info = DebugInfo::new(info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("should have a unit result") .expect("and it should be ok"); let abbrevs_buf = &entries_cursor_tests_abbrev_buf(); let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit .entries_at_offset(&abbrevs, UnitOffset(unit.header_size())) .unwrap(); assert_next_entry(&mut cursor, "001"); let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0)); match cursor { Err(Error::OffsetOutOfBounds) => {} otherwise => { println!("Unexpected result = {:#?}", otherwise); assert!(false); } } } fn entries_tree_tests_debug_abbrevs_buf() -> Vec { #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes) .abbrev_attr(DW_AT_name, DW_FORM_string) .abbrev_attr_null() .abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no) .abbrev_attr(DW_AT_name, DW_FORM_string) .abbrev_attr_null() .abbrev_null() .get_contents() .unwrap(); section } fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec, UnitOffset) { let start = Label::new(); let entry2 = Label::new(); #[rustfmt::skip] let section = Section::with_endian(Endian::Little) .mark(&start) .die(1, |s| s.attr_string("root")) .die(1, |s| s.attr_string("1")) .die(1, |s| s.attr_string("1a")) .die_null() .die(2, |s| s.attr_string("1b")) .die_null() .mark(&entry2) .die(1, |s| s.attr_string("2")) .die(1, |s| s.attr_string("2a")) .die(1, |s| s.attr_string("2a1")) .die_null() .die_null() .die(1, |s| s.attr_string("2b")) .die(2, |s| s.attr_string("2b1")) .die_null() .die_null() .die(1, |s| s.attr_string("3")) .die(1, |s| s.attr_string("3a")) .die(2, |s| s.attr_string("3a1")) .die(2, |s| s.attr_string("3a2")) .die_null() .die(2, |s| s.attr_string("3b")) .die_null() .die(2, |s| s.attr_string("final")) .die_null() .get_contents() .unwrap(); let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize); (section, entry2) } #[test] fn test_entries_tree() { fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>( node: Result< Option>>, >, name: &str, ) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>> where Endian: Endianity, { let node = node .expect("Should parse entry") .expect("Should have entry"); assert_entry_name(node.entry(), name); node.children() } fn assert_null(node: Result>>>) { match node { Ok(None) => {} otherwise => { println!("Unexpected parse result = {:#?}", otherwise); assert!(false); } } } let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf(); let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian); let format = Format::Dwarf32; let header_size = CompilationUnitHeader::, _>::size_of_header(format); let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size); let encoding = Encoding { format, version: 4, address_size: 4, }; let mut unit = CompilationUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&entries_buf, LittleEndian), }, offset: DebugInfoOffset(0), }; let info_buf = Section::with_endian(Endian::Little) .comp_unit(&mut unit) .get_contents() .unwrap(); let debug_info = DebugInfo::new(&info_buf, LittleEndian); let unit = debug_info .units() .next() .expect("Should parse unit") .expect("and it should be some"); let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut tree = unit .entries_tree(&abbrevs, None) .expect("Should have entries tree"); // Test we can restart iteration of the tree. { let mut iter = assert_entry(tree.root().map(Some), "root"); assert_entry(iter.next(), "1"); } { let mut iter = assert_entry(tree.root().map(Some), "root"); assert_entry(iter.next(), "1"); } let mut iter = assert_entry(tree.root().map(Some), "root"); { // Test iteration with children. let mut iter = assert_entry(iter.next(), "1"); { // Test iteration with children flag, but no children. let mut iter = assert_entry(iter.next(), "1a"); assert_null(iter.next()); assert_null(iter.next()); } { // Test iteration without children flag. let mut iter = assert_entry(iter.next(), "1b"); assert_null(iter.next()); assert_null(iter.next()); } assert_null(iter.next()); assert_null(iter.next()); } { // Test skipping over children. let mut iter = assert_entry(iter.next(), "2"); assert_entry(iter.next(), "2a"); assert_entry(iter.next(), "2b"); assert_null(iter.next()); } { // Test skipping after partial iteration. let mut iter = assert_entry(iter.next(), "3"); { let mut iter = assert_entry(iter.next(), "3a"); assert_entry(iter.next(), "3a1"); // Parent iter should be able to skip over "3a2". } assert_entry(iter.next(), "3b"); assert_null(iter.next()); } assert_entry(iter.next(), "final"); assert_null(iter.next()); // Test starting at an offset. let mut tree = unit .entries_tree(&abbrevs, Some(entry2)) .expect("Should have entries tree"); let mut iter = assert_entry(tree.root().map(Some), "2"); assert_entry(iter.next(), "2a"); assert_entry(iter.next(), "2b"); assert_null(iter.next()); } #[test] fn test_debug_info_offset() { let padding = &[0; 10]; let entries = &[0; 20]; let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut unit = CompilationUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(entries, LittleEndian), }, offset: DebugInfoOffset(0), }; Section::with_endian(Endian::Little) .append_bytes(padding) .comp_unit(&mut unit); let offset = padding.len(); let header_length = CompilationUnitHeader::, _>::size_of_header(unit.format()); let length = unit.length_including_self(); assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None); assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None); assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None); assert_eq!( DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit), None ); assert_eq!( DebugInfoOffset(offset + header_length).to_unit_offset(&unit), Some(UnitOffset(header_length)) ); assert_eq!( DebugInfoOffset(offset + length - 1).to_unit_offset(&unit), Some(UnitOffset(length - 1)) ); assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None); assert_eq!( UnitOffset(header_length).to_debug_info_offset(&unit), DebugInfoOffset(offset + header_length) ); assert_eq!( UnitOffset(length - 1).to_debug_info_offset(&unit), DebugInfoOffset(offset + length - 1) ); } #[test] fn test_debug_types_offset() { let padding = &[0; 10]; let entries = &[0; 20]; let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut unit = TypeUnitHeader { header: UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(entries, LittleEndian), }, type_signature: DebugTypeSignature(0), type_offset: UnitOffset(0), offset: DebugTypesOffset(0), }; Section::with_endian(Endian::Little) .append_bytes(padding) .type_unit(&mut unit); let offset = padding.len(); let header_length = TypeUnitHeader::, _>::size_of_header(unit.format()); let length = unit.length_including_self(); assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None); assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None); assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None); assert_eq!( DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit), None ); assert_eq!( DebugTypesOffset(offset + header_length).to_unit_offset(&unit), Some(UnitOffset(header_length)) ); assert_eq!( DebugTypesOffset(offset + length - 1).to_unit_offset(&unit), Some(UnitOffset(length - 1)) ); assert_eq!( DebugTypesOffset(offset + length).to_unit_offset(&unit), None ); assert_eq!( UnitOffset(header_length).to_debug_types_offset(&unit), DebugTypesOffset(offset + header_length) ); assert_eq!( UnitOffset(length - 1).to_debug_types_offset(&unit), DebugTypesOffset(offset + length - 1) ); } #[test] fn test_length_including_self() { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let mut unit = UnitHeader { encoding, unit_length: 0, debug_abbrev_offset: DebugAbbrevOffset(0), entries_buf: EndianSlice::new(&[], LittleEndian), }; unit.encoding.format = Format::Dwarf32; assert_eq!(unit.length_including_self(), 4); unit.encoding.format = Format::Dwarf64; assert_eq!(unit.length_including_self(), 12); unit.unit_length = 10; assert_eq!(unit.length_including_self(), 22); } } gimli-0.19.0/src/read/value.rs010066400017500001750000002163141346020377600143300ustar0000000000000000//! Definitions for values used in DWARF expressions. use std::mem; use crate::constants; use crate::read::{AttributeValue, DebuggingInformationEntry, Error, Reader, Result}; /// Convert a u64 to an i64, with sign extension if required. /// /// This is primarily used when needing to treat `Value::Generic` /// as a signed value. #[inline] fn sign_extend(value: u64, mask: u64) -> i64 { let value = (value & mask) as i64; let sign = ((mask >> 1) + 1) as i64; (value ^ sign).wrapping_sub(sign) } #[inline] fn mask_bit_size(addr_mask: u64) -> u32 { 64 - addr_mask.leading_zeros() } /// The type of an entry on the DWARF stack. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ValueType { /// The generic type, which is address-sized and of unspecified sign, /// as specified in the DWARF 5 standard, section 2.5.1. /// This type is also used to represent address base types. Generic, /// Signed 8-bit integer type. I8, /// Unsigned 8-bit integer type. U8, /// Signed 16-bit integer type. I16, /// Unsigned 16-bit integer type. U16, /// Signed 32-bit integer type. I32, /// Unsigned 32-bit integer type. U32, /// Signed 64-bit integer type. I64, /// Unsigned 64-bit integer type. U64, /// 32-bit floating point type. F32, /// 64-bit floating point type. F64, } /// The value of an entry on the DWARF stack. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Value { /// A generic value, which is address-sized and of unspecified sign. Generic(u64), /// A signed 8-bit integer value. I8(i8), /// An unsigned 8-bit integer value. U8(u8), /// A signed 16-bit integer value. I16(i16), /// An unsigned 16-bit integer value. U16(u16), /// A signed 32-bit integer value. I32(i32), /// An unsigned 32-bit integer value. U32(u32), /// A signed 64-bit integer value. I64(i64), /// An unsigned 64-bit integer value. U64(u64), /// A 32-bit floating point value. F32(f32), /// A 64-bit floating point value. F64(f64), } impl ValueType { /// The size in bits of a value for this type. pub fn bit_size(self, addr_mask: u64) -> u32 { match self { ValueType::Generic => mask_bit_size(addr_mask), ValueType::I8 | ValueType::U8 => 8, ValueType::I16 | ValueType::U16 => 16, ValueType::I32 | ValueType::U32 | ValueType::F32 => 32, ValueType::I64 | ValueType::U64 | ValueType::F64 => 64, } } /// Construct a `ValueType` from the attributes of a base type DIE. pub fn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option { Some(match (encoding, byte_size) { (constants::DW_ATE_signed, 1) => ValueType::I8, (constants::DW_ATE_signed, 2) => ValueType::I16, (constants::DW_ATE_signed, 4) => ValueType::I32, (constants::DW_ATE_signed, 8) => ValueType::I64, (constants::DW_ATE_unsigned, 1) => ValueType::U8, (constants::DW_ATE_unsigned, 2) => ValueType::U16, (constants::DW_ATE_unsigned, 4) => ValueType::U32, (constants::DW_ATE_unsigned, 8) => ValueType::U64, (constants::DW_ATE_float, 4) => ValueType::F32, (constants::DW_ATE_float, 8) => ValueType::F64, _ => return None, }) } /// Construct a `ValueType` from a base type DIE. pub fn from_entry( entry: &DebuggingInformationEntry, ) -> Result> { if entry.tag() != constants::DW_TAG_base_type { return Ok(None); } let mut encoding = None; let mut byte_size = None; let mut endianity = constants::DW_END_default; let mut attrs = entry.attrs(); while let Some(attr) = attrs.next()? { match attr.name() { constants::DW_AT_byte_size => byte_size = attr.udata_value(), constants::DW_AT_encoding => { if let AttributeValue::Encoding(x) = attr.value() { encoding = Some(x); } } constants::DW_AT_endianity => { if let AttributeValue::Endianity(x) = attr.value() { endianity = x; } } _ => {} } } if endianity != constants::DW_END_default { // TODO: we could check if it matches the reader endianity, // but normally it would use DW_END_default in that case. return Ok(None); } if let (Some(encoding), Some(byte_size)) = (encoding, byte_size) { Ok(ValueType::from_encoding(encoding, byte_size)) } else { Ok(None) } } } impl Value { /// Return the `ValueType` corresponding to this `Value`. pub fn value_type(&self) -> ValueType { match *self { Value::Generic(_) => ValueType::Generic, Value::I8(_) => ValueType::I8, Value::U8(_) => ValueType::U8, Value::I16(_) => ValueType::I16, Value::U16(_) => ValueType::U16, Value::I32(_) => ValueType::I32, Value::U32(_) => ValueType::U32, Value::I64(_) => ValueType::I64, Value::U64(_) => ValueType::U64, Value::F32(_) => ValueType::F32, Value::F64(_) => ValueType::F64, } } /// Read a `Value` with the given `value_type` from a `Reader`. pub fn parse(value_type: ValueType, mut bytes: R) -> Result { let value = match value_type { ValueType::I8 => Value::I8(bytes.read_i8()?), ValueType::U8 => Value::U8(bytes.read_u8()?), ValueType::I16 => Value::I16(bytes.read_i16()?), ValueType::U16 => Value::U16(bytes.read_u16()?), ValueType::I32 => Value::I32(bytes.read_i32()?), ValueType::U32 => Value::U32(bytes.read_u32()?), ValueType::I64 => Value::I64(bytes.read_i64()?), ValueType::U64 => Value::U64(bytes.read_u64()?), ValueType::F32 => Value::F32(bytes.read_f32()?), ValueType::F64 => Value::F64(bytes.read_f64()?), _ => return Err(Error::UnsupportedTypeOperation), }; Ok(value) } /// Convert a `Value` to a `u64`. /// /// The `ValueType` of `self` must be integral. /// Values are sign extended if the source value is signed. pub fn to_u64(self, addr_mask: u64) -> Result { let value = match self { Value::Generic(value) => value & addr_mask, Value::I8(value) => value as u64, Value::U8(value) => u64::from(value), Value::I16(value) => value as u64, Value::U16(value) => u64::from(value), Value::I32(value) => value as u64, Value::U32(value) => u64::from(value), Value::I64(value) => value as u64, Value::U64(value) => value as u64, _ => return Err(Error::IntegralTypeRequired), }; Ok(value) } /// Create a `Value` with the given `value_type` from a `u64` value. /// /// The `value_type` may be integral or floating point. /// The result is truncated if the `u64` value does /// not fit the bounds of the `value_type`. pub fn from_u64(value_type: ValueType, value: u64) -> Result { let value = match value_type { ValueType::Generic => Value::Generic(value), ValueType::I8 => Value::I8(value as i8), ValueType::U8 => Value::U8(value as u8), ValueType::I16 => Value::I16(value as i16), ValueType::U16 => Value::U16(value as u16), ValueType::I32 => Value::I32(value as i32), ValueType::U32 => Value::U32(value as u32), ValueType::I64 => Value::I64(value as i64), ValueType::U64 => Value::U64(value), ValueType::F32 => Value::F32(value as f32), ValueType::F64 => Value::F64(value as f64), }; Ok(value) } /// Create a `Value` with the given `value_type` from a `f32` value. /// /// The `value_type` may be integral or floating point. /// The result is not defined if the `f32` value does /// not fit the bounds of the `value_type`. fn from_f32(value_type: ValueType, value: f32) -> Result { let value = match value_type { ValueType::Generic => Value::Generic(value as u64), ValueType::I8 => Value::I8(value as i8), ValueType::U8 => Value::U8(value as u8), ValueType::I16 => Value::I16(value as i16), ValueType::U16 => Value::U16(value as u16), ValueType::I32 => Value::I32(value as i32), ValueType::U32 => Value::U32(value as u32), ValueType::I64 => Value::I64(value as i64), ValueType::U64 => Value::U64(value as u64), ValueType::F32 => Value::F32(value), ValueType::F64 => Value::F64(f64::from(value)), }; Ok(value) } /// Create a `Value` with the given `value_type` from a `f64` value. /// /// The `value_type` may be integral or floating point. /// The result is not defined if the `f64` value does /// not fit the bounds of the `value_type`. fn from_f64(value_type: ValueType, value: f64) -> Result { let value = match value_type { ValueType::Generic => Value::Generic(value as u64), ValueType::I8 => Value::I8(value as i8), ValueType::U8 => Value::U8(value as u8), ValueType::I16 => Value::I16(value as i16), ValueType::U16 => Value::U16(value as u16), ValueType::I32 => Value::I32(value as i32), ValueType::U32 => Value::U32(value as u32), ValueType::I64 => Value::I64(value as i64), ValueType::U64 => Value::U64(value as u64), ValueType::F32 => Value::F32(value as f32), ValueType::F64 => Value::F64(value), }; Ok(value) } /// Convert a `Value` to the given `value_type`. /// /// When converting between integral types, the result is truncated /// if the source value does not fit the bounds of the `value_type`. /// When converting from floating point types, the result is not defined /// if the source value does not fit the bounds of the `value_type`. /// /// This corresponds to the DWARF `DW_OP_convert` operation. pub fn convert(self, value_type: ValueType, addr_mask: u64) -> Result { match self { Value::F32(value) => Value::from_f32(value_type, value), Value::F64(value) => Value::from_f64(value_type, value), _ => Value::from_u64(value_type, self.to_u64(addr_mask)?), } } /// Reinterpret the bits in a `Value` as the given `value_type`. /// /// The source and result value types must have equal sizes. /// /// This corresponds to the DWARF `DW_OP_reinterpret` operation. pub fn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result { if self.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) { return Err(Error::TypeMismatch); } let bits = match self { Value::Generic(value) => value, Value::I8(value) => value as u64, Value::U8(value) => u64::from(value), Value::I16(value) => value as u64, Value::U16(value) => u64::from(value), Value::I32(value) => value as u64, Value::U32(value) => u64::from(value), Value::I64(value) => value as u64, Value::U64(value) => value, Value::F32(value) => u64::from(unsafe { mem::transmute::(value) }), Value::F64(value) => unsafe { mem::transmute(value) }, }; let value = match value_type { ValueType::Generic => Value::Generic(bits), ValueType::I8 => Value::I8(bits as i8), ValueType::U8 => Value::U8(bits as u8), ValueType::I16 => Value::I16(bits as i16), ValueType::U16 => Value::U16(bits as u16), ValueType::I32 => Value::I32(bits as i32), ValueType::U32 => Value::U32(bits as u32), ValueType::I64 => Value::I64(bits as i64), ValueType::U64 => Value::U64(bits), ValueType::F32 => Value::F32(f32::from_bits(bits as u32)), ValueType::F64 => Value::F64(f64::from_bits(bits)), }; Ok(value) } /// Perform an absolute value operation. /// /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_abs` operation. pub fn abs(self, addr_mask: u64) -> Result { // wrapping_abs() can be used because DWARF specifies that the result is undefined // for negative minimal values. let value = match self { Value::Generic(value) => { Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64) } Value::I8(value) => Value::I8(value.wrapping_abs()), Value::I16(value) => Value::I16(value.wrapping_abs()), Value::I32(value) => Value::I32(value.wrapping_abs()), Value::I64(value) => Value::I64(value.wrapping_abs()), // f32/f64::abs() is not available in libcore Value::F32(value) => Value::F32(if value < 0. { -value } else { value }), Value::F64(value) => Value::F64(if value < 0. { -value } else { value }), Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self, }; Ok(value) } /// Perform a negation operation. /// /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_neg` operation. pub fn neg(self, addr_mask: u64) -> Result { // wrapping_neg() can be used because DWARF specifies that the result is undefined // for negative minimal values. let value = match self { Value::Generic(value) => { Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64) } Value::I8(value) => Value::I8(value.wrapping_neg()), Value::I16(value) => Value::I16(value.wrapping_neg()), Value::I32(value) => Value::I32(value.wrapping_neg()), Value::I64(value) => Value::I64(value.wrapping_neg()), Value::F32(value) => Value::F32(-value), Value::F64(value) => Value::F64(-value), // It's unclear if these should implicity convert to a signed value. // For now, we don't support them. Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { return Err(Error::UnsupportedTypeOperation); } }; Ok(value) } /// Perform an addition operation. /// /// This operation requires matching types. /// /// This corresponds to the DWARF `DW_OP_plus` operation. pub fn add(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { Value::Generic(v1.wrapping_add(v2) & addr_mask) } (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_add(v2)), (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_add(v2)), (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_add(v2)), (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_add(v2)), (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)), (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)), (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)), (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)), (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 + v2), (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 + v2), _ => return Err(Error::TypeMismatch), }; Ok(value) } /// Perform a subtraction operation. /// /// This operation requires matching types. /// /// This corresponds to the DWARF `DW_OP_minus` operation. pub fn sub(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { Value::Generic(v1.wrapping_sub(v2) & addr_mask) } (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_sub(v2)), (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_sub(v2)), (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_sub(v2)), (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_sub(v2)), (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_sub(v2)), (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_sub(v2)), (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_sub(v2)), (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_sub(v2)), (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 - v2), (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 - v2), _ => return Err(Error::TypeMismatch), }; Ok(value) } /// Perform a multiplication operation. /// /// This operation requires matching types. /// /// This corresponds to the DWARF `DW_OP_mul` operation. pub fn mul(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { Value::Generic(v1.wrapping_mul(v2) & addr_mask) } (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_mul(v2)), (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_mul(v2)), (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_mul(v2)), (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_mul(v2)), (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_mul(v2)), (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_mul(v2)), (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_mul(v2)), (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_mul(v2)), (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 * v2), (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 * v2), _ => return Err(Error::TypeMismatch), }; Ok(value) } /// Perform a division operation. /// /// This operation requires matching types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_div` operation. pub fn div(self, rhs: Value, addr_mask: u64) -> Result { match rhs { Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => { return Err(Error::DivisionByZero); } Value::I8(0) | Value::U8(0) | Value::I16(0) | Value::U16(0) | Value::I32(0) | Value::U32(0) | Value::I64(0) | Value::U64(0) => { return Err(Error::DivisionByZero); } _ => {} } let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { // Signed division Value::Generic( sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64, ) } (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)), (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)), (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)), (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)), (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)), (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)), (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)), (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)), (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2), (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2), _ => return Err(Error::TypeMismatch), }; Ok(value) } /// Perform a remainder operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as an unsigned value. /// /// This corresponds to the DWARF `DW_OP_mod` operation. pub fn rem(self, rhs: Value, addr_mask: u64) -> Result { match rhs { Value::Generic(rhs) if (rhs & addr_mask) == 0 => { return Err(Error::DivisionByZero); } Value::I8(0) | Value::U8(0) | Value::I16(0) | Value::U16(0) | Value::I32(0) | Value::U32(0) | Value::I64(0) | Value::U64(0) => { return Err(Error::DivisionByZero); } _ => {} } let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { // Unsigned modulus Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask)) } (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)), (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)), (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)), (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)), (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)), (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)), (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)), (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)), (Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired), (Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired), _ => return Err(Error::TypeMismatch), }; Ok(value) } /// Perform a bitwise not operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_not` operation. pub fn not(self, addr_mask: u64) -> Result { let value_type = self.value_type(); let v = self.to_u64(addr_mask)?; Value::from_u64(value_type, !v) } /// Perform a bitwise and operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_and` operation. pub fn and(self, rhs: Value, addr_mask: u64) -> Result { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch); } let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?; Value::from_u64(value_type, v1 & v2) } /// Perform a bitwise or operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_or` operation. pub fn or(self, rhs: Value, addr_mask: u64) -> Result { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch); } let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?; Value::from_u64(value_type, v1 | v2) } /// Perform a bitwise exclusive-or operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_xor` operation. pub fn xor(self, rhs: Value, addr_mask: u64) -> Result { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch); } let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?; Value::from_u64(value_type, v1 ^ v2) } /// Convert value to bit length suitable for a shift operation. /// /// If the value is negative then an error is returned. fn shift_length(self) -> Result { let value = match self { Value::Generic(value) => value, Value::I8(value) if value >= 0 => value as u64, Value::U8(value) => u64::from(value), Value::I16(value) if value >= 0 => value as u64, Value::U16(value) => u64::from(value), Value::I32(value) if value >= 0 => value as u64, Value::U32(value) => u64::from(value), Value::I64(value) if value >= 0 => value as u64, Value::U64(value) => value, _ => return Err(Error::InvalidShiftExpression), }; Ok(value) } /// Perform a shift left operation. /// /// This operation requires integral types. /// If the shift length exceeds the type size, then 0 is returned. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shl` operation. pub fn shl(self, rhs: Value, addr_mask: u64) -> Result { let v2 = rhs.shift_length()?; let value = match self { Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { 0 } else { (v1 & addr_mask) << v2 }), Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }), Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }), Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }), Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }), Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }), Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }), Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }), Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }), _ => return Err(Error::IntegralTypeRequired), }; Ok(value) } /// Perform a logical shift right operation. /// /// This operation requires an unsigned integral type for the value. /// If the value type is `Generic`, then it is interpreted as an unsigned value. /// /// This operation requires an integral type for the shift length. /// If the shift length exceeds the type size, then 0 is returned. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shr` operation. pub fn shr(self, rhs: Value, addr_mask: u64) -> Result { let v2 = rhs.shift_length()?; let value = match self { Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { 0 } else { (v1 & addr_mask) >> v2 }), Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }), Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }), Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }), Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }), // It's unclear if signed values should implicity convert to an unsigned value. // For now, we don't support them. Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => { return Err(Error::UnsupportedTypeOperation); } _ => return Err(Error::IntegralTypeRequired), }; Ok(value) } /// Perform an arithmetic shift right operation. /// /// This operation requires a signed integral type for the value. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This operation requires an integral type for the shift length. /// If the shift length exceeds the type size, then 0 is returned for positive values, /// and -1 is returned for negative values. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shra` operation. pub fn shra(self, rhs: Value, addr_mask: u64) -> Result { let v2 = rhs.shift_length()?; let value = match self { Value::Generic(v1) => { let v1 = sign_extend(v1, addr_mask); let value = if v2 >= u64::from(mask_bit_size(addr_mask)) { if v1 < 0 { !0 } else { 0 } } else { (v1 >> v2) as u64 }; Value::Generic(value) } Value::I8(v1) => Value::I8(if v2 >= 8 { if v1 < 0 { !0 } else { 0 } } else { v1 >> v2 }), Value::I16(v1) => Value::I16(if v2 >= 16 { if v1 < 0 { !0 } else { 0 } } else { v1 >> v2 }), Value::I32(v1) => Value::I32(if v2 >= 32 { if v1 < 0 { !0 } else { 0 } } else { v1 >> v2 }), Value::I64(v1) => Value::I64(if v2 >= 64 { if v1 < 0 { !0 } else { 0 } } else { v1 >> v2 }), // It's unclear if unsigned values should implicity convert to a signed value. // For now, we don't support them. Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { return Err(Error::UnsupportedTypeOperation); } _ => return Err(Error::IntegralTypeRequired), }; Ok(value) } /// Perform the `==` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_eq` operation. pub fn eq(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 == v2, (Value::U8(v1), Value::U8(v2)) => v1 == v2, (Value::I16(v1), Value::I16(v2)) => v1 == v2, (Value::U16(v1), Value::U16(v2)) => v1 == v2, (Value::I32(v1), Value::I32(v2)) => v1 == v2, (Value::U32(v1), Value::U32(v2)) => v1 == v2, (Value::I64(v1), Value::I64(v2)) => v1 == v2, (Value::U64(v1), Value::U64(v2)) => v1 == v2, (Value::F32(v1), Value::F32(v2)) => v1 == v2, (Value::F64(v1), Value::F64(v2)) => v1 == v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } /// Perform the `>=` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_ge` operation. pub fn ge(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 >= v2, (Value::U8(v1), Value::U8(v2)) => v1 >= v2, (Value::I16(v1), Value::I16(v2)) => v1 >= v2, (Value::U16(v1), Value::U16(v2)) => v1 >= v2, (Value::I32(v1), Value::I32(v2)) => v1 >= v2, (Value::U32(v1), Value::U32(v2)) => v1 >= v2, (Value::I64(v1), Value::I64(v2)) => v1 >= v2, (Value::U64(v1), Value::U64(v2)) => v1 >= v2, (Value::F32(v1), Value::F32(v2)) => v1 >= v2, (Value::F64(v1), Value::F64(v2)) => v1 >= v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } /// Perform the `>` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_gt` operation. pub fn gt(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 > v2, (Value::U8(v1), Value::U8(v2)) => v1 > v2, (Value::I16(v1), Value::I16(v2)) => v1 > v2, (Value::U16(v1), Value::U16(v2)) => v1 > v2, (Value::I32(v1), Value::I32(v2)) => v1 > v2, (Value::U32(v1), Value::U32(v2)) => v1 > v2, (Value::I64(v1), Value::I64(v2)) => v1 > v2, (Value::U64(v1), Value::U64(v2)) => v1 > v2, (Value::F32(v1), Value::F32(v2)) => v1 > v2, (Value::F64(v1), Value::F64(v2)) => v1 > v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } /// Perform the `<= relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_le` operation. pub fn le(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 <= v2, (Value::U8(v1), Value::U8(v2)) => v1 <= v2, (Value::I16(v1), Value::I16(v2)) => v1 <= v2, (Value::U16(v1), Value::U16(v2)) => v1 <= v2, (Value::I32(v1), Value::I32(v2)) => v1 <= v2, (Value::U32(v1), Value::U32(v2)) => v1 <= v2, (Value::I64(v1), Value::I64(v2)) => v1 <= v2, (Value::U64(v1), Value::U64(v2)) => v1 <= v2, (Value::F32(v1), Value::F32(v2)) => v1 <= v2, (Value::F64(v1), Value::F64(v2)) => v1 <= v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } /// Perform the `< relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_lt` operation. pub fn lt(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 < v2, (Value::U8(v1), Value::U8(v2)) => v1 < v2, (Value::I16(v1), Value::I16(v2)) => v1 < v2, (Value::U16(v1), Value::U16(v2)) => v1 < v2, (Value::I32(v1), Value::I32(v2)) => v1 < v2, (Value::U32(v1), Value::U32(v2)) => v1 < v2, (Value::I64(v1), Value::I64(v2)) => v1 < v2, (Value::U64(v1), Value::U64(v2)) => v1 < v2, (Value::F32(v1), Value::F32(v2)) => v1 < v2, (Value::F64(v1), Value::F64(v2)) => v1 < v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } /// Perform the `!= relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_ne` operation. pub fn ne(self, rhs: Value, addr_mask: u64) -> Result { let value = match (self, rhs) { (Value::Generic(v1), Value::Generic(v2)) => { sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask) } (Value::I8(v1), Value::I8(v2)) => v1 != v2, (Value::U8(v1), Value::U8(v2)) => v1 != v2, (Value::I16(v1), Value::I16(v2)) => v1 != v2, (Value::U16(v1), Value::U16(v2)) => v1 != v2, (Value::I32(v1), Value::I32(v2)) => v1 != v2, (Value::U32(v1), Value::U32(v2)) => v1 != v2, (Value::I64(v1), Value::I64(v2)) => v1 != v2, (Value::U64(v1), Value::U64(v2)) => v1 != v2, (Value::F32(v1), Value::F32(v2)) => v1 != v2, (Value::F64(v1), Value::F64(v2)) => v1 != v2, _ => return Err(Error::TypeMismatch), }; Ok(Value::Generic(value as u64)) } } #[cfg(test)] mod tests { use super::*; use crate::common::{DebugAbbrevOffset, Encoding, Format}; use crate::endianity::LittleEndian; use crate::read::{ Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader, UnitOffset, }; #[test] #[rustfmt::skip] fn valuetype_from_encoding() { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 4, }; let unit = UnitHeader::new( encoding, 7, DebugAbbrevOffset(0), EndianSlice::new(&[], LittleEndian), ); let abbrev = Abbreviation::new( 42, constants::DW_TAG_base_type, constants::DW_CHILDREN_no, vec![ AttributeSpecification::new( constants::DW_AT_byte_size, constants::DW_FORM_udata, None, ), AttributeSpecification::new( constants::DW_AT_encoding, constants::DW_FORM_udata, None, ), AttributeSpecification::new( constants::DW_AT_endianity, constants::DW_FORM_udata, None, ), ], ); for &(attrs, result) in &[ ([0x01, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I8), ([0x02, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I16), ([0x04, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I32), ([0x08, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I64), ([0x01, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U8), ([0x02, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U16), ([0x04, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U32), ([0x08, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U64), ([0x04, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F32), ([0x08, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F64), ] { let entry = DebuggingInformationEntry::new( UnitOffset(0), EndianSlice::new(&attrs, LittleEndian), &abbrev, &unit, ); assert_eq!(ValueType::from_entry(&entry), Ok(Some(result))); } for attrs in &[ [0x03, constants::DW_ATE_signed.0, constants::DW_END_default.0], [0x02, constants::DW_ATE_signed.0, constants::DW_END_big.0], ] { let entry = DebuggingInformationEntry::new( UnitOffset(0), EndianSlice::new(attrs, LittleEndian), &abbrev, &unit, ); assert_eq!(ValueType::from_entry(&entry), Ok(None)); } } #[test] fn value_convert() { let addr_mask = !0 >> 32; for &(v, t, result) in &[ (Value::Generic(1), ValueType::I8, Ok(Value::I8(1))), (Value::I8(1), ValueType::U8, Ok(Value::U8(1))), (Value::U8(1), ValueType::I16, Ok(Value::I16(1))), (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), (Value::U16(1), ValueType::I32, Ok(Value::I32(1))), (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), (Value::U32(1), ValueType::F32, Ok(Value::F32(1.))), (Value::F32(1.), ValueType::I64, Ok(Value::I64(1))), (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), (Value::U64(1), ValueType::F64, Ok(Value::F64(1.))), (Value::F64(1.), ValueType::Generic, Ok(Value::Generic(1))), ] { assert_eq!(v.convert(t, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_reinterpret() { let addr_mask = !0 >> 32; for &(v, t, result) in &[ // 8-bit (Value::I8(-1), ValueType::U8, Ok(Value::U8(0xff))), (Value::U8(0xff), ValueType::I8, Ok(Value::I8(-1))), // 16-bit (Value::I16(1), ValueType::U16, Ok(Value::U16(1))), (Value::U16(1), ValueType::I16, Ok(Value::I16(1))), // 32-bit (Value::Generic(1), ValueType::I32, Ok(Value::I32(1))), (Value::I32(1), ValueType::U32, Ok(Value::U32(1))), (Value::U32(0x3f80_0000), ValueType::F32, Ok(Value::F32(1.0))), (Value::F32(1.0), ValueType::Generic, Ok(Value::Generic(0x3f80_0000))), // Type mismatches (Value::Generic(1), ValueType::U8, Err(Error::TypeMismatch)), (Value::U8(1), ValueType::U16, Err(Error::TypeMismatch)), (Value::U16(1), ValueType::U32, Err(Error::TypeMismatch)), (Value::U32(1), ValueType::U64, Err(Error::TypeMismatch)), (Value::U64(1), ValueType::Generic, Err(Error::TypeMismatch)), ] { assert_eq!(v.reinterpret(t, addr_mask), result); } let addr_mask = !0; for &(v, t, result) in &[ // 64-bit (Value::Generic(1), ValueType::I64, Ok(Value::I64(1))), (Value::I64(1), ValueType::U64, Ok(Value::U64(1))), (Value::U64(0x3ff0_0000_0000_0000), ValueType::F64, Ok(Value::F64(1.0))), (Value::F64(1.0), ValueType::Generic, Ok(Value::Generic(0x3ff0_0000_0000_0000))), ] { assert_eq!(v.reinterpret(t, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_abs() { let addr_mask = 0xffff_ffff; for &(v, result) in &[ (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), (Value::I8(-1), Ok(Value::I8(1))), (Value::U8(1), Ok(Value::U8(1))), (Value::I16(-1), Ok(Value::I16(1))), (Value::U16(1), Ok(Value::U16(1))), (Value::I32(-1), Ok(Value::I32(1))), (Value::U32(1), Ok(Value::U32(1))), (Value::I64(-1), Ok(Value::I64(1))), (Value::U64(1), Ok(Value::U64(1))), (Value::F32(-1.), Ok(Value::F32(1.))), (Value::F64(-1.), Ok(Value::F64(1.))), ] { assert_eq!(v.abs(addr_mask), result); } } #[test] #[rustfmt::skip] fn value_neg() { let addr_mask = 0xffff_ffff; for &(v, result) in &[ (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))), (Value::I8(1), Ok(Value::I8(-1))), (Value::U8(1), Err(Error::UnsupportedTypeOperation)), (Value::I16(1), Ok(Value::I16(-1))), (Value::U16(1), Err(Error::UnsupportedTypeOperation)), (Value::I32(1), Ok(Value::I32(-1))), (Value::U32(1), Err(Error::UnsupportedTypeOperation)), (Value::I64(1), Ok(Value::I64(-1))), (Value::U64(1), Err(Error::UnsupportedTypeOperation)), (Value::F32(1.), Ok(Value::F32(-1.))), (Value::F64(1.), Ok(Value::F64(-1.))), ] { assert_eq!(v.neg(addr_mask), result); } } #[test] #[rustfmt::skip] fn value_add() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(1), Value::Generic(2), Ok(Value::Generic(3))), (Value::I8(-1), Value::I8(2), Ok(Value::I8(1))), (Value::U8(1), Value::U8(2), Ok(Value::U8(3))), (Value::I16(-1), Value::I16(2), Ok(Value::I16(1))), (Value::U16(1), Value::U16(2), Ok(Value::U16(3))), (Value::I32(-1), Value::I32(2), Ok(Value::I32(1))), (Value::U32(1), Value::U32(2), Ok(Value::U32(3))), (Value::I64(-1), Value::I64(2), Ok(Value::I64(1))), (Value::U64(1), Value::U64(2), Ok(Value::U64(3))), (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(1.))), (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(1.))), (Value::Generic(1), Value::U32(2), Err(Error::TypeMismatch)), ] { assert_eq!(v1.add(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_sub() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), (Value::I8(-1), Value::I8(2), Ok(Value::I8(-3))), (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), (Value::I16(-1), Value::I16(2), Ok(Value::I16(-3))), (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), (Value::I32(-1), Value::I32(2), Ok(Value::I32(-3))), (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), (Value::I64(-1), Value::I64(2), Ok(Value::I64(-3))), (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(-3.))), (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(-3.))), (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), ] { assert_eq!(v1.sub(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_mul() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(2), Value::Generic(3), Ok(Value::Generic(6))), (Value::I8(-2), Value::I8(3), Ok(Value::I8(-6))), (Value::U8(2), Value::U8(3), Ok(Value::U8(6))), (Value::I16(-2), Value::I16(3), Ok(Value::I16(-6))), (Value::U16(2), Value::U16(3), Ok(Value::U16(6))), (Value::I32(-2), Value::I32(3), Ok(Value::I32(-6))), (Value::U32(2), Value::U32(3), Ok(Value::U32(6))), (Value::I64(-2), Value::I64(3), Ok(Value::I64(-6))), (Value::U64(2), Value::U64(3), Ok(Value::U64(6))), (Value::F32(-2.), Value::F32(3.), Ok(Value::F32(-6.))), (Value::F64(-2.), Value::F64(3.), Ok(Value::F64(-6.))), (Value::Generic(2), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.mul(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_div() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(6), Value::Generic(3), Ok(Value::Generic(2))), (Value::I8(-6), Value::I8(3), Ok(Value::I8(-2))), (Value::U8(6), Value::U8(3), Ok(Value::U8(2))), (Value::I16(-6), Value::I16(3), Ok(Value::I16(-2))), (Value::U16(6), Value::U16(3), Ok(Value::U16(2))), (Value::I32(-6), Value::I32(3), Ok(Value::I32(-2))), (Value::U32(6), Value::U32(3), Ok(Value::U32(2))), (Value::I64(-6), Value::I64(3), Ok(Value::I64(-2))), (Value::U64(6), Value::U64(3), Ok(Value::U64(2))), (Value::F32(-6.), Value::F32(3.), Ok(Value::F32(-2.))), (Value::F64(-6.), Value::F64(3.), Ok(Value::F64(-2.))), (Value::Generic(6), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.div(v2, addr_mask), result); } for &(v1, v2, result) in &[ (Value::Generic(6), Value::Generic(0), Err(Error::DivisionByZero)), (Value::I8(-6), Value::I8(0), Err(Error::DivisionByZero)), (Value::U8(6), Value::U8(0), Err(Error::DivisionByZero)), (Value::I16(-6), Value::I16(0), Err(Error::DivisionByZero)), (Value::U16(6), Value::U16(0), Err(Error::DivisionByZero)), (Value::I32(-6), Value::I32(0), Err(Error::DivisionByZero)), (Value::U32(6), Value::U32(0), Err(Error::DivisionByZero)), (Value::I64(-6), Value::I64(0), Err(Error::DivisionByZero)), (Value::U64(6), Value::U64(0), Err(Error::DivisionByZero)), (Value::F32(-6.), Value::F32(0.), Ok(Value::F32(-6. / 0.))), (Value::F64(-6.), Value::F64(0.), Ok(Value::F64(-6. / 0.))), ] { assert_eq!(v1.div(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_rem() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))), (Value::I8(-3), Value::I8(2), Ok(Value::I8(-1))), (Value::U8(3), Value::U8(2), Ok(Value::U8(1))), (Value::I16(-3), Value::I16(2), Ok(Value::I16(-1))), (Value::U16(3), Value::U16(2), Ok(Value::U16(1))), (Value::I32(-3), Value::I32(2), Ok(Value::I32(-1))), (Value::U32(3), Value::U32(2), Ok(Value::U32(1))), (Value::I64(-3), Value::I64(2), Ok(Value::I64(-1))), (Value::U64(3), Value::U64(2), Ok(Value::U64(1))), (Value::F32(-3.), Value::F32(2.), Err(Error::IntegralTypeRequired)), (Value::F64(-3.), Value::F64(2.), Err(Error::IntegralTypeRequired)), (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)), ] { assert_eq!(v1.rem(v2, addr_mask), result); } for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(0), Err(Error::DivisionByZero)), (Value::I8(-3), Value::I8(0), Err(Error::DivisionByZero)), (Value::U8(3), Value::U8(0), Err(Error::DivisionByZero)), (Value::I16(-3), Value::I16(0), Err(Error::DivisionByZero)), (Value::U16(3), Value::U16(0), Err(Error::DivisionByZero)), (Value::I32(-3), Value::I32(0), Err(Error::DivisionByZero)), (Value::U32(3), Value::U32(0), Err(Error::DivisionByZero)), (Value::I64(-3), Value::I64(0), Err(Error::DivisionByZero)), (Value::U64(3), Value::U64(0), Err(Error::DivisionByZero)), ] { assert_eq!(v1.rem(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_not() { let addr_mask = 0xffff_ffff; for &(v, result) in &[ (Value::Generic(1), Ok(Value::Generic(!1))), (Value::I8(1), Ok(Value::I8(!1))), (Value::U8(1), Ok(Value::U8(!1))), (Value::I16(1), Ok(Value::I16(!1))), (Value::U16(1), Ok(Value::U16(!1))), (Value::I32(1), Ok(Value::I32(!1))), (Value::U32(1), Ok(Value::U32(!1))), (Value::I64(1), Ok(Value::I64(!1))), (Value::U64(1), Ok(Value::U64(!1))), (Value::F32(1.), Err(Error::IntegralTypeRequired)), (Value::F64(1.), Err(Error::IntegralTypeRequired)), ] { assert_eq!(v.not(addr_mask), result); } } #[test] #[rustfmt::skip] fn value_and() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(1))), (Value::I8(3), Value::I8(5), Ok(Value::I8(1))), (Value::U8(3), Value::U8(5), Ok(Value::U8(1))), (Value::I16(3), Value::I16(5), Ok(Value::I16(1))), (Value::U16(3), Value::U16(5), Ok(Value::U16(1))), (Value::I32(3), Value::I32(5), Ok(Value::I32(1))), (Value::U32(3), Value::U32(5), Ok(Value::U32(1))), (Value::I64(3), Value::I64(5), Ok(Value::I64(1))), (Value::U64(3), Value::U64(5), Ok(Value::U64(1))), (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), ] { assert_eq!(v1.and(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_or() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(7))), (Value::I8(3), Value::I8(5), Ok(Value::I8(7))), (Value::U8(3), Value::U8(5), Ok(Value::U8(7))), (Value::I16(3), Value::I16(5), Ok(Value::I16(7))), (Value::U16(3), Value::U16(5), Ok(Value::U16(7))), (Value::I32(3), Value::I32(5), Ok(Value::I32(7))), (Value::U32(3), Value::U32(5), Ok(Value::U32(7))), (Value::I64(3), Value::I64(5), Ok(Value::I64(7))), (Value::U64(3), Value::U64(5), Ok(Value::U64(7))), (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), ] { assert_eq!(v1.or(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_xor() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(6))), (Value::I8(3), Value::I8(5), Ok(Value::I8(6))), (Value::U8(3), Value::U8(5), Ok(Value::U8(6))), (Value::I16(3), Value::I16(5), Ok(Value::I16(6))), (Value::U16(3), Value::U16(5), Ok(Value::U16(6))), (Value::I32(3), Value::I32(5), Ok(Value::I32(6))), (Value::U32(3), Value::U32(5), Ok(Value::U32(6))), (Value::I64(3), Value::I64(5), Ok(Value::I64(6))), (Value::U64(3), Value::U64(5), Ok(Value::U64(6))), (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)), (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)), (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)), ] { assert_eq!(v1.xor(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_shl() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ // One of each type (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(96))), (Value::I8(3), Value::U8(5), Ok(Value::I8(96))), (Value::U8(3), Value::I8(5), Ok(Value::U8(96))), (Value::I16(3), Value::U16(5), Ok(Value::I16(96))), (Value::U16(3), Value::I16(5), Ok(Value::U16(96))), (Value::I32(3), Value::U32(5), Ok(Value::I32(96))), (Value::U32(3), Value::I32(5), Ok(Value::U32(96))), (Value::I64(3), Value::U64(5), Ok(Value::I64(96))), (Value::U64(3), Value::I64(5), Ok(Value::U64(96))), (Value::F32(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), (Value::F64(3.), Value::U8(5), Err(Error::IntegralTypeRequired)), // Invalid shifts (Value::U8(3), Value::I8(-5), Err(Error::InvalidShiftExpression)), (Value::U8(3), Value::I16(-5), Err(Error::InvalidShiftExpression)), (Value::U8(3), Value::I32(-5), Err(Error::InvalidShiftExpression)), (Value::U8(3), Value::I64(-5), Err(Error::InvalidShiftExpression)), (Value::U8(3), Value::F32(5.), Err(Error::InvalidShiftExpression)), (Value::U8(3), Value::F64(5.), Err(Error::InvalidShiftExpression)), // Large shifts (Value::Generic(3), Value::Generic(32), Ok(Value::Generic(0))), (Value::I8(3), Value::U8(8), Ok(Value::I8(0))), (Value::U8(3), Value::I8(9), Ok(Value::U8(0))), (Value::I16(3), Value::U16(17), Ok(Value::I16(0))), (Value::U16(3), Value::I16(16), Ok(Value::U16(0))), (Value::I32(3), Value::U32(32), Ok(Value::I32(0))), (Value::U32(3), Value::I32(33), Ok(Value::U32(0))), (Value::I64(3), Value::U64(65), Ok(Value::I64(0))), (Value::U64(3), Value::I64(64), Ok(Value::U64(0))), ] { assert_eq!(v1.shl(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_shr() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ // One of each type (Value::Generic(96), Value::Generic(5), Ok(Value::Generic(3))), (Value::I8(96), Value::U8(5), Err(Error::UnsupportedTypeOperation)), (Value::U8(96), Value::I8(5), Ok(Value::U8(3))), (Value::I16(96), Value::U16(5), Err(Error::UnsupportedTypeOperation)), (Value::U16(96), Value::I16(5), Ok(Value::U16(3))), (Value::I32(96), Value::U32(5), Err(Error::UnsupportedTypeOperation)), (Value::U32(96), Value::I32(5), Ok(Value::U32(3))), (Value::I64(96), Value::U64(5), Err(Error::UnsupportedTypeOperation)), (Value::U64(96), Value::I64(5), Ok(Value::U64(3))), (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), // Invalid shifts (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), // Large shifts (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), (Value::U8(96), Value::I8(9), Ok(Value::U8(0))), (Value::U16(96), Value::I16(16), Ok(Value::U16(0))), (Value::U32(96), Value::I32(33), Ok(Value::U32(0))), (Value::U64(96), Value::I64(64), Ok(Value::U64(0))), ] { assert_eq!(v1.shr(v2, addr_mask), result); } } #[test] #[rustfmt::skip] fn value_shra() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ // One of each type (Value::Generic(u64::from(-96i32 as u32)), Value::Generic(5), Ok(Value::Generic(-3i64 as u64))), (Value::I8(-96), Value::U8(5), Ok(Value::I8(-3))), (Value::U8(96), Value::I8(5), Err(Error::UnsupportedTypeOperation)), (Value::I16(-96), Value::U16(5), Ok(Value::I16(-3))), (Value::U16(96), Value::I16(5), Err(Error::UnsupportedTypeOperation)), (Value::I32(-96), Value::U32(5), Ok(Value::I32(-3))), (Value::U32(96), Value::I32(5), Err(Error::UnsupportedTypeOperation)), (Value::I64(-96), Value::U64(5), Ok(Value::I64(-3))), (Value::U64(96), Value::I64(5), Err(Error::UnsupportedTypeOperation)), (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)), // Invalid shifts (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)), (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)), // Large shifts (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))), (Value::I8(96), Value::U8(8), Ok(Value::I8(0))), (Value::I8(-96), Value::U8(8), Ok(Value::I8(-1))), (Value::I16(96), Value::U16(17), Ok(Value::I16(0))), (Value::I16(-96), Value::U16(17), Ok(Value::I16(-1))), (Value::I32(96), Value::U32(32), Ok(Value::I32(0))), (Value::I32(-96), Value::U32(32), Ok(Value::I32(-1))), (Value::I64(96), Value::U64(65), Ok(Value::I64(0))), (Value::I64(-96), Value::U64(65), Ok(Value::I64(-1))), ] { assert_eq!(v1.shra(v2, addr_mask), result); } } #[test] fn value_eq() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(1))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), (Value::I8(3), Value::I8(3), Ok(Value::Generic(1))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), (Value::U8(3), Value::U8(3), Ok(Value::Generic(1))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), (Value::I16(3), Value::I16(3), Ok(Value::Generic(1))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), (Value::U16(3), Value::U16(3), Ok(Value::Generic(1))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), (Value::I32(3), Value::I32(3), Ok(Value::Generic(1))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), (Value::U32(3), Value::U32(3), Ok(Value::Generic(1))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), (Value::I64(3), Value::I64(3), Ok(Value::Generic(1))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), (Value::U64(3), Value::U64(3), Ok(Value::Generic(1))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(1))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(1))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.eq(v2, addr_mask), result); } } #[test] fn value_ne() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(0))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), (Value::I8(3), Value::I8(3), Ok(Value::Generic(0))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), (Value::U8(3), Value::U8(3), Ok(Value::Generic(0))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), (Value::I16(3), Value::I16(3), Ok(Value::Generic(0))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), (Value::U16(3), Value::U16(3), Ok(Value::Generic(0))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), (Value::I32(3), Value::I32(3), Ok(Value::Generic(0))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), (Value::U32(3), Value::U32(3), Ok(Value::Generic(0))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), (Value::I64(3), Value::I64(3), Ok(Value::Generic(0))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), (Value::U64(3), Value::U64(3), Ok(Value::Generic(0))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(0))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(0))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.ne(v2, addr_mask), result); } } #[test] fn value_ge() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.ge(v2, addr_mask), result); } } #[test] fn value_gt() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))), (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))), (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))), (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))), (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))), (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))), (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))), (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))), (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))), (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))), (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.gt(v2, addr_mask), result); } } #[test] fn value_le() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.le(v2, addr_mask), result); } } #[test] fn value_lt() { let addr_mask = 0xffff_ffff; for &(v1, v2, result) in &[ (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))), (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))), (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))), (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))), (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))), (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))), (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))), (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))), (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))), (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))), (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))), (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))), (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))), (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))), (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))), (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))), (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))), (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))), (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))), (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))), (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))), (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))), (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)), ] { assert_eq!(v1.lt(v2, addr_mask), result); } } } gimli-0.19.0/src/test_util.rs010066400017500001750000000027661346020377600143210ustar0000000000000000#![allow(missing_docs)] use crate::vec::Vec; use crate::leb128; use crate::Format; use test_assembler::{Label, Section}; pub trait GimliSectionMethods { fn sleb(self, val: i64) -> Self; fn uleb(self, val: u64) -> Self; fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self; fn word(self, size: u8, val: u64) -> Self; fn word_label(self, size: u8, val: &Label) -> Self; } impl GimliSectionMethods for Section { fn sleb(self, val: i64) -> Self { let mut buf = Vec::new(); let written = leb128::write::signed(&mut buf, val).unwrap(); self.append_bytes(&buf[0..written]) } fn uleb(self, val: u64) -> Self { let mut buf = Vec::new(); let written = leb128::write::unsigned(&mut buf, val).unwrap(); self.append_bytes(&buf[0..written]) } fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self { match format { Format::Dwarf32 => self.D32(length).mark(start), Format::Dwarf64 => self.D32(0xffff_ffff).D64(length).mark(start), } } fn word(self, size: u8, val: u64) -> Self { match size { 4 => self.D32(val as u32), 8 => self.D64(val), _ => panic!("unsupported word size"), } } fn word_label(self, size: u8, val: &Label) -> Self { match size { 4 => self.D32(val), 8 => self.D64(val), _ => panic!("unsupported word size"), } } } gimli-0.19.0/src/write/abbrev.rs010066400017500001750000000137041346020377600146720ustar0000000000000000use crate::vec::Vec; use indexmap::IndexSet; use std::ops::{Deref, DerefMut}; use crate::common::{DebugAbbrevOffset, SectionId}; use crate::constants; use crate::write::{Result, Section, Writer}; /// A table of abbreviations that will be stored in a `.debug_abbrev` section. // Requirements: // - values are `Abbreviation` // - insertion returns an abbreviation code for use in writing a DIE // - inserting a duplicate returns the code of the existing value #[derive(Debug, Default)] pub(crate) struct AbbreviationTable { abbrevs: IndexSet, } impl AbbreviationTable { /// Add an abbreviation to the table and return its code. pub fn add(&mut self, abbrev: Abbreviation) -> u64 { let (code, _) = self.abbrevs.insert_full(abbrev); // Code must be non-zero (code + 1) as u64 } /// Write the abbreviation table to the `.debug_abbrev` section. pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { for (code, abbrev) in self.abbrevs.iter().enumerate() { w.write_uleb128((code + 1) as u64)?; abbrev.write(w)?; } // Null abbreviation code w.write_u8(0) } } /// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: /// its tag type, whether it has children, and its set of attributes. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct Abbreviation { tag: constants::DwTag, has_children: bool, attributes: Vec, } impl Abbreviation { /// Construct a new `Abbreviation`. #[inline] pub fn new( tag: constants::DwTag, has_children: bool, attributes: Vec, ) -> Abbreviation { Abbreviation { tag, has_children, attributes, } } /// Write the abbreviation to the `.debug_abbrev` section. pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { w.write_uleb128(self.tag.0)?; w.write_u8(if self.has_children { constants::DW_CHILDREN_yes.0 } else { constants::DW_CHILDREN_no.0 })?; for attr in &self.attributes { attr.write(w)?; } // Null name and form w.write_u8(0)?; w.write_u8(0) } } /// The description of an attribute in an abbreviated type. // TODO: support implicit const #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct AttributeSpecification { name: constants::DwAt, form: constants::DwForm, } impl AttributeSpecification { /// Construct a new `AttributeSpecification`. #[inline] pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification { AttributeSpecification { name, form } } /// Write the attribute specification to the `.debug_abbrev` section. #[inline] pub fn write(&self, w: &mut DebugAbbrev) -> Result<()> { w.write_uleb128(self.name.0)?; w.write_uleb128(self.form.0) } } define_section!( DebugAbbrev, DebugAbbrevOffset, "A writable `.debug_abbrev` section." ); #[cfg(test)] mod tests { use super::*; use crate::constants; use crate::read; use crate::write::EndianVec; use crate::LittleEndian; #[test] fn test_abbreviation_table() { let mut abbrevs = AbbreviationTable::default(); let abbrev1 = Abbreviation::new( constants::DW_TAG_subprogram, false, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, )], ); let abbrev2 = Abbreviation::new( constants::DW_TAG_compile_unit, true, vec![ AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp), AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2), ], ); let code1 = abbrevs.add(abbrev1.clone()); assert_eq!(code1, 1); let code2 = abbrevs.add(abbrev2.clone()); assert_eq!(code2, 2); assert_eq!(abbrevs.add(abbrev1.clone()), code1); assert_eq!(abbrevs.add(abbrev2.clone()), code2); let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian)); let debug_abbrev_offset = debug_abbrev.offset(); assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0)); abbrevs.write(&mut debug_abbrev).unwrap(); assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17)); let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian); let read_abbrevs = read_debug_abbrev .abbreviations(debug_abbrev_offset) .unwrap(); let read_abbrev1 = read_abbrevs.get(code1).unwrap(); assert_eq!(abbrev1.tag, read_abbrev1.tag()); assert_eq!(abbrev1.has_children, read_abbrev1.has_children()); assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len()); assert_eq!( abbrev1.attributes[0].name, read_abbrev1.attributes()[0].name() ); assert_eq!( abbrev1.attributes[0].form, read_abbrev1.attributes()[0].form() ); let read_abbrev2 = read_abbrevs.get(code2).unwrap(); assert_eq!(abbrev2.tag, read_abbrev2.tag()); assert_eq!(abbrev2.has_children, read_abbrev2.has_children()); assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len()); assert_eq!( abbrev2.attributes[0].name, read_abbrev2.attributes()[0].name() ); assert_eq!( abbrev2.attributes[0].form, read_abbrev2.attributes()[0].form() ); assert_eq!( abbrev2.attributes[1].name, read_abbrev2.attributes()[1].name() ); assert_eq!( abbrev2.attributes[1].form, read_abbrev2.attributes()[1].form() ); } } gimli-0.19.0/src/write/cfi.rs010066400017500001750000001153031346020377600141700ustar0000000000000000use crate::collections::hash_map; use crate::vec::Vec; use indexmap::IndexSet; use std::ops::{Deref, DerefMut}; use crate::collections::HashMap; use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId}; use crate::constants; use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer}; define_section!( DebugFrame, DebugFrameOffset, "A writable `.debug_frame` section." ); define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section."); define_id!(CieId, "An identifier for a CIE in a `FrameTable`."); /// A table of frame description entries. #[derive(Debug, Default)] pub struct FrameTable { /// Base id for CIEs. base_id: BaseId, /// The common information entries. cies: IndexSet, /// The frame description entries. fdes: Vec<(CieId, FrameDescriptionEntry)>, } impl FrameTable { /// Add a CIE and return its id. /// /// If the CIE already exists, then return the id of the existing CIE. pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId { let (index, _) = self.cies.insert_full(cie); CieId::new(self.base_id, index) } /// The number of CIEs. pub fn cie_count(&self) -> usize { self.cies.len() } /// Add a FDE. /// /// Does not check for duplicates. /// /// # Panics /// /// Panics if the CIE id is invalid. pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) { debug_assert_eq!(self.base_id, cie.base_id); self.fdes.push((cie, fde)); } /// The number of FDEs. pub fn fde_count(&self) -> usize { self.fdes.len() } /// Write the frame table entries to the given `.debug_frame` section. pub fn write_debug_frame(&self, w: &mut DebugFrame) -> Result<()> { self.write(&mut w.0, false) } /// Write the frame table entries to the given `.eh_frame` section. pub fn write_eh_frame(&self, w: &mut EhFrame) -> Result<()> { self.write(&mut w.0, true) } fn write(&self, w: &mut W, eh_frame: bool) -> Result<()> { let mut cie_offsets = vec![None; self.cies.len()]; for (cie_id, fde) in &self.fdes { let cie_index = cie_id.index; let cie = self.cies.get_index(cie_index).unwrap(); let cie_offset = match cie_offsets[cie_index] { Some(offset) => offset, None => { // Only write CIEs as they are referenced. let offset = cie.write(w, eh_frame)?; cie_offsets[cie_index] = Some(offset); offset } }; fde.write(w, eh_frame, cie_offset, cie)?; } // TODO: write length 0 terminator for eh_frame? Ok(()) } } /// A common information entry. This contains information that is shared between FDEs. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CommonInformationEntry { encoding: Encoding, /// A constant that is factored out of code offsets. /// /// This should be set to the minimum instruction length. /// Writing a code offset that is not a multiple of this factor will generate an error. code_alignment_factor: u8, /// A constant that is factored out of data offsets. /// /// This should be set to the minimum data alignment for the frame. /// Writing a data offset that is not a multiple of this factor will generate an error. data_alignment_factor: i8, /// The return address register. This might not correspond to an actual machine register. return_address_register: Register, /// The address of the personality function and its encoding. pub personality: Option<(constants::DwEhPe, Address)>, /// The encoding to use for the LSDA address in FDEs. /// /// If set then all FDEs which use this CIE must have a LSDA address. pub lsda_encoding: Option, /// The encoding to use for addresses in FDEs. pub fde_address_encoding: constants::DwEhPe, /// True for signal trampolines. pub signal_trampoline: bool, /// The initial instructions upon entry to this function. instructions: Vec, } impl CommonInformationEntry { /// Create a new common information entry. /// /// The encoding version must be a CFI version, not a DWARF version. pub fn new( encoding: Encoding, code_alignment_factor: u8, data_alignment_factor: i8, return_address_register: Register, ) -> Self { CommonInformationEntry { encoding, code_alignment_factor, data_alignment_factor, return_address_register, personality: None, lsda_encoding: None, fde_address_encoding: constants::DW_EH_PE_absptr, signal_trampoline: false, instructions: Vec::new(), } } /// Add an initial instruction. pub fn add_instruction(&mut self, instruction: CallFrameInstruction) { self.instructions.push(instruction); } fn has_augmentation(&self) -> bool { self.personality.is_some() || self.lsda_encoding.is_some() || self.signal_trampoline || self.fde_address_encoding != constants::DW_EH_PE_absptr } /// Returns the section offset of the CIE. fn write(&self, w: &mut W, eh_frame: bool) -> Result { let encoding = self.encoding; let offset = w.len(); let length_offset = w.write_initial_length(encoding.format)?; let length_base = w.len(); if eh_frame { w.write_u32(0)?; } else { match encoding.format { Format::Dwarf32 => w.write_u32(0xffff_ffff)?, Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?, } } if eh_frame { if encoding.version != 1 { return Err(Error::UnsupportedVersion(encoding.version)); }; } else { match encoding.version { 1 | 3 | 4 => {} _ => return Err(Error::UnsupportedVersion(encoding.version)), }; } w.write_u8(encoding.version as u8)?; let augmentation = self.has_augmentation(); if augmentation { w.write_u8(b'z')?; if self.lsda_encoding.is_some() { w.write_u8(b'L')?; } if self.personality.is_some() { w.write_u8(b'P')?; } if self.fde_address_encoding != constants::DW_EH_PE_absptr { w.write_u8(b'R')?; } if self.signal_trampoline { w.write_u8(b'S')?; } } w.write_u8(0)?; if encoding.version >= 4 { w.write_u8(encoding.address_size)?; // TODO: segment_selector_size w.write_u8(0)?; } w.write_uleb128(self.code_alignment_factor.into())?; w.write_sleb128(self.data_alignment_factor.into())?; if !eh_frame && encoding.version == 1 { let register = self.return_address_register.0 as u8; if u16::from(register) != self.return_address_register.0 { return Err(Error::ValueTooLarge); } w.write_u8(register)?; } else { w.write_uleb128(self.return_address_register.0.into())?; } if augmentation { let augmentation_length_offset = w.len(); w.write_u8(0)?; let augmentation_length_base = w.len(); if let Some(eh_pe) = self.lsda_encoding { w.write_u8(eh_pe.0)?; } if let Some((eh_pe, address)) = self.personality { w.write_u8(eh_pe.0)?; w.write_eh_pointer(address, constants::DW_EH_PE_absptr, encoding.address_size)?; } if self.fde_address_encoding != constants::DW_EH_PE_absptr { w.write_u8(self.fde_address_encoding.0)?; } let augmentation_length = (w.len() - augmentation_length_base) as u64; debug_assert!(augmentation_length < 0x80); w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?; } for instruction in &self.instructions { instruction.write(w, self)?; } write_nop( w, encoding.format.word_size() as usize + w.len() - length_base, encoding.address_size, )?; let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, encoding.format)?; Ok(offset) } } /// A frame description entry. There should be one FDE per function. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FrameDescriptionEntry { /// The initial address of the function. address: Address, /// The length in bytes of the function. length: u32, /// The address of the LSDA. pub lsda: Option
, /// The instructions for this function, ordered by offset. instructions: Vec<(u32, CallFrameInstruction)>, } impl FrameDescriptionEntry { /// Create a new frame description entry for a function. pub fn new(address: Address, length: u32) -> Self { FrameDescriptionEntry { address, length, lsda: None, instructions: Vec::new(), } } /// Add an instruction. /// /// Instructions must be added in increasing order of offset, or writing will fail. pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) { debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset); self.instructions.push((offset, instruction)); } fn write( &self, w: &mut W, eh_frame: bool, cie_offset: usize, cie: &CommonInformationEntry, ) -> Result<()> { let encoding = cie.encoding; let length_offset = w.write_initial_length(encoding.format)?; let length_base = w.len(); if eh_frame { // .eh_frame uses a relative offset which doesn't need relocation. w.write_udata((w.len() - cie_offset) as u64, 4)?; } else { w.write_offset( cie_offset, SectionId::DebugFrame, encoding.format.word_size(), )?; } if cie.fde_address_encoding != constants::DW_EH_PE_absptr { w.write_eh_pointer( self.address, cie.fde_address_encoding, encoding.address_size, )?; w.write_eh_pointer_data( self.length.into(), cie.fde_address_encoding.format(), encoding.address_size, )?; } else { w.write_address(self.address, encoding.address_size)?; w.write_udata(self.length.into(), encoding.address_size)?; } if cie.has_augmentation() { let mut augmentation_length = 0u64; if self.lsda.is_some() { augmentation_length += u64::from(encoding.address_size); } w.write_uleb128(augmentation_length)?; debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some()); if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) { w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?; } } let mut prev_offset = 0; for (offset, instruction) in &self.instructions { write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?; prev_offset = *offset; instruction.write(w, cie)?; } write_nop( w, encoding.format.word_size() as usize + w.len() - length_base, encoding.address_size, )?; let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, encoding.format)?; Ok(()) } } /// An instruction in a frame description entry. /// /// This may be a CFA definition, a register rule, or some other directive. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CallFrameInstruction { /// Define the CFA rule to use the provided register and offset. Cfa(Register, i32), /// Update the CFA rule to use the provided register. The offset is unchanged. CfaRegister(Register), /// Update the CFA rule to use the provided offset. The register is unchanged. CfaOffset(i32), /// Define the CFA rule to use the provided expression. CfaExpression(Expression), /// Restore the initial rule for the register. Restore(Register), /// The previous value of the register is not recoverable. Undefined(Register), /// The register has not been modified. SameValue(Register), /// The previous value of the register is saved at address CFA + offset. Offset(Register, i32), /// The previous value of the register is CFA + offset. ValOffset(Register, i32), /// The previous value of the register is stored in another register. Register(Register, Register), /// The previous value of the register is saved at address given by the expression. Expression(Register, Expression), /// The previous value of the register is given by the expression. ValExpression(Register, Expression), /// Push all register rules onto a stack. RememberState, /// Pop all register rules off the stack. RestoreState, /// The size of the arguments that have been pushed onto the stack. ArgsSize(u32), } impl CallFrameInstruction { fn write(&self, w: &mut W, cie: &CommonInformationEntry) -> Result<()> { match *self { CallFrameInstruction::Cfa(register, offset) => { if offset < 0 { let offset = factored_data_offset(offset, cie.data_alignment_factor)?; w.write_u8(constants::DW_CFA_def_cfa_sf.0)?; w.write_uleb128(register.0.into())?; w.write_sleb128(offset.into())?; } else { // Unfactored offset. w.write_u8(constants::DW_CFA_def_cfa.0)?; w.write_uleb128(register.0.into())?; w.write_uleb128(offset as u64)?; } } CallFrameInstruction::CfaRegister(register) => { w.write_u8(constants::DW_CFA_def_cfa_register.0)?; w.write_uleb128(register.0.into())?; } CallFrameInstruction::CfaOffset(offset) => { if offset < 0 { let offset = factored_data_offset(offset, cie.data_alignment_factor)?; w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?; w.write_sleb128(offset.into())?; } else { // Unfactored offset. w.write_u8(constants::DW_CFA_def_cfa_offset.0)?; w.write_uleb128(offset as u64)?; } } CallFrameInstruction::CfaExpression(ref expression) => { w.write_u8(constants::DW_CFA_def_cfa_expression.0)?; w.write_uleb128(expression.0.len() as u64)?; w.write(&expression.0)?; } CallFrameInstruction::Restore(register) => { if register.0 < 0x40 { w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?; } else { w.write_u8(constants::DW_CFA_restore_extended.0)?; w.write_uleb128(register.0.into())?; } } CallFrameInstruction::Undefined(register) => { w.write_u8(constants::DW_CFA_undefined.0)?; w.write_uleb128(register.0.into())?; } CallFrameInstruction::SameValue(register) => { w.write_u8(constants::DW_CFA_same_value.0)?; w.write_uleb128(register.0.into())?; } CallFrameInstruction::Offset(register, offset) => { let offset = factored_data_offset(offset, cie.data_alignment_factor)?; if offset < 0 { w.write_u8(constants::DW_CFA_offset_extended_sf.0)?; w.write_uleb128(register.0.into())?; w.write_sleb128(offset.into())?; } else if register.0 < 0x40 { w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?; w.write_uleb128(offset as u64)?; } else { w.write_u8(constants::DW_CFA_offset_extended.0)?; w.write_uleb128(register.0.into())?; w.write_uleb128(offset as u64)?; } } CallFrameInstruction::ValOffset(register, offset) => { let offset = factored_data_offset(offset, cie.data_alignment_factor)?; if offset < 0 { w.write_u8(constants::DW_CFA_val_offset_sf.0)?; w.write_uleb128(register.0.into())?; w.write_sleb128(offset.into())?; } else { w.write_u8(constants::DW_CFA_val_offset.0)?; w.write_uleb128(register.0.into())?; w.write_uleb128(offset as u64)?; } } CallFrameInstruction::Register(register1, register2) => { w.write_u8(constants::DW_CFA_register.0)?; w.write_uleb128(register1.0.into())?; w.write_uleb128(register2.0.into())?; } CallFrameInstruction::Expression(register, ref expression) => { w.write_u8(constants::DW_CFA_expression.0)?; w.write_uleb128(register.0.into())?; w.write_uleb128(expression.0.len() as u64)?; w.write(&expression.0)?; } CallFrameInstruction::ValExpression(register, ref expression) => { w.write_u8(constants::DW_CFA_val_expression.0)?; w.write_uleb128(register.0.into())?; w.write_uleb128(expression.0.len() as u64)?; w.write(&expression.0)?; } CallFrameInstruction::RememberState => { w.write_u8(constants::DW_CFA_remember_state.0)?; } CallFrameInstruction::RestoreState => { w.write_u8(constants::DW_CFA_restore_state.0)?; } CallFrameInstruction::ArgsSize(size) => { w.write_u8(constants::DW_CFA_GNU_args_size.0)?; w.write_uleb128(size.into())?; } } Ok(()) } } fn write_advance_loc( w: &mut W, code_alignment_factor: u8, prev_offset: u32, offset: u32, ) -> Result<()> { if offset == prev_offset { return Ok(()); } let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?; if delta < 0x40 { w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?; } else if delta < 0x100 { w.write_u8(constants::DW_CFA_advance_loc1.0)?; w.write_u8(delta as u8)?; } else if delta < 0x10000 { w.write_u8(constants::DW_CFA_advance_loc2.0)?; w.write_u16(delta as u16)?; } else { w.write_u8(constants::DW_CFA_advance_loc4.0)?; w.write_u32(delta)?; } Ok(()) } fn write_nop(w: &mut W, len: usize, align: u8) -> Result<()> { debug_assert_eq!(align & (align - 1), 0); let tail_len = (!len + 1) & (align as usize - 1); for _ in 0..tail_len { w.write_u8(constants::DW_CFA_nop.0)?; } Ok(()) } fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result { if offset < prev_offset { return Err(Error::InvalidFrameCodeOffset(offset)); } let delta = offset - prev_offset; let factor = u32::from(factor); let factored_delta = delta / factor; if delta != factored_delta * factor { return Err(Error::InvalidFrameCodeOffset(offset)); } Ok(factored_delta) } fn factored_data_offset(offset: i32, factor: i8) -> Result { let factor = i32::from(factor); let factored_offset = offset / factor; if offset != factored_offset * factor { return Err(Error::InvalidFrameDataOffset(offset)); } Ok(factored_offset) } #[cfg(feature = "read")] pub(crate) mod convert { use super::*; use crate::read::{self, Reader}; use crate::write::{ConvertError, ConvertResult}; impl FrameTable { /// Create a frame table by reading the data in the given section. /// /// `convert_address` is a function to convert read addresses into the `Address` /// type. For non-relocatable addresses, this function may simply return /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. pub fn from( frame: &Section, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { let bases = read::BaseAddresses::default().set_eh_frame(0); let mut frame_table = FrameTable::default(); let mut cie_ids = HashMap::new(); let mut entries = frame.entries(&bases); while let Some(entry) = entries.next()? { let partial = match entry { read::CieOrFde::Cie(_) => continue, read::CieOrFde::Fde(partial) => partial, }; // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only // stored a reference. let from_fde = partial.parse(Section::cie_from_offset)?; let from_cie = from_fde.cie(); let cie_id = match cie_ids.entry(from_cie.offset()) { hash_map::Entry::Occupied(o) => *o.get(), hash_map::Entry::Vacant(e) => { let cie = CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?; let cie_id = frame_table.add_cie(cie); e.insert(cie_id); cie_id } }; let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?; frame_table.add_fde(cie_id, fde); } Ok(frame_table) } } impl CommonInformationEntry { fn from( from_cie: &read::CommonInformationEntry, frame: &Section, bases: &read::BaseAddresses, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { let mut cie = CommonInformationEntry::new( from_cie.encoding(), from_cie.code_alignment_factor() as u8, from_cie.data_alignment_factor() as i8, from_cie.return_address_register(), ); cie.personality = match from_cie.personality_with_encoding() { // We treat these the same because the encoding already determines // whether it is indirect. Some((eh_pe, read::Pointer::Direct(p))) | Some((eh_pe, read::Pointer::Indirect(p))) => { let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; Some((eh_pe, address)) } _ => None, }; cie.lsda_encoding = from_cie.lsda_encoding(); cie.fde_address_encoding = from_cie .fde_address_encoding() .unwrap_or(constants::DW_EH_PE_absptr); cie.signal_trampoline = from_cie.is_signal_trampoline(); let mut offset = 0; let mut from_instructions = from_cie.instructions(frame, bases); while let Some(from_instruction) = from_instructions.next()? { if let Some(instruction) = CallFrameInstruction::from(from_instruction, from_cie, &mut offset)? { cie.instructions.push(instruction); } } Ok(cie) } } impl FrameDescriptionEntry { fn from( from_fde: &read::FrameDescriptionEntry, frame: &Section, bases: &read::BaseAddresses, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { let address = convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?; let length = from_fde.len() as u32; let mut fde = FrameDescriptionEntry::new(address, length); match from_fde.lsda() { // We treat these the same because the encoding already determines // whether it is indirect. Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => { let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?; fde.lsda = Some(address); } None => {} } let from_cie = from_fde.cie(); let mut offset = 0; let mut from_instructions = from_fde.instructions(frame, bases); while let Some(from_instruction) = from_instructions.next()? { if let Some(instruction) = CallFrameInstruction::from(from_instruction, from_cie, &mut offset)? { fde.instructions.push((offset, instruction)); } } Ok(fde) } } impl CallFrameInstruction { fn from>( from_instruction: read::CallFrameInstruction, from_cie: &read::CommonInformationEntry, offset: &mut u32, ) -> ConvertResult> { // TODO: validate integer type conversions Ok(Some(match from_instruction { read::CallFrameInstruction::SetLoc { .. } => { return Err(ConvertError::UnsupportedCfiInstruction); } read::CallFrameInstruction::AdvanceLoc { delta } => { *offset += delta * from_cie.code_alignment_factor() as u32; return Ok(None); } read::CallFrameInstruction::DefCfa { register, offset } => { CallFrameInstruction::Cfa(register, offset as i32) } read::CallFrameInstruction::DefCfaSf { register, factored_offset, } => { let offset = factored_offset * from_cie.data_alignment_factor(); CallFrameInstruction::Cfa(register, offset as i32) } read::CallFrameInstruction::DefCfaRegister { register } => { CallFrameInstruction::CfaRegister(register) } read::CallFrameInstruction::DefCfaOffset { offset } => { CallFrameInstruction::CfaOffset(offset as i32) } read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => { let offset = factored_offset * from_cie.data_alignment_factor(); CallFrameInstruction::CfaOffset(offset as i32) } read::CallFrameInstruction::DefCfaExpression { expression } => { let expression = Expression(expression.0.to_slice()?.into()); CallFrameInstruction::CfaExpression(expression) } read::CallFrameInstruction::Undefined { register } => { CallFrameInstruction::Undefined(register) } read::CallFrameInstruction::SameValue { register } => { CallFrameInstruction::SameValue(register) } read::CallFrameInstruction::Offset { register, factored_offset, } => { let offset = factored_offset as i64 * from_cie.data_alignment_factor(); CallFrameInstruction::Offset(register, offset as i32) } read::CallFrameInstruction::OffsetExtendedSf { register, factored_offset, } => { let offset = factored_offset * from_cie.data_alignment_factor(); CallFrameInstruction::Offset(register, offset as i32) } read::CallFrameInstruction::ValOffset { register, factored_offset, } => { let offset = factored_offset as i64 * from_cie.data_alignment_factor(); CallFrameInstruction::ValOffset(register, offset as i32) } read::CallFrameInstruction::ValOffsetSf { register, factored_offset, } => { let offset = factored_offset * from_cie.data_alignment_factor(); CallFrameInstruction::ValOffset(register, offset as i32) } read::CallFrameInstruction::Register { dest_register, src_register, } => CallFrameInstruction::Register(dest_register, src_register), read::CallFrameInstruction::Expression { register, expression, } => { let expression = Expression(expression.0.to_slice()?.into()); CallFrameInstruction::Expression(register, expression) } read::CallFrameInstruction::ValExpression { register, expression, } => { let expression = Expression(expression.0.to_slice()?.into()); CallFrameInstruction::ValExpression(register, expression) } read::CallFrameInstruction::Restore { register } => { CallFrameInstruction::Restore(register) } read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState, read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState, read::CallFrameInstruction::ArgsSize { size } => { CallFrameInstruction::ArgsSize(size as u32) } read::CallFrameInstruction::Nop => return Ok(None), })) } } } #[cfg(test)] mod tests { use super::*; use crate::arch::X86_64; use crate::read; use crate::write::EndianVec; use crate::LittleEndian; #[test] fn test_frame_table() { for &version in &[1, 3, 4] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut frames = FrameTable::default(); let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); let cie1_id = frames.add_cie(cie1.clone()); assert_eq!(cie1_id, frames.add_cie(cie1.clone())); let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr); cie2.personality = Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234))); cie2.signal_trampoline = true; let cie2_id = frames.add_cie(cie2.clone()); assert_ne!(cie1_id, cie2_id); assert_eq!(cie2_id, frames.add_cie(cie2.clone())); let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); frames.add_fde(cie1_id, fde1.clone()); let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20); frames.add_fde(cie1_id, fde2.clone()); let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30); fde3.lsda = Some(Address::Constant(0x3300)); frames.add_fde(cie2_id, fde3.clone()); let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40); fde4.lsda = Some(Address::Constant(0x4400)); frames.add_fde(cie2_id, fde4.clone()); // Test writing `.debug_frame`. let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); frames.write_debug_frame(&mut debug_frame).unwrap(); let mut read_debug_frame = read::DebugFrame::new(debug_frame.slice(), LittleEndian); read_debug_frame.set_address_size(address_size); let convert_frames = FrameTable::from(&read_debug_frame, &|address| { Some(Address::Constant(address)) }) .unwrap(); assert_eq!(frames.cies, convert_frames.cies); assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { assert_eq!(a.1, b.1); } if version == 1 { // Test writing `.eh_frame`. let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian)); frames.write_eh_frame(&mut eh_frame).unwrap(); let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian); read_eh_frame.set_address_size(address_size); let convert_frames = FrameTable::from(&read_eh_frame, &|address| { Some(Address::Constant(address)) }) .unwrap(); assert_eq!(frames.cies, convert_frames.cies); assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) { assert_eq!(a.1, b.1); } } } } } } #[test] fn test_frame_instruction() { let cie_instructions = [ CallFrameInstruction::Cfa(X86_64::RSP, 8), CallFrameInstruction::Offset(X86_64::RA, -8), ]; let fde_instructions = [ (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)), (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)), (2, CallFrameInstruction::CfaRegister(X86_64::RBP)), (4, CallFrameInstruction::CfaOffset(8)), (4, CallFrameInstruction::CfaOffset(0)), (4, CallFrameInstruction::CfaOffset(-8)), ( 6, CallFrameInstruction::CfaExpression(Expression(vec![1, 2, 3])), ), (8, CallFrameInstruction::Restore(Register(1))), (8, CallFrameInstruction::Restore(Register(101))), (10, CallFrameInstruction::Undefined(Register(2))), (12, CallFrameInstruction::SameValue(Register(3))), (14, CallFrameInstruction::Offset(Register(4), 16)), (14, CallFrameInstruction::Offset(Register(104), 16)), (16, CallFrameInstruction::ValOffset(Register(5), -24)), (16, CallFrameInstruction::ValOffset(Register(5), 24)), (18, CallFrameInstruction::Register(Register(6), Register(7))), ( 20, CallFrameInstruction::Expression(Register(8), Expression(vec![2, 3, 4])), ), ( 22, CallFrameInstruction::ValExpression(Register(9), Expression(vec![3, 4, 5])), ), (24 + 0x80, CallFrameInstruction::RememberState), (26 + 0x280, CallFrameInstruction::RestoreState), (28 + 0x20280, CallFrameInstruction::ArgsSize(23)), ]; for &version in &[1, 3, 4] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut frames = FrameTable::default(); let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA); for i in &cie_instructions { cie.add_instruction(i.clone()); } let cie_id = frames.add_cie(cie); let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); for (o, i) in &fde_instructions { fde.add_instruction(*o, i.clone()); } frames.add_fde(cie_id, fde); let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian)); frames.write_debug_frame(&mut debug_frame).unwrap(); let mut read_debug_frame = read::DebugFrame::new(debug_frame.slice(), LittleEndian); read_debug_frame.set_address_size(address_size); let frames = FrameTable::from(&read_debug_frame, &|address| { Some(Address::Constant(address)) }) .unwrap(); assert_eq!( &frames.cies.get_index(0).unwrap().instructions, &cie_instructions ); assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions); } } } } } gimli-0.19.0/src/write/dwarf.rs010066400017500001750000000113421346020377600145300ustar0000000000000000use crate::vec::Vec; use crate::common::Encoding; use crate::write::{ AbbreviationTable, LineProgram, LineStringTable, Result, Sections, StringTable, Unit, UnitTable, Writer, }; /// Writable DWARF information for more than one unit. #[derive(Debug, Default)] pub struct Dwarf { /// A table of units. These are primarily stored in the `.debug_info` section, /// but they also contain information that is stored in other sections. pub units: UnitTable, /// Extra line number programs that are not associated with a unit. /// /// These should only be used when generating DWARF5 line-only debug /// information. pub line_programs: Vec, /// A table of strings that will be stored in the `.debug_line_str` section. pub line_strings: LineStringTable, /// A table of strings that will be stored in the `.debug_str` section. pub strings: StringTable, } impl Dwarf { /// Create a new `Dwarf` instance. #[inline] pub fn new() -> Self { Self::default() } /// Write the DWARF information to the given sections. pub fn write(&mut self, sections: &mut Sections) -> Result<()> { let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; let strings = self.strings.write(&mut sections.debug_str)?; self.units.write(sections, &line_strings, &strings)?; for line_program in &self.line_programs { line_program.write( &mut sections.debug_line, line_program.encoding(), &line_strings, &strings, )?; } Ok(()) } } /// Writable DWARF information for a single unit. #[derive(Debug)] pub struct DwarfUnit { /// A unit. This is primarily stored in the `.debug_info` section, /// but also contains information that is stored in other sections. pub unit: Unit, /// A table of strings that will be stored in the `.debug_line_str` section. pub line_strings: LineStringTable, /// A table of strings that will be stored in the `.debug_str` section. pub strings: StringTable, } impl DwarfUnit { /// Create a new `DwarfUnit`. /// /// Note: you should set `self.unit.line_program` after creation. /// This cannot be done earlier because it may need to reference /// `self.line_strings`. pub fn new(encoding: Encoding) -> Self { let unit = Unit::new(encoding, LineProgram::none()); DwarfUnit { unit, line_strings: LineStringTable::default(), strings: StringTable::default(), } } /// Write the DWARf information to the given sections. pub fn write(&mut self, sections: &mut Sections) -> Result<()> { let line_strings = self.line_strings.write(&mut sections.debug_line_str)?; let strings = self.strings.write(&mut sections.debug_str)?; let abbrev_offset = sections.debug_abbrev.offset(); let mut abbrevs = AbbreviationTable::default(); let mut debug_info_refs = Vec::new(); self.unit.write( sections, abbrev_offset, &mut abbrevs, &line_strings, &strings, &mut debug_info_refs, )?; // None should exist because we didn't give out any UnitId. assert!(debug_info_refs.is_empty()); abbrevs.write(&mut sections.debug_abbrev)?; Ok(()) } } #[cfg(feature = "read")] pub(crate) mod convert { use super::*; use crate::read::{self, Reader}; use crate::write::{Address, ConvertResult}; impl Dwarf { /// Create a `write::Dwarf` by converting a `read::Dwarf`. /// /// `convert_address` is a function to convert read addresses into the `Address` /// type. For non-relocatable addresses, this function may simply return /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. pub fn from>( dwarf: &read::Dwarf, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult { let mut line_strings = LineStringTable::default(); let mut strings = StringTable::default(); let units = UnitTable::from(dwarf, &mut line_strings, &mut strings, convert_address)?; // TODO: convert the line programs that were not referenced by a unit. let line_programs = Vec::new(); Ok(Dwarf { units, line_programs, line_strings, strings, }) } } } gimli-0.19.0/src/write/endian_vec.rs010066400017500001750000000054331346020377600155240ustar0000000000000000use crate::vec::Vec; use std::mem; use crate::endianity::Endianity; use crate::write::{Error, Result, Writer}; /// A `Vec` with endianity metadata. /// /// This implements the `Writer` trait, which is used for all writing of DWARF sections. #[derive(Debug, Clone)] pub struct EndianVec where Endian: Endianity, { vec: Vec, endian: Endian, } impl EndianVec where Endian: Endianity, { /// Construct an empty `EndianVec` with the given endianity. pub fn new(endian: Endian) -> EndianVec { EndianVec { vec: Vec::new(), endian, } } /// Return a reference to the raw slice. pub fn slice(&self) -> &[u8] { &self.vec } /// Convert into a `Vec`. pub fn into_vec(self) -> Vec { self.vec } /// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place. pub fn take(&mut self) -> Vec { let mut vec = Vec::new(); mem::swap(&mut self.vec, &mut vec); vec } } impl Writer for EndianVec where Endian: Endianity, { type Endian = Endian; #[inline] fn endian(&self) -> Self::Endian { self.endian } #[inline] fn len(&self) -> usize { self.vec.len() } fn write(&mut self, bytes: &[u8]) -> Result<()> { self.vec.extend(bytes); Ok(()) } fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { if offset > self.vec.len() { return Err(Error::OffsetOutOfBounds); } let to = &mut self.vec[offset..]; if bytes.len() > to.len() { return Err(Error::LengthOutOfBounds); } let to = &mut to[..bytes.len()]; to.copy_from_slice(bytes); Ok(()) } } #[cfg(test)] mod tests { use super::*; use crate::LittleEndian; #[test] fn test_endian_vec() { let mut w = EndianVec::new(LittleEndian); assert_eq!(w.endian(), LittleEndian); assert_eq!(w.len(), 0); w.write(&[1, 2]).unwrap(); assert_eq!(w.slice(), &[1, 2]); assert_eq!(w.len(), 2); w.write(&[3, 4, 5]).unwrap(); assert_eq!(w.slice(), &[1, 2, 3, 4, 5]); assert_eq!(w.len(), 5); w.write_at(0, &[6, 7]).unwrap(); assert_eq!(w.slice(), &[6, 7, 3, 4, 5]); assert_eq!(w.len(), 5); w.write_at(3, &[8, 9]).unwrap(); assert_eq!(w.slice(), &[6, 7, 3, 8, 9]); assert_eq!(w.len(), 5); assert_eq!(w.write_at(4, &[6, 7]), Err(Error::LengthOutOfBounds)); assert_eq!(w.write_at(5, &[6, 7]), Err(Error::LengthOutOfBounds)); assert_eq!(w.write_at(6, &[6, 7]), Err(Error::OffsetOutOfBounds)); assert_eq!(w.into_vec(), vec![6, 7, 3, 8, 9]); } } gimli-0.19.0/src/write/line.rs010066400017500001750000002242421351057326000143530ustar0000000000000000use crate::vec::Vec; use indexmap::{IndexMap, IndexSet}; use std::ops::{Deref, DerefMut}; use crate::common::{DebugLineOffset, Encoding, Format, LineEncoding, SectionId}; use crate::constants; use crate::leb128; use crate::write::{ Address, DebugLineStrOffsets, DebugStrOffsets, Error, LineStringId, LineStringTable, Result, Section, StringId, Writer, }; /// The number assigned to the first special opcode. // // We output all instructions for all DWARF versions, since readers // should be able to ignore instructions they don't support. const OPCODE_BASE: u8 = 13; /// A line number program. #[derive(Debug, Clone)] pub struct LineProgram { /// True if this line program was created with `LineProgram::none()`. none: bool, encoding: Encoding, line_encoding: LineEncoding, /// A list of source directory path names. /// /// If a path is relative, then the directory is located relative to the working /// directory of the compilation unit. /// /// The first entry is for the working directory of the compilation unit. directories: IndexSet, /// A list of source file entries. /// /// Each entry has a path name and a directory. /// /// If a path is a relative, then the file is located relative to the /// directory. Otherwise the directory is meaningless. /// /// Does not include comp_file, even for version >= 5. files: IndexMap<(LineString, DirectoryId), FileInfo>, /// The primary source file of the compilation unit. /// This is required for version >= 5, but we never reference it elsewhere /// because DWARF defines DW_AT_decl_file=0 to mean not specified. comp_file: (LineString, FileInfo), /// True if the file entries may have valid timestamps. /// /// Entries may still have a timestamp of 0 even if this is set. /// For version <= 4, this is ignored. /// For version 5, this controls whether to emit `DW_LNCT_timestamp`. pub file_has_timestamp: bool, /// True if the file entries may have valid sizes. /// /// Entries may still have a size of 0 even if this is set. /// For version <= 4, this is ignored. /// For version 5, this controls whether to emit `DW_LNCT_size`. pub file_has_size: bool, /// True if the file entries have valid MD5 checksums. /// /// For version <= 4, this is ignored. /// For version 5, this controls whether to emit `DW_LNCT_MD5`. pub file_has_md5: bool, prev_row: LineRow, row: LineRow, // TODO: this probably should be either rows or sequences instead instructions: Vec, in_sequence: bool, } impl LineProgram { /// Create a new `LineProgram`. /// /// `comp_dir` defines the working directory of the compilation unit, /// and must be the same as the `DW_AT_comp_dir` attribute /// of the compilation unit DIE. /// /// `comp_file` and `comp_file_info` define the primary source file /// of the compilation unit and must be the same as the `DW_AT_name` /// attribute of the compilation unit DIE. /// /// # Panics /// /// Panics if `line_encoding.line_base` > 0. /// /// Panics if `line_encoding.line_base` + `line_encoding.line_range` <= 0. /// /// Panics if `comp_dir` is empty or contains a null byte. /// /// Panics if `comp_file` is empty or contains a null byte. #[allow(clippy::too_many_arguments)] #[allow(clippy::new_ret_no_self)] pub fn new( encoding: Encoding, line_encoding: LineEncoding, comp_dir: LineString, comp_file: LineString, comp_file_info: Option, ) -> LineProgram { // We require a special opcode for a line advance of 0. // See the debug_asserts in generate_row(). assert!(line_encoding.line_base <= 0); assert!(line_encoding.line_base + line_encoding.line_range as i8 > 0); let mut program = LineProgram { none: false, encoding, line_encoding, directories: IndexSet::new(), files: IndexMap::new(), comp_file: (comp_file, comp_file_info.unwrap_or_default()), prev_row: LineRow::initial_state(line_encoding), row: LineRow::initial_state(line_encoding), instructions: Vec::new(), in_sequence: false, file_has_timestamp: false, file_has_size: false, file_has_md5: false, }; // For all DWARF versions, directory index 0 is comp_dir. // For version <= 4, the entry is implicit. We still add // it here so that we use it, but we don't emit it. program.add_directory(comp_dir); program } /// Create a new `LineProgram` with no fields set. /// /// This can be used when the `LineProgram` will not be used. /// /// You should not attempt to add files or line instructions to /// this line program, or write it to the `.debug_line` section. pub fn none() -> Self { let line_encoding = LineEncoding::default(); LineProgram { none: true, encoding: Encoding { format: Format::Dwarf32, version: 2, address_size: 0, }, line_encoding, directories: IndexSet::new(), files: IndexMap::new(), comp_file: (LineString::String(Vec::new()), FileInfo::default()), prev_row: LineRow::initial_state(line_encoding), row: LineRow::initial_state(line_encoding), instructions: Vec::new(), in_sequence: false, file_has_timestamp: false, file_has_size: false, file_has_md5: false, } } /// Return true if this line program was created with `LineProgram::none()`. #[inline] pub fn is_none(&self) -> bool { self.none } /// Return the encoding parameters for this line program. #[inline] pub fn encoding(&self) -> Encoding { self.encoding } /// Return the DWARF version for this line program. #[inline] pub fn version(&self) -> u16 { self.encoding.version } /// Return the address size in bytes for this line program. #[inline] pub fn address_size(&self) -> u8 { self.encoding.address_size } /// Return the DWARF format for this line program. #[inline] pub fn format(&self) -> Format { self.encoding.format } /// Return the id for the working directory of the compilation unit. #[inline] pub fn default_directory(&self) -> DirectoryId { DirectoryId(0) } /// Add a directory entry and return its id. /// /// If the directory already exists, then return the id of the existing entry. /// /// If the path is relative, then the directory is located relative to the working /// directory of the compilation unit. /// /// # Panics /// /// Panics if `directory` is empty or contains a null byte. pub fn add_directory(&mut self, directory: LineString) -> DirectoryId { if let LineString::String(ref val) = directory { // For DWARF version <= 4, directories must not be empty. // The first directory isn't emitted so skip the check for it. if self.encoding.version <= 4 && !self.directories.is_empty() { assert!(!val.is_empty()); } assert!(!val.contains(&0)); } let (index, _) = self.directories.insert_full(directory); DirectoryId(index) } /// Get a reference to a directory entry. /// /// # Panics /// /// Panics if `id` is invalid. pub fn get_directory(&self, id: DirectoryId) -> &LineString { self.directories.get_index(id.0).unwrap() } /// Add a file entry and return its id. /// /// If the file already exists, then return the id of the existing entry. /// /// If the file path is relative, then the file is located relative /// to the directory. Otherwise the directory is meaningless, but it /// is still used as a key for file entries. /// /// If `info` is `None`, then new entries are assigned /// default information, and existing entries are unmodified. /// /// If `info` is not `None`, then it is always assigned to the /// entry, even if the entry already exists. /// /// # Panics /// /// Panics if 'file' is empty or contains a null byte. pub fn add_file( &mut self, file: LineString, directory: DirectoryId, info: Option, ) -> FileId { if let LineString::String(ref val) = file { assert!(!val.is_empty()); assert!(!val.contains(&0)); } let key = (file, directory); let index = if let Some(info) = info { let (index, _) = self.files.insert_full(key, info); index } else { let entry = self.files.entry(key); let index = entry.index(); entry.or_insert(FileInfo::default()); index }; FileId::new(index) } /// Get a reference to a file entry. /// /// # Panics /// /// Panics if `id` is invalid. pub fn get_file(&self, id: FileId) -> (&LineString, DirectoryId) { match id.index() { None => (&self.comp_file.0, DirectoryId(0)), Some(index) => self .files .get_index(index) .map(|entry| (&(entry.0).0, (entry.0).1)) .unwrap(), } } /// Get a reference to the info for a file entry. /// /// # Panics /// /// Panics if `id` is invalid. pub fn get_file_info(&self, id: FileId) -> &FileInfo { match id.index() { None => &self.comp_file.1, Some(index) => self.files.get_index(index).map(|entry| entry.1).unwrap(), } } /// Get a mutable reference to the info for a file entry. /// /// # Panics /// /// Panics if `id` is invalid. pub fn get_file_info_mut(&mut self, id: FileId) -> &mut FileInfo { match id.index() { None => &mut self.comp_file.1, Some(index) => self .files .get_index_mut(index) .map(|entry| entry.1) .unwrap(), } } /// Begin a new sequence and set its base address. /// /// # Panics /// /// Panics if a sequence has already begun. pub fn begin_sequence(&mut self, address: Option
) { assert!(!self.in_sequence); self.in_sequence = true; if let Some(address) = address { self.instructions.push(LineInstruction::SetAddress(address)); } } /// End the sequence, and reset the row to its default values. /// /// Only the `address_offset` and op_index` fields of the current row are used. /// /// # Panics /// /// Panics if a sequence has not begun. pub fn end_sequence(&mut self, address_offset: u64) { assert!(self.in_sequence); self.in_sequence = false; self.row.address_offset = address_offset; let op_advance = self.op_advance(); if op_advance != 0 { self.instructions .push(LineInstruction::AdvancePc(op_advance)); } self.instructions.push(LineInstruction::EndSequence); self.prev_row = LineRow::initial_state(self.line_encoding); self.row = LineRow::initial_state(self.line_encoding); } /// Return true if a sequence has begun. #[inline] pub fn in_sequence(&self) -> bool { self.in_sequence } /// Returns a reference to the data for the current row. #[inline] pub fn row(&mut self) -> &mut LineRow { &mut self.row } /// Generates the line number information instructions for the current row. /// /// After the instructions are generated, it sets `discriminator` to 0, and sets /// `basic_block`, `prologue_end`, and `epilogue_begin` to false. /// /// # Panics /// /// Panics if a sequence has not begun. /// Panics if the address_offset decreases. pub fn generate_row(&mut self) { assert!(self.in_sequence); // Output fields that are reset on every row. if self.row.discriminator != 0 { self.instructions .push(LineInstruction::SetDiscriminator(self.row.discriminator)); self.row.discriminator = 0; } if self.row.basic_block { self.instructions.push(LineInstruction::SetBasicBlock); self.row.basic_block = false; } if self.row.prologue_end { self.instructions.push(LineInstruction::SetPrologueEnd); self.row.prologue_end = false; } if self.row.epilogue_begin { self.instructions.push(LineInstruction::SetEpilogueBegin); self.row.epilogue_begin = false; } // Output fields that are not reset on every row. if self.row.is_statement != self.prev_row.is_statement { self.instructions.push(LineInstruction::NegateStatement); } if self.row.file != self.prev_row.file { self.instructions .push(LineInstruction::SetFile(self.row.file)); } if self.row.column != self.prev_row.column { self.instructions .push(LineInstruction::SetColumn(self.row.column)); } if self.row.isa != self.prev_row.isa { self.instructions .push(LineInstruction::SetIsa(self.row.isa)); } // Advance the line, address, and operation index. let line_base = i64::from(self.line_encoding.line_base) as u64; let line_range = u64::from(self.line_encoding.line_range); let line_advance = self.row.line as i64 - self.prev_row.line as i64; let op_advance = self.op_advance(); // Default to special advances of 0. let special_base = u64::from(OPCODE_BASE); // TODO: handle lack of special opcodes for 0 line advance debug_assert!(self.line_encoding.line_base <= 0); debug_assert!(self.line_encoding.line_base + self.line_encoding.line_range as i8 >= 0); let special_default = special_base.wrapping_sub(line_base); let mut special = special_default; let mut use_special = false; if line_advance != 0 { let special_line = (line_advance as u64).wrapping_sub(line_base); if special_line < line_range { special = special_base + special_line; use_special = true; } else { self.instructions .push(LineInstruction::AdvanceLine(line_advance)); } } if op_advance != 0 { // Using ConstAddPc can save a byte. let (special_op_advance, const_add_pc) = if special + op_advance * line_range <= 255 { (op_advance, false) } else { let op_range = (255 - special_base) / line_range; (op_advance - op_range, true) }; let special_op = special_op_advance * line_range; if special + special_op <= 255 { special += special_op; use_special = true; if const_add_pc { self.instructions.push(LineInstruction::ConstAddPc); } } else { self.instructions .push(LineInstruction::AdvancePc(op_advance)); } } if use_special && special != special_default { debug_assert!(special >= special_base); debug_assert!(special <= 255); self.instructions .push(LineInstruction::Special(special as u8)); } else { self.instructions.push(LineInstruction::Copy); } self.prev_row = self.row; } fn op_advance(&self) -> u64 { debug_assert!(self.row.address_offset >= self.prev_row.address_offset); debug_assert_eq!( self.row.address_offset % u64::from(self.line_encoding.minimum_instruction_length), 0 ); let address_advance = (self.row.address_offset - self.prev_row.address_offset) / u64::from(self.line_encoding.minimum_instruction_length); address_advance * u64::from(self.line_encoding.maximum_operations_per_instruction) + self.row.op_index - self.prev_row.op_index } /// Returns true if the line number program has no instructions. /// /// Does not check the file or directory entries. #[inline] pub fn is_empty(&self) -> bool { self.instructions.is_empty() } /// Write the line number program to the given section. /// /// # Panics /// /// Panics if `self.is_none()`. pub fn write( &self, w: &mut DebugLine, encoding: Encoding, debug_line_str_offsets: &DebugLineStrOffsets, debug_str_offsets: &DebugStrOffsets, ) -> Result { assert!(!self.is_none()); if encoding.version < self.version() || encoding.format != self.format() || encoding.address_size != self.address_size() { return Err(Error::IncompatibleLineProgramEncoding); } let offset = w.offset(); let length_offset = w.write_initial_length(self.format())?; let length_base = w.len(); if self.version() < 2 || self.version() > 5 { return Err(Error::UnsupportedVersion(self.version())); } w.write_u16(self.version())?; if self.version() >= 5 { w.write_u8(self.address_size())?; // Segment selector size. w.write_u8(0)?; } let header_length_offset = w.len(); w.write_udata(0, self.format().word_size())?; let header_length_base = w.len(); w.write_u8(self.line_encoding.minimum_instruction_length)?; if self.version() >= 4 { w.write_u8(self.line_encoding.maximum_operations_per_instruction)?; } else if self.line_encoding.maximum_operations_per_instruction != 1 { return Err(Error::NeedVersion(4)); }; w.write_u8(if self.line_encoding.default_is_stmt { 1 } else { 0 })?; w.write_u8(self.line_encoding.line_base as u8)?; w.write_u8(self.line_encoding.line_range)?; w.write_u8(OPCODE_BASE)?; w.write(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1])?; if self.version() <= 4 { // The first directory is stored as DW_AT_comp_dir. for dir in self.directories.iter().skip(1) { dir.write( w, constants::DW_FORM_string, self.encoding, debug_line_str_offsets, debug_str_offsets, )?; } w.write_u8(0)?; for ((file, dir), info) in self.files.iter() { file.write( w, constants::DW_FORM_string, self.encoding, debug_line_str_offsets, debug_str_offsets, )?; w.write_uleb128(dir.0 as u64)?; w.write_uleb128(info.timestamp)?; w.write_uleb128(info.size)?; } w.write_u8(0)?; } else { // Directory entry formats (only ever 1). w.write_u8(1)?; w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; let dir_form = self.directories.get_index(0).unwrap().form(); w.write_uleb128(dir_form.0)?; // Directory entries. w.write_uleb128(self.directories.len() as u64)?; for dir in self.directories.iter() { dir.write( w, dir_form, self.encoding, debug_line_str_offsets, debug_str_offsets, )?; } // File name entry formats. let count = 2 + if self.file_has_timestamp { 1 } else { 0 } + if self.file_has_size { 1 } else { 0 } + if self.file_has_md5 { 1 } else { 0 }; w.write_u8(count)?; w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; let file_form = self.comp_file.0.form(); w.write_uleb128(file_form.0)?; w.write_uleb128(u64::from(constants::DW_LNCT_directory_index.0))?; w.write_uleb128(constants::DW_FORM_udata.0)?; if self.file_has_timestamp { w.write_uleb128(u64::from(constants::DW_LNCT_timestamp.0))?; w.write_uleb128(constants::DW_FORM_udata.0)?; } if self.file_has_size { w.write_uleb128(u64::from(constants::DW_LNCT_size.0))?; w.write_uleb128(constants::DW_FORM_udata.0)?; } if self.file_has_md5 { w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?; w.write_uleb128(constants::DW_FORM_data16.0)?; } // File name entries. w.write_uleb128(self.files.len() as u64 + 1)?; let mut write_file = |file: &LineString, dir: DirectoryId, info: &FileInfo| { file.write( w, file_form, self.encoding, debug_line_str_offsets, debug_str_offsets, )?; w.write_uleb128(dir.0 as u64)?; if self.file_has_timestamp { w.write_uleb128(info.timestamp)?; } if self.file_has_size { w.write_uleb128(info.size)?; } if self.file_has_md5 { w.write(&info.md5)?; } Ok(()) }; write_file(&self.comp_file.0, DirectoryId(0), &self.comp_file.1)?; for ((file, dir), info) in self.files.iter() { write_file(file, *dir, info)?; } } let header_length = (w.len() - header_length_base) as u64; w.write_udata_at( header_length_offset, header_length, self.format().word_size(), )?; for instruction in &self.instructions { instruction.write(w, self.address_size())?; } let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, self.format())?; Ok(offset) } } /// A row in the line number table that corresponds to a machine instruction. #[derive(Debug, Clone, Copy)] pub struct LineRow { /// The offset of the instruction from the start address of the sequence. pub address_offset: u64, /// The index of an operation within a VLIW instruction. /// /// The index of the first operation is 0. /// Set to 0 for non-VLIW instructions. pub op_index: u64, /// The source file corresponding to the instruction. pub file: FileId, /// The line number within the source file. /// /// Lines are numbered beginning at 1. Set to 0 if there is no source line. pub line: u64, /// The column number within the source line. /// /// Columns are numbered beginning at 1. Set to 0 for the "left edge" of the line. pub column: u64, /// An additional discriminator used to distinguish between source locations. /// This value is assigned arbitrarily by the DWARF producer. pub discriminator: u64, /// Set to true if the instruction is a recommended breakpoint for a statement. pub is_statement: bool, /// Set to true if the instruction is the beginning of a basic block. pub basic_block: bool, /// Set to true if the instruction is a recommended breakpoint at the entry of a /// function. pub prologue_end: bool, /// Set to true if the instruction is a recommended breakpoint prior to the exit of /// a function. pub epilogue_begin: bool, /// The instruction set architecture of the instruction. /// /// Set to 0 for the default ISA. Other values are defined by the architecture ABI. pub isa: u64, } impl LineRow { /// Return the initial state as specified in the DWARF standard. fn initial_state(line_encoding: LineEncoding) -> Self { LineRow { address_offset: 0, op_index: 0, file: FileId::initial_state(), line: 1, column: 0, discriminator: 0, is_statement: line_encoding.default_is_stmt, basic_block: false, prologue_end: false, epilogue_begin: false, isa: 0, } } } /// An instruction in a line number program. #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum LineInstruction { // Special opcodes Special(u8), // Standard opcodes Copy, AdvancePc(u64), AdvanceLine(i64), SetFile(FileId), SetColumn(u64), NegateStatement, SetBasicBlock, ConstAddPc, // DW_LNS_fixed_advance_pc is not supported. SetPrologueEnd, SetEpilogueBegin, SetIsa(u64), // Extended opcodes EndSequence, // TODO: this doubles the size of this enum. SetAddress(Address), // DW_LNE_define_file is not supported. SetDiscriminator(u64), } impl LineInstruction { /// Write the line number instruction to the given section. fn write(self, w: &mut DebugLine, address_size: u8) -> Result<()> { use self::LineInstruction::*; match self { Special(val) => w.write_u8(val)?, Copy => w.write_u8(constants::DW_LNS_copy.0)?, AdvancePc(val) => { w.write_u8(constants::DW_LNS_advance_pc.0)?; w.write_uleb128(val)?; } AdvanceLine(val) => { w.write_u8(constants::DW_LNS_advance_line.0)?; w.write_sleb128(val)?; } SetFile(val) => { w.write_u8(constants::DW_LNS_set_file.0)?; w.write_uleb128(val.raw())?; } SetColumn(val) => { w.write_u8(constants::DW_LNS_set_column.0)?; w.write_uleb128(val)?; } NegateStatement => w.write_u8(constants::DW_LNS_negate_stmt.0)?, SetBasicBlock => w.write_u8(constants::DW_LNS_set_basic_block.0)?, ConstAddPc => w.write_u8(constants::DW_LNS_const_add_pc.0)?, SetPrologueEnd => w.write_u8(constants::DW_LNS_set_prologue_end.0)?, SetEpilogueBegin => w.write_u8(constants::DW_LNS_set_epilogue_begin.0)?, SetIsa(val) => { w.write_u8(constants::DW_LNS_set_isa.0)?; w.write_uleb128(val)?; } EndSequence => { w.write_u8(0)?; w.write_uleb128(1)?; w.write_u8(constants::DW_LNE_end_sequence.0)?; } SetAddress(address) => { w.write_u8(0)?; w.write_uleb128(1 + u64::from(address_size))?; w.write_u8(constants::DW_LNE_set_address.0)?; w.write_address(address, address_size)?; } SetDiscriminator(val) => { let mut bytes = [0u8; 10]; // bytes is long enough so this will never fail. let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); w.write_u8(0)?; w.write_uleb128(1 + len as u64)?; w.write_u8(constants::DW_LNE_set_discriminator.0)?; w.write(&bytes[..len])?; } } Ok(()) } } /// A string value for use in defining paths in line number programs. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum LineString { /// A slice of bytes representing a string. Must not include null bytes. /// Not guaranteed to be UTF-8 or anything like that. String(Vec), /// A reference to a string in the `.debug_str` section. StringRef(StringId), /// A reference to a string in the `.debug_line_str` section. LineStringRef(LineStringId), } impl LineString { /// Create a `LineString` using the normal form for the given encoding. pub fn new(val: T, encoding: Encoding, line_strings: &mut LineStringTable) -> Self where T: Into>, { let val = val.into(); if encoding.version <= 4 { LineString::String(val) } else { LineString::LineStringRef(line_strings.add(val)) } } fn form(&self) -> constants::DwForm { match *self { LineString::String(..) => constants::DW_FORM_string, LineString::StringRef(..) => constants::DW_FORM_strp, LineString::LineStringRef(..) => constants::DW_FORM_line_strp, } } fn write( &self, w: &mut DebugLine, form: constants::DwForm, encoding: Encoding, debug_line_str_offsets: &DebugLineStrOffsets, debug_str_offsets: &DebugStrOffsets, ) -> Result<()> { if form != self.form() { return Err(Error::LineStringFormMismatch); } match *self { LineString::String(ref val) => { if encoding.version <= 4 { debug_assert!(!val.is_empty()); } w.write(val)?; w.write_u8(0)?; } LineString::StringRef(val) => { if encoding.version < 5 { return Err(Error::NeedVersion(5)); } w.write_offset( debug_str_offsets.get(val).0, SectionId::DebugStr, encoding.format.word_size(), )?; } LineString::LineStringRef(val) => { if encoding.version < 5 { return Err(Error::NeedVersion(5)); } w.write_offset( debug_line_str_offsets.get(val).0, SectionId::DebugLineStr, encoding.format.word_size(), )?; } } Ok(()) } } /// An identifier for a directory in a `LineProgram`. /// /// Defaults to the working directory of the compilation unit. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DirectoryId(usize); // Force FileId access via the methods. mod id { /// An identifier for a file in a `LineProgram`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FileId(usize); impl FileId { /// Create a FileId given an index into `LineProgram::files`. pub(crate) fn new(index: usize) -> Self { FileId(index + 1) } /// The index of the file in `LineProgram::files`. pub(super) fn index(self) -> Option { if self.0 == 0 { None } else { Some(self.0 - 1) } } /// The initial state of the file register. pub(super) fn initial_state() -> Self { FileId(1) } /// The raw value used when writing. pub(crate) fn raw(self) -> u64 { self.0 as u64 } /// The id for file index 0 in DWARF version 5. /// Only used when converting. pub(super) fn zero() -> Self { FileId(0) } } } pub use self::id::*; /// Extra information for file in a `LineProgram`. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct FileInfo { /// The implementation defined timestamp of the last modification of the file, /// or 0 if not available. pub timestamp: u64, /// The size of the file in bytes, or 0 if not available. pub size: u64, /// A 16-byte MD5 digest of the file contents. /// /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`. pub md5: [u8; 16], } define_section!( DebugLine, DebugLineOffset, "A writable `.debug_line` section." ); #[cfg(feature = "read")] mod convert { use super::*; use crate::read::{self, Reader}; use crate::write::{self, ConvertError, ConvertResult}; impl LineProgram { /// Create a line number program by reading the data from the given program. /// /// Return the program and a mapping from file index to `FileId`. pub fn from>( mut from_program: read::IncompleteLineProgram, dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult<(LineProgram, Vec)> { // Create mappings in case the source has duplicate files or directories. let mut dirs = Vec::new(); let mut files = Vec::new(); let mut program = { let from_header = from_program.header(); let encoding = from_header.encoding(); let comp_dir = match from_header.directory(0) { Some(comp_dir) => LineString::from(comp_dir, dwarf, line_strings, strings)?, None => LineString::new(&[][..], encoding, line_strings), }; let (comp_name, comp_file_info) = match from_header.file(0) { Some(comp_file) => { if comp_file.directory_index() != 0 { return Err(ConvertError::InvalidDirectoryIndex); } ( LineString::from(comp_file.path_name(), dwarf, line_strings, strings)?, Some(FileInfo { timestamp: comp_file.timestamp(), size: comp_file.size(), md5: *comp_file.md5(), }), ) } None => (LineString::new(&[][..], encoding, line_strings), None), }; if from_header.line_base() > 0 { return Err(ConvertError::InvalidLineBase); } let mut program = LineProgram::new( encoding, from_header.line_encoding(), comp_dir, comp_name, comp_file_info, ); let file_skip; if from_header.version() <= 4 { // The first directory is implicit. dirs.push(DirectoryId(0)); // A file index of 0 is invalid for version <= 4, but putting // something there makes the indexing easier. file_skip = 0; files.push(FileId::zero()); } else { // We don't add the first file to `files`, but still allow // it to be referenced from converted instructions. file_skip = 1; files.push(FileId::zero()); } for from_dir in from_header.include_directories() { let from_dir = LineString::from(from_dir.clone(), dwarf, line_strings, strings)?; dirs.push(program.add_directory(from_dir)); } program.file_has_timestamp = from_header.file_has_timestamp(); program.file_has_size = from_header.file_has_size(); program.file_has_md5 = from_header.file_has_md5(); for from_file in from_header.file_names().iter().skip(file_skip) { let from_name = LineString::from(from_file.path_name(), dwarf, line_strings, strings)?; let from_dir = from_file.directory_index(); if from_dir >= dirs.len() as u64 { return Err(ConvertError::InvalidDirectoryIndex); } let from_dir = dirs[from_dir as usize]; let from_info = Some(FileInfo { timestamp: from_file.timestamp(), size: from_file.size(), md5: *from_file.md5(), }); files.push(program.add_file(from_name, from_dir, from_info)); } program }; // We can't use the `from_program.rows()` because that wouldn't let // us preserve address relocations. let mut from_row = read::LineRow::new(from_program.header()); let mut instructions = from_program.header().instructions(); let mut address = None; while let Some(instruction) = instructions.next_instruction(from_program.header())? { match instruction { read::LineInstruction::SetAddress(val) => { if program.in_sequence() { return Err(ConvertError::UnsupportedLineInstruction); } match convert_address(val) { Some(val) => address = Some(val), None => return Err(ConvertError::InvalidAddress), } from_row.execute(read::LineInstruction::SetAddress(0), &mut from_program); } read::LineInstruction::DefineFile(_) => { return Err(ConvertError::UnsupportedLineInstruction); } _ => { if from_row.execute(instruction, &mut from_program) { if !program.in_sequence() { program.begin_sequence(address); address = None; } if from_row.end_sequence() { program.end_sequence(from_row.address()); } else { program.row().address_offset = from_row.address(); program.row().op_index = from_row.op_index(); program.row().file = { let file = from_row.file_index(); if file >= files.len() as u64 { return Err(ConvertError::InvalidFileIndex); } if file == 0 && program.version() <= 4 { return Err(ConvertError::InvalidFileIndex); } files[file as usize] }; program.row().line = from_row.line().unwrap_or(0); program.row().column = match from_row.column() { read::ColumnType::LeftEdge => 0, read::ColumnType::Column(val) => val, }; program.row().discriminator = from_row.discriminator(); program.row().is_statement = from_row.is_stmt(); program.row().basic_block = from_row.basic_block(); program.row().prologue_end = from_row.prologue_end(); program.row().epilogue_begin = from_row.epilogue_begin(); program.row().isa = from_row.isa(); program.generate_row(); } from_row.reset(from_program.header()); } } }; } Ok((program, files)) } } impl LineString { fn from>( from_attr: read::AttributeValue, dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, ) -> ConvertResult { Ok(match from_attr { read::AttributeValue::String(r) => LineString::String(r.to_slice()?.to_vec()), read::AttributeValue::DebugStrRef(offset) => { let r = dwarf.debug_str.get_str(offset)?; let id = strings.add(r.to_slice()?); LineString::StringRef(id) } read::AttributeValue::DebugLineStrRef(offset) => { let r = dwarf.debug_line_str.get_str(offset)?; let id = line_strings.add(r.to_slice()?); LineString::LineStringRef(id) } _ => return Err(ConvertError::UnsupportedLineStringForm), }) } } } #[cfg(test)] mod tests { use super::*; use crate::read; use crate::write::{DebugLineStr, DebugStr, EndianVec, StringTable}; use crate::LittleEndian; #[test] fn test_line_program_table() { let dir1 = LineString::String(b"dir1".to_vec()); let file1 = LineString::String(b"file1".to_vec()); let dir2 = LineString::String(b"dir2".to_vec()); let file2 = LineString::String(b"file2".to_vec()); let mut programs = Vec::new(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut program = LineProgram::new( encoding, LineEncoding::default(), dir1.clone(), file1.clone(), None, ); { assert_eq!(&dir1, program.get_directory(program.default_directory())); program.file_has_timestamp = true; program.file_has_size = true; if encoding.version >= 5 { program.file_has_md5 = true; } let dir_id = program.add_directory(dir2.clone()); assert_eq!(&dir2, program.get_directory(dir_id)); assert_eq!(dir_id, program.add_directory(dir2.clone())); let file_info = FileInfo { timestamp: 1, size: 2, md5: if encoding.version >= 5 { [3; 16] } else { [0; 16] }, }; let file_id = program.add_file(file2.clone(), dir_id, Some(file_info)); assert_eq!((&file2, dir_id), program.get_file(file_id)); assert_eq!(file_info, *program.get_file_info(file_id)); program.get_file_info_mut(file_id).size = 3; assert_ne!(file_info, *program.get_file_info(file_id)); assert_eq!(file_id, program.add_file(file2.clone(), dir_id, None)); assert_ne!(file_info, *program.get_file_info(file_id)); assert_eq!( file_id, program.add_file(file2.clone(), dir_id, Some(file_info)) ); assert_eq!(file_info, *program.get_file_info(file_id)); programs.push((program, file_id, encoding)); } } } } let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let mut debug_line_offsets = Vec::new(); for (program, _, encoding) in &programs { debug_line_offsets.push( program .write( &mut debug_line, *encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(), ); } let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let convert_address = &|address| Some(Address::Constant(address)); for ((program, file_id, encoding), offset) in programs.iter().zip(debug_line_offsets.iter()) { let read_program = read_debug_line .program( *offset, encoding.address_size, Some(read::EndianSlice::new(b"dir1", LittleEndian)), Some(read::EndianSlice::new(b"file1", LittleEndian)), ) .unwrap(); let dwarf = read::Dwarf::default(); let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let (convert_program, convert_files) = LineProgram::from( read_program, &dwarf, &mut convert_line_strings, &mut convert_strings, convert_address, ) .unwrap(); assert_eq!(convert_program.version(), program.version()); assert_eq!(convert_program.address_size(), program.address_size()); assert_eq!(convert_program.format(), program.format()); let convert_file_id = convert_files[file_id.raw() as usize]; let (file, dir) = program.get_file(*file_id); let (convert_file, convert_dir) = convert_program.get_file(convert_file_id); assert_eq!(file, convert_file); assert_eq!( program.get_directory(dir), convert_program.get_directory(convert_dir) ); assert_eq!( program.get_file_info(*file_id), convert_program.get_file_info(convert_file_id) ); } } #[test] fn test_line_row() { let dir1 = &b"dir1"[..]; let file1 = &b"file1"[..]; let file2 = &b"file2"[..]; let convert_address = &|address| Some(Address::Constant(address)); let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let line_base = -5; let line_range = 14; let neg_line_base = (-line_base) as u8; let mut program = LineProgram::new( encoding, LineEncoding { line_base, line_range, ..Default::default() }, LineString::String(dir1.to_vec()), LineString::String(file1.to_vec()), None, ); let dir_id = program.default_directory(); program.add_file(LineString::String(file1.to_vec()), dir_id, None); let file_id = program.add_file(LineString::String(file2.to_vec()), dir_id, None); // Test sequences. { let mut program = program.clone(); let address = Address::Constant(0x12); program.begin_sequence(Some(address)); assert_eq!( program.instructions, vec![LineInstruction::SetAddress(address)] ); } { let mut program = program.clone(); program.begin_sequence(None); assert_eq!(program.instructions, Vec::new()); } { let mut program = program.clone(); program.begin_sequence(None); program.end_sequence(0x1234); assert_eq!( program.instructions, vec![ LineInstruction::AdvancePc(0x1234), LineInstruction::EndSequence ] ); } // Create a base program. program.begin_sequence(None); program.row.line = 0x1000; program.generate_row(); let base_row = program.row; let base_instructions = program.instructions.clone(); // Create test cases. let mut tests = Vec::new(); let row = base_row; tests.push((row, vec![LineInstruction::Copy])); let mut row = base_row; row.line -= u64::from(neg_line_base); tests.push((row, vec![LineInstruction::Special(OPCODE_BASE)])); let mut row = base_row; row.line += u64::from(line_range) - 1; row.line -= u64::from(neg_line_base); tests.push(( row, vec![LineInstruction::Special(OPCODE_BASE + line_range - 1)], )); let mut row = base_row; row.line += u64::from(line_range); row.line -= u64::from(neg_line_base); tests.push(( row, vec![ LineInstruction::AdvanceLine(i64::from(line_range - neg_line_base)), LineInstruction::Copy, ], )); let mut row = base_row; row.address_offset = 1; row.line -= u64::from(neg_line_base); tests.push(( row, vec![LineInstruction::Special(OPCODE_BASE + line_range)], )); let op_range = (255 - OPCODE_BASE) / line_range; let mut row = base_row; row.address_offset = u64::from(op_range); row.line -= u64::from(neg_line_base); tests.push(( row, vec![LineInstruction::Special( OPCODE_BASE + op_range * line_range, )], )); let mut row = base_row; row.address_offset = u64::from(op_range); row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); row.line -= u64::from(neg_line_base); tests.push((row, vec![LineInstruction::Special(255)])); let mut row = base_row; row.address_offset = u64::from(op_range); row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; row.line -= u64::from(neg_line_base); tests.push(( row, vec![LineInstruction::ConstAddPc, LineInstruction::Copy], )); let mut row = base_row; row.address_offset = u64::from(op_range); row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; row.line -= u64::from(neg_line_base); tests.push(( row, vec![ LineInstruction::ConstAddPc, LineInstruction::Special(OPCODE_BASE + 6), ], )); let mut row = base_row; row.address_offset = u64::from(op_range) * 2; row.line += u64::from(255 - OPCODE_BASE - op_range * line_range); row.line -= u64::from(neg_line_base); tests.push(( row, vec![LineInstruction::ConstAddPc, LineInstruction::Special(255)], )); let mut row = base_row; row.address_offset = u64::from(op_range) * 2; row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1; row.line -= u64::from(neg_line_base); tests.push(( row, vec![ LineInstruction::AdvancePc(row.address_offset), LineInstruction::Copy, ], )); let mut row = base_row; row.address_offset = u64::from(op_range) * 2; row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2; row.line -= u64::from(neg_line_base); tests.push(( row, vec![ LineInstruction::AdvancePc(row.address_offset), LineInstruction::Special(OPCODE_BASE + 6), ], )); let mut row = base_row; row.address_offset = 0x1234; tests.push(( row, vec![LineInstruction::AdvancePc(0x1234), LineInstruction::Copy], )); let mut row = base_row; row.line += 0x1234; tests.push(( row, vec![LineInstruction::AdvanceLine(0x1234), LineInstruction::Copy], )); let mut row = base_row; row.file = file_id; tests.push(( row, vec![LineInstruction::SetFile(file_id), LineInstruction::Copy], )); let mut row = base_row; row.column = 0x1234; tests.push(( row, vec![LineInstruction::SetColumn(0x1234), LineInstruction::Copy], )); let mut row = base_row; row.discriminator = 0x1234; tests.push(( row, vec![ LineInstruction::SetDiscriminator(0x1234), LineInstruction::Copy, ], )); let mut row = base_row; row.is_statement = !row.is_statement; tests.push(( row, vec![LineInstruction::NegateStatement, LineInstruction::Copy], )); let mut row = base_row; row.basic_block = true; tests.push(( row, vec![LineInstruction::SetBasicBlock, LineInstruction::Copy], )); let mut row = base_row; row.prologue_end = true; tests.push(( row, vec![LineInstruction::SetPrologueEnd, LineInstruction::Copy], )); let mut row = base_row; row.epilogue_begin = true; tests.push(( row, vec![LineInstruction::SetEpilogueBegin, LineInstruction::Copy], )); let mut row = base_row; row.isa = 0x1234; tests.push(( row, vec![LineInstruction::SetIsa(0x1234), LineInstruction::Copy], )); for test in tests { // Test generate_row(). let mut program = program.clone(); program.row = test.0; program.generate_row(); assert_eq!( &program.instructions[base_instructions.len()..], &test.1[..] ); // Test LineProgram::from(). let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let debug_line_offset = program .write( &mut debug_line, encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_program = read_debug_line .program( debug_line_offset, address_size, Some(read::EndianSlice::new(dir1, LittleEndian)), Some(read::EndianSlice::new(file1, LittleEndian)), ) .unwrap(); let dwarf = read::Dwarf::default(); let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let (convert_program, _convert_files) = LineProgram::from( read_program, &dwarf, &mut convert_line_strings, &mut convert_strings, convert_address, ) .unwrap(); assert_eq!( &convert_program.instructions[base_instructions.len()..], &test.1[..] ); } } } } } #[test] fn test_line_instruction() { let dir1 = &b"dir1"[..]; let file1 = &b"file1"[..]; let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut program = LineProgram::new( encoding, LineEncoding::default(), LineString::String(dir1.to_vec()), LineString::String(file1.to_vec()), None, ); let dir_id = program.default_directory(); let file_id = program.add_file(LineString::String(file1.to_vec()), dir_id, None); for &(ref inst, ref expect_inst) in &[ ( LineInstruction::Special(OPCODE_BASE), read::LineInstruction::Special(OPCODE_BASE), ), ( LineInstruction::Special(255), read::LineInstruction::Special(255), ), (LineInstruction::Copy, read::LineInstruction::Copy), ( LineInstruction::AdvancePc(0x12), read::LineInstruction::AdvancePc(0x12), ), ( LineInstruction::AdvanceLine(0x12), read::LineInstruction::AdvanceLine(0x12), ), ( LineInstruction::SetFile(file_id), read::LineInstruction::SetFile(file_id.raw()), ), ( LineInstruction::SetColumn(0x12), read::LineInstruction::SetColumn(0x12), ), ( LineInstruction::NegateStatement, read::LineInstruction::NegateStatement, ), ( LineInstruction::SetBasicBlock, read::LineInstruction::SetBasicBlock, ), ( LineInstruction::ConstAddPc, read::LineInstruction::ConstAddPc, ), ( LineInstruction::SetPrologueEnd, read::LineInstruction::SetPrologueEnd, ), ( LineInstruction::SetEpilogueBegin, read::LineInstruction::SetEpilogueBegin, ), ( LineInstruction::SetIsa(0x12), read::LineInstruction::SetIsa(0x12), ), ( LineInstruction::EndSequence, read::LineInstruction::EndSequence, ), ( LineInstruction::SetAddress(Address::Constant(0x12)), read::LineInstruction::SetAddress(0x12), ), ( LineInstruction::SetDiscriminator(0x12), read::LineInstruction::SetDiscriminator(0x12), ), ][..] { let mut program = program.clone(); program.instructions.push(*inst); let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let debug_line_offset = program .write( &mut debug_line, encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_program = read_debug_line .program( debug_line_offset, address_size, Some(read::EndianSlice::new(dir1, LittleEndian)), Some(read::EndianSlice::new(file1, LittleEndian)), ) .unwrap(); let read_header = read_program.header(); let mut read_insts = read_header.instructions(); assert_eq!( *expect_inst, read_insts.next_instruction(read_header).unwrap().unwrap() ); assert_eq!(None, read_insts.next_instruction(read_header).unwrap()); } } } } } // Test that the address/line advance is correct. We don't test for optimality. #[test] #[allow(clippy::useless_vec)] fn test_advance() { let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 8, }; let dir1 = &b"dir1"[..]; let file1 = &b"file1"[..]; let addresses = 0..50; let lines = -10..25i64; let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); for minimum_instruction_length in vec![1, 4] { for maximum_operations_per_instruction in vec![1, 3] { for line_base in vec![-5, 0] { for line_range in vec![10, 20] { let line_encoding = LineEncoding { minimum_instruction_length, maximum_operations_per_instruction, line_base, line_range, default_is_stmt: true, }; let mut program = LineProgram::new( encoding, line_encoding, LineString::String(dir1.to_vec()), LineString::String(file1.to_vec()), None, ); for address_advance in addresses.clone() { program.begin_sequence(Some(Address::Constant(0x1000))); program.row().line = 0x10000; program.generate_row(); for line_advance in lines.clone() { { let row = program.row(); row.address_offset += address_advance * u64::from(minimum_instruction_length); row.line = row.line.wrapping_add(line_advance as u64); } program.generate_row(); } let address_offset = program.row().address_offset + u64::from(minimum_instruction_length); program.end_sequence(address_offset); } let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let debug_line_offset = program .write( &mut debug_line, encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_program = read_debug_line .program( debug_line_offset, 8, Some(read::EndianSlice::new(dir1, LittleEndian)), Some(read::EndianSlice::new(file1, LittleEndian)), ) .unwrap(); let mut rows = read_program.rows(); for address_advance in addresses.clone() { let mut address; let mut line; { let row = rows.next_row().unwrap().unwrap().1; address = row.address(); line = row.line().unwrap(); } assert_eq!(address, 0x1000); assert_eq!(line, 0x10000); for line_advance in lines.clone() { let row = rows.next_row().unwrap().unwrap().1; assert_eq!( row.address() - address, address_advance * u64::from(minimum_instruction_length) ); assert_eq!( (row.line().unwrap() as i64) - (line as i64), line_advance ); address = row.address(); line = row.line().unwrap(); } let row = rows.next_row().unwrap().unwrap().1; assert!(row.end_sequence()); } } } } } } #[test] fn test_line_string() { let version = 5; let file = b"file1"; let mut strings = StringTable::default(); let string_id = strings.add("file2"); let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); let debug_str_offsets = strings.write(&mut debug_str).unwrap(); let mut line_strings = LineStringTable::default(); let line_string_id = line_strings.add("file3"); let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; for (file, expect_file) in vec![ ( LineString::String(file.to_vec()), read::AttributeValue::String(read::EndianSlice::new(file, LittleEndian)), ), ( LineString::StringRef(string_id), read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), ), ( LineString::LineStringRef(line_string_id), read::AttributeValue::DebugLineStrRef( debug_line_str_offsets.get(line_string_id), ), ), ] { let program = LineProgram::new( encoding, LineEncoding::default(), LineString::String(b"dir".to_vec()), file, None, ); let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let debug_line_offset = program .write( &mut debug_line, encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_program = read_debug_line .program(debug_line_offset, address_size, None, None) .unwrap(); let read_header = read_program.header(); assert_eq!(read_header.file(0).unwrap().path_name(), expect_file); } } } } #[test] fn test_missing_comp_dir() { let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let program = LineProgram::new( encoding, LineEncoding::default(), LineString::String(Vec::new()), LineString::String(Vec::new()), None, ); let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let debug_line_offset = program .write( &mut debug_line, encoding, &debug_line_str_offsets, &debug_str_offsets, ) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_program = read_debug_line .program( debug_line_offset, address_size, // Testing missing comp_dir/comp_name. None, None, ) .unwrap(); let dwarf = read::Dwarf::default(); let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let convert_address = &|address| Some(Address::Constant(address)); LineProgram::from( read_program, &dwarf, &mut convert_line_strings, &mut convert_strings, convert_address, ) .unwrap(); } } } } } gimli-0.19.0/src/write/loc.rs010066400017500001750000000500451351057326000141770ustar0000000000000000use crate::vec::Vec; use indexmap::IndexSet; use std::ops::{Deref, DerefMut}; use crate::common::{Encoding, LocationListsOffset, SectionId}; use crate::write::{Address, BaseId, Error, Expression, Result, Section, Sections, Writer}; define_section!( DebugLoc, LocationListsOffset, "A writable `.debug_loc` section." ); define_section!( DebugLocLists, LocationListsOffset, "A writable `.debug_loclists` section." ); define_offsets!( LocationListOffsets: LocationListId => LocationListsOffset, "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections." ); define_id!( LocationListId, "An identifier for a location list in a `LocationListTable`." ); /// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section. #[derive(Debug, Default)] pub struct LocationListTable { base_id: BaseId, locations: IndexSet, } impl LocationListTable { /// Add a location list to the table. pub fn add(&mut self, loc_list: LocationList) -> LocationListId { let (index, _) = self.locations.insert_full(loc_list); LocationListId::new(self.base_id, index) } /// Write the location list table to the appropriate section for the given DWARF version. pub(crate) fn write( &self, sections: &mut Sections, encoding: Encoding, ) -> Result { if self.locations.is_empty() { return Ok(LocationListOffsets::none()); } match encoding.version { 2..=4 => self.write_loc(&mut sections.debug_loc, encoding.address_size), 5 => self.write_loclists(&mut sections.debug_loclists, encoding), _ => Err(Error::UnsupportedVersion(encoding.version)), } } /// Write the location list table to the `.debug_loc` section. fn write_loc( &self, w: &mut DebugLoc, address_size: u8, ) -> Result { let mut offsets = Vec::new(); for loc_list in self.locations.iter() { offsets.push(w.offset()); for loc in &loc_list.0 { // Note that we must ensure none of the ranges have both begin == 0 and end == 0. // We do this by ensuring that begin != end, which is a bit more restrictive // than required, but still seems reasonable. match *loc { Location::BaseAddress { address } => { let marker = !0 >> (64 - address_size * 8); w.write_udata(marker, address_size)?; w.write_address(address, address_size)?; } Location::OffsetPair { begin, end, ref data, } => { if begin == end { return Err(Error::InvalidRange); } w.write_udata(begin, address_size)?; w.write_udata(end, address_size)?; w.write_u16(data.0.len() as u16)?; w.write(&data.0)?; } Location::StartEnd { begin, end, ref data, } => { if begin == end { return Err(Error::InvalidRange); } w.write_address(begin, address_size)?; w.write_address(end, address_size)?; w.write_u16(data.0.len() as u16)?; w.write(&data.0)?; } Location::StartLength { begin, length, ref data, } => { let end = match begin { Address::Constant(begin) => Address::Constant(begin + length), Address::Symbol { symbol, addend } => Address::Symbol { symbol, addend: addend + length as i64, }, }; if begin == end { return Err(Error::InvalidRange); } w.write_address(begin, address_size)?; w.write_address(end, address_size)?; w.write_u16(data.0.len() as u16)?; w.write(&data.0)?; } Location::DefaultLocation { .. } => { return Err(Error::InvalidRange); } } } w.write_udata(0, address_size)?; w.write_udata(0, address_size)?; } Ok(LocationListOffsets { base_id: self.base_id, offsets, }) } /// Write the location list table to the `.debug_loclists` section. fn write_loclists( &self, w: &mut DebugLocLists, encoding: Encoding, ) -> Result { let mut offsets = Vec::new(); if encoding.version != 5 { return Err(Error::NeedVersion(5)); } let length_offset = w.write_initial_length(encoding.format)?; let length_base = w.len(); w.write_u16(encoding.version)?; w.write_u8(encoding.address_size)?; w.write_u8(0)?; // segment_selector_size w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list for loc_list in self.locations.iter() { offsets.push(w.offset()); for loc in &loc_list.0 { match *loc { Location::BaseAddress { address } => { w.write_u8(crate::constants::DW_LLE_base_address.0)?; w.write_address(address, encoding.address_size)?; } Location::OffsetPair { begin, end, ref data, } => { w.write_u8(crate::constants::DW_LLE_offset_pair.0)?; w.write_uleb128(begin)?; w.write_uleb128(end)?; w.write_uleb128(data.0.len() as u64)?; w.write(&data.0)?; } Location::StartEnd { begin, end, ref data, } => { w.write_u8(crate::constants::DW_LLE_start_end.0)?; w.write_address(begin, encoding.address_size)?; w.write_address(end, encoding.address_size)?; w.write_uleb128(data.0.len() as u64)?; w.write(&data.0)?; } Location::StartLength { begin, length, ref data, } => { w.write_u8(crate::constants::DW_LLE_start_length.0)?; w.write_address(begin, encoding.address_size)?; w.write_uleb128(length)?; w.write_uleb128(data.0.len() as u64)?; w.write(&data.0)?; } Location::DefaultLocation { ref data } => { w.write_u8(crate::constants::DW_LLE_default_location.0)?; w.write_uleb128(data.0.len() as u64)?; w.write(&data.0)?; } } } w.write_u8(crate::constants::DW_LLE_end_of_list.0)?; } let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, encoding.format)?; Ok(LocationListOffsets { base_id: self.base_id, offsets, }) } } /// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct LocationList(pub Vec); /// A single location. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum Location { /// DW_LLE_base_address BaseAddress { /// Base address. address: Address, }, /// DW_LLE_offset_pair OffsetPair { /// Start of range relative to base address. begin: u64, /// End of range relative to base address. end: u64, /// Location description. data: Expression, }, /// DW_LLE_start_end StartEnd { /// Start of range. begin: Address, /// End of range. end: Address, /// Location description. data: Expression, }, /// DW_LLE_start_length StartLength { /// Start of range. begin: Address, /// Length of range. length: u64, /// Location description. data: Expression, }, /// DW_LLE_default_location DefaultLocation { /// Location description. data: Expression, }, } #[cfg(feature = "read")] mod convert { use super::*; use crate::read::{self, Reader}; use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; impl LocationList { /// Create a location list by reading the data from the give location list iter. pub(crate) fn from>( mut from: read::RawLocListIter, context: &ConvertUnitContext, ) -> ConvertResult { let mut have_base_address = context.base_address != Address::Constant(0); let convert_address = |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); let mut loc_list = Vec::new(); while let Some(from_loc) = from.next()? { let loc = match from_loc { read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => { // These were parsed as addresses, even if they are offsets. let begin = convert_address(begin)?; let end = convert_address(end)?; let data = Expression(data.0.to_slice()?.into()); match (begin, end) { (Address::Constant(begin_offset), Address::Constant(end_offset)) => { if have_base_address { Location::OffsetPair { begin: begin_offset, end: end_offset, data, } } else { Location::StartEnd { begin, end, data } } } _ => { if have_base_address { // At least one of begin/end is an address, but we also have // a base address. Adding addresses is undefined. return Err(ConvertError::InvalidRangeRelativeAddress); } Location::StartEnd { begin, end, data } } } } read::RawLocListEntry::BaseAddress { addr } => { have_base_address = true; let address = convert_address(addr)?; Location::BaseAddress { address } } read::RawLocListEntry::BaseAddressx { addr } => { have_base_address = true; let address = convert_address(context.dwarf.address(context.unit, addr)?)?; Location::BaseAddress { address } } read::RawLocListEntry::StartxEndx { begin, end, data } => { let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; let end = convert_address(context.dwarf.address(context.unit, end)?)?; let data = Expression(data.0.to_slice()?.into()); Location::StartEnd { begin, end, data } } read::RawLocListEntry::StartxLength { begin, length, data, } => { let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; let data = Expression(data.0.to_slice()?.into()); Location::StartLength { begin, length, data, } } read::RawLocListEntry::OffsetPair { begin, end, data } => { let data = Expression(data.0.to_slice()?.into()); Location::OffsetPair { begin, end, data } } read::RawLocListEntry::StartEnd { begin, end, data } => { let begin = convert_address(begin)?; let end = convert_address(end)?; let data = Expression(data.0.to_slice()?.into()); Location::StartEnd { begin, end, data } } read::RawLocListEntry::StartLength { begin, length, data, } => { let begin = convert_address(begin)?; let data = Expression(data.0.to_slice()?.into()); Location::StartLength { begin, length, data, } } read::RawLocListEntry::DefaultLocation { data } => { let data = Expression(data.0.to_slice()?.into()); Location::DefaultLocation { data } } }; // In some cases, existing data may contain begin == end, filtering // these out. match loc { Location::StartLength { length, .. } if length == 0 => continue, Location::StartEnd { begin, end, .. } if begin == end => continue, Location::OffsetPair { begin, end, .. } if begin == end => continue, _ => (), } loc_list.push(loc); } Ok(LocationList(loc_list)) } } } #[cfg(test)] mod tests { use super::*; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, Format, UnitSectionOffset, }; use crate::read; use crate::write::{ ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable, }; use crate::LittleEndian; #[test] fn test_loc_list() { let mut line_strings = LineStringTable::default(); let mut strings = StringTable::default(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut loc_list = LocationList(vec![ Location::StartLength { begin: Address::Constant(6666), length: 7777, data: Expression(vec![1, 0, 0, 0]), }, Location::StartEnd { begin: Address::Constant(4444), end: Address::Constant(5555), data: Expression(vec![2, 0, 0, 0]), }, Location::BaseAddress { address: Address::Constant(1111), }, Location::OffsetPair { begin: 2222, end: 3333, data: Expression(vec![3, 0, 0, 0]), }, ]); if version >= 5 { loc_list.0.push(Location::DefaultLocation { data: Expression(vec![4, 0, 0, 0]), }); } let mut locations = LocationListTable::default(); let loc_list_id = locations.add(loc_list.clone()); let mut sections = Sections::new(EndianVec::new(LittleEndian)); let loc_list_offsets = locations.write(&mut sections, encoding).unwrap(); let read_debug_loc = read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); let read_debug_loclists = read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists); let offset = loc_list_offsets.get(loc_list_id); let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap(); let dwarf = read::Dwarf { locations: read_loc, ..Default::default() }; let unit = read::Unit { offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: read::UnitHeader::new( encoding, 0, DebugAbbrevOffset(0), read::EndianSlice::default(), ), abbreviations: read::Abbreviations::default(), name: None, comp_dir: None, low_pc: 0, str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), loclists_base: DebugLocListsBase(0), rnglists_base: DebugRngListsBase(0), line_program: None, }; let context = ConvertUnitContext { dwarf: &dwarf, unit: &unit, line_strings: &mut line_strings, strings: &mut strings, ranges: &mut RangeListTable::default(), locations: &mut locations, convert_address: &|address| Some(Address::Constant(address)), base_address: Address::Constant(0), line_program_offset: None, line_program_files: Vec::new(), }; let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap(); if version <= 4 { loc_list.0[0] = Location::StartEnd { begin: Address::Constant(6666), end: Address::Constant(6666 + 7777), data: Expression(vec![1, 0, 0, 0]), }; } assert_eq!(loc_list, convert_loc_list); } } } } } gimli-0.19.0/src/write/mod.rs010066400017500001750000000306701351057326000142030ustar0000000000000000//! Write DWARF debugging information. //! //! ## API Structure //! //! This module works by building up a representation of the debugging information //! in memory, and then writing it all at once. It supports two major use cases: //! //! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF //! for a single compilation unit. //! //! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple //! compilation units. //! //! The module also supports reading in DWARF debugging information and writing it out //! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) //! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert //! it to a writable instance. //! //! ## Example Usage //! //! Write a compilation unit containing only the top level DIE. //! //! ```rust //! use gimli::write::{ //! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, //! }; //! //! fn example() -> Result<(), Error> { //! // Choose the encoding parameters. //! let encoding = gimli::Encoding { //! format: gimli::Format::Dwarf32, //! version: 5, //! address_size: 8, //! }; //! // Create a container for a single compilation unit. //! let mut dwarf = DwarfUnit::new(encoding); //! // Set a range attribute on the root DIE. //! let range_list = RangeList(vec![Range::StartLength { //! begin: Address::Constant(0x100), //! length: 42, //! }]); //! let range_list_id = dwarf.unit.ranges.add(range_list); //! let root = dwarf.unit.root(); //! dwarf.unit.get_mut(root).set( //! gimli::DW_AT_ranges, //! AttributeValue::RangeListRef(range_list_id), //! ); //! // Create a `Vec` for each DWARF section. //! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); //! // Finally, write the DWARF data to the sections. //! dwarf.write(&mut sections)?; //! sections.for_each(|id, data| { //! // Here you can add the data to the output object file. //! Ok(()) //! }) //! } //! # fn main() { //! # example().unwrap(); //! # } use std::error; use std::fmt; use std::result; use crate::constants; mod endian_vec; pub use self::endian_vec::*; mod writer; pub use self::writer::*; #[macro_use] mod section; pub use self::section::*; macro_rules! define_id { ($name:ident, $docs:expr) => { #[doc=$docs] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct $name { base_id: BaseId, index: usize, } impl $name { #[inline] fn new(base_id: BaseId, index: usize) -> Self { $name { base_id, index } } } }; } macro_rules! define_offsets { ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { #[doc=$off_doc] #[derive(Debug)] pub struct $offsets { base_id: BaseId, // We know ids start at 0. offsets: Vec<$offset>, } impl $offsets { /// Return an empty list of offsets. #[inline] pub fn none() -> Self { $offsets { base_id: BaseId::default(), offsets: Vec::new(), } } /// Get the offset /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get(&self, id: $id) -> $offset { debug_assert_eq!(self.base_id, id.base_id); self.offsets[id.index] } /// Return the number of offsets. #[inline] pub fn count(&self) -> usize { self.offsets.len() } } }; } mod abbrev; pub use self::abbrev::*; mod cfi; pub use self::cfi::*; mod dwarf; pub use self::dwarf::*; mod line; pub use self::line::*; mod range; pub use self::range::*; mod loc; pub use self::loc::*; mod str; pub use self::str::*; mod unit; pub use self::unit::*; /// An error that occurred when writing. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { /// The given offset is out of bounds. OffsetOutOfBounds, /// The given length is out of bounds. LengthOutOfBounds, /// The attribute value is an invalid for writing. InvalidAttributeValue, /// The value is too large for the encoding form. ValueTooLarge, /// Unsupported word size. UnsupportedWordSize(u8), /// Unsupported DWARF version. UnsupportedVersion(u16), /// The unit length is too large for the requested DWARF format. InitialLengthOverflow, /// The address is invalid. InvalidAddress, /// A requested feature requires a different DWARF version. NeedVersion(u16), /// Strings in line number program have mismatched forms. LineStringFormMismatch, /// The range is empty or otherwise invalid. InvalidRange, /// The line number program encoding is incompatible with the unit encoding. IncompatibleLineProgramEncoding, /// Could not encode code offset for a frame instruction. InvalidFrameCodeOffset(u32), /// Could not encode data offset for a frame instruction. InvalidFrameDataOffset(i32), /// Unsupported eh_frame pointer encoding. UnsupportedPointerEncoding(constants::DwEhPe), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { match *self { Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), Error::InvalidAttributeValue => { write!(f, "The attribute value is an invalid for writing.") } Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), Error::UnsupportedVersion(version) => { write!(f, "Unsupported DWARF version: {}", version) } Error::InitialLengthOverflow => write!( f, "The unit length is too large for the requested DWARF format." ), Error::InvalidAddress => write!(f, "The address is invalid."), Error::NeedVersion(version) => write!( f, "A requested feature requires a DWARF version {}.", version ), Error::LineStringFormMismatch => { write!(f, "Strings in line number program have mismatched forms.") } Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), Error::IncompatibleLineProgramEncoding => write!( f, "The line number program encoding is incompatible with the unit encoding." ), Error::InvalidFrameCodeOffset(offset) => write!( f, "Could not encode code offset ({}) for a frame instruction.", offset, ), Error::InvalidFrameDataOffset(offset) => write!( f, "Could not encode data offset ({}) for a frame instruction.", offset, ), Error::UnsupportedPointerEncoding(eh_pe) => { write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) } } } } impl error::Error for Error {} /// The result of a write. pub type Result = result::Result; /// An address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Address { /// A fixed address that does not require relocation. Constant(u64), /// An address that is relative to a symbol which may be relocated. Symbol { /// The symbol that the address is relative to. /// /// The meaning of this value is decided by the writer, but /// will typically be an index into a symbol table. symbol: usize, /// The offset of the address relative to the symbol. /// /// This will typically be used as the addend in a relocation. addend: i64, }, } // This type is only used in debug assertions. #[cfg(not(debug_assertions))] type BaseId = (); #[cfg(debug_assertions)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct BaseId(usize); #[cfg(debug_assertions)] impl Default for BaseId { fn default() -> Self { use std::sync::atomic; static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) } } #[cfg(feature = "read")] mod convert { use super::*; use crate::read; pub(crate) use super::unit::convert::*; /// An error that occurred when converting a read value into a write value. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ConvertError { /// An error occurred when reading. Read(read::Error), /// Writing of this attribute value is not implemented yet. UnsupportedAttributeValue, /// This attribute value is an invalid name/form combination. InvalidAttributeValue, /// A `.debug_info` reference does not refer to a valid entry. InvalidDebugInfoOffset, /// An address could not be converted. InvalidAddress, /// Writing this line number instruction is not implemented yet. UnsupportedLineInstruction, /// Writing this form of line string is not implemented yet. UnsupportedLineStringForm, /// A `.debug_line` file index is invalid. InvalidFileIndex, /// A `.debug_line` directory index is invalid. InvalidDirectoryIndex, /// A `.debug_line` line base is invalid. InvalidLineBase, /// A `.debug_line` reference is invalid. InvalidLineRef, /// Invalid relative address in a range list. InvalidRangeRelativeAddress, /// Writing this CFI instruction is not implemented yet. UnsupportedCfiInstruction, /// Writing indirect pointers is not implemented yet. UnsupportedIndirectAddress, } impl fmt::Display for ConvertError { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { use self::ConvertError::*; match *self { Read(ref e) => e.fmt(f), UnsupportedAttributeValue => { write!(f, "Writing of this attribute value is not implemented yet.") } InvalidAttributeValue => write!( f, "This attribute value is an invalid name/form combination." ), InvalidDebugInfoOffset => write!( f, "A `.debug_info` reference does not refer to a valid entry." ), InvalidAddress => write!(f, "An address could not be converted."), UnsupportedLineInstruction => write!( f, "Writing this line number instruction is not implemented yet." ), UnsupportedLineStringForm => write!( f, "Writing this form of line string is not implemented yet." ), InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), InvalidRangeRelativeAddress => { write!(f, "Invalid relative address in a range list.") } UnsupportedCfiInstruction => { write!(f, "Writing this CFI instruction is not implemented yet.") } UnsupportedIndirectAddress => { write!(f, "Writing indirect pointers is not implemented yet.") } } } } impl error::Error for ConvertError {} impl From for ConvertError { fn from(e: read::Error) -> Self { ConvertError::Read(e) } } /// The result of a conversion. pub type ConvertResult = result::Result; } #[cfg(feature = "read")] pub use self::convert::*; gimli-0.19.0/src/write/range.rs010066400017500001750000000405051351057326000145160ustar0000000000000000use crate::vec::Vec; use indexmap::IndexSet; use std::ops::{Deref, DerefMut}; use crate::common::{Encoding, RangeListsOffset, SectionId}; use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer}; define_section!( DebugRanges, RangeListsOffset, "A writable `.debug_ranges` section." ); define_section!( DebugRngLists, RangeListsOffset, "A writable `.debug_rnglists` section." ); define_offsets!( RangeListOffsets: RangeListId => RangeListsOffset, "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections." ); define_id!( RangeListId, "An identifier for a range list in a `RangeListTable`." ); /// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section. #[derive(Debug, Default)] pub struct RangeListTable { base_id: BaseId, ranges: IndexSet, } impl RangeListTable { /// Add a range list to the table. pub fn add(&mut self, range_list: RangeList) -> RangeListId { let (index, _) = self.ranges.insert_full(range_list); RangeListId::new(self.base_id, index) } /// Write the range list table to the appropriate section for the given DWARF version. pub(crate) fn write( &self, sections: &mut Sections, encoding: Encoding, ) -> Result { if self.ranges.is_empty() { return Ok(RangeListOffsets::none()); } match encoding.version { 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size), 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding), _ => Err(Error::UnsupportedVersion(encoding.version)), } } /// Write the range list table to the `.debug_ranges` section. fn write_ranges( &self, w: &mut DebugRanges, address_size: u8, ) -> Result { let mut offsets = Vec::new(); for range_list in self.ranges.iter() { offsets.push(w.offset()); for range in &range_list.0 { // Note that we must ensure none of the ranges have both begin == 0 and end == 0. // We do this by ensuring that begin != end, which is a bit more restrictive // than required, but still seems reasonable. match *range { Range::BaseAddress { address } => { let marker = !0 >> (64 - address_size * 8); w.write_udata(marker, address_size)?; w.write_address(address, address_size)?; } Range::OffsetPair { begin, end } => { if begin == end { return Err(Error::InvalidRange); } w.write_udata(begin, address_size)?; w.write_udata(end, address_size)?; } Range::StartEnd { begin, end } => { if begin == end { return Err(Error::InvalidRange); } w.write_address(begin, address_size)?; w.write_address(end, address_size)?; } Range::StartLength { begin, length } => { let end = match begin { Address::Constant(begin) => Address::Constant(begin + length), Address::Symbol { symbol, addend } => Address::Symbol { symbol, addend: addend + length as i64, }, }; if begin == end { return Err(Error::InvalidRange); } w.write_address(begin, address_size)?; w.write_address(end, address_size)?; } } } w.write_udata(0, address_size)?; w.write_udata(0, address_size)?; } Ok(RangeListOffsets { base_id: self.base_id, offsets, }) } /// Write the range list table to the `.debug_rnglists` section. fn write_rnglists( &self, w: &mut DebugRngLists, encoding: Encoding, ) -> Result { let mut offsets = Vec::new(); if encoding.version != 5 { return Err(Error::NeedVersion(5)); } let length_offset = w.write_initial_length(encoding.format)?; let length_base = w.len(); w.write_u16(encoding.version)?; w.write_u8(encoding.address_size)?; w.write_u8(0)?; // segment_selector_size w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list for range_list in self.ranges.iter() { offsets.push(w.offset()); for range in &range_list.0 { match *range { Range::BaseAddress { address } => { w.write_u8(crate::constants::DW_RLE_base_address.0)?; w.write_address(address, encoding.address_size)?; } Range::OffsetPair { begin, end } => { w.write_u8(crate::constants::DW_RLE_offset_pair.0)?; w.write_uleb128(begin)?; w.write_uleb128(end)?; } Range::StartEnd { begin, end } => { w.write_u8(crate::constants::DW_RLE_start_end.0)?; w.write_address(begin, encoding.address_size)?; w.write_address(end, encoding.address_size)?; } Range::StartLength { begin, length } => { w.write_u8(crate::constants::DW_RLE_start_length.0)?; w.write_address(begin, encoding.address_size)?; w.write_uleb128(length)?; } } } w.write_u8(crate::constants::DW_RLE_end_of_list.0)?; } let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, encoding.format)?; Ok(RangeListOffsets { base_id: self.base_id, offsets, }) } } /// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct RangeList(pub Vec); /// A single range. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum Range { /// DW_RLE_base_address BaseAddress { /// Base address. address: Address, }, /// DW_RLE_offset_pair OffsetPair { /// Start of range relative to base address. begin: u64, /// End of range relative to base address. end: u64, }, /// DW_RLE_start_end StartEnd { /// Start of range. begin: Address, /// End of range. end: Address, }, /// DW_RLE_start_length StartLength { /// Start of range. begin: Address, /// Length of range. length: u64, }, } #[cfg(feature = "read")] mod convert { use super::*; use crate::read::{self, Reader}; use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; impl RangeList { /// Create a range list by reading the data from the give range list iter. pub(crate) fn from>( mut from: read::RawRngListIter, context: &ConvertUnitContext, ) -> ConvertResult { let mut have_base_address = context.base_address != Address::Constant(0); let convert_address = |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); let mut ranges = Vec::new(); while let Some(from_range) = from.next()? { let range = match from_range { read::RawRngListEntry::AddressOrOffsetPair { begin, end } => { // These were parsed as addresses, even if they are offsets. let begin = convert_address(begin)?; let end = convert_address(end)?; match (begin, end) { (Address::Constant(begin_offset), Address::Constant(end_offset)) => { if have_base_address { Range::OffsetPair { begin: begin_offset, end: end_offset, } } else { Range::StartEnd { begin, end } } } _ => { if have_base_address { // At least one of begin/end is an address, but we also have // a base address. Adding addresses is undefined. return Err(ConvertError::InvalidRangeRelativeAddress); } Range::StartEnd { begin, end } } } } read::RawRngListEntry::BaseAddress { addr } => { have_base_address = true; let address = convert_address(addr)?; Range::BaseAddress { address } } read::RawRngListEntry::BaseAddressx { addr } => { have_base_address = true; let address = convert_address(context.dwarf.address(context.unit, addr)?)?; Range::BaseAddress { address } } read::RawRngListEntry::StartxEndx { begin, end } => { let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; let end = convert_address(context.dwarf.address(context.unit, end)?)?; Range::StartEnd { begin, end } } read::RawRngListEntry::StartxLength { begin, length } => { let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; Range::StartLength { begin, length } } read::RawRngListEntry::OffsetPair { begin, end } => { Range::OffsetPair { begin, end } } read::RawRngListEntry::StartEnd { begin, end } => { let begin = convert_address(begin)?; let end = convert_address(end)?; Range::StartEnd { begin, end } } read::RawRngListEntry::StartLength { begin, length } => { let begin = convert_address(begin)?; Range::StartLength { begin, length } } }; // Filtering empty ranges out. match range { Range::StartLength { length, .. } if length == 0 => continue, Range::StartEnd { begin, end, .. } if begin == end => continue, Range::OffsetPair { begin, end, .. } if begin == end => continue, _ => (), } ranges.push(range); } Ok(RangeList(ranges)) } } } #[cfg(test)] mod tests { use super::*; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, Format, UnitSectionOffset, }; use crate::read; use crate::write::{ ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable, StringTable, }; use crate::LittleEndian; #[test] fn test_range() { let mut line_strings = LineStringTable::default(); let mut strings = StringTable::default(); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut range_list = RangeList(vec![ Range::StartLength { begin: Address::Constant(6666), length: 7777, }, Range::StartEnd { begin: Address::Constant(4444), end: Address::Constant(5555), }, Range::BaseAddress { address: Address::Constant(1111), }, Range::OffsetPair { begin: 2222, end: 3333, }, ]); let mut ranges = RangeListTable::default(); let range_list_id = ranges.add(range_list.clone()); let mut sections = Sections::new(EndianVec::new(LittleEndian)); let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); let read_debug_ranges = read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); let read_debug_rnglists = read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists); let offset = range_list_offsets.get(range_list_id); let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap(); let dwarf = read::Dwarf { ranges: read_ranges, ..Default::default() }; let unit = read::Unit { offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: read::UnitHeader::new( encoding, 0, DebugAbbrevOffset(0), read::EndianSlice::default(), ), abbreviations: read::Abbreviations::default(), name: None, comp_dir: None, low_pc: 0, str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), loclists_base: DebugLocListsBase(0), rnglists_base: DebugRngListsBase(0), line_program: None, }; let context = ConvertUnitContext { dwarf: &dwarf, unit: &unit, line_strings: &mut line_strings, strings: &mut strings, ranges: &mut ranges, locations: &mut LocationListTable::default(), convert_address: &|address| Some(Address::Constant(address)), base_address: Address::Constant(0), line_program_offset: None, line_program_files: Vec::new(), }; let convert_range_list = RangeList::from(read_range_list, &context).unwrap(); if version <= 4 { range_list.0[0] = Range::StartEnd { begin: Address::Constant(6666), end: Address::Constant(6666 + 7777), }; } assert_eq!(range_list, convert_range_list); } } } } } gimli-0.19.0/src/write/section.rs010066400017500001750000000106141351057326000150640ustar0000000000000000use std::ops::DerefMut; use std::result; use crate::common::SectionId; use crate::write::{ DebugAbbrev, DebugInfo, DebugLine, DebugLineStr, DebugLoc, DebugLocLists, DebugRanges, DebugRngLists, DebugStr, Writer, }; macro_rules! define_section { ($name:ident, $offset:ident, $docs:expr) => { #[doc=$docs] #[derive(Debug, Default)] pub struct $name(pub W); impl $name { /// Return the offset of the next write. pub fn offset(&self) -> $offset { $offset(self.len()) } } impl From for $name { #[inline] fn from(w: W) -> Self { $name(w) } } impl Deref for $name { type Target = W; #[inline] fn deref(&self) -> &W { &self.0 } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut W { &mut self.0 } } impl Section for $name { #[inline] fn id(&self) -> SectionId { SectionId::$name } } }; } /// Functionality common to all writable DWARF sections. pub trait Section: DerefMut { /// Returns the DWARF section kind for this type. fn id(&self) -> SectionId; /// Returns the ELF section name for this type. fn name(&self) -> &'static str { self.id().name() } } /// All of the writable DWARF sections. #[derive(Debug, Default)] pub struct Sections { /// The `.debug_abbrev` section. pub debug_abbrev: DebugAbbrev, /// The `.debug_info` section. pub debug_info: DebugInfo, /// The `.debug_line` section. pub debug_line: DebugLine, /// The `.debug_line_str` section. pub debug_line_str: DebugLineStr, /// The `.debug_ranges` section. pub debug_ranges: DebugRanges, /// The `.debug_rnglists` section. pub debug_rnglists: DebugRngLists, /// The `.debug_loc` section. pub debug_loc: DebugLoc, /// The `.debug_loclists` section. pub debug_loclists: DebugLocLists, /// The `.debug_str` section. pub debug_str: DebugStr, } impl Sections { /// Create a new `Sections` using clones of the given `section`. pub fn new(section: W) -> Self { Sections { debug_abbrev: DebugAbbrev(section.clone()), debug_info: DebugInfo(section.clone()), debug_line: DebugLine(section.clone()), debug_line_str: DebugLineStr(section.clone()), debug_ranges: DebugRanges(section.clone()), debug_rnglists: DebugRngLists(section.clone()), debug_loc: DebugLoc(section.clone()), debug_loclists: DebugLocLists(section.clone()), debug_str: DebugStr(section.clone()), } } } impl Sections { /// For each section, call `f` once with a shared reference. pub fn for_each(&self, mut f: F) -> result::Result<(), E> where F: FnMut(SectionId, &W) -> result::Result<(), E>, { macro_rules! f { ($s:expr) => { f($s.id(), &$s) }; } // Ordered so that earlier sections do not reference later sections. f!(self.debug_abbrev)?; f!(self.debug_str)?; f!(self.debug_line_str)?; f!(self.debug_line)?; f!(self.debug_ranges)?; f!(self.debug_rnglists)?; f!(self.debug_loc)?; f!(self.debug_loclists)?; f!(self.debug_info)?; Ok(()) } /// For each section, call `f` once with a mutable reference. pub fn for_each_mut(&mut self, mut f: F) -> result::Result<(), E> where F: FnMut(SectionId, &mut W) -> result::Result<(), E>, { macro_rules! f { ($s:expr) => { f($s.id(), &mut $s) }; } // Ordered so that earlier sections do not reference later sections. f!(self.debug_abbrev)?; f!(self.debug_str)?; f!(self.debug_line_str)?; f!(self.debug_line)?; f!(self.debug_ranges)?; f!(self.debug_rnglists)?; f!(self.debug_loc)?; f!(self.debug_loclists)?; f!(self.debug_info)?; Ok(()) } } gimli-0.19.0/src/write/str.rs010066400017500001750000000127101346020377600142350ustar0000000000000000use crate::vec::Vec; use indexmap::IndexSet; use std::ops::{Deref, DerefMut}; use crate::common::{DebugLineStrOffset, DebugStrOffset, SectionId}; use crate::write::{BaseId, Result, Section, Writer}; // Requirements: // - values are `[u8]`, null bytes are not allowed // - insertion returns a fixed id // - inserting a duplicate returns the id of the existing value // - able to convert an id to a section offset // Optional? // - able to get an existing value given an id // // Limitations of current implementation (using IndexSet): // - inserting requires either an allocation for duplicates, // or a double lookup for non-duplicates // - doesn't preserve offsets when updating an existing `.debug_str` section // // Possible changes: // - calculate offsets as we add values, and use that as the id. // This would avoid the need for DebugStrOffsets but would make it // hard to implement `get`. macro_rules! define_string_table { ($name:ident, $id:ident, $section:ident, $offsets:ident, $docs:expr) => { #[doc=$docs] #[derive(Debug, Default)] pub struct $name { base_id: BaseId, strings: IndexSet>, } impl $name { /// Add a string to the string table and return its id. /// /// If the string already exists, then return the id of the existing string. /// /// # Panics /// /// Panics if `bytes` contains a null byte. pub fn add(&mut self, bytes: T) -> $id where T: Into>, { let bytes = bytes.into(); assert!(!bytes.contains(&0)); let (index, _) = self.strings.insert_full(bytes); $id::new(self.base_id, index) } /// Return the number of strings in the table. #[inline] pub fn count(&self) -> usize { self.strings.len() } /// Get a reference to a string in the table. /// /// # Panics /// /// Panics if `id` is invalid. pub fn get(&self, id: $id) -> &[u8] { debug_assert_eq!(self.base_id, id.base_id); self.strings.get_index(id.index).map(Vec::as_slice).unwrap() } /// Write the string table to the `.debug_str` section. /// /// Returns the offsets at which the strings are written. pub fn write(&self, w: &mut $section) -> Result<$offsets> { let mut offsets = Vec::new(); for bytes in self.strings.iter() { offsets.push(w.offset()); w.write(bytes)?; w.write_u8(0)?; } Ok($offsets { base_id: self.base_id, offsets, }) } } }; } define_id!(StringId, "An identifier for a string in a `StringTable`."); define_string_table!( StringTable, StringId, DebugStr, DebugStrOffsets, "A table of strings that will be stored in a `.debug_str` section." ); define_section!(DebugStr, DebugStrOffset, "A writable `.debug_str` section."); define_offsets!( DebugStrOffsets: StringId => DebugStrOffset, "The section offsets of all strings within a `.debug_str` section." ); define_id!( LineStringId, "An identifier for a string in a `LineStringTable`." ); define_string_table!( LineStringTable, LineStringId, DebugLineStr, DebugLineStrOffsets, "A table of strings that will be stored in a `.debug_line_str` section." ); define_section!( DebugLineStr, DebugLineStrOffset, "A writable `.debug_line_str` section." ); define_offsets!( DebugLineStrOffsets: LineStringId => DebugLineStrOffset, "The section offsets of all strings within a `.debug_line_str` section." ); #[cfg(test)] mod tests { use super::*; use crate::read; use crate::write::EndianVec; use crate::LittleEndian; #[test] fn test_string_table() { let mut strings = StringTable::default(); assert_eq!(strings.count(), 0); let id1 = strings.add(&b"one"[..]); let id2 = strings.add(&b"two"[..]); assert_eq!(strings.add(&b"one"[..]), id1); assert_eq!(strings.add(&b"two"[..]), id2); assert_eq!(strings.get(id1), &b"one"[..]); assert_eq!(strings.get(id2), &b"two"[..]); assert_eq!(strings.count(), 2); let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); let offsets = strings.write(&mut debug_str).unwrap(); assert_eq!(debug_str.slice(), b"one\0two\0"); assert_eq!(offsets.get(id1), DebugStrOffset(0)); assert_eq!(offsets.get(id2), DebugStrOffset(4)); assert_eq!(offsets.count(), 2); } #[test] fn test_string_table_read() { let mut strings = StringTable::default(); let id1 = strings.add(&b"one"[..]); let id2 = strings.add(&b"two"[..]); let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); let offsets = strings.write(&mut debug_str).unwrap(); let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); let str1 = read_debug_str.get_str(offsets.get(id1)).unwrap(); let str2 = read_debug_str.get_str(offsets.get(id2)).unwrap(); assert_eq!(str1.slice(), &b"one"[..]); assert_eq!(str2.slice(), &b"two"[..]); } } gimli-0.19.0/src/write/unit.rs010066400017500001750000003244141351057326000144050ustar0000000000000000use crate::vec::Vec; use std::ops::{Deref, DerefMut}; use std::{slice, usize}; use crate::common::{ DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId, UnitSectionOffset, }; use crate::constants; use crate::write::{ Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets, DebugStrOffsets, Error, FileId, LineProgram, LineStringId, LocationList, LocationListId, LocationListOffsets, LocationListTable, RangeList, RangeListId, RangeListOffsets, RangeListTable, Result, Section, Sections, StringId, Writer, }; define_id!(UnitId, "An identifier for a unit in a `UnitTable`."); define_id!(UnitEntryId, "An identifier for an entry in a `Unit`."); /// The bytecode for a DWARF expression or location description. // TODO: this needs to be a `Vec` so we can handle relocations #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Expression(pub Vec); /// A table of units that will be stored in the `.debug_info` section. #[derive(Debug, Default)] pub struct UnitTable { base_id: BaseId, units: Vec, } impl UnitTable { /// Create a new unit and add it to the table. /// /// `address_size` must be in bytes. /// /// Returns the `UnitId` of the new unit. #[inline] pub fn add(&mut self, unit: Unit) -> UnitId { let id = UnitId::new(self.base_id, self.units.len()); self.units.push(unit); id } /// Return the number of units. #[inline] pub fn count(&self) -> usize { self.units.len() } /// Return the id of a unit. /// /// # Panics /// /// Panics if `index >= self.count()`. #[inline] pub fn id(&self, index: usize) -> UnitId { assert!(index < self.count()); UnitId::new(self.base_id, index) } /// Get a reference to a unit. /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get(&self, id: UnitId) -> &Unit { debug_assert_eq!(self.base_id, id.base_id); &self.units[id.index] } /// Get a mutable reference to a unit. /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get_mut(&mut self, id: UnitId) -> &mut Unit { debug_assert_eq!(self.base_id, id.base_id); &mut self.units[id.index] } /// Write the units to the given sections. /// /// `strings` must contain the `.debug_str` offsets of the corresponding /// `StringTable`. pub fn write( &mut self, sections: &mut Sections, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, ) -> Result { let mut debug_info_refs = Vec::new(); let mut offsets = DebugInfoOffsets { base_id: self.base_id, units: Vec::new(), }; for unit in &mut self.units { // TODO: maybe share abbreviation tables let abbrev_offset = sections.debug_abbrev.offset(); let mut abbrevs = AbbreviationTable::default(); offsets.units.push(unit.write( sections, abbrev_offset, &mut abbrevs, line_strings, strings, &mut debug_info_refs, )?); abbrevs.write(&mut sections.debug_abbrev)?; } for (offset, (unit, entry), size) in debug_info_refs { let entry_offset = offsets.entry(unit, entry).0; debug_assert_ne!(entry_offset, 0); sections.debug_info.write_offset_at( offset.0, entry_offset, SectionId::DebugInfo, size, )?; } Ok(offsets) } } /// A unit's debugging information. #[derive(Debug)] pub struct Unit { base_id: BaseId, /// The encoding parameters for this unit. encoding: Encoding, /// The line number program for this unit. pub line_program: LineProgram, /// A table of range lists used by this unit. pub ranges: RangeListTable, /// A table of location lists used by this unit. pub locations: LocationListTable, /// All entries in this unit. The order is unrelated to the tree order. // Requirements: // - entries form a tree // - entries can be added in any order // - entries have a fixed id // - able to quickly lookup an entry from its id // Limitations of current implemention: // - mutable iteration of children is messy due to borrow checker entries: Vec, /// The index of the root entry in entries. root: UnitEntryId, } impl Unit { /// Create a new `Unit`. pub fn new(encoding: Encoding, line_program: LineProgram) -> Self { let base_id = BaseId::default(); let ranges = RangeListTable::default(); let locations = LocationListTable::default(); let mut entries = Vec::new(); let root = DebuggingInformationEntry::new( base_id, &mut entries, None, constants::DW_TAG_compile_unit, ); Unit { base_id, encoding, line_program, ranges, locations, entries, root, } } /// Return the encoding parameters for this unit. #[inline] pub fn encoding(&self) -> Encoding { self.encoding } /// Return the DWARF version for this unit. #[inline] pub fn version(&self) -> u16 { self.encoding.version } /// Return the address size in bytes for this unit. #[inline] pub fn address_size(&self) -> u8 { self.encoding.address_size } /// Return the DWARF format for this unit. #[inline] pub fn format(&self) -> Format { self.encoding.format } /// Return the number of `DebuggingInformationEntry`s created for this unit. /// /// This includes entries that no longer have a parent. #[inline] pub fn count(&self) -> usize { self.entries.len() } /// Return the id of the root entry. #[inline] pub fn root(&self) -> UnitEntryId { self.root } /// Add a new `DebuggingInformationEntry` to this unit and return its id. /// /// The `parent` must be within the same unit. /// /// # Panics /// /// Panics if `parent` is invalid. #[inline] pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId { debug_assert_eq!(self.base_id, parent.base_id); DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag) } /// Get a reference to an entry. /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry { debug_assert_eq!(self.base_id, id.base_id); &self.entries[id.index] } /// Get a mutable reference to an entry. /// /// # Panics /// /// Panics if `id` is invalid. #[inline] pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry { debug_assert_eq!(self.base_id, id.base_id); &mut self.entries[id.index] } /// Return true if `self.line_program` is used by a DIE. fn line_program_in_use(&self) -> bool { if self.line_program.is_none() { return false; } if !self.line_program.is_empty() { return true; } for entry in &self.entries { for attr in &entry.attrs { if let AttributeValue::FileIndex(Some(_)) = attr.value { return true; } } } false } /// Write the unit to the given sections. pub(crate) fn write( &mut self, sections: &mut Sections, abbrev_offset: DebugAbbrevOffset, abbrevs: &mut AbbreviationTable, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, debug_info_refs: &mut Vec<(DebugInfoOffset, (UnitId, UnitEntryId), u8)>, ) -> Result { let line_program = if self.line_program_in_use() { self.entries[self.root.index] .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef); Some(self.line_program.write( &mut sections.debug_line, self.encoding, line_strings, strings, )?) } else { self.entries[self.root.index].delete(constants::DW_AT_stmt_list); None }; let range_lists = self.ranges.write(sections, self.encoding)?; let loc_lists = self.locations.write(sections, self.encoding)?; // TODO: use .debug_types for type units in DWARF v4. let w = &mut sections.debug_info; let mut offsets = UnitOffsets { base_id: self.base_id, unit: w.offset(), // Entries can be written in any order, so create the complete vec now. entries: vec![DebugInfoOffset(0); self.entries.len()], }; let mut unit_refs = Vec::new(); let length_offset = w.write_initial_length(self.format())?; let length_base = w.len(); w.write_u16(self.version())?; if 2 <= self.version() && self.version() <= 4 { w.write_offset( abbrev_offset.0, SectionId::DebugAbbrev, self.format().word_size(), )?; w.write_u8(self.address_size())?; } else if self.version() == 5 { w.write_u8(constants::DW_UT_compile.0)?; w.write_u8(self.address_size())?; w.write_offset( abbrev_offset.0, SectionId::DebugAbbrev, self.format().word_size(), )?; } else { return Err(Error::UnsupportedVersion(self.version())); } self.entries[self.root.index].write( w, self, &mut offsets, abbrevs, line_program, line_strings, strings, &range_lists, &loc_lists, &mut unit_refs, debug_info_refs, )?; let length = (w.len() - length_base) as u64; w.write_initial_length_at(length_offset, length, self.format())?; for (offset, entry) in unit_refs { let entry_offset = offsets.entry(entry).0; debug_assert_ne!(entry_offset, 0); // This does not need relocation. w.write_udata_at( offset.0, (entry_offset - offsets.unit.0) as u64, self.format().word_size(), )?; } Ok(offsets) } } /// A Debugging Information Entry (DIE). /// /// DIEs have a set of attributes and optionally have children DIEs as well. /// /// DIEs form a tree without any cycles. This is enforced by specifying the /// parent when creating a DIE, and disallowing changes of parent. #[derive(Debug)] pub struct DebuggingInformationEntry { id: UnitEntryId, parent: Option, tag: constants::DwTag, /// Whether to emit `DW_AT_sibling`. sibling: bool, attrs: Vec, children: Vec, } impl DebuggingInformationEntry { /// Create a new `DebuggingInformationEntry`. /// /// # Panics /// /// Panics if `parent` is invalid. #[allow(clippy::new_ret_no_self)] fn new( base_id: BaseId, entries: &mut Vec, parent: Option, tag: constants::DwTag, ) -> UnitEntryId { let id = UnitEntryId::new(base_id, entries.len()); entries.push(DebuggingInformationEntry { id, parent, tag, sibling: false, attrs: Vec::new(), children: Vec::new(), }); if let Some(parent) = parent { debug_assert_eq!(base_id, parent.base_id); assert_ne!(parent, id); entries[parent.index].children.push(id); } id } /// Return the id of this entry. #[inline] pub fn id(&self) -> UnitEntryId { self.id } /// Return the parent of this entry. #[inline] pub fn parent(&self) -> Option { self.parent } /// Return the tag of this entry. #[inline] pub fn tag(&self) -> constants::DwTag { self.tag } /// Return `true` if a `DW_AT_sibling` attribute will be emitted. #[inline] pub fn sibling(&self) -> bool { self.sibling } /// Set whether a `DW_AT_sibling` attribute will be emitted. /// /// The attribute will only be emitted if the DIE has children. #[inline] pub fn set_sibling(&mut self, sibling: bool) { self.sibling = sibling; } /// Iterate over the attributes of this entry. #[inline] pub fn attrs(&self) -> slice::Iter { self.attrs.iter() } /// Iterate over the attributes of this entry for modification. #[inline] pub fn attrs_mut(&mut self) -> slice::IterMut { self.attrs.iter_mut() } /// Get an attribute. pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> { self.attrs .iter() .find(|attr| attr.name == name) .map(|attr| &attr.value) } /// Get an attribute for modification. pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> { self.attrs .iter_mut() .find(|attr| attr.name == name) .map(|attr| &mut attr.value) } /// Set an attribute. /// /// Replaces any existing attribute with the same name. /// /// # Panics /// /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead. pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) { assert_ne!(name, constants::DW_AT_sibling); if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) { attr.value = value; return; } self.attrs.push(Attribute { name, value }); } /// Delete an attribute. /// /// Replaces any existing attribute with the same name. pub fn delete(&mut self, name: constants::DwAt) { self.attrs.retain(|x| x.name != name); } /// Iterate over the children of this entry. /// /// Note: use `Unit::add` to add a new child to this entry. #[inline] pub fn children(&self) -> slice::Iter { self.children.iter() } /// Return the type abbreviation for this DIE. fn abbreviation(&self, encoding: Encoding) -> Result { let mut attrs = Vec::new(); if self.sibling && !self.children.is_empty() { let form = match encoding.format { Format::Dwarf32 => constants::DW_FORM_ref4, Format::Dwarf64 => constants::DW_FORM_ref8, }; attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form)); } for attr in &self.attrs { attrs.push(attr.specification(encoding)?); } Ok(Abbreviation::new( self.tag, !self.children.is_empty(), attrs, )) } /// Write the entry to the given sections. #[allow(clippy::too_many_arguments)] fn write( &self, w: &mut DebugInfo, unit: &Unit, offsets: &mut UnitOffsets, abbrevs: &mut AbbreviationTable, line_program: Option, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, range_lists: &RangeListOffsets, loc_lists: &LocationListOffsets, unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, debug_info_refs: &mut Vec<(DebugInfoOffset, (UnitId, UnitEntryId), u8)>, ) -> Result<()> { offsets.entries[self.id.index] = w.offset(); let code = abbrevs.add(self.abbreviation(unit.encoding())?); w.write_uleb128(code)?; let sibling_offset = if self.sibling && !self.children.is_empty() { let offset = w.offset(); w.write_udata(0, unit.format().word_size())?; Some(offset) } else { None }; for attr in &self.attrs { attr.write( w, unit, line_program, line_strings, strings, range_lists, loc_lists, unit_refs, debug_info_refs, )?; } if !self.children.is_empty() { for child in &self.children { unit.entries[child.index].write( w, unit, offsets, abbrevs, line_program, line_strings, strings, range_lists, loc_lists, unit_refs, debug_info_refs, )?; } // Null child w.write_u8(0)?; } if let Some(offset) = sibling_offset { let next_offset = (w.offset().0 - offsets.unit.0) as u64; // This does not need relocation. w.write_udata_at(offset.0, next_offset, unit.format().word_size())?; } Ok(()) } } /// An attribute in a `DebuggingInformationEntry`, consisting of a name and /// associated value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Attribute { name: constants::DwAt, value: AttributeValue, } impl Attribute { /// Get the name of this attribute. #[inline] pub fn name(&self) -> constants::DwAt { self.name } /// Get the value of this attribute. #[inline] pub fn get(&self) -> &AttributeValue { &self.value } /// Set the value of this attribute. #[inline] pub fn set(&mut self, value: AttributeValue) { self.value = value; } /// Return the type specification for this attribute. fn specification(&self, encoding: Encoding) -> Result { Ok(AttributeSpecification::new( self.name, self.value.form(encoding)?, )) } /// Write the attribute to the given sections. #[inline] #[allow(clippy::too_many_arguments)] fn write( &self, w: &mut DebugInfo, unit: &Unit, line_program: Option, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, range_lists: &RangeListOffsets, loc_lists: &LocationListOffsets, unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, debug_info_refs: &mut Vec<(DebugInfoOffset, (UnitId, UnitEntryId), u8)>, ) -> Result<()> { self.value.write( w, unit, line_program, line_strings, strings, range_lists, loc_lists, unit_refs, debug_info_refs, ) } } /// The value of an attribute in a `DebuggingInformationEntry`. #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttributeValue { /// "Refers to some location in the address space of the described program." Address(Address), /// A slice of an arbitrary number of bytes. Block(Vec), /// A one byte constant data value. How to interpret the byte depends on context. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data1(u8), /// A two byte constant data value. How to interpret the bytes depends on context. /// /// This value will be converted to the target endian before writing. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data2(u16), /// A four byte constant data value. How to interpret the bytes depends on context. /// /// This value will be converted to the target endian before writing. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data4(u32), /// An eight byte constant data value. How to interpret the bytes depends on context. /// /// This value will be converted to the target endian before writing. /// /// From section 7 of the standard: "Depending on context, it may be a /// signed integer, an unsigned integer, a floating-point constant, or /// anything else." Data8(u64), /// A signed integer constant. Sdata(i64), /// An unsigned integer constant. Udata(u64), /// "The information bytes contain a DWARF expression (see Section 2.5) or /// location description (see Section 2.6)." Exprloc(Expression), /// A boolean that indicates presence or absence of the attribute. Flag(bool), /// An attribute that is always present. FlagPresent, /// A reference to a `DebuggingInformationEntry` in the this unit. ThisUnitEntryRef(UnitEntryId), /// A reference to a `DebuggingInformationEntry` in a potentially different unit. AnyUnitEntryRef((UnitId, UnitEntryId)), /// A reference to the current `.debug_info` section, but possibly a different /// unit from the current one. /// /// This is an internal attribute that must only be used when converting an /// existing `.debug_info` section. #[doc(hidden)] UnitSectionRef(UnitSectionOffset), /// An offset into the `.debug_info` section of the supplementary object file. /// /// It is the user's responsibility to ensure the offset is valid. /// This variant will be removed from the API once support for writing /// supplementary object files is implemented. DebugInfoRefSup(DebugInfoOffset), /// A reference to a line number program. LineProgramRef, /// A reference to a location list. LocationListRef(LocationListId), /// An offset into the `.debug_macinfo` section. /// /// It is the user's responsibility to ensure the offset is valid. /// This variant will be removed from the API once support for writing /// `.debug_macinfo` sections is implemented. DebugMacinfoRef(DebugMacinfoOffset), /// A reference to a range list. RangeListRef(RangeListId), /// A type signature. /// /// It is the user's responsibility to ensure the signature is valid. /// This variant will be removed from the API once support for writing /// `.debug_types` sections is implemented. DebugTypesRef(DebugTypeSignature), /// A reference to a string in the `.debug_str` section. StringRef(StringId), /// An offset into the `.debug_str` section of the supplementary object file. /// /// It is the user's responsibility to ensure the offset is valid. /// This variant will be removed from the API once support for writing /// supplementary object files is implemented. DebugStrRefSup(DebugStrOffset), /// A reference to a string in the `.debug_line_str` section. LineStringRef(LineStringId), /// A slice of bytes representing a string. Must not include null bytes. /// Not guaranteed to be UTF-8 or anything like that. String(Vec), /// The value of a `DW_AT_encoding` attribute. Encoding(constants::DwAte), /// The value of a `DW_AT_decimal_sign` attribute. DecimalSign(constants::DwDs), /// The value of a `DW_AT_endianity` attribute. Endianity(constants::DwEnd), /// The value of a `DW_AT_accessibility` attribute. Accessibility(constants::DwAccess), /// The value of a `DW_AT_visibility` attribute. Visibility(constants::DwVis), /// The value of a `DW_AT_virtuality` attribute. Virtuality(constants::DwVirtuality), /// The value of a `DW_AT_language` attribute. Language(constants::DwLang), /// The value of a `DW_AT_address_class` attribute. AddressClass(constants::DwAddr), /// The value of a `DW_AT_identifier_case` attribute. IdentifierCase(constants::DwId), /// The value of a `DW_AT_calling_convention` attribute. CallingConvention(constants::DwCc), /// The value of a `DW_AT_inline` attribute. Inline(constants::DwInl), /// The value of a `DW_AT_ordering` attribute. Ordering(constants::DwOrd), /// An index into the filename entries from the line number information /// table for the unit containing this value. FileIndex(Option), } impl AttributeValue { /// Return the form that will be used to encode this value. pub fn form(&self, encoding: Encoding) -> Result { // TODO: missing forms: // - DW_FORM_indirect // - DW_FORM_implicit_const // - FW_FORM_block1/block2/block4 // - DW_FORM_str/strx1/strx2/strx3/strx4 // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4 // - DW_FORM_data16 // - DW_FORM_line_strp // - DW_FORM_loclistx // - DW_FORM_rnglistx let form = match *self { AttributeValue::Address(_) => constants::DW_FORM_addr, AttributeValue::Block(_) => constants::DW_FORM_block, AttributeValue::Data1(_) => constants::DW_FORM_data1, AttributeValue::Data2(_) => constants::DW_FORM_data2, AttributeValue::Data4(_) => constants::DW_FORM_data4, AttributeValue::Data8(_) => constants::DW_FORM_data8, AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc, AttributeValue::Flag(_) => constants::DW_FORM_flag, AttributeValue::FlagPresent => constants::DW_FORM_flag_present, AttributeValue::ThisUnitEntryRef(_) => { // Using a fixed size format lets us write a placeholder before we know // the value. match encoding.format { Format::Dwarf32 => constants::DW_FORM_ref4, Format::Dwarf64 => constants::DW_FORM_ref8, } } AttributeValue::AnyUnitEntryRef(_) => constants::DW_FORM_ref_addr, AttributeValue::DebugInfoRefSup(_) => { // TODO: should this depend on the size of supplementary section? match encoding.format { Format::Dwarf32 => constants::DW_FORM_ref_sup4, Format::Dwarf64 => constants::DW_FORM_ref_sup8, } } AttributeValue::LineProgramRef | AttributeValue::LocationListRef(_) | AttributeValue::DebugMacinfoRef(_) | AttributeValue::RangeListRef(_) => { if encoding.version == 2 || encoding.version == 3 { match encoding.format { Format::Dwarf32 => constants::DW_FORM_data4, Format::Dwarf64 => constants::DW_FORM_data8, } } else { constants::DW_FORM_sec_offset } } AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8, AttributeValue::StringRef(_) => constants::DW_FORM_strp, AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup, AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp, AttributeValue::String(_) => constants::DW_FORM_string, AttributeValue::Encoding(_) | AttributeValue::DecimalSign(_) | AttributeValue::Endianity(_) | AttributeValue::Accessibility(_) | AttributeValue::Visibility(_) | AttributeValue::Virtuality(_) | AttributeValue::Language(_) | AttributeValue::AddressClass(_) | AttributeValue::IdentifierCase(_) | AttributeValue::CallingConvention(_) | AttributeValue::Inline(_) | AttributeValue::Ordering(_) | AttributeValue::FileIndex(_) | AttributeValue::Udata(_) => constants::DW_FORM_udata, AttributeValue::Sdata(_) => constants::DW_FORM_sdata, AttributeValue::UnitSectionRef(_) => { return Err(Error::InvalidAttributeValue); } }; Ok(form) } /// Write the attribute value to the given sections. #[allow(clippy::cyclomatic_complexity, clippy::too_many_arguments)] fn write( &self, w: &mut DebugInfo, unit: &Unit, line_program: Option, line_strings: &DebugLineStrOffsets, strings: &DebugStrOffsets, range_lists: &RangeListOffsets, loc_lists: &LocationListOffsets, unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>, debug_info_refs: &mut Vec<(DebugInfoOffset, (UnitId, UnitEntryId), u8)>, ) -> Result<()> { macro_rules! debug_assert_form { ($form:expr) => { debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form) }; } match *self { AttributeValue::Address(val) => { debug_assert_form!(constants::DW_FORM_addr); w.write_address(val, unit.address_size())?; } AttributeValue::Block(ref val) => { debug_assert_form!(constants::DW_FORM_block); w.write_uleb128(val.len() as u64)?; w.write(&val)?; } AttributeValue::Data1(val) => { debug_assert_form!(constants::DW_FORM_data1); w.write_u8(val)?; } AttributeValue::Data2(val) => { debug_assert_form!(constants::DW_FORM_data2); w.write_u16(val)?; } AttributeValue::Data4(val) => { debug_assert_form!(constants::DW_FORM_data4); w.write_u32(val)?; } AttributeValue::Data8(val) => { debug_assert_form!(constants::DW_FORM_data8); w.write_u64(val)?; } AttributeValue::Sdata(val) => { debug_assert_form!(constants::DW_FORM_sdata); w.write_sleb128(val)?; } AttributeValue::Udata(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(val)?; } AttributeValue::Exprloc(ref val) => { debug_assert_form!(constants::DW_FORM_exprloc); w.write_uleb128(val.0.len() as u64)?; w.write(&val.0)?; } AttributeValue::Flag(val) => { debug_assert_form!(constants::DW_FORM_flag); w.write_u8(val as u8)?; } AttributeValue::FlagPresent => { debug_assert_form!(constants::DW_FORM_flag_present); } AttributeValue::ThisUnitEntryRef(id) => { match unit.format() { Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4), Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8), } unit_refs.push((w.offset(), id)); w.write_udata(0, unit.format().word_size())?; } AttributeValue::AnyUnitEntryRef(id) => { debug_assert_form!(constants::DW_FORM_ref_addr); let size = if unit.version() == 2 { unit.address_size() } else { unit.format().word_size() }; debug_info_refs.push((w.offset(), id, size)); w.write_udata(0, size)?; } AttributeValue::DebugInfoRefSup(val) => { match unit.format() { Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4), Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8), } w.write_udata(val.0 as u64, unit.format().word_size())?; } AttributeValue::LineProgramRef => { if unit.version() >= 4 { debug_assert_form!(constants::DW_FORM_sec_offset); } match line_program { Some(line_program) => { w.write_offset( line_program.0, SectionId::DebugLine, unit.format().word_size(), )?; } None => return Err(Error::InvalidAttributeValue), } } AttributeValue::LocationListRef(val) => { if unit.version() >= 4 { debug_assert_form!(constants::DW_FORM_sec_offset); } let section = if unit.version() <= 4 { SectionId::DebugLoc } else { SectionId::DebugLocLists }; w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?; } AttributeValue::DebugMacinfoRef(val) => { if unit.version() >= 4 { debug_assert_form!(constants::DW_FORM_sec_offset); } w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?; } AttributeValue::RangeListRef(val) => { if unit.version() >= 4 { debug_assert_form!(constants::DW_FORM_sec_offset); } let section = if unit.version() <= 4 { SectionId::DebugRanges } else { SectionId::DebugRngLists }; w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?; } AttributeValue::DebugTypesRef(val) => { debug_assert_form!(constants::DW_FORM_ref_sig8); w.write_u64(val.0)?; } AttributeValue::StringRef(val) => { debug_assert_form!(constants::DW_FORM_strp); w.write_offset( strings.get(val).0, SectionId::DebugStr, unit.format().word_size(), )?; } AttributeValue::DebugStrRefSup(val) => { debug_assert_form!(constants::DW_FORM_strp_sup); w.write_udata(val.0 as u64, unit.format().word_size())?; } AttributeValue::LineStringRef(val) => { debug_assert_form!(constants::DW_FORM_line_strp); w.write_offset( line_strings.get(val).0, SectionId::DebugLineStr, unit.format().word_size(), )?; } AttributeValue::String(ref val) => { debug_assert_form!(constants::DW_FORM_string); w.write(&val)?; w.write_u8(0)?; } AttributeValue::Encoding(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::DecimalSign(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Endianity(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Accessibility(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Visibility(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Virtuality(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Language(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::AddressClass(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(val.0)?; } AttributeValue::IdentifierCase(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::CallingConvention(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Inline(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::Ordering(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(u64::from(val.0))?; } AttributeValue::FileIndex(val) => { debug_assert_form!(constants::DW_FORM_udata); w.write_uleb128(val.map(FileId::raw).unwrap_or(0))?; } AttributeValue::UnitSectionRef(_) => { return Err(Error::InvalidAttributeValue); } } Ok(()) } } define_section!( DebugInfo, DebugInfoOffset, "A writable `.debug_info` section." ); /// The section offsets of all elements within a `.debug_info` section. #[derive(Debug, Default)] pub struct DebugInfoOffsets { base_id: BaseId, units: Vec, } impl DebugInfoOffsets { /// Get the `.debug_info` section offset for the given unit. #[inline] pub fn unit(&self, unit: UnitId) -> DebugInfoOffset { debug_assert_eq!(self.base_id, unit.base_id); self.units[unit.index].unit } /// Get the `.debug_info` section offset for the given entry. #[inline] pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset { debug_assert_eq!(self.base_id, unit.base_id); self.units[unit.index].entry(entry) } } /// The section offsets of all elements of a unit within a `.debug_info` section. #[derive(Debug)] pub(crate) struct UnitOffsets { base_id: BaseId, unit: DebugInfoOffset, entries: Vec, } impl UnitOffsets { #[inline] fn entry(&self, entry: UnitEntryId) -> DebugInfoOffset { debug_assert_eq!(self.base_id, entry.base_id); self.entries[entry.index] } } #[cfg(feature = "read")] pub(crate) mod convert { use super::*; use crate::collections::HashMap; use crate::read::{self, Reader}; use crate::write::{self, ConvertError, ConvertResult}; pub(crate) struct ConvertUnitContext<'a, R: Reader> { pub dwarf: &'a read::Dwarf, pub unit: &'a read::Unit, pub line_strings: &'a mut write::LineStringTable, pub strings: &'a mut write::StringTable, pub ranges: &'a mut write::RangeListTable, pub locations: &'a mut write::LocationListTable, pub convert_address: &'a dyn Fn(u64) -> Option
, pub base_address: Address, pub line_program_offset: Option, pub line_program_files: Vec, } impl UnitTable { /// Create a unit table by reading the data in the given sections. /// /// This also updates the given tables with the values that are referenced from /// attributes in this section. /// /// `convert_address` is a function to convert read addresses into the `Address` /// type. For non-relocatable addresses, this function may simply return /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. pub fn from>( dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult { let base_id = BaseId::default(); let mut units = Vec::new(); let mut unit_entry_offsets = HashMap::new(); let mut from_units = dwarf.units(); while let Some(from_unit) = from_units.next()? { let unit_id = UnitId::new(base_id, units.len()); units.push(Unit::from( from_unit, unit_id, &mut unit_entry_offsets, dwarf, line_strings, strings, convert_address, )?); } // Convert all DebugInfoOffset to UnitEntryId for (unit_id, unit) in units.iter_mut().enumerate() { let unit_id = UnitId::new(base_id, unit_id); for entry in &mut unit.entries { for attr in &mut entry.attrs { let id = match attr.value { AttributeValue::UnitSectionRef(ref offset) => { match unit_entry_offsets.get(offset) { Some(id) => Some(*id), None => return Err(ConvertError::InvalidDebugInfoOffset), } } _ => None, }; if let Some(id) = id { if id.0 == unit_id { attr.value = AttributeValue::ThisUnitEntryRef(id.1) } else { attr.value = AttributeValue::AnyUnitEntryRef(id) } } } } } Ok(UnitTable { base_id, units }) } } impl Unit { /// Create a unit by reading the data in the given sections. #[allow(clippy::too_many_arguments)] pub(crate) fn from>( from_header: read::CompilationUnitHeader, unit_id: UnitId, unit_entry_offsets: &mut HashMap, dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult { let base_id = BaseId::default(); let from_unit = dwarf.unit(from_header)?; let encoding = from_unit.encoding(); let base_address = convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?; let (line_program_offset, line_program, line_program_files) = match from_unit.line_program { Some(ref from_program) => { let from_program = from_program.clone(); let line_program_offset = from_program.header().offset(); let (line_program, line_program_files) = LineProgram::from( from_program, dwarf, line_strings, strings, convert_address, )?; (Some(line_program_offset), line_program, line_program_files) } None => (None, LineProgram::none(), Vec::new()), }; let mut ranges = RangeListTable::default(); let mut locations = LocationListTable::default(); let mut entries = Vec::new(); let root = { let mut context = ConvertUnitContext { dwarf, unit: &from_unit, line_strings, strings, ranges: &mut ranges, locations: &mut locations, convert_address, base_address, line_program_offset, line_program_files, }; let mut from_tree = from_unit.entries_tree(None)?; let from_root = from_tree.root()?; DebuggingInformationEntry::from( &mut context, from_root, base_id, &mut entries, None, unit_id, unit_entry_offsets, )? }; Ok(Unit { base_id, encoding, line_program, ranges, locations, entries, root, }) } } impl DebuggingInformationEntry { /// Create an entry by reading the data in the given sections. fn from>( context: &mut ConvertUnitContext, from: read::EntriesTreeNode, base_id: BaseId, entries: &mut Vec, parent: Option, unit_id: UnitId, unit_entry_offsets: &mut HashMap, ) -> ConvertResult { let id = { let from = from.entry(); let entry = DebuggingInformationEntry::new(base_id, entries, parent, from.tag()); let entry = &mut entries[entry.index]; let offset = from.offset().to_unit_section_offset(context.unit); unit_entry_offsets.insert(offset, (unit_id, entry.id)); let mut from_attrs = from.attrs(); while let Some(from_attr) = from_attrs.next()? { if from_attr.name() == constants::DW_AT_sibling { // This may point to a null entry, so we have to treat it differently. entry.set_sibling(true); } else if let Some(attr) = Attribute::from(context, &from_attr)? { entry.set(attr.name, attr.value); } } entry.id }; let mut from_children = from.children(); while let Some(from_child) = from_children.next()? { DebuggingInformationEntry::from( context, from_child, base_id, entries, Some(id), unit_id, unit_entry_offsets, )?; } Ok(id) } } impl Attribute { /// Create an attribute by reading the data in the given sections. pub(crate) fn from>( context: &mut ConvertUnitContext, from: &read::Attribute, ) -> ConvertResult> { let value = AttributeValue::from(context, from.value())?; Ok(value.map(|value| Attribute { name: from.name(), value, })) } } impl AttributeValue { /// Create an attribute value by reading the data in the given sections. pub(crate) fn from>( context: &mut ConvertUnitContext, from: read::AttributeValue, ) -> ConvertResult> { let to = match from { read::AttributeValue::Addr(val) => match (context.convert_address)(val) { Some(val) => AttributeValue::Address(val), None => return Err(ConvertError::InvalidAddress), }, read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()), read::AttributeValue::Data1(val) => AttributeValue::Data1(val), read::AttributeValue::Data2(val) => AttributeValue::Data2(val), read::AttributeValue::Data4(val) => AttributeValue::Data4(val), read::AttributeValue::Data8(val) => AttributeValue::Data8(val), read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val), read::AttributeValue::Udata(val) => AttributeValue::Udata(val), // TODO: addresses and offsets in expressions need special handling. read::AttributeValue::Exprloc(read::Expression(val)) => { AttributeValue::Exprloc(Expression(val.to_slice()?.into())) } // TODO: it would be nice to preserve the flag form. read::AttributeValue::Flag(val) => AttributeValue::Flag(val), read::AttributeValue::DebugAddrBase(_base) => { // We convert all address indices to addresses, // so this is unneeded. return Ok(None); } read::AttributeValue::DebugAddrIndex(index) => { let val = context.dwarf.address(context.unit, index)?; match (context.convert_address)(val) { Some(val) => AttributeValue::Address(val), None => return Err(ConvertError::InvalidAddress), } } read::AttributeValue::UnitRef(val) => { AttributeValue::UnitSectionRef(val.to_unit_section_offset(context.unit)) } read::AttributeValue::DebugInfoRef(val) => { AttributeValue::UnitSectionRef(UnitSectionOffset::DebugInfoOffset(val)) } read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val), read::AttributeValue::DebugLineRef(val) => { // There should only be the line program in the CU DIE which we've already // converted, so check if it matches that. if Some(val) == context.line_program_offset { AttributeValue::LineProgramRef } else { return Err(ConvertError::InvalidLineRef); } } read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val), read::AttributeValue::LocationListsRef(val) => { let iter = context .dwarf .locations .raw_locations(val, context.unit.encoding())?; let loc_list = LocationList::from(iter, context)?; let loc_id = context.locations.add(loc_list); AttributeValue::LocationListRef(loc_id) } read::AttributeValue::DebugLocListsBase(_base) => { // We convert all location list indices to offsets, // so this is unneeded. return Ok(None); } read::AttributeValue::DebugLocListsIndex(index) => { let offset = context.dwarf.locations_offset(context.unit, index)?; let iter = context .dwarf .locations .raw_locations(offset, context.unit.encoding())?; let loc_list = LocationList::from(iter, context)?; let loc_id = context.locations.add(loc_list); AttributeValue::LocationListRef(loc_id) } read::AttributeValue::RangeListsRef(val) => { let iter = context .dwarf .ranges .raw_ranges(val, context.unit.encoding())?; let range_list = RangeList::from(iter, context)?; let range_id = context.ranges.add(range_list); AttributeValue::RangeListRef(range_id) } read::AttributeValue::DebugRngListsBase(_base) => { // We convert all range list indices to offsets, // so this is unneeded. return Ok(None); } read::AttributeValue::DebugRngListsIndex(index) => { let offset = context.dwarf.ranges_offset(context.unit, index)?; let iter = context .dwarf .ranges .raw_ranges(offset, context.unit.encoding())?; let range_list = RangeList::from(iter, context)?; let range_id = context.ranges.add(range_list); AttributeValue::RangeListRef(range_id) } read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val), read::AttributeValue::DebugStrRef(offset) => { let r = context.dwarf.string(offset)?; let id = context.strings.add(r.to_slice()?); AttributeValue::StringRef(id) } read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val), read::AttributeValue::DebugStrOffsetsBase(_base) => { // We convert all string offsets to `.debug_str` references, // so this is unneeded. return Ok(None); } read::AttributeValue::DebugStrOffsetsIndex(index) => { let offset = context.dwarf.string_offset(context.unit, index)?; let r = context.dwarf.string(offset)?; let id = context.strings.add(r.to_slice()?); AttributeValue::StringRef(id) } read::AttributeValue::DebugLineStrRef(offset) => { let r = context.dwarf.line_string(offset)?; let id = context.line_strings.add(r.to_slice()?); AttributeValue::LineStringRef(id) } read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()), read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val), read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val), read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val), read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val), read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val), read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val), read::AttributeValue::Language(val) => AttributeValue::Language(val), read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val), read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val), read::AttributeValue::CallingConvention(val) => { AttributeValue::CallingConvention(val) } read::AttributeValue::Inline(val) => AttributeValue::Inline(val), read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val), read::AttributeValue::FileIndex(val) => { if val == 0 { // 0 means not specified, even for version 5. AttributeValue::FileIndex(None) } else { match context.line_program_files.get(val as usize) { Some(id) => AttributeValue::FileIndex(Some(*id)), None => return Err(ConvertError::InvalidFileIndex), } } } // Should always be a more specific section reference. read::AttributeValue::SecOffset(_) => { return Err(ConvertError::InvalidAttributeValue); } }; Ok(Some(to)) } } } #[cfg(test)] mod tests { use super::*; use crate::common::{ DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding, }; use crate::constants; use crate::read; use crate::write::{ DebugLine, DebugLineStr, DebugStr, EndianVec, LineString, LineStringTable, Location, LocationListTable, Range, RangeListOffsets, RangeListTable, StringTable, }; use crate::LittleEndian; use std::mem; #[test] #[allow(clippy::cyclomatic_complexity)] fn test_unit_table() { let mut strings = StringTable::default(); let mut units = UnitTable::default(); let unit_id1 = units.add(Unit::new( Encoding { version: 4, address_size: 8, format: Format::Dwarf32, }, LineProgram::none(), )); let unit2 = units.add(Unit::new( Encoding { version: 2, address_size: 4, format: Format::Dwarf64, }, LineProgram::none(), )); let unit3 = units.add(Unit::new( Encoding { version: 5, address_size: 4, format: Format::Dwarf32, }, LineProgram::none(), )); assert_eq!(units.count(), 3); { let unit1 = units.get_mut(unit_id1); assert_eq!(unit1.version(), 4); assert_eq!(unit1.address_size(), 8); assert_eq!(unit1.format(), Format::Dwarf32); assert_eq!(unit1.count(), 1); let root_id = unit1.root(); assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0)); { let root = unit1.get_mut(root_id); assert_eq!(root.id(), root_id); assert!(root.parent().is_none()); assert_eq!(root.tag(), constants::DW_TAG_compile_unit); // Test get/get_mut assert!(root.get(constants::DW_AT_producer).is_none()); assert!(root.get_mut(constants::DW_AT_producer).is_none()); let mut producer = AttributeValue::String(b"root"[..].into()); root.set(constants::DW_AT_producer, producer.clone()); assert_eq!(root.get(constants::DW_AT_producer), Some(&producer)); assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer)); // Test attrs let mut attrs = root.attrs(); let attr = attrs.next().unwrap(); assert_eq!(attr.name(), constants::DW_AT_producer); assert_eq!(attr.get(), &producer); assert!(attrs.next().is_none()); } let child1 = unit1.add(root_id, constants::DW_TAG_subprogram); assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1)); { let child1 = unit1.get_mut(child1); assert_eq!(child1.parent(), Some(root_id)); let tmp = AttributeValue::String(b"tmp"[..].into()); child1.set(constants::DW_AT_name, tmp.clone()); assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp)); // Test attrs_mut let name = AttributeValue::StringRef(strings.add(&b"child1"[..])); { let attr = child1.attrs_mut().next().unwrap(); assert_eq!(attr.name(), constants::DW_AT_name); attr.set(name.clone()); } assert_eq!(child1.get(constants::DW_AT_name), Some(&name)); } let child2 = unit1.add(root_id, constants::DW_TAG_subprogram); assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2)); { let child2 = unit1.get_mut(child2); assert_eq!(child2.parent(), Some(root_id)); let tmp = AttributeValue::String(b"tmp"[..].into()); child2.set(constants::DW_AT_name, tmp.clone()); assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp)); // Test replace let name = AttributeValue::StringRef(strings.add(&b"child2"[..])); child2.set(constants::DW_AT_name, name.clone()); assert_eq!(child2.get(constants::DW_AT_name), Some(&name)); } { let root = unit1.get(root_id); assert_eq!( root.children().cloned().collect::>(), vec![child1, child2] ); } } { let unit2 = units.get(unit2); assert_eq!(unit2.version(), 2); assert_eq!(unit2.address_size(), 4); assert_eq!(unit2.format(), Format::Dwarf64); assert_eq!(unit2.count(), 1); let root = unit2.root(); assert_eq!(root, UnitEntryId::new(unit2.base_id, 0)); let root = unit2.get(root); assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0)); assert!(root.parent().is_none()); assert_eq!(root.tag(), constants::DW_TAG_compile_unit); } let mut sections = Sections::new(EndianVec::new(LittleEndian)); let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap(); units .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) .unwrap(); println!("{:?}", sections.debug_str); println!("{:?}", sections.debug_info); println!("{:?}", sections.debug_abbrev); let dwarf = read::Dwarf { debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian), ..Default::default() }; let mut read_units = dwarf.units(); { let read_unit1 = read_units.next().unwrap().unwrap(); let unit1 = units.get(unit_id1); assert_eq!(unit1.version(), read_unit1.version()); assert_eq!(unit1.address_size(), read_unit1.address_size()); assert_eq!(unit1.format(), read_unit1.format()); let read_unit1 = dwarf.unit(read_unit1).unwrap(); let mut read_entries = read_unit1.entries(); let root = unit1.get(unit1.root()); { let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); assert_eq!(depth, 0); assert_eq!(root.tag(), read_root.tag()); assert!(read_root.has_children()); let producer = match root.get(constants::DW_AT_producer).unwrap() { AttributeValue::String(ref producer) => &**producer, otherwise => panic!("unexpected {:?}", otherwise), }; assert_eq!(producer, b"root"); let read_producer = read_root .attr_value(constants::DW_AT_producer) .unwrap() .unwrap(); assert_eq!( dwarf .attr_string(&read_unit1, read_producer) .unwrap() .slice(), producer ); } let mut children = root.children().cloned(); { let child = children.next().unwrap(); assert_eq!(child, UnitEntryId::new(unit1.base_id, 1)); let child = unit1.get(child); let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); assert_eq!(depth, 1); assert_eq!(child.tag(), read_child.tag()); assert!(!read_child.has_children()); let name = match child.get(constants::DW_AT_name).unwrap() { AttributeValue::StringRef(name) => *name, otherwise => panic!("unexpected {:?}", otherwise), }; let name = strings.get(name); assert_eq!(name, b"child1"); let read_name = read_child .attr_value(constants::DW_AT_name) .unwrap() .unwrap(); assert_eq!( dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), name ); } { let child = children.next().unwrap(); assert_eq!(child, UnitEntryId::new(unit1.base_id, 2)); let child = unit1.get(child); let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap(); assert_eq!(depth, 0); assert_eq!(child.tag(), read_child.tag()); assert!(!read_child.has_children()); let name = match child.get(constants::DW_AT_name).unwrap() { AttributeValue::StringRef(name) => *name, otherwise => panic!("unexpected {:?}", otherwise), }; let name = strings.get(name); assert_eq!(name, b"child2"); let read_name = read_child .attr_value(constants::DW_AT_name) .unwrap() .unwrap(); assert_eq!( dwarf.attr_string(&read_unit1, read_name).unwrap().slice(), name ); } assert!(read_entries.next_dfs().unwrap().is_none()); } { let read_unit2 = read_units.next().unwrap().unwrap(); let unit2 = units.get(unit2); assert_eq!(unit2.version(), read_unit2.version()); assert_eq!(unit2.address_size(), read_unit2.address_size()); assert_eq!(unit2.format(), read_unit2.format()); let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); let mut read_entries = read_unit2.entries(&abbrevs); { let root = unit2.get(unit2.root()); let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); assert_eq!(depth, 0); assert_eq!(root.tag(), read_root.tag()); assert!(!read_root.has_children()); } assert!(read_entries.next_dfs().unwrap().is_none()); } { let read_unit3 = read_units.next().unwrap().unwrap(); let unit3 = units.get(unit3); assert_eq!(unit3.version(), read_unit3.version()); assert_eq!(unit3.address_size(), read_unit3.address_size()); assert_eq!(unit3.format(), read_unit3.format()); let abbrevs = dwarf.abbreviations(&read_unit3).unwrap(); let mut read_entries = read_unit3.entries(&abbrevs); { let root = unit3.get(unit3.root()); let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap(); assert_eq!(depth, 0); assert_eq!(root.tag(), read_root.tag()); assert!(!read_root.has_children()); } assert!(read_entries.next_dfs().unwrap().is_none()); } assert!(read_units.next().unwrap().is_none()); let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let convert_units = UnitTable::from( &dwarf, &mut convert_line_strings, &mut convert_strings, &|address| Some(Address::Constant(address)), ) .unwrap(); assert_eq!(convert_units.count(), units.count()); for i in 0..convert_units.count() { let unit_id = units.id(i); let unit = units.get(unit_id); let convert_unit_id = convert_units.id(i); let convert_unit = convert_units.get(convert_unit_id); assert_eq!(convert_unit.version(), unit.version()); assert_eq!(convert_unit.address_size(), unit.address_size()); assert_eq!(convert_unit.format(), unit.format()); assert_eq!(convert_unit.count(), unit.count()); let root = unit.get(unit.root()); let convert_root = convert_unit.get(convert_unit.root()); assert_eq!(convert_root.tag(), root.tag()); for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { assert_eq!(convert_attr, attr); } } } #[test] fn test_attribute_value() { // Create a string table and a string with a non-zero id/offset. let mut strings = StringTable::default(); strings.add("string one"); let string_id = strings.add("string two"); let mut ranges = RangeListTable::default(); let range_id = ranges.add(RangeList(vec![Range::StartEnd { begin: Address::Constant(0x1234), end: Address::Constant(0x2345), }])); let mut locations = LocationListTable::default(); let loc_id = locations.add(LocationList(vec![Location::StartEnd { begin: Address::Constant(0x1234), end: Address::Constant(0x2345), data: Expression(vec![1, 0, 0, 0]), }])); let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian)); let debug_str_offsets = strings.write(&mut debug_str).unwrap(); let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian); let mut line_strings = LineStringTable::default(); line_strings.add("line string one"); let line_string_id = line_strings.add("line string two"); let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian)); let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap(); let read_debug_line_str = read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian)); let data = vec![1, 2, 3, 4]; let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian); for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; let mut sections = Sections::new(EndianVec::new(LittleEndian)); let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); let loc_list_offsets = locations.write(&mut sections, encoding).unwrap(); let read_debug_ranges = read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); let read_debug_rnglists = read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); let read_debug_loc = read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian); let read_debug_loclists = read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian); let mut units = UnitTable::default(); let unit = units.add(Unit::new(encoding, LineProgram::none())); let unit = units.get(unit); let encoding = Encoding { format, version, address_size, }; let from_unit = read::UnitHeader::new( encoding, 0, DebugAbbrevOffset(0), read::EndianSlice::new(&[], LittleEndian), ); for &(ref name, ref value, ref expect_value) in &[ ( constants::DW_AT_name, AttributeValue::Address(Address::Constant(0x1234)), read::AttributeValue::Addr(0x1234), ), ( constants::DW_AT_name, AttributeValue::Block(data.clone()), read::AttributeValue::Block(read_data), ), ( constants::DW_AT_name, AttributeValue::Data1(0x12), read::AttributeValue::Data1(0x12), ), ( constants::DW_AT_name, AttributeValue::Data2(0x1234), read::AttributeValue::Data2(0x1234), ), ( constants::DW_AT_name, AttributeValue::Data4(0x1234), read::AttributeValue::Data4(0x1234), ), ( constants::DW_AT_name, AttributeValue::Data8(0x1234), read::AttributeValue::Data8(0x1234), ), ( constants::DW_AT_name, AttributeValue::Sdata(0x1234), read::AttributeValue::Sdata(0x1234), ), ( constants::DW_AT_name, AttributeValue::Udata(0x1234), read::AttributeValue::Udata(0x1234), ), ( constants::DW_AT_name, AttributeValue::Exprloc(Expression(data.clone())), read::AttributeValue::Exprloc(read::Expression(read_data)), ), ( constants::DW_AT_name, AttributeValue::Flag(false), read::AttributeValue::Flag(false), ), /* ( constants::DW_AT_name, AttributeValue::FlagPresent, read::AttributeValue::Flag(true), ), */ ( constants::DW_AT_name, AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)), ), ( constants::DW_AT_location, AttributeValue::LocationListRef(loc_id), read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0), ), ( constants::DW_AT_macro_info, AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)), read::AttributeValue::SecOffset(0x1234), ), ( constants::DW_AT_ranges, AttributeValue::RangeListRef(range_id), read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0), ), ( constants::DW_AT_name, AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)), ), ( constants::DW_AT_name, AttributeValue::StringRef(string_id), read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)), ), ( constants::DW_AT_name, AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)), ), ( constants::DW_AT_name, AttributeValue::LineStringRef(line_string_id), read::AttributeValue::DebugLineStrRef( debug_line_str_offsets.get(line_string_id), ), ), ( constants::DW_AT_name, AttributeValue::String(data.clone()), read::AttributeValue::String(read_data), ), ( constants::DW_AT_encoding, AttributeValue::Encoding(constants::DwAte(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_decimal_sign, AttributeValue::DecimalSign(constants::DwDs(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_endianity, AttributeValue::Endianity(constants::DwEnd(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_accessibility, AttributeValue::Accessibility(constants::DwAccess(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_visibility, AttributeValue::Visibility(constants::DwVis(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_virtuality, AttributeValue::Virtuality(constants::DwVirtuality(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_language, AttributeValue::Language(constants::DwLang(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_address_class, AttributeValue::AddressClass(constants::DwAddr(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_identifier_case, AttributeValue::IdentifierCase(constants::DwId(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_calling_convention, AttributeValue::CallingConvention(constants::DwCc(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_ordering, AttributeValue::Ordering(constants::DwOrd(0x12)), read::AttributeValue::Udata(0x12), ), ( constants::DW_AT_inline, AttributeValue::Inline(constants::DwInl(0x12)), read::AttributeValue::Udata(0x12), ), ][..] { let form = value.form(encoding).unwrap(); let attr = Attribute { name: *name, value: value.clone(), }; let line_program_offset = None; let mut unit_refs = Vec::new(); let mut debug_info_refs = Vec::new(); let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); attr.write( &mut debug_info, &unit, line_program_offset, &debug_line_str_offsets, &debug_str_offsets, &range_list_offsets, &loc_list_offsets, &mut unit_refs, &mut debug_info_refs, ) .unwrap(); let spec = read::AttributeSpecification::new(*name, form, None); let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); let (read_attr, _) = read::parse_attribute(&mut r, &from_unit, &[spec]).unwrap(); let read_value = &read_attr.raw_value(); // read::AttributeValue is invariant in the lifetime of R. // The lifetimes here are all okay, so transmute it. let read_value = unsafe { mem::transmute::< &read::AttributeValue>, &read::AttributeValue>, >(read_value) }; assert_eq!(read_value, expect_value); let dwarf = read::Dwarf { debug_str: read_debug_str.clone(), debug_line_str: read_debug_line_str.clone(), ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists), locations: read::LocationLists::new( read_debug_loc, read_debug_loclists, ), ..Default::default() }; let unit = read::Unit { offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: from_unit, abbreviations: read::Abbreviations::default(), name: None, comp_dir: None, low_pc: 0, str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), loclists_base: DebugLocListsBase(0), rnglists_base: DebugRngListsBase(0), line_program: None, }; let mut context = convert::ConvertUnitContext { dwarf: &dwarf, unit: &unit, line_strings: &mut line_strings, strings: &mut strings, ranges: &mut ranges, locations: &mut locations, convert_address: &|address| Some(Address::Constant(address)), base_address: Address::Constant(0), line_program_offset: None, line_program_files: Vec::new(), }; let convert_attr = Attribute::from(&mut context, &read_attr).unwrap().unwrap(); assert_eq!(convert_attr, attr); } } } } } #[test] #[allow(clippy::cyclomatic_complexity)] fn test_unit_ref() { let mut units = UnitTable::default(); let unit_id1 = units.add(Unit::new( Encoding { version: 4, address_size: 8, format: Format::Dwarf32, }, LineProgram::none(), )); assert_eq!(unit_id1, UnitId::new(units.base_id, 0)); let unit_id2 = units.add(Unit::new( Encoding { version: 2, address_size: 4, format: Format::Dwarf64, }, LineProgram::none(), )); assert_eq!(unit_id2, UnitId::new(units.base_id, 1)); let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1); let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2); let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1); let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2); { let unit1 = units.get_mut(unit_id1); let root = unit1.root(); let child_id1 = unit1.add(root, constants::DW_TAG_subprogram); assert_eq!(child_id1, unit1_child1); let child_id2 = unit1.add(root, constants::DW_TAG_subprogram); assert_eq!(child_id2, unit1_child2); { let child1 = unit1.get_mut(child_id1); child1.set( constants::DW_AT_type, AttributeValue::ThisUnitEntryRef(child_id2), ); } { let child2 = unit1.get_mut(child_id2); child2.set( constants::DW_AT_type, AttributeValue::AnyUnitEntryRef((unit_id2, unit2_child1)), ); } } { let unit2 = units.get_mut(unit_id2); let root = unit2.root(); let child_id1 = unit2.add(root, constants::DW_TAG_subprogram); assert_eq!(child_id1, unit2_child1); let child_id2 = unit2.add(root, constants::DW_TAG_subprogram); assert_eq!(child_id2, unit2_child2); { let child1 = unit2.get_mut(child_id1); child1.set( constants::DW_AT_type, AttributeValue::ThisUnitEntryRef(child_id2), ); } { let child2 = unit2.get_mut(child_id2); child2.set( constants::DW_AT_type, AttributeValue::AnyUnitEntryRef((unit_id1, unit1_child1)), ); } } let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); let mut sections = Sections::new(EndianVec::new(LittleEndian)); let debug_info_offsets = units .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) .unwrap(); println!("{:?}", sections.debug_info); println!("{:?}", sections.debug_abbrev); let dwarf = read::Dwarf { debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian), debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian), ..Default::default() }; let mut read_units = dwarf.units(); { let read_unit1 = read_units.next().unwrap().unwrap(); assert_eq!(read_unit1.offset(), debug_info_offsets.unit(unit_id1)); let abbrevs = dwarf.abbreviations(&read_unit1).unwrap(); let mut read_entries = read_unit1.entries(&abbrevs); { let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); } { let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); let offset = debug_info_offsets .entry(unit_id1, unit1_child2) .to_unit_offset(&read_unit1) .unwrap(); assert_eq!( read_child1.attr_value(constants::DW_AT_type).unwrap(), Some(read::AttributeValue::UnitRef(offset)) ); } { let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); let offset = debug_info_offsets.entry(unit_id2, unit2_child1); assert_eq!( read_child2.attr_value(constants::DW_AT_type).unwrap(), Some(read::AttributeValue::DebugInfoRef(offset)) ); } } { let read_unit2 = read_units.next().unwrap().unwrap(); assert_eq!(read_unit2.offset(), debug_info_offsets.unit(unit_id2)); let abbrevs = dwarf.abbreviations(&read_unit2).unwrap(); let mut read_entries = read_unit2.entries(&abbrevs); { let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap(); } { let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap(); let offset = debug_info_offsets .entry(unit_id2, unit2_child2) .to_unit_offset(&read_unit2) .unwrap(); assert_eq!( read_child1.attr_value(constants::DW_AT_type).unwrap(), Some(read::AttributeValue::UnitRef(offset)) ); } { let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap(); let offset = debug_info_offsets.entry(unit_id1, unit1_child1); assert_eq!( read_child2.attr_value(constants::DW_AT_type).unwrap(), Some(read::AttributeValue::DebugInfoRef(offset)) ); } } let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let convert_units = UnitTable::from( &dwarf, &mut convert_line_strings, &mut convert_strings, &|address| Some(Address::Constant(address)), ) .unwrap(); assert_eq!(convert_units.count(), units.count()); for unit_id in 0..convert_units.count() { let unit = units.get(UnitId::new(units.base_id, unit_id)); let convert_unit = convert_units.get(UnitId::new(convert_units.base_id, unit_id)); assert_eq!(convert_unit.version(), unit.version()); assert_eq!(convert_unit.address_size(), unit.address_size()); assert_eq!(convert_unit.format(), unit.format()); assert_eq!(convert_unit.count(), unit.count()); let root = unit.get(unit.root()); let convert_root = convert_unit.get(convert_unit.root()); assert_eq!(convert_root.tag(), root.tag()); for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) { assert_eq!(convert_attr, attr); } let child1 = unit.get(UnitEntryId::new(unit.base_id, 1)); let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1)); assert_eq!(convert_child1.tag(), child1.tag()); for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) { assert_eq!(convert_attr.name, attr.name); match (convert_attr.value.clone(), attr.value.clone()) { ( AttributeValue::AnyUnitEntryRef(convert_id), AttributeValue::AnyUnitEntryRef(id), ) => { assert_eq!((convert_id.0).index, (id.0).index); assert_eq!((convert_id.1).index, (id.1).index); } ( AttributeValue::ThisUnitEntryRef(convert_id), AttributeValue::ThisUnitEntryRef(id), ) => { assert_eq!(convert_id.index, id.index); } (convert_value, value) => assert_eq!(convert_value, value), } } let child2 = unit.get(UnitEntryId::new(unit.base_id, 2)); let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2)); assert_eq!(convert_child2.tag(), child2.tag()); for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) { assert_eq!(convert_attr.name, attr.name); match (convert_attr.value.clone(), attr.value.clone()) { ( AttributeValue::AnyUnitEntryRef(convert_id), AttributeValue::AnyUnitEntryRef(id), ) => { assert_eq!((convert_id.0).index, (id.0).index); assert_eq!((convert_id.1).index, (id.1).index); } ( AttributeValue::ThisUnitEntryRef(convert_id), AttributeValue::ThisUnitEntryRef(id), ) => { assert_eq!(convert_id.index, id.index); } (convert_value, value) => assert_eq!(convert_value, value), } } } } #[test] fn test_sibling() { fn add_child( unit: &mut Unit, parent: UnitEntryId, tag: constants::DwTag, name: &str, ) -> UnitEntryId { let id = unit.add(parent, tag); let child = unit.get_mut(id); child.set(constants::DW_AT_name, AttributeValue::String(name.into())); child.set_sibling(true); id } fn add_children(units: &mut UnitTable, unit_id: UnitId) { let unit = units.get_mut(unit_id); let root = unit.root(); let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1"); add_child(unit, child1, constants::DW_TAG_variable, "grandchild1"); add_child(unit, root, constants::DW_TAG_subprogram, "child2"); add_child(unit, root, constants::DW_TAG_subprogram, "child3"); } fn next_child>( entries: &mut read::EntriesCursor, ) -> (read::UnitOffset, Option) { let (_, entry) = entries.next_dfs().unwrap().unwrap(); let offset = entry.offset(); let sibling = entry .attr_value(constants::DW_AT_sibling) .unwrap() .map(|attr| match attr { read::AttributeValue::UnitRef(offset) => offset, _ => panic!("bad sibling value"), }); (offset, sibling) } fn check_sibling>( unit: &read::CompilationUnitHeader, debug_abbrev: &read::DebugAbbrev, ) { let abbrevs = unit.abbreviations(debug_abbrev).unwrap(); let mut entries = unit.entries(&abbrevs); // root entries.next_dfs().unwrap().unwrap(); // child1 let (_, sibling1) = next_child(&mut entries); // grandchild1 entries.next_dfs().unwrap().unwrap(); // child2 let (offset2, sibling2) = next_child(&mut entries); // child3 let (_, _) = next_child(&mut entries); assert_eq!(sibling1, Some(offset2)); assert_eq!(sibling2, None); } let encoding = Encoding { format: Format::Dwarf32, version: 4, address_size: 8, }; let mut units = UnitTable::default(); let unit_id1 = units.add(Unit::new(encoding, LineProgram::none())); add_children(&mut units, unit_id1); let unit_id2 = units.add(Unit::new(encoding, LineProgram::none())); add_children(&mut units, unit_id2); let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); let mut sections = Sections::new(EndianVec::new(LittleEndian)); units .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) .unwrap(); println!("{:?}", sections.debug_info); println!("{:?}", sections.debug_abbrev); let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian); let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian); let mut read_units = read_debug_info.units(); check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev); } #[test] fn test_line_ref() { for &version in &[2, 3, 4, 5] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding { format, version, address_size, }; // The line program we'll be referencing. let mut line_program = LineProgram::new( encoding, LineEncoding::default(), LineString::String(b"comp_dir".to_vec()), LineString::String(b"comp_name".to_vec()), None, ); let dir = line_program.default_directory(); let file1 = line_program.add_file(LineString::String(b"file1".to_vec()), dir, None); let file2 = line_program.add_file(LineString::String(b"file2".to_vec()), dir, None); // Write, read, and convert the line program, so that we have the info // required to convert the attributes. let line_strings = DebugLineStrOffsets::none(); let strings = DebugStrOffsets::none(); let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian)); let line_program_offset = line_program .write(&mut debug_line, encoding, &line_strings, &strings) .unwrap(); let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian); let read_line_program = read_debug_line .program( line_program_offset, address_size, Some(read::EndianSlice::new(b"comp_dir", LittleEndian)), Some(read::EndianSlice::new(b"comp_name", LittleEndian)), ) .unwrap(); let dwarf = read::Dwarf::default(); let mut convert_line_strings = LineStringTable::default(); let mut convert_strings = StringTable::default(); let (_, line_program_files) = LineProgram::from( read_line_program, &dwarf, &mut convert_line_strings, &mut convert_strings, &|address| Some(Address::Constant(address)), ) .unwrap(); // Fake the unit. let mut units = UnitTable::default(); let unit = units.add(Unit::new(encoding, LineProgram::none())); let unit = units.get(unit); let from_unit = read::UnitHeader::new( encoding, 0, DebugAbbrevOffset(0), read::EndianSlice::new(&[], LittleEndian), ); for &(ref name, ref value, ref expect_value) in &[ ( constants::DW_AT_stmt_list, AttributeValue::LineProgramRef, read::AttributeValue::SecOffset(line_program_offset.0), ), ( constants::DW_AT_decl_file, AttributeValue::FileIndex(Some(file1)), read::AttributeValue::Udata(file1.raw()), ), ( constants::DW_AT_decl_file, AttributeValue::FileIndex(Some(file2)), read::AttributeValue::Udata(file2.raw()), ), ][..] { let mut ranges = RangeListTable::default(); let mut locations = LocationListTable::default(); let mut strings = StringTable::default(); let debug_str_offsets = DebugStrOffsets::none(); let mut line_strings = LineStringTable::default(); let debug_line_str_offsets = DebugLineStrOffsets::none(); let form = value.form(encoding).unwrap(); let attr = Attribute { name: *name, value: value.clone(), }; let mut unit_refs = Vec::new(); let mut debug_info_refs = Vec::new(); let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian)); let range_list_offsets = RangeListOffsets::none(); let loc_list_offsets = LocationListOffsets::none(); attr.write( &mut debug_info, &unit, Some(line_program_offset), &debug_line_str_offsets, &debug_str_offsets, &range_list_offsets, &loc_list_offsets, &mut unit_refs, &mut debug_info_refs, ) .unwrap(); let spec = read::AttributeSpecification::new(*name, form, None); let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian); let (read_attr, _) = read::parse_attribute(&mut r, &from_unit, &[spec]).unwrap(); let read_value = &read_attr.raw_value(); // read::AttributeValue is invariant in the lifetime of R. // The lifetimes here are all okay, so transmute it. let read_value = unsafe { mem::transmute::< &read::AttributeValue>, &read::AttributeValue>, >(read_value) }; assert_eq!(read_value, expect_value); let unit = read::Unit { offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), header: from_unit, abbreviations: read::Abbreviations::default(), name: None, comp_dir: None, low_pc: 0, str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), loclists_base: DebugLocListsBase(0), rnglists_base: DebugRngListsBase(0), line_program: None, }; let mut context = convert::ConvertUnitContext { dwarf: &dwarf, unit: &unit, line_strings: &mut line_strings, strings: &mut strings, ranges: &mut ranges, locations: &mut locations, convert_address: &|address| Some(Address::Constant(address)), base_address: Address::Constant(0), line_program_offset: Some(line_program_offset), line_program_files: line_program_files.clone(), }; let convert_attr = Attribute::from(&mut context, &read_attr).unwrap().unwrap(); assert_eq!(convert_attr, attr); } } } } } #[test] fn test_line_program_used() { for used in vec![false, true] { let encoding = Encoding { format: Format::Dwarf32, version: 5, address_size: 8, }; let line_program = LineProgram::new( encoding, LineEncoding::default(), LineString::String(b"comp_dir".to_vec()), LineString::String(b"comp_name".to_vec()), None, ); let mut unit = Unit::new(encoding, line_program); let file_id = if used { Some(FileId::new(0)) } else { None }; let root = unit.root(); unit.get_mut(root).set( constants::DW_AT_decl_file, AttributeValue::FileIndex(file_id), ); let mut units = UnitTable::default(); units.add(unit); let debug_line_str_offsets = DebugLineStrOffsets::none(); let debug_str_offsets = DebugStrOffsets::none(); let mut sections = Sections::new(EndianVec::new(LittleEndian)); units .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets) .unwrap(); assert_eq!(!used, sections.debug_line.slice().is_empty()); } } } gimli-0.19.0/src/write/writer.rs010066400017500001750000000417171346020377600147520ustar0000000000000000use crate::common::{Format, SectionId}; use crate::constants; use crate::endianity::Endianity; use crate::leb128; use crate::write::{Address, Error, Result}; /// A trait for writing the data to a DWARF section. /// /// All write operations append to the section unless otherwise specified. #[allow(clippy::len_without_is_empty)] pub trait Writer { /// The endianity of bytes that are written. type Endian: Endianity; /// Return the endianity of bytes that are written. fn endian(&self) -> Self::Endian; /// Return the current section length. /// /// This may be used as an offset for future `write_at` calls. fn len(&self) -> usize; /// Write a slice. fn write(&mut self, bytes: &[u8]) -> Result<()>; /// Write a slice at a given offset. /// /// The write must not extend past the current section length. fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; /// Write an address. /// /// If the writer supports relocations, then it must provide its own implementation /// of this method. fn write_address(&mut self, address: Address, size: u8) -> Result<()> { match address { Address::Constant(val) => self.write_udata(val, size), Address::Symbol { .. } => Err(Error::InvalidAddress), } } /// Write an address with a `.eh_frame` pointer encoding. /// /// The given size is only used for `DW_EH_PE_absptr` formats. /// /// If the writer supports relocations, then it must provide its own implementation /// of this method. fn write_eh_pointer( &mut self, address: Address, eh_pe: constants::DwEhPe, size: u8, ) -> Result<()> { match address { Address::Constant(val) => { // Indirect doesn't matter here. let val = match eh_pe.application() { constants::DW_EH_PE_absptr => val, constants::DW_EH_PE_pcrel => { // TODO: better handling of sign let offset = self.len() as u64; offset.wrapping_sub(val) } _ => { return Err(Error::UnsupportedPointerEncoding(eh_pe)); } }; self.write_eh_pointer_data(val, eh_pe.format(), size) } Address::Symbol { .. } => Err(Error::InvalidAddress), } } /// Write a value with a `.eh_frame` pointer format. /// /// The given size is only used for `DW_EH_PE_absptr` formats. /// /// This must not be used directly for values that may require relocation. fn write_eh_pointer_data( &mut self, val: u64, format: constants::DwEhPe, size: u8, ) -> Result<()> { match format { constants::DW_EH_PE_absptr => self.write_udata(val, size), constants::DW_EH_PE_uleb128 => self.write_uleb128(val), constants::DW_EH_PE_udata2 => self.write_udata(val, 2), constants::DW_EH_PE_udata4 => self.write_udata(val, 4), constants::DW_EH_PE_udata8 => self.write_udata(val, 8), constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64), constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2), constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4), constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8), _ => { return Err(Error::UnsupportedPointerEncoding(format)); } } } /// Write an offset that is relative to the start of the given section. /// /// If the writer supports relocations, then it must provide its own implementation /// of this method. fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> { self.write_udata(val as u64, size) } /// Write an offset that is relative to the start of the given section. /// /// If the writer supports relocations, then it must provide its own implementation /// of this method. fn write_offset_at( &mut self, offset: usize, val: usize, _section: SectionId, size: u8, ) -> Result<()> { self.write_udata_at(offset, val as u64, size) } /// Write a u8. fn write_u8(&mut self, val: u8) -> Result<()> { let bytes = [val]; self.write(&bytes) } /// Write a u16. fn write_u16(&mut self, val: u16) -> Result<()> { let mut bytes = [0; 2]; self.endian().write_u16(&mut bytes, val); self.write(&bytes) } /// Write a u32. fn write_u32(&mut self, val: u32) -> Result<()> { let mut bytes = [0; 4]; self.endian().write_u32(&mut bytes, val); self.write(&bytes) } /// Write a u64. fn write_u64(&mut self, val: u64) -> Result<()> { let mut bytes = [0; 8]; self.endian().write_u64(&mut bytes, val); self.write(&bytes) } /// Write a u8 at the given offset. fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> { let bytes = [val]; self.write_at(offset, &bytes) } /// Write a u16 at the given offset. fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> { let mut bytes = [0; 2]; self.endian().write_u16(&mut bytes, val); self.write_at(offset, &bytes) } /// Write a u32 at the given offset. fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> { let mut bytes = [0; 4]; self.endian().write_u32(&mut bytes, val); self.write_at(offset, &bytes) } /// Write a u64 at the given offset. fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> { let mut bytes = [0; 8]; self.endian().write_u64(&mut bytes, val); self.write_at(offset, &bytes) } /// Write unsigned data of the given size. /// /// Returns an error if the value is too large for the size. /// This must not be used directly for values that may require relocation. fn write_udata(&mut self, val: u64, size: u8) -> Result<()> { match size { 1 => { let write_val = val as u8; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u8(write_val) } 2 => { let write_val = val as u16; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u16(write_val) } 4 => { let write_val = val as u32; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u32(write_val) } 8 => self.write_u64(val), otherwise => Err(Error::UnsupportedWordSize(otherwise)), } } /// Write signed data of the given size. /// /// Returns an error if the value is too large for the size. /// This must not be used directly for values that may require relocation. fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> { match size { 1 => { let write_val = val as i8; if val != i64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u8(write_val as u8) } 2 => { let write_val = val as i16; if val != i64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u16(write_val as u16) } 4 => { let write_val = val as i32; if val != i64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u32(write_val as u32) } 8 => self.write_u64(val as u64), otherwise => Err(Error::UnsupportedWordSize(otherwise)), } } /// Write a word of the given size at the given offset. /// /// Returns an error if the value is too large for the size. /// This must not be used directly for values that may require relocation. fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> { match size { 1 => { let write_val = val as u8; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u8_at(offset, write_val) } 2 => { let write_val = val as u16; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u16_at(offset, write_val) } 4 => { let write_val = val as u32; if val != u64::from(write_val) { return Err(Error::ValueTooLarge); } self.write_u32_at(offset, write_val) } 8 => self.write_u64_at(offset, val), otherwise => Err(Error::UnsupportedWordSize(otherwise)), } } /// Write an unsigned LEB128 encoded integer. fn write_uleb128(&mut self, val: u64) -> Result<()> { let mut bytes = [0u8; 10]; // bytes is long enough so this will never fail. let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap(); self.write(&bytes[..len]) } /// Read an unsigned LEB128 encoded integer. fn write_sleb128(&mut self, val: i64) -> Result<()> { let mut bytes = [0u8; 10]; // bytes is long enough so this will never fail. let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap(); self.write(&bytes[..len]) } /// Write an initial length according to the given DWARF format. /// /// This will only write a length of zero, since the length isn't /// known yet, and a subsequent call to `write_initial_length_at` /// will write the actual length. fn write_initial_length(&mut self, format: Format) -> Result { if format == Format::Dwarf64 { self.write_u32(0xffff_ffff)?; } let offset = InitialLengthOffset(self.len()); self.write_udata(0, format.word_size())?; Ok(offset) } /// Write an initial length at the given offset according to the given DWARF format. /// /// `write_initial_length` must have previously returned the offset. fn write_initial_length_at( &mut self, offset: InitialLengthOffset, length: u64, format: Format, ) -> Result<()> { self.write_udata_at(offset.0, length, format.word_size()) } } /// The offset at which an initial length should be written. #[derive(Debug, Clone, Copy)] pub struct InitialLengthOffset(usize); #[cfg(test)] mod tests { use super::*; use crate::write; use crate::{BigEndian, LittleEndian}; use std::{i64, u64}; #[test] #[allow(clippy::cyclomatic_complexity)] fn test_writer() { let mut w = write::EndianVec::new(LittleEndian); w.write_address(Address::Constant(0x1122_3344), 4).unwrap(); assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); assert_eq!( w.write_address( Address::Symbol { symbol: 0, addend: 0 }, 4 ), Err(Error::InvalidAddress) ); let mut w = write::EndianVec::new(LittleEndian); w.write_offset(0x1122_3344, SectionId::DebugInfo, 4) .unwrap(); assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2) .unwrap(); assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]); let mut w = write::EndianVec::new(LittleEndian); w.write_u8(0x11).unwrap(); w.write_u16(0x2233).unwrap(); w.write_u32(0x4455_6677).unwrap(); w.write_u64(0x8081_8283_8485_8687).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, ]); w.write_u8_at(14, 0x11).unwrap(); w.write_u16_at(12, 0x2233).unwrap(); w.write_u32_at(8, 0x4455_6677).unwrap(); w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, ]); let mut w = write::EndianVec::new(BigEndian); w.write_u8(0x11).unwrap(); w.write_u16(0x2233).unwrap(); w.write_u32(0x4455_6677).unwrap(); w.write_u64(0x8081_8283_8485_8687).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ]); w.write_u8_at(14, 0x11).unwrap(); w.write_u16_at(12, 0x2233).unwrap(); w.write_u32_at(8, 0x4455_6677).unwrap(); w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x44, 0x55, 0x66, 0x77, 0x22, 0x33, 0x11, ]); let mut w = write::EndianVec::new(LittleEndian); w.write_udata(0x11, 1).unwrap(); w.write_udata(0x2233, 2).unwrap(); w.write_udata(0x4455_6677, 4).unwrap(); w.write_udata(0x8081_8283_8485_8687, 8).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, ]); assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge)); assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge)); assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge)); assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3))); w.write_udata_at(14, 0x11, 1).unwrap(); w.write_udata_at(12, 0x2233, 2).unwrap(); w.write_udata_at(8, 0x4455_6677, 4).unwrap(); w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap(); #[rustfmt::skip] assert_eq!(w.slice(), &[ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, ]); assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge)); assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge)); assert_eq!( w.write_udata_at(0, 0x1_0000_0000, 4), Err(Error::ValueTooLarge) ); assert_eq!( w.write_udata_at(0, 0x00, 3), Err(Error::UnsupportedWordSize(3)) ); let mut w = write::EndianVec::new(LittleEndian); w.write_uleb128(0).unwrap(); assert_eq!(w.slice(), &[0]); let mut w = write::EndianVec::new(LittleEndian); w.write_uleb128(u64::MAX).unwrap(); assert_eq!( w.slice(), &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1] ); let mut w = write::EndianVec::new(LittleEndian); w.write_sleb128(0).unwrap(); assert_eq!(w.slice(), &[0]); let mut w = write::EndianVec::new(LittleEndian); w.write_sleb128(i64::MAX).unwrap(); assert_eq!( w.slice(), &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0] ); let mut w = write::EndianVec::new(LittleEndian); w.write_sleb128(i64::MIN).unwrap(); assert_eq!( w.slice(), &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f] ); let mut w = write::EndianVec::new(LittleEndian); let offset = w.write_initial_length(Format::Dwarf32).unwrap(); assert_eq!(w.slice(), &[0, 0, 0, 0]); w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32) .unwrap(); assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]); assert_eq!( w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32), Err(Error::ValueTooLarge) ); let mut w = write::EndianVec::new(LittleEndian); let offset = w.write_initial_length(Format::Dwarf64).unwrap(); assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]); w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64) .unwrap(); assert_eq!( w.slice(), &[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11] ); } } gimli-0.19.0/tests/convert_self.rs010066400017500001750000000131201351057326000153250ustar0000000000000000use std::env; use std::fs::File; use std::io::Read; use std::path::PathBuf; use gimli::read; use gimli::write::{self, Address, EndianVec}; use gimli::LittleEndian; fn read_section(section: &str) -> Vec { let mut path = PathBuf::new(); if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") { path.push(dir); } path.push("fixtures/self"); path.push(section); println!("Reading section \"{}\" at path {:?}", section, path); assert!(path.is_file()); let mut file = File::open(path).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); buf } #[test] fn test_convert_debug_info() { // Convert existing sections let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = read::DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_info = read_section("debug_info"); let debug_info = read::DebugInfo::new(&debug_info, LittleEndian); let debug_line = read_section("debug_line"); let debug_line = read::DebugLine::new(&debug_line, LittleEndian); let debug_str = read_section("debug_str"); let debug_str = read::DebugStr::new(&debug_str, LittleEndian); let debug_ranges = read_section("debug_ranges"); let debug_ranges = read::DebugRanges::new(&debug_ranges, LittleEndian); let debug_rnglists = read::DebugRngLists::new(&[], LittleEndian); let ranges = gimli::RangeLists::new(debug_ranges, debug_rnglists); let debug_loc = read_section("debug_loc"); let debug_loc = read::DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = read::DebugLocLists::new(&[], LittleEndian); let locations = gimli::LocationLists::new(debug_loc, debug_loclists); let dwarf = read::Dwarf { debug_abbrev, debug_info, debug_line, debug_str, ranges, locations, ..Default::default() }; let mut dwarf = write::Dwarf::from(&dwarf, &|address| Some(Address::Constant(address))) .expect("Should convert DWARF information"); assert_eq!(dwarf.units.count(), 23); let entries: usize = (0..dwarf.units.count()) .map(|i| dwarf.units.get(dwarf.units.id(i)).count()) .sum(); assert_eq!(entries, 29_560); assert_eq!(dwarf.line_strings.count(), 0); assert_eq!(dwarf.strings.count(), 3921); // Write to new sections let mut write_sections = write::Sections::new(EndianVec::new(LittleEndian)); dwarf .write(&mut write_sections) .expect("Should write DWARF information"); let debug_info_data = write_sections.debug_info.slice(); let debug_abbrev_data = write_sections.debug_abbrev.slice(); let debug_line_data = write_sections.debug_line.slice(); let debug_ranges_data = write_sections.debug_ranges.slice(); let debug_loc_data = write_sections.debug_loc.slice(); let debug_str_data = write_sections.debug_str.slice(); assert_eq!(debug_info_data.len(), 394_930); assert_eq!(debug_abbrev_data.len(), 9701); assert_eq!(debug_line_data.len(), 105_797); assert_eq!(debug_ranges_data.len(), 155_712); assert_eq!(debug_loc_data.len(), 245_768); assert_eq!(debug_str_data.len(), 144_731); // Convert new sections let debug_abbrev = read::DebugAbbrev::new(debug_abbrev_data, LittleEndian); let debug_info = read::DebugInfo::new(debug_info_data, LittleEndian); let debug_line = read::DebugLine::new(debug_line_data, LittleEndian); let debug_str = read::DebugStr::new(debug_str_data, LittleEndian); let debug_ranges = read::DebugRanges::new(debug_ranges_data, LittleEndian); let debug_rnglists = read::DebugRngLists::new(&[], LittleEndian); let debug_loc = read::DebugLoc::new(debug_loc_data, LittleEndian); let debug_loclists = read::DebugLocLists::new(&[], LittleEndian); let ranges = gimli::RangeLists::new(debug_ranges, debug_rnglists); let locations = gimli::LocationLists::new(debug_loc, debug_loclists); let dwarf = read::Dwarf { debug_abbrev, debug_info, debug_line, debug_str, ranges, locations, ..Default::default() }; let dwarf = write::Dwarf::from(&dwarf, &|address| Some(Address::Constant(address))) .expect("Should convert DWARF information"); assert_eq!(dwarf.units.count(), 23); let entries: usize = (0..dwarf.units.count()) .map(|i| dwarf.units.get(dwarf.units.id(i)).count()) .sum(); assert_eq!(entries, 29_560); assert_eq!(dwarf.strings.count(), 3921); } #[test] fn test_convert_eh_frame() { // Convert existing section let eh_frame = read_section("eh_frame"); let mut eh_frame = read::EhFrame::new(&eh_frame, LittleEndian); // The `.eh_frame` fixture data was created on a 64-bit machine. eh_frame.set_address_size(8); let frames = write::FrameTable::from(&eh_frame, &|address| Some(Address::Constant(address))) .expect("Should convert eh_frame information"); assert_eq!(frames.cie_count(), 2); assert_eq!(frames.fde_count(), 3482); // Write to new section let mut write_eh_frame = write::EhFrame(EndianVec::new(LittleEndian)); frames .write_eh_frame(&mut write_eh_frame) .expect("Should write eh_frame information"); let eh_frame = write_eh_frame.slice(); assert_eq!(eh_frame.len(), 147152); // Convert new section let mut eh_frame = read::EhFrame::new(&eh_frame, LittleEndian); eh_frame.set_address_size(8); let frames = write::FrameTable::from(&eh_frame, &|address| Some(Address::Constant(address))) .expect("Should convert eh_frame information"); assert_eq!(frames.cie_count(), 2); assert_eq!(frames.fde_count(), 3482); } gimli-0.19.0/tests/parse_self.rs010066400017500001750000000361021346020377600147720ustar0000000000000000use gimli::{ AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr, Encoding, EndianSlice, Expression, LittleEndian, LocationLists, Operation, RangeLists, Reader, }; use std::collections::hash_map::HashMap; use std::env; use std::fs::File; use std::io::Read; use std::path::PathBuf; use std::rc::Rc; fn read_section(section: &str) -> Vec { let mut path = PathBuf::new(); if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") { path.push(dir); } path.push("fixtures/self"); path.push(section); println!("Reading section \"{}\" at path {:?}", section, path); assert!(path.is_file()); let mut file = File::open(path).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); buf } fn parse_expression(expr: Expression, encoding: Encoding) { let mut pc = expr.0.clone(); while !pc.is_empty() { Operation::parse(&mut pc, &expr.0, encoding).expect("Should parse operation"); } // Also attempt to evaluate some of it. let mut eval = expr.evaluation(encoding); eval.set_initial_value(0); eval.evaluate().expect("Should evaluate expression"); } fn impl_parse_self_debug_info( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, ) { let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::Exprloc(expression) = attr.value() { parse_expression(expression, unit.encoding()); } } } } } #[test] fn test_parse_self_debug_info() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); impl_parse_self_debug_info(&debug_info, &debug_abbrev); } #[test] fn test_parse_self_debug_info_with_endian_rc_slice() { let debug_info = read_section("debug_info"); let debug_info = Rc::from(&debug_info[..]); let debug_info = gimli::EndianRcSlice::new(debug_info, LittleEndian); let debug_info = DebugInfo::from(debug_info); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = Rc::from(&debug_abbrev[..]); let debug_abbrev = gimli::EndianRcSlice::new(debug_abbrev, LittleEndian); let debug_abbrev = DebugAbbrev::from(debug_abbrev); impl_parse_self_debug_info(&debug_info, &debug_abbrev); } #[test] fn test_parse_self_debug_line() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_line = read_section("debug_line"); let debug_line = DebugLine::new(&debug_line, LittleEndian); let debug_str = read_section("debug_str"); let debug_str = DebugStr::new(&debug_str, LittleEndian); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let unit_entry = cursor.current().expect("Should have a root entry"); let comp_dir = unit_entry .attr_value(gimli::DW_AT_comp_dir) .expect("Should parse comp_dir attribute") .and_then(|val| val.string_value(&debug_str)); let comp_name = unit_entry .attr_value(gimli::DW_AT_name) .expect("Should parse name attribute") .and_then(|val| val.string_value(&debug_str)); if let Some(AttributeValue::DebugLineRef(offset)) = unit_entry .attr_value(gimli::DW_AT_stmt_list) .expect("Should parse stmt_list") { let program = debug_line .program(offset, unit.address_size(), comp_dir, comp_name) .expect("should parse line number program header"); let mut results = Vec::new(); let mut rows = program.rows(); while let Some((_, row)) = rows .next_row() .expect("Should parse and execute all rows in the line number program") { results.push(*row); } results.reverse(); let program = debug_line .program(offset, unit.address_size(), comp_dir, comp_name) .expect("should parse line number program header"); let (program, sequences) = program .sequences() .expect("should parse and execute the entire line number program"); assert!(!sequences.is_empty()); // Should be at least one sequence. for sequence in sequences { let mut rows = program.resume_from(&sequence); while let Some((_, row)) = rows .next_row() .expect("Should parse and execute all rows after resuming") { let other_row = results.pop().unwrap(); assert!(row.address() >= sequence.start); assert!(row.address() <= sequence.end); assert_eq!(row.address(), other_row.address()); assert_eq!(row.line(), other_row.line()); } } assert!(results.is_empty()); } } } #[test] fn test_parse_self_debug_loc() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let mut low_pc = 0; { let unit_entry = cursor.current().expect("Should have a root entry"); let low_pc_attr = unit_entry .attr_value(gimli::DW_AT_low_pc) .expect("Should parse low_pc"); if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr { low_pc = address; } } while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::LocationListsRef(offset) = attr.value() { let mut locs = loclists .locations( offset, unit.encoding(), low_pc, &debug_addr, debug_addr_base, ) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { assert!(loc.range.begin <= loc.range.end); parse_expression(loc.data, unit.encoding()); } } } } } } #[test] fn test_parse_self_debug_ranges() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); let debug_addr_base = DebugAddrBase(0); let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { let abbrevs = unit .abbreviations(&debug_abbrev) .expect("Should parse abbreviations"); let mut cursor = unit.entries(&abbrevs); cursor.next_dfs().expect("Should parse next dfs"); let mut low_pc = 0; { let unit_entry = cursor.current().expect("Should have a root entry"); let low_pc_attr = unit_entry .attr_value(gimli::DW_AT_low_pc) .expect("Should parse low_pc"); if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr { low_pc = address; } } while cursor.next_dfs().expect("Should parse next dfs").is_some() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::RangeListsRef(offset) = attr.value() { let mut ranges = rnglists .ranges( offset, unit.encoding(), low_pc, &debug_addr, debug_addr_base, ) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { assert!(range.begin <= range.end); } } } } } } #[test] fn test_parse_self_debug_aranges() { let debug_aranges = read_section("debug_aranges"); let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian); let mut aranges = debug_aranges.items(); while let Some(_) = aranges.next().expect("Should parse arange OK") { // Not really anything else we can check right now. } } #[test] fn test_parse_self_debug_pubnames() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_pubnames = read_section("debug_pubnames"); let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian); let mut units = HashMap::new(); let mut abbrevs = HashMap::new(); let mut pubnames = debug_pubnames.items(); while let Some(entry) = pubnames.next().expect("Should parse pubname OK") { let unit_offset = entry.unit_header_offset(); let unit = units.entry(unit_offset).or_insert_with(|| { debug_info .header_from_offset(unit_offset) .expect("Should parse unit header OK") }); let abbrev_offset = unit.debug_abbrev_offset(); let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| { debug_abbrev .abbreviations(abbrev_offset) .expect("Should parse abbreviations OK") }); let mut cursor = unit .entries_at_offset(abbrevs, entry.die_offset()) .expect("DIE offset should be valid"); assert!(cursor.next_dfs().expect("Should parse DIE").is_some()); } } #[test] fn test_parse_self_debug_pubtypes() { let debug_info = read_section("debug_info"); let debug_info = DebugInfo::new(&debug_info, LittleEndian); let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); let debug_pubtypes = read_section("debug_pubtypes"); let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian); let mut units = HashMap::new(); let mut abbrevs = HashMap::new(); let mut pubtypes = debug_pubtypes.items(); while let Some(entry) = pubtypes.next().expect("Should parse pubtype OK") { let unit_offset = entry.unit_header_offset(); let unit = units.entry(unit_offset).or_insert_with(|| { debug_info .header_from_offset(unit_offset) .expect("Should parse unit header OK") }); let abbrev_offset = unit.debug_abbrev_offset(); let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| { debug_abbrev .abbreviations(abbrev_offset) .expect("Should parse abbreviations OK") }); let mut cursor = unit .entries_at_offset(abbrevs, entry.die_offset()) .expect("DIE offset should be valid"); assert!(cursor.next_dfs().expect("Should parse DIE").is_some()); } } #[test] fn test_parse_self_eh_frame() { use gimli::{BaseAddresses, CieOrFde, EhFrame, UnwindSection}; let eh_frame = read_section("eh_frame"); let mut eh_frame = EhFrame::new(&eh_frame, LittleEndian); // The `.eh_frame` fixture data was created on a 64-bit machine. eh_frame.set_address_size(8); let bases = BaseAddresses::default() .set_eh_frame(0) .set_text(0) .set_got(0); let mut entries = eh_frame.entries(&bases); while let Some(entry) = entries.next().expect("Should parse CFI entry OK") { match entry { CieOrFde::Cie(cie) => { let mut instrs = cie.instructions(&eh_frame, &bases); while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") { // TODO FITZGEN } } CieOrFde::Fde(partial) => { let fde = partial .parse(UnwindSection::cie_from_offset) .expect("Should be able to get CIE for FDE"); let mut instrs = fde.instructions(&eh_frame, &bases); while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") { // TODO FITZGEN } } } } } gimli-0.19.0/.cargo_vcs_info.json0000644000000001120000000000000122550ustar00{ "git": { "sha1": "91e38653f2f4d615d7acc5da1df2fcbec0b50eb0" } }