Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/gimli/.cargo-checksum.json
vendored
Normal file
1
vendor/gimli/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"CHANGELOG.md":"8c5e124875aaba1b8ff61ab55e64164d866486874dd408cf90d9a22b659e0afe","Cargo.toml":"bf0b2be9dd65dbf7a867d52aa57affed9080d081e96cd9236a02d6294633359a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"847d6fe37773df4748bc20e9e810c6d378d3d9320a0a35f6a03feee630b99558","src/arch.rs":"7b5037bc1fa263c51b37bcab337e8a94ef82b6d4b70c0158e43a3c4154e61d58","src/common.rs":"301ec88e624ea0ab28a0b4c6819712feacc2886a3640b159f1a8b7eb007ac634","src/constants.rs":"cf37acb6703a3f7cbb5b26467721560a074a03f2a8dfd1a6104d916cb5255117","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"996d5c79d027f97c010ca487bc4ff5f8265f4b9e63d62b4e4fa291383c259ee9","src/lib.rs":"0dd6cff2e1fa56a79188b3b83c738b747af3288ef37f5e867e2a53971190818c","src/read/abbrev.rs":"4fc0efffe69e291dda890f0a66c12ae27053618119eefd7ec7303137364be18a","src/read/addr.rs":"f63f289edf889e87107bb2090fb1c50b48af7015f31b7c39c3d6ea09630a38e9","src/read/aranges.rs":"ba3302f87cffb7ee15f48b0530ebd707f45ad056934223078d25ae2a1b034f1c","src/read/cfi.rs":"c1d7977921128721ecebafc56b86dac27a49664f9a0defb6dcfb50c4c4ff4dcf","src/read/dwarf.rs":"17c5daba222a268d48621fbacb451082fdc63891fc356e94fdc3c95616fe3b8b","src/read/endian_reader.rs":"320983a859c2bb0dd44a3e6fae55ff0a84dba3fa80c2edbc64aa8135c44eddf0","src/read/endian_slice.rs":"c3e153a8a786498ee63a2d11b87371c7edb85d0e144242fe887c126250be80e3","src/read/index.rs":"e79b8d591b8e2007a37f5ea85a6d71b69d56ca3739a85cf7bf361724c5b829fa","src/read/line.rs":"19d38cbd27645885c59c41f7b8e7a509e0be1d701e4b30be13780744384c674b","src/read/lists.rs":"67ca9e1a36a91feb4996d035211de845205212bfda02163685d217818567ff93","src/read/loclists.rs":"857701a9e86aee809bfca3fd661e283b4f05038764dfc9c3cb1a349acc00bc47","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"35ba9167bbfbe38a82996fc343f79e22d6c83eba9daff6d048587ef6feb6baaa","src/read/op.rs":"2305f90e6cdf48ed7fbe67814d99d7a14662d030515b51aaad198807c13433e3","src/read/pubnames.rs":"ed752ee1a7017e6d3be42d81e4ddaaac960ef08081463a19106c9f041526d4a3","src/read/pubtypes.rs":"5e75b32c0923e827aff0bb2db456797a0e8d38ba46be992558a7990b3196bcf5","src/read/reader.rs":"3e8ce504b651e14b839ef63c080c705ba7aef956ac2c7a74e298c015b791e2d2","src/read/rnglists.rs":"4ec166e73fdfc85efa97b3b005b514bb64d454edb1ba0f201c45df4f2127e745","src/read/str.rs":"4c2f50014451621fea45969cd313f6840fcd3a99d7a2d081bfa1f8e0e434133a","src/read/unit.rs":"60ecb8099d9386d85119b45ab92d628f3d3409b04669489b76e732d338b27f65","src/read/util.rs":"61e41212f1c8336988c9a7a1523c2913af8c8a66d2dd59d3631ba179e801e3bd","src/read/value.rs":"5ce8ef633f5af47bd367a5e4cde2c71bcef297c91a8d567192e460c890aef6de","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"e274b8b28f4e58c49ce530a5c630a26c6074be12f0faffed09709b700748afd7","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"73bf3bab57433fe1dc891c48303cbc4e482306a1b9425f3483ad2985a9676ee9","src/write/loc.rs":"5c1f8d97d8e871a6663ad704f5e15694bddd54b85f2d801b52a520522f1258fd","src/write/mod.rs":"d8aa1da854cdee629d470d00d87e00dc6998e4bec1ca951f8d2f277730ab9d69","src/write/op.rs":"08fec7613aaa9061aae6e31d8b49933c812a6b7609f69e611a2a953af09aa18a","src/write/range.rs":"259e21e32bebbf7cdd8027d401862dee95cb5111e45bc4ff30bf54e3306d0262","src/write/section.rs":"effefef0d5e4557cb099431a20a7304392e6bf4ce04941d72b8bd2df9100e297","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"4a96a5f302b3bdf03faf3ff404bbcbed60d295080853ab8dabff5efa53f9ba37","src/write/writer.rs":"7d5dd07b82ec3becebb060c106d4ea697cbd8b9b64a5de78403511a5244e08b1"},"package":"4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"}
|
1022
vendor/gimli/CHANGELOG.md
vendored
Normal file
1022
vendor/gimli/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
109
vendor/gimli/Cargo.toml
vendored
Normal file
109
vendor/gimli/Cargo.toml
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
# 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 are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.60"
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
include = [
|
||||
"/CHANGELOG.md",
|
||||
"/Cargo.toml",
|
||||
"/LICENSE-APACHE",
|
||||
"/LICENSE-MIT",
|
||||
"/README.md",
|
||||
"/src",
|
||||
]
|
||||
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 = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/gimli-rs/gimli"
|
||||
resolver = "2"
|
||||
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
split-debuginfo = "packed"
|
||||
|
||||
[profile.test]
|
||||
split-debuginfo = "packed"
|
||||
|
||||
[dependencies.alloc]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-alloc"
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
version = "0.1.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
|
||||
[dependencies.fallible-iterator]
|
||||
version = "0.3.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "2.0.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.stable_deref_trait]
|
||||
version = "1.1.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.test-assembler]
|
||||
version = "0.1.3"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"read-all",
|
||||
"write",
|
||||
]
|
||||
endian-reader = [
|
||||
"read",
|
||||
"dep:stable_deref_trait",
|
||||
]
|
||||
fallible-iterator = ["dep:fallible-iterator"]
|
||||
read = ["read-core"]
|
||||
read-all = [
|
||||
"read",
|
||||
"std",
|
||||
"fallible-iterator",
|
||||
"endian-reader",
|
||||
]
|
||||
read-core = []
|
||||
rustc-dep-of-std = [
|
||||
"dep:core",
|
||||
"dep:alloc",
|
||||
"dep:compiler_builtins",
|
||||
]
|
||||
std = [
|
||||
"fallible-iterator?/std",
|
||||
"stable_deref_trait?/std",
|
||||
]
|
||||
write = ["dep:indexmap"]
|
201
vendor/gimli/LICENSE-APACHE
vendored
Normal file
201
vendor/gimli/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
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.
|
25
vendor/gimli/LICENSE-MIT
vendored
Normal file
25
vendor/gimli/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (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.
|
81
vendor/gimli/README.md
vendored
Normal file
81
vendor/gimli/README.md
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
# `gimli`
|
||||
|
||||
[ ](https://crates.io/crates/gimli)
|
||||
[](https://docs.rs/gimli/)
|
||||
[](https://github.com/gimli-rs/gimli/actions)
|
||||
[](https://coveralls.io/github/gimli-rs/gimli?branch=master)
|
||||
|
||||
`gimli` is a library for reading and writing the
|
||||
[DWARF debugging format](https://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 macOS.
|
||||
|
||||
* Unsure which object file parser to use? Try the cross-platform
|
||||
[`object`](https://github.com/gimli-rs/object) crate. See the
|
||||
[`gimli-examples`](./crates/examples/src/bin) crate for usage with `gimli`.
|
||||
|
||||
## Install
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
gimli = "0.28.1"
|
||||
```
|
||||
|
||||
The minimum supported Rust version is:
|
||||
|
||||
* 1.60.0 for the `read` feature and its dependencies.
|
||||
* 1.65.0 for other features.
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Documentation on docs.rs](https://docs.rs/gimli/)
|
||||
|
||||
* Example programs:
|
||||
|
||||
* [A simple `.debug_info` parser](./crates/examples/src/bin/simple.rs)
|
||||
|
||||
* [A simple `.debug_line` parser](./crates/examples/src/bin/simple_line.rs)
|
||||
|
||||
* [A `dwarfdump` clone](./crates/examples/src/bin/dwarfdump.rs)
|
||||
|
||||
* [An `addr2line` clone](https://github.com/gimli-rs/addr2line)
|
||||
|
||||
* [`ddbug`](https://github.com/gimli-rs/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`](./crates/examples/src/bin/dwarf-validate.rs), a program to validate the
|
||||
integrity of some DWARF and its references between sections and compilation
|
||||
units.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://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.
|
839
vendor/gimli/src/arch.rs
vendored
Normal file
839
vendor/gimli/src/arch.rs
vendored
Normal file
@ -0,0 +1,839 @@
|
||||
use crate::common::Register;
|
||||
|
||||
macro_rules! registers {
|
||||
($struct_name:ident, { $($name:ident = ($val:expr, $disp:expr)),+ $(,)? }
|
||||
$(, aliases { $($alias_name:ident = ($alias_val:expr, $alias_disp:expr)),+ $(,)? })?) => {
|
||||
#[allow(missing_docs)]
|
||||
impl $struct_name {
|
||||
$(
|
||||
pub const $name: Register = Register($val);
|
||||
)+
|
||||
$(
|
||||
$(pub const $alias_name: Register = Register($alias_val);)+
|
||||
)*
|
||||
}
|
||||
|
||||
impl $struct_name {
|
||||
/// The name of a register, or `None` if the register number is unknown.
|
||||
///
|
||||
/// Only returns the primary name for registers that alias with others.
|
||||
pub fn register_name(register: Register) -> Option<&'static str> {
|
||||
match register {
|
||||
$(
|
||||
Self::$name => Some($disp),
|
||||
)+
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a register name into a register number.
|
||||
pub fn name_to_register(value: &str) -> Option<Register> {
|
||||
match value {
|
||||
$(
|
||||
$disp => Some(Self::$name),
|
||||
)+
|
||||
$(
|
||||
$($alias_disp => Some(Self::$alias_name),)+
|
||||
)*
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// ARM architecture specific definitions.
|
||||
///
|
||||
/// See [DWARF for the ARM Architecture](
|
||||
/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Arm;
|
||||
|
||||
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"),
|
||||
|
||||
WCGR0 = (104, "wCGR0"),
|
||||
WCGR1 = (105, "wCGR1"),
|
||||
WCGR2 = (106, "wCGR2"),
|
||||
WCGR3 = (107, "wCGR3"),
|
||||
WCGR4 = (108, "wCGR4"),
|
||||
WCGR5 = (109, "wCGR5"),
|
||||
WCGR6 = (110, "wCGR6"),
|
||||
WCGR7 = (111, "wCGR7"),
|
||||
|
||||
WR0 = (112, "wR0"),
|
||||
WR1 = (113, "wR1"),
|
||||
WR2 = (114, "wR2"),
|
||||
WR3 = (115, "wR3"),
|
||||
WR4 = (116, "wR4"),
|
||||
WR5 = (117, "wR5"),
|
||||
WR6 = (118, "wR6"),
|
||||
WR7 = (119, "wR7"),
|
||||
WR8 = (120, "wR8"),
|
||||
WR9 = (121, "wR9"),
|
||||
WR10 = (122, "wR10"),
|
||||
WR11 = (123, "wR11"),
|
||||
WR12 = (124, "wR12"),
|
||||
WR13 = (125, "wR13"),
|
||||
WR14 = (126, "wR14"),
|
||||
WR15 = (127, "wR15"),
|
||||
|
||||
SPSR = (128, "SPSR"),
|
||||
SPSR_FIQ = (129, "SPSR_FIQ"),
|
||||
SPSR_IRQ = (130, "SPSR_IRQ"),
|
||||
SPSR_ABT = (131, "SPSR_ABT"),
|
||||
SPSR_UND = (132, "SPSR_UND"),
|
||||
SPSR_SVC = (133, "SPSR_SVC"),
|
||||
|
||||
RA_AUTH_CODE = (143, "RA_AUTH_CODE"),
|
||||
|
||||
R8_USR = (144, "R8_USR"),
|
||||
R9_USR = (145, "R9_USR"),
|
||||
R10_USR = (146, "R10_USR"),
|
||||
R11_USR = (147, "R11_USR"),
|
||||
R12_USR = (148, "R12_USR"),
|
||||
R13_USR = (149, "R13_USR"),
|
||||
R14_USR = (150, "R14_USR"),
|
||||
|
||||
R8_FIQ = (151, "R8_FIQ"),
|
||||
R9_FIQ = (152, "R9_FIQ"),
|
||||
R10_FIQ = (153, "R10_FIQ"),
|
||||
R11_FIQ = (154, "R11_FIQ"),
|
||||
R12_FIQ = (155, "R12_FIQ"),
|
||||
R13_FIQ = (156, "R13_FIQ"),
|
||||
R14_FIQ = (157, "R14_FIQ"),
|
||||
|
||||
R13_IRQ = (158, "R13_IRQ"),
|
||||
R14_IRQ = (159, "R14_IRQ"),
|
||||
|
||||
R13_ABT = (160, "R13_ABT"),
|
||||
R14_ABT = (161, "R14_ABT"),
|
||||
|
||||
R13_UND = (162, "R13_UND"),
|
||||
R14_UND = (163, "R14_UND"),
|
||||
|
||||
R13_SVC = (164, "R13_SVC"),
|
||||
R14_SVC = (165, "R14_SVC"),
|
||||
|
||||
WC0 = (192, "wC0"),
|
||||
WC1 = (193, "wC1"),
|
||||
WC2 = (194, "wC2"),
|
||||
WC3 = (195, "wC3"),
|
||||
WC4 = (196, "wC4"),
|
||||
WC5 = (197, "wC5"),
|
||||
WC6 = (198, "wC6"),
|
||||
WC7 = (199, "wC7"),
|
||||
|
||||
D0 = (256, "D0"),
|
||||
D1 = (257, "D1"),
|
||||
D2 = (258, "D2"),
|
||||
D3 = (259, "D3"),
|
||||
D4 = (260, "D4"),
|
||||
D5 = (261, "D5"),
|
||||
D6 = (262, "D6"),
|
||||
D7 = (263, "D7"),
|
||||
D8 = (264, "D8"),
|
||||
D9 = (265, "D9"),
|
||||
D10 = (266, "D10"),
|
||||
D11 = (267, "D11"),
|
||||
D12 = (268, "D12"),
|
||||
D13 = (269, "D13"),
|
||||
D14 = (270, "D14"),
|
||||
D15 = (271, "D15"),
|
||||
D16 = (272, "D16"),
|
||||
D17 = (273, "D17"),
|
||||
D18 = (274, "D18"),
|
||||
D19 = (275, "D19"),
|
||||
D20 = (276, "D20"),
|
||||
D21 = (277, "D21"),
|
||||
D22 = (278, "D22"),
|
||||
D23 = (279, "D23"),
|
||||
D24 = (280, "D24"),
|
||||
D25 = (281, "D25"),
|
||||
D26 = (282, "D26"),
|
||||
D27 = (283, "D27"),
|
||||
D28 = (284, "D28"),
|
||||
D29 = (285, "D29"),
|
||||
D30 = (286, "D30"),
|
||||
D31 = (287, "D31"),
|
||||
|
||||
TPIDRURO = (320, "TPIDRURO"),
|
||||
TPIDRURW = (321, "TPIDRURW"),
|
||||
TPIDPR = (322, "TPIDPR"),
|
||||
HTPIDPR = (323, "HTPIDPR"),
|
||||
},
|
||||
aliases {
|
||||
SP = (13, "SP"),
|
||||
LR = (14, "LR"),
|
||||
PC = (15, "PC"),
|
||||
|
||||
ACC0 = (104, "ACC0"),
|
||||
ACC1 = (105, "ACC1"),
|
||||
ACC2 = (106, "ACC2"),
|
||||
ACC3 = (107, "ACC3"),
|
||||
ACC4 = (108, "ACC4"),
|
||||
ACC5 = (109, "ACC5"),
|
||||
ACC6 = (110, "ACC6"),
|
||||
ACC7 = (111, "ACC7"),
|
||||
|
||||
S0 = (256, "S0"),
|
||||
S1 = (256, "S1"),
|
||||
S2 = (257, "S2"),
|
||||
S3 = (257, "S3"),
|
||||
S4 = (258, "S4"),
|
||||
S5 = (258, "S5"),
|
||||
S6 = (259, "S6"),
|
||||
S7 = (259, "S7"),
|
||||
S8 = (260, "S8"),
|
||||
S9 = (260, "S9"),
|
||||
S10 = (261, "S10"),
|
||||
S11 = (261, "S11"),
|
||||
S12 = (262, "S12"),
|
||||
S13 = (262, "S13"),
|
||||
S14 = (263, "S14"),
|
||||
S15 = (263, "S15"),
|
||||
S16 = (264, "S16"),
|
||||
S17 = (264, "S17"),
|
||||
S18 = (265, "S18"),
|
||||
S19 = (265, "S19"),
|
||||
S20 = (266, "S20"),
|
||||
S21 = (266, "S21"),
|
||||
S22 = (267, "S22"),
|
||||
S23 = (267, "S23"),
|
||||
S24 = (268, "S24"),
|
||||
S25 = (268, "S25"),
|
||||
S26 = (269, "S26"),
|
||||
S27 = (269, "S27"),
|
||||
S28 = (270, "S28"),
|
||||
S29 = (270, "S29"),
|
||||
S30 = (271, "S30"),
|
||||
S31 = (271, "S31"),
|
||||
});
|
||||
|
||||
/// ARM 64-bit (AArch64) architecture specific definitions.
|
||||
///
|
||||
/// See [DWARF for the ARM 64-bit Architecture](
|
||||
/// https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AArch64;
|
||||
|
||||
registers!(AArch64, {
|
||||
X0 = (0, "X0"),
|
||||
X1 = (1, "X1"),
|
||||
X2 = (2, "X2"),
|
||||
X3 = (3, "X3"),
|
||||
X4 = (4, "X4"),
|
||||
X5 = (5, "X5"),
|
||||
X6 = (6, "X6"),
|
||||
X7 = (7, "X7"),
|
||||
X8 = (8, "X8"),
|
||||
X9 = (9, "X9"),
|
||||
X10 = (10, "X10"),
|
||||
X11 = (11, "X11"),
|
||||
X12 = (12, "X12"),
|
||||
X13 = (13, "X13"),
|
||||
X14 = (14, "X14"),
|
||||
X15 = (15, "X15"),
|
||||
X16 = (16, "X16"),
|
||||
X17 = (17, "X17"),
|
||||
X18 = (18, "X18"),
|
||||
X19 = (19, "X19"),
|
||||
X20 = (20, "X20"),
|
||||
X21 = (21, "X21"),
|
||||
X22 = (22, "X22"),
|
||||
X23 = (23, "X23"),
|
||||
X24 = (24, "X24"),
|
||||
X25 = (25, "X25"),
|
||||
X26 = (26, "X26"),
|
||||
X27 = (27, "X27"),
|
||||
X28 = (28, "X28"),
|
||||
X29 = (29, "X29"),
|
||||
X30 = (30, "X30"),
|
||||
SP = (31, "SP"),
|
||||
PC = (32, "PC"),
|
||||
ELR_MODE = (33, "ELR_mode"),
|
||||
RA_SIGN_STATE = (34, "RA_SIGN_STATE"),
|
||||
TPIDRRO_EL0 = (35, "TPIDRRO_EL0"),
|
||||
TPIDR_EL0 = (36, "TPIDR_EL0"),
|
||||
TPIDR_EL1 = (37, "TPIDR_EL1"),
|
||||
TPIDR_EL2 = (38, "TPIDR_EL2"),
|
||||
TPIDR_EL3 = (39, "TPIDR_EL3"),
|
||||
|
||||
VG = (46, "VG"),
|
||||
FFR = (47, "FFR"),
|
||||
|
||||
P0 = (48, "P0"),
|
||||
P1 = (49, "P1"),
|
||||
P2 = (50, "P2"),
|
||||
P3 = (51, "P3"),
|
||||
P4 = (52, "P4"),
|
||||
P5 = (53, "P5"),
|
||||
P6 = (54, "P6"),
|
||||
P7 = (55, "P7"),
|
||||
P8 = (56, "P8"),
|
||||
P9 = (57, "P9"),
|
||||
P10 = (58, "P10"),
|
||||
P11 = (59, "P11"),
|
||||
P12 = (60, "P12"),
|
||||
P13 = (61, "P13"),
|
||||
P14 = (62, "P14"),
|
||||
P15 = (63, "P15"),
|
||||
|
||||
V0 = (64, "V0"),
|
||||
V1 = (65, "V1"),
|
||||
V2 = (66, "V2"),
|
||||
V3 = (67, "V3"),
|
||||
V4 = (68, "V4"),
|
||||
V5 = (69, "V5"),
|
||||
V6 = (70, "V6"),
|
||||
V7 = (71, "V7"),
|
||||
V8 = (72, "V8"),
|
||||
V9 = (73, "V9"),
|
||||
V10 = (74, "V10"),
|
||||
V11 = (75, "V11"),
|
||||
V12 = (76, "V12"),
|
||||
V13 = (77, "V13"),
|
||||
V14 = (78, "V14"),
|
||||
V15 = (79, "V15"),
|
||||
V16 = (80, "V16"),
|
||||
V17 = (81, "V17"),
|
||||
V18 = (82, "V18"),
|
||||
V19 = (83, "V19"),
|
||||
V20 = (84, "V20"),
|
||||
V21 = (85, "V21"),
|
||||
V22 = (86, "V22"),
|
||||
V23 = (87, "V23"),
|
||||
V24 = (88, "V24"),
|
||||
V25 = (89, "V25"),
|
||||
V26 = (90, "V26"),
|
||||
V27 = (91, "V27"),
|
||||
V28 = (92, "V28"),
|
||||
V29 = (93, "V29"),
|
||||
V30 = (94, "V30"),
|
||||
V31 = (95, "V31"),
|
||||
|
||||
Z0 = (96, "Z0"),
|
||||
Z1 = (97, "Z1"),
|
||||
Z2 = (98, "Z2"),
|
||||
Z3 = (99, "Z3"),
|
||||
Z4 = (100, "Z4"),
|
||||
Z5 = (101, "Z5"),
|
||||
Z6 = (102, "Z6"),
|
||||
Z7 = (103, "Z7"),
|
||||
Z8 = (104, "Z8"),
|
||||
Z9 = (105, "Z9"),
|
||||
Z10 = (106, "Z10"),
|
||||
Z11 = (107, "Z11"),
|
||||
Z12 = (108, "Z12"),
|
||||
Z13 = (109, "Z13"),
|
||||
Z14 = (110, "Z14"),
|
||||
Z15 = (111, "Z15"),
|
||||
Z16 = (112, "Z16"),
|
||||
Z17 = (113, "Z17"),
|
||||
Z18 = (114, "Z18"),
|
||||
Z19 = (115, "Z19"),
|
||||
Z20 = (116, "Z20"),
|
||||
Z21 = (117, "Z21"),
|
||||
Z22 = (118, "Z22"),
|
||||
Z23 = (119, "Z23"),
|
||||
Z24 = (120, "Z24"),
|
||||
Z25 = (121, "Z25"),
|
||||
Z26 = (122, "Z26"),
|
||||
Z27 = (123, "Z27"),
|
||||
Z28 = (124, "Z28"),
|
||||
Z29 = (125, "Z29"),
|
||||
Z30 = (126, "Z30"),
|
||||
Z31 = (127, "Z31"),
|
||||
});
|
||||
|
||||
/// LoongArch architecture specific definitions.
|
||||
///
|
||||
/// See [LoongArch ELF psABI specification](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct LoongArch;
|
||||
|
||||
registers!(LoongArch, {
|
||||
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"),
|
||||
R16 = (16, "$r16"),
|
||||
R17 = (17, "$r17"),
|
||||
R18 = (18, "$r18"),
|
||||
R19 = (19, "$r19"),
|
||||
R20 = (20, "$r20"),
|
||||
R21 = (21, "$r21"),
|
||||
R22 = (22, "$r22"),
|
||||
R23 = (23, "$r23"),
|
||||
R24 = (24, "$r24"),
|
||||
R25 = (25, "$r25"),
|
||||
R26 = (26, "$r26"),
|
||||
R27 = (27, "$r27"),
|
||||
R28 = (28, "$r28"),
|
||||
R29 = (29, "$r29"),
|
||||
R30 = (30, "$r30"),
|
||||
R31 = (31, "$r31"),
|
||||
|
||||
F0 = (32, "$f0"),
|
||||
F1 = (33, "$f1"),
|
||||
F2 = (34, "$f2"),
|
||||
F3 = (35, "$f3"),
|
||||
F4 = (36, "$f4"),
|
||||
F5 = (37, "$f5"),
|
||||
F6 = (38, "$f6"),
|
||||
F7 = (39, "$f7"),
|
||||
F8 = (40, "$f8"),
|
||||
F9 = (41, "$f9"),
|
||||
F10 = (42, "$f10"),
|
||||
F11 = (43, "$f11"),
|
||||
F12 = (44, "$f12"),
|
||||
F13 = (45, "$f13"),
|
||||
F14 = (46, "$f14"),
|
||||
F15 = (47, "$f15"),
|
||||
F16 = (48, "$f16"),
|
||||
F17 = (49, "$f17"),
|
||||
F18 = (50, "$f18"),
|
||||
F19 = (51, "$f19"),
|
||||
F20 = (52, "$f20"),
|
||||
F21 = (53, "$f21"),
|
||||
F22 = (54, "$f22"),
|
||||
F23 = (55, "$f23"),
|
||||
F24 = (56, "$f24"),
|
||||
F25 = (57, "$f25"),
|
||||
F26 = (58, "$f26"),
|
||||
F27 = (59, "$f27"),
|
||||
F28 = (60, "$f28"),
|
||||
F29 = (61, "$f29"),
|
||||
F30 = (62, "$f30"),
|
||||
F31 = (63, "$f31"),
|
||||
FCC0 = (64, "$fcc0"),
|
||||
FCC1 = (65, "$fcc1"),
|
||||
FCC2 = (66, "$fcc2"),
|
||||
FCC3 = (67, "$fcc3"),
|
||||
FCC4 = (68, "$fcc4"),
|
||||
FCC5 = (69, "$fcc5"),
|
||||
FCC6 = (70, "$fcc6"),
|
||||
FCC7 = (71, "$fcc7"),
|
||||
},
|
||||
aliases {
|
||||
ZERO = (0, "$zero"),
|
||||
RA = (1, "$ra"),
|
||||
TP = (2, "$tp"),
|
||||
SP = (3, "$sp"),
|
||||
A0 = (4, "$a0"),
|
||||
A1 = (5, "$a1"),
|
||||
A2 = (6, "$a2"),
|
||||
A3 = (7, "$a3"),
|
||||
A4 = (8, "$a4"),
|
||||
A5 = (9, "$a5"),
|
||||
A6 = (10, "$a6"),
|
||||
A7 = (11, "$a7"),
|
||||
T0 = (12, "$t0"),
|
||||
T1 = (13, "$t1"),
|
||||
T2 = (14, "$t2"),
|
||||
T3 = (15, "$t3"),
|
||||
T4 = (16, "$t4"),
|
||||
T5 = (17, "$t5"),
|
||||
T6 = (18, "$t6"),
|
||||
T7 = (19, "$t7"),
|
||||
T8 = (20, "$t8"),
|
||||
FP = (22, "$fp"),
|
||||
S0 = (23, "$s0"),
|
||||
S1 = (24, "$s1"),
|
||||
S2 = (25, "$s2"),
|
||||
S3 = (26, "$s3"),
|
||||
S4 = (27, "$s4"),
|
||||
S5 = (28, "$s5"),
|
||||
S6 = (29, "$s6"),
|
||||
S7 = (30, "$s7"),
|
||||
S8 = (31, "$s8"),
|
||||
|
||||
FA0 = (32, "$fa0"),
|
||||
FA1 = (33, "$fa1"),
|
||||
FA2 = (34, "$fa2"),
|
||||
FA3 = (35, "$fa3"),
|
||||
FA4 = (36, "$fa4"),
|
||||
FA5 = (37, "$fa5"),
|
||||
FA6 = (38, "$fa6"),
|
||||
FA7 = (39, "$fa7"),
|
||||
FT0 = (40, "$ft0"),
|
||||
FT1 = (41, "$ft1"),
|
||||
FT2 = (42, "$ft2"),
|
||||
FT3 = (43, "$ft3"),
|
||||
FT4 = (44, "$ft4"),
|
||||
FT5 = (45, "$ft5"),
|
||||
FT6 = (46, "$ft6"),
|
||||
FT7 = (47, "$ft7"),
|
||||
FT8 = (48, "$ft8"),
|
||||
FT9 = (49, "$ft9"),
|
||||
FT10 = (50, "$ft10"),
|
||||
FT11 = (51, "$ft11"),
|
||||
FT12 = (52, "$ft12"),
|
||||
FT13 = (53, "$ft13"),
|
||||
FT14 = (54, "$ft14"),
|
||||
FT15 = (55, "$ft15"),
|
||||
FS0 = (56, "$fs0"),
|
||||
FS1 = (57, "$fs1"),
|
||||
FS2 = (58, "$fs2"),
|
||||
FS3 = (59, "$fs3"),
|
||||
FS4 = (60, "$fs4"),
|
||||
FS5 = (61, "$fs5"),
|
||||
FS6 = (62, "$fs6"),
|
||||
FS7 = (63, "$fs7"),
|
||||
});
|
||||
|
||||
/// RISC-V architecture specific definitions.
|
||||
///
|
||||
/// See [RISC-V ELF psABI specification](https://github.com/riscv/riscv-elf-psabi-doc).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RiscV;
|
||||
|
||||
registers!(RiscV, {
|
||||
X0 = (0, "x0"),
|
||||
X1 = (1, "x1"),
|
||||
X2 = (2, "x2"),
|
||||
X3 = (3, "x3"),
|
||||
X4 = (4, "x4"),
|
||||
X5 = (5, "x5"),
|
||||
X6 = (6, "x6"),
|
||||
X7 = (7, "x7"),
|
||||
X8 = (8, "x8"),
|
||||
X9 = (9, "x9"),
|
||||
X10 = (10, "x10"),
|
||||
X11 = (11, "x11"),
|
||||
X12 = (12, "x12"),
|
||||
X13 = (13, "x13"),
|
||||
X14 = (14, "x14"),
|
||||
X15 = (15, "x15"),
|
||||
X16 = (16, "x16"),
|
||||
X17 = (17, "x17"),
|
||||
X18 = (18, "x18"),
|
||||
X19 = (19, "x19"),
|
||||
X20 = (20, "x20"),
|
||||
X21 = (21, "x21"),
|
||||
X22 = (22, "x22"),
|
||||
X23 = (23, "x23"),
|
||||
X24 = (24, "x24"),
|
||||
X25 = (25, "x25"),
|
||||
X26 = (26, "x26"),
|
||||
X27 = (27, "x27"),
|
||||
X28 = (28, "x28"),
|
||||
X29 = (29, "x29"),
|
||||
X30 = (30, "x30"),
|
||||
X31 = (31, "x31"),
|
||||
|
||||
F0 = (32, "f0"),
|
||||
F1 = (33, "f1"),
|
||||
F2 = (34, "f2"),
|
||||
F3 = (35, "f3"),
|
||||
F4 = (36, "f4"),
|
||||
F5 = (37, "f5"),
|
||||
F6 = (38, "f6"),
|
||||
F7 = (39, "f7"),
|
||||
F8 = (40, "f8"),
|
||||
F9 = (41, "f9"),
|
||||
F10 = (42, "f10"),
|
||||
F11 = (43, "f11"),
|
||||
F12 = (44, "f12"),
|
||||
F13 = (45, "f13"),
|
||||
F14 = (46, "f14"),
|
||||
F15 = (47, "f15"),
|
||||
F16 = (48, "f16"),
|
||||
F17 = (49, "f17"),
|
||||
F18 = (50, "f18"),
|
||||
F19 = (51, "f19"),
|
||||
F20 = (52, "f20"),
|
||||
F21 = (53, "f21"),
|
||||
F22 = (54, "f22"),
|
||||
F23 = (55, "f23"),
|
||||
F24 = (56, "f24"),
|
||||
F25 = (57, "f25"),
|
||||
F26 = (58, "f26"),
|
||||
F27 = (59, "f27"),
|
||||
F28 = (60, "f28"),
|
||||
F29 = (61, "f29"),
|
||||
F30 = (62, "f30"),
|
||||
F31 = (63, "f31"),
|
||||
},
|
||||
aliases {
|
||||
ZERO = (0, "zero"),
|
||||
RA = (1, "ra"),
|
||||
SP = (2, "sp"),
|
||||
GP = (3, "gp"),
|
||||
TP = (4, "tp"),
|
||||
T0 = (5, "t0"),
|
||||
T1 = (6, "t1"),
|
||||
T2 = (7, "t2"),
|
||||
S0 = (8, "s0"),
|
||||
S1 = (9, "s1"),
|
||||
A0 = (10, "a0"),
|
||||
A1 = (11, "a1"),
|
||||
A2 = (12, "a2"),
|
||||
A3 = (13, "a3"),
|
||||
A4 = (14, "a4"),
|
||||
A5 = (15, "a5"),
|
||||
A6 = (16, "a6"),
|
||||
A7 = (17, "a7"),
|
||||
S2 = (18, "s2"),
|
||||
S3 = (19, "s3"),
|
||||
S4 = (20, "s4"),
|
||||
S5 = (21, "s5"),
|
||||
S6 = (22, "s6"),
|
||||
S7 = (23, "s7"),
|
||||
S8 = (24, "s8"),
|
||||
S9 = (25, "s9"),
|
||||
S10 = (26, "s10"),
|
||||
S11 = (27, "s11"),
|
||||
T3 = (28, "t3"),
|
||||
T4 = (29, "t4"),
|
||||
T5 = (30, "t5"),
|
||||
T6 = (31, "t6"),
|
||||
|
||||
FT0 = (32, "ft0"),
|
||||
FT1 = (33, "ft1"),
|
||||
FT2 = (34, "ft2"),
|
||||
FT3 = (35, "ft3"),
|
||||
FT4 = (36, "ft4"),
|
||||
FT5 = (37, "ft5"),
|
||||
FT6 = (38, "ft6"),
|
||||
FT7 = (39, "ft7"),
|
||||
FS0 = (40, "fs0"),
|
||||
FS1 = (41, "fs1"),
|
||||
FA0 = (42, "fa0"),
|
||||
FA1 = (43, "fa1"),
|
||||
FA2 = (44, "fa2"),
|
||||
FA3 = (45, "fa3"),
|
||||
FA4 = (46, "fa4"),
|
||||
FA5 = (47, "fa5"),
|
||||
FA6 = (48, "fa6"),
|
||||
FA7 = (49, "fa7"),
|
||||
FS2 = (50, "fs2"),
|
||||
FS3 = (51, "fs3"),
|
||||
FS4 = (52, "fs4"),
|
||||
FS5 = (53, "fs5"),
|
||||
FS6 = (54, "fs6"),
|
||||
FS7 = (55, "fs7"),
|
||||
FS8 = (56, "fs8"),
|
||||
FS9 = (57, "fs9"),
|
||||
FS10 = (58, "fs10"),
|
||||
FS11 = (59, "fs11"),
|
||||
FT8 = (60, "ft8"),
|
||||
FT9 = (61, "ft9"),
|
||||
FT10 = (62, "ft10"),
|
||||
FT11 = (63, "ft11"),
|
||||
});
|
||||
|
||||
/// 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"),
|
||||
});
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn test_aarch64_registers() {
|
||||
use super::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
let mut names = HashSet::new();
|
||||
for n in (0..=39).chain(46..=127) {
|
||||
let name = AArch64::register_name(Register(n))
|
||||
.unwrap_or_else(|| panic!("Register {} should have a name.", n));
|
||||
assert!(names.insert(name));
|
||||
}
|
||||
}
|
||||
}
|
391
vendor/gimli/src/common.rs
vendored
Normal file
391
vendor/gimli/src/common.rs
vendored
Normal file
@ -0,0 +1,391 @@
|
||||
/// 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 = 8,
|
||||
/// 32-bit DWARF
|
||||
Dwarf32 = 4,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Which vendor extensions to support.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Vendor {
|
||||
/// A default set of extensions, including some common GNU extensions.
|
||||
Default,
|
||||
/// AAarch64 extensions.
|
||||
AArch64,
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
// `address_size` and `format` are used more often than `version`, so keep
|
||||
// them first.
|
||||
#[repr(C)]
|
||||
pub struct Encoding {
|
||||
/// The size of an address.
|
||||
pub address_size: u8,
|
||||
|
||||
// The size of a segment selector.
|
||||
// TODO: pub segment_size: u8,
|
||||
/// Whether the DWARF format is 32- or 64-bit.
|
||||
pub format: Format,
|
||||
|
||||
/// The DWARF version of the header.
|
||||
pub version: u16,
|
||||
}
|
||||
|
||||
/// 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<T = usize>(pub T);
|
||||
|
||||
/// An offset to a set of entries in the `.debug_addr` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugAddrBase<T = usize>(pub T);
|
||||
|
||||
/// An index into a set of addresses in the `.debug_addr` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugAddrIndex<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_aranges` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugArangesOffset<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_info` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
pub struct DebugInfoOffset<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_line` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugLineOffset<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_line_str` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugLineStrOffset<T = usize>(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<T = usize>(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<T = usize>(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<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_macinfo` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DebugMacinfoOffset<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_macro` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DebugMacroOffset<T = usize>(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.
|
||||
///
|
||||
/// If this is from a DWARF 4 DWO file, then it must additionally be offset by the
|
||||
/// value of `DW_AT_GNU_ranges_base`. You can use `Dwarf::ranges_offset_from_raw` to do this.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RawRangeListsOffset<T = usize>(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<T = usize>(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<T = usize>(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<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_str` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugStrOffset<T = usize>(pub T);
|
||||
|
||||
/// An offset to a set of entries in the `.debug_str_offsets` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugStrOffsetsBase<T = usize>(pub T);
|
||||
|
||||
/// An index into a set of entries in the `.debug_str_offsets` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DebugStrOffsetsIndex<T = usize>(pub T);
|
||||
|
||||
/// An offset into the `.debug_types` section.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
pub struct DebugTypesOffset<T = usize>(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<T = usize>(pub T);
|
||||
|
||||
impl<T> From<T> for DebugFrameOffset<T> {
|
||||
#[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<T = usize>(pub T);
|
||||
|
||||
impl<T> From<T> for EhFrameOffset<T> {
|
||||
#[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<T = usize> {
|
||||
/// An offset into the `.debug_info` section.
|
||||
DebugInfoOffset(DebugInfoOffset<T>),
|
||||
/// An offset into the `.debug_types` section.
|
||||
DebugTypesOffset(DebugTypesOffset<T>),
|
||||
}
|
||||
|
||||
impl<T> From<DebugInfoOffset<T>> for UnitSectionOffset<T> {
|
||||
fn from(offset: DebugInfoOffset<T>) -> Self {
|
||||
UnitSectionOffset::DebugInfoOffset(offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<DebugTypesOffset<T>> for UnitSectionOffset<T> {
|
||||
fn from(offset: DebugTypesOffset<T>) -> Self {
|
||||
UnitSectionOffset::DebugTypesOffset(offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UnitSectionOffset<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
/// Returns the `DebugInfoOffset` inside, or `None` otherwise.
|
||||
pub fn as_debug_info_offset(&self) -> Option<DebugInfoOffset<T>> {
|
||||
match self {
|
||||
UnitSectionOffset::DebugInfoOffset(offset) => Some(offset.clone()),
|
||||
UnitSectionOffset::DebugTypesOffset(_) => None,
|
||||
}
|
||||
}
|
||||
/// Returns the `DebugTypesOffset` inside, or `None` otherwise.
|
||||
pub fn as_debug_types_offset(&self) -> Option<DebugTypesOffset<T>> {
|
||||
match self {
|
||||
UnitSectionOffset::DebugInfoOffset(_) => None,
|
||||
UnitSectionOffset::DebugTypesOffset(offset) => Some(offset.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_cu_index` section.
|
||||
DebugCuIndex,
|
||||
/// 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_macro` section.
|
||||
DebugMacro,
|
||||
/// 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_tu_index` section.
|
||||
DebugTuIndex,
|
||||
/// 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::DebugCuIndex => ".debug_cu_index",
|
||||
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::DebugMacro => ".debug_macro",
|
||||
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::DebugTuIndex => ".debug_tu_index",
|
||||
SectionId::DebugTypes => ".debug_types",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the ELF section name for this kind, when found in a .dwo or .dwp file.
|
||||
pub fn dwo_name(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
SectionId::DebugAbbrev => ".debug_abbrev.dwo",
|
||||
SectionId::DebugCuIndex => ".debug_cu_index",
|
||||
SectionId::DebugInfo => ".debug_info.dwo",
|
||||
SectionId::DebugLine => ".debug_line.dwo",
|
||||
// The debug_loc section can be present in the dwo when using the
|
||||
// GNU split-dwarf extension to DWARF4.
|
||||
SectionId::DebugLoc => ".debug_loc.dwo",
|
||||
SectionId::DebugLocLists => ".debug_loclists.dwo",
|
||||
SectionId::DebugMacro => ".debug_macro.dwo",
|
||||
SectionId::DebugRngLists => ".debug_rnglists.dwo",
|
||||
SectionId::DebugStr => ".debug_str.dwo",
|
||||
SectionId::DebugStrOffsets => ".debug_str_offsets.dwo",
|
||||
SectionId::DebugTuIndex => ".debug_tu_index",
|
||||
SectionId::DebugTypes => ".debug_types.dwo",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the XCOFF section name for this kind.
|
||||
pub fn xcoff_name(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
SectionId::DebugAbbrev => ".dwabrev",
|
||||
SectionId::DebugAranges => ".dwarnge",
|
||||
SectionId::DebugFrame => ".dwframe",
|
||||
SectionId::DebugInfo => ".dwinfo",
|
||||
SectionId::DebugLine => ".dwline",
|
||||
SectionId::DebugLoc => ".dwloc",
|
||||
SectionId::DebugMacinfo => ".dwmac",
|
||||
SectionId::DebugPubNames => ".dwpbnms",
|
||||
SectionId::DebugPubTypes => ".dwpbtyp",
|
||||
SectionId::DebugRanges => ".dwrnges",
|
||||
SectionId::DebugStr => ".dwstr",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An optionally-provided implementation-defined compilation unit ID to enable
|
||||
/// split DWARF and linking a split compilation unit back together.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DwoId(pub u64);
|
||||
|
||||
/// The "type" of file with DWARF debugging information. This determines, among other things,
|
||||
/// which files DWARF sections should be loaded from.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DwarfFileType {
|
||||
/// A normal executable or object file.
|
||||
Main,
|
||||
/// A .dwo split DWARF file.
|
||||
Dwo,
|
||||
// TODO: Supplementary files, .dwps?
|
||||
}
|
||||
|
||||
impl Default for DwarfFileType {
|
||||
fn default() -> Self {
|
||||
DwarfFileType::Main
|
||||
}
|
||||
}
|
1435
vendor/gimli/src/constants.rs
vendored
Normal file
1435
vendor/gimli/src/constants.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
256
vendor/gimli/src/endianity.rs
vendored
Normal file
256
vendor/gimli/src/endianity.rs
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
//! Types for compile-time and run-time endianity.
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::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 {
|
||||
let bytes: &[u8; 2] = buf[..2].try_into().unwrap();
|
||||
if self.is_big_endian() {
|
||||
u16::from_be_bytes(*bytes)
|
||||
} else {
|
||||
u16::from_le_bytes(*bytes)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an unsigned 32 bit integer from `buf`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when `buf.len() < 4`.
|
||||
#[inline]
|
||||
fn read_u32(self, buf: &[u8]) -> u32 {
|
||||
let bytes: &[u8; 4] = buf[..4].try_into().unwrap();
|
||||
if self.is_big_endian() {
|
||||
u32::from_be_bytes(*bytes)
|
||||
} else {
|
||||
u32::from_le_bytes(*bytes)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an unsigned 64 bit integer from `buf`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when `buf.len() < 8`.
|
||||
#[inline]
|
||||
fn read_u64(self, buf: &[u8]) -> u64 {
|
||||
let bytes: &[u8; 8] = buf[..8].try_into().unwrap();
|
||||
if self.is_big_endian() {
|
||||
u64::from_be_bytes(*bytes)
|
||||
} else {
|
||||
u64::from_le_bytes(*bytes)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
let mut tmp = [0; 8];
|
||||
if self.is_big_endian() {
|
||||
tmp[8 - buf.len()..].copy_from_slice(buf);
|
||||
} else {
|
||||
tmp[..buf.len()].copy_from_slice(buf);
|
||||
}
|
||||
self.read_u64(&tmp)
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
let bytes = if self.is_big_endian() {
|
||||
n.to_be_bytes()
|
||||
} else {
|
||||
n.to_le_bytes()
|
||||
};
|
||||
buf[..2].copy_from_slice(&bytes);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
let bytes = if self.is_big_endian() {
|
||||
n.to_be_bytes()
|
||||
} else {
|
||||
n.to_le_bytes()
|
||||
};
|
||||
buf[..4].copy_from_slice(&bytes);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
let bytes = if self.is_big_endian() {
|
||||
n.to_be_bytes()
|
||||
} else {
|
||||
n.to_le_bytes()
|
||||
};
|
||||
buf[..8].copy_from_slice(&bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
612
vendor/gimli/src/leb128.rs
vendored
Normal file
612
vendor/gimli/src/leb128.rs
vendored
Normal file
@ -0,0 +1,612 @@
|
||||
//! 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:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(all(feature = "read", feature = "write"))] {
|
||||
//! 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:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(all(feature = "read", feature = "write"))] {
|
||||
//! 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);
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
const CONTINUATION_BIT: u8 = 1 << 7;
|
||||
#[cfg(feature = "read-core")]
|
||||
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(core::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-core")]
|
||||
pub mod read {
|
||||
use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT};
|
||||
use crate::read::{Error, Reader, Result};
|
||||
|
||||
/// Read bytes until the LEB128 continuation bit is not set.
|
||||
pub fn skip<R: Reader>(r: &mut R) -> Result<()> {
|
||||
loop {
|
||||
let byte = r.read_u8()?;
|
||||
if byte & CONTINUATION_BIT == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read an unsigned LEB128 number from the given `Reader` and
|
||||
/// return it or an error if reading failed.
|
||||
pub fn unsigned<R: Reader>(r: &mut R) -> Result<u64> {
|
||||
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 an LEB128 u16 from the given `Reader` and
|
||||
/// return it or an error if reading failed.
|
||||
pub fn u16<R: Reader>(r: &mut R) -> Result<u16> {
|
||||
let byte = r.read_u8()?;
|
||||
let mut result = u16::from(low_bits_of_byte(byte));
|
||||
if byte & CONTINUATION_BIT == 0 {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let byte = r.read_u8()?;
|
||||
result |= u16::from(low_bits_of_byte(byte)) << 7;
|
||||
if byte & CONTINUATION_BIT == 0 {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let byte = r.read_u8()?;
|
||||
if byte > 0x03 {
|
||||
return Err(Error::BadUnsignedLeb128);
|
||||
}
|
||||
result += u16::from(byte) << 14;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Read a signed LEB128 number from the given `Reader` and
|
||||
/// return it or an error if reading failed.
|
||||
pub fn signed<R: Reader>(r: &mut R) -> Result<i64> {
|
||||
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>(w: &mut W, mut val: u64) -> Result<usize, io::Error>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the size of the LEB128 encoding of the given unsigned number.
|
||||
pub fn uleb128_size(mut val: u64) -> usize {
|
||||
let mut size = 0;
|
||||
loop {
|
||||
val >>= 7;
|
||||
size += 1;
|
||||
if val == 0 {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>(w: &mut W, mut val: i64) -> Result<usize, io::Error>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the size of the LEB128 encoding of the given signed number.
|
||||
pub fn sleb128_size(mut val: i64) -> usize {
|
||||
let mut size = 0;
|
||||
loop {
|
||||
val >>= 6;
|
||||
let done = val == 0 || val == -1;
|
||||
val >>= 1;
|
||||
size += 1;
|
||||
if done {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(feature = "read", feature = "write"))]
|
||||
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};
|
||||
|
||||
trait ResultExt {
|
||||
fn map_eof(self, input: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
impl<T> ResultExt for Result<T, Error> {
|
||||
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(), std::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(), std::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(core::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
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u16() {
|
||||
for (buf, val) in [
|
||||
(&[2][..], 2),
|
||||
(&[0x7f][..], 0x7f),
|
||||
(&[0x80, 1][..], 0x80),
|
||||
(&[0x81, 1][..], 0x81),
|
||||
(&[0x82, 1][..], 0x82),
|
||||
(&[0xff, 0x7f][..], 0x3fff),
|
||||
(&[0x80, 0x80, 1][..], 0x4000),
|
||||
(&[0xff, 0xff, 1][..], 0x7fff),
|
||||
(&[0xff, 0xff, 3][..], 0xffff),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
let mut readable = EndianSlice::new(buf, NativeEndian);
|
||||
assert_eq!(*val, read::u16(&mut readable).expect("Should read number"));
|
||||
}
|
||||
|
||||
for buf in [
|
||||
&[0x80][..],
|
||||
&[0x80, 0x80][..],
|
||||
&[0x80, 0x80, 4][..],
|
||||
&[0x80, 0x80, 0x80, 3][..],
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
let mut readable = EndianSlice::new(buf, NativeEndian);
|
||||
assert!(read::u16(&mut readable).is_err(), "{:?}", buf);
|
||||
}
|
||||
}
|
||||
}
|
79
vendor/gimli/src/lib.rs
vendored
Normal file
79
vendor/gimli/src/lib.rs
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
//! `gimli` is a library for reading and writing the
|
||||
//! [DWARF debugging format](https://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.
|
||||
//!
|
||||
//! * `read`: Enabled by default. Enables the `read` module. Use of `std` is
|
||||
//! optional.
|
||||
//!
|
||||
//! * `write`: Enabled by default. Enables the `write` module. Always uses
|
||||
//! the `std` library.
|
||||
#![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)]
|
||||
// Style.
|
||||
#![allow(clippy::bool_to_int_with_if)]
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
#![allow(clippy::comparison_chain)]
|
||||
#![allow(clippy::manual_range_contains)]
|
||||
#![allow(clippy::needless_late_init)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
// False positives with `fallible_iterator`.
|
||||
#![allow(clippy::should_implement_trait)]
|
||||
// False positives.
|
||||
#![allow(clippy::derive_partial_eq_without_eq)]
|
||||
#![no_std]
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(any(feature = "read", feature = "write"))]
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "write"))]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
#[cfg(feature = "endian-reader")]
|
||||
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::*;
|
||||
|
||||
pub mod leb128;
|
||||
|
||||
#[cfg(feature = "read-core")]
|
||||
pub mod read;
|
||||
// For backwards compat.
|
||||
#[cfg(feature = "read-core")]
|
||||
pub use crate::read::*;
|
||||
|
||||
#[cfg(feature = "write")]
|
||||
pub mod write;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_util;
|
1102
vendor/gimli/src/read/abbrev.rs
vendored
Normal file
1102
vendor/gimli/src/read/abbrev.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
128
vendor/gimli/src/read/addr.rs
vendored
Normal file
128
vendor/gimli/src/read/addr.rs
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
use 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<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugAddr<R> {
|
||||
// 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<R::Offset>,
|
||||
index: DebugAddrIndex<R::Offset>,
|
||||
) -> Result<u64> {
|
||||
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<T> DebugAddr<T> {
|
||||
/// 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<Vec<u8>> = 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<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugAddr<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugAddr
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugAddr<R> {
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
660
vendor/gimli/src/read/aranges.rs
vendored
Normal file
660
vendor/gimli/src/read/aranges.rs
vendored
Normal file
@ -0,0 +1,660 @@
|
||||
use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId};
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section};
|
||||
|
||||
/// The `DebugAranges` struct represents the DWARF address range information
|
||||
/// found in the `.debug_aranges` section.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugAranges<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugAranges<EndianSlice<'input, Endian>>
|
||||
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 macOS, 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(section: &'input [u8], endian: Endian) -> Self {
|
||||
DebugAranges {
|
||||
section: EndianSlice::new(section, endian),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugAranges<R> {
|
||||
/// Iterate the sets of entries in the `.debug_aranges` section.
|
||||
///
|
||||
/// Each set of entries belongs to a single unit.
|
||||
pub fn headers(&self) -> ArangeHeaderIter<R> {
|
||||
ArangeHeaderIter {
|
||||
input: self.section.clone(),
|
||||
offset: DebugArangesOffset(R::Offset::from_u8(0)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the header at the given offset.
|
||||
pub fn header(&self, offset: DebugArangesOffset<R::Offset>) -> Result<ArangeHeader<R>> {
|
||||
let mut input = self.section.clone();
|
||||
input.skip(offset.0)?;
|
||||
ArangeHeader::parse(&mut input, offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugAranges<T> {
|
||||
/// Create a `DebugAranges` 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::DebugAranges<Vec<u8>> = 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) -> DebugAranges<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugAranges<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugAranges
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugAranges<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugAranges { section }
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the headers of a `.debug_aranges` section.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArangeHeaderIter<R: Reader> {
|
||||
input: R,
|
||||
offset: DebugArangesOffset<R::Offset>,
|
||||
}
|
||||
|
||||
impl<R: Reader> ArangeHeaderIter<R> {
|
||||
/// Advance the iterator to the next header.
|
||||
pub fn next(&mut self) -> Result<Option<ArangeHeader<R>>> {
|
||||
if self.input.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let len = self.input.len();
|
||||
match ArangeHeader::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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<R: Reader> fallible_iterator::FallibleIterator for ArangeHeaderIter<R> {
|
||||
type Item = ArangeHeader<R>;
|
||||
type Error = Error;
|
||||
|
||||
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
|
||||
ArangeHeaderIter::next(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A header for a set of entries in the `.debug_arange` section.
|
||||
///
|
||||
/// These entries all belong to a single unit.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ArangeHeader<R, Offset = <R as Reader>::Offset>
|
||||
where
|
||||
R: Reader<Offset = Offset>,
|
||||
Offset: ReaderOffset,
|
||||
{
|
||||
offset: DebugArangesOffset<Offset>,
|
||||
encoding: Encoding,
|
||||
length: Offset,
|
||||
debug_info_offset: DebugInfoOffset<Offset>,
|
||||
segment_size: u8,
|
||||
entries: R,
|
||||
}
|
||||
|
||||
impl<R, Offset> ArangeHeader<R, Offset>
|
||||
where
|
||||
R: Reader<Offset = Offset>,
|
||||
Offset: ReaderOffset,
|
||||
{
|
||||
fn parse(input: &mut R, offset: DebugArangesOffset<Offset>) -> Result<Self> {
|
||||
let (length, format) = input.read_initial_length()?;
|
||||
let mut rest = input.split(length)?;
|
||||
|
||||
// Check the version. The DWARF 5 spec says that this is always 2, but version 3
|
||||
// has been observed in the wild, potentially due to a bug; see
|
||||
// https://github.com/gimli-rs/gimli/issues/559 for more information.
|
||||
// lldb allows versions 2 through 5, possibly by mistake.
|
||||
let version = rest.read_u16()?;
|
||||
if version != 2 && version != 3 {
|
||||
return Err(Error::UnknownVersion(u64::from(version)));
|
||||
}
|
||||
|
||||
let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?;
|
||||
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 = address_size
|
||||
.checked_mul(2)
|
||||
.and_then(|x| x.checked_add(segment_size))
|
||||
.ok_or(Error::InvalidAddressRange)?;
|
||||
if tuple_length == 0 {
|
||||
return Err(Error::InvalidAddressRange)?;
|
||||
}
|
||||
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(ArangeHeader {
|
||||
offset,
|
||||
encoding,
|
||||
length,
|
||||
debug_info_offset,
|
||||
segment_size,
|
||||
entries: rest,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the offset of this header within the `.debug_aranges` section.
|
||||
#[inline]
|
||||
pub fn offset(&self) -> DebugArangesOffset<Offset> {
|
||||
self.offset
|
||||
}
|
||||
|
||||
/// Return the length of this set of entries, including the header.
|
||||
#[inline]
|
||||
pub fn length(&self) -> Offset {
|
||||
self.length
|
||||
}
|
||||
|
||||
/// Return the encoding parameters for this set of entries.
|
||||
#[inline]
|
||||
pub fn encoding(&self) -> Encoding {
|
||||
self.encoding
|
||||
}
|
||||
|
||||
/// Return the segment size for this set of entries.
|
||||
#[inline]
|
||||
pub fn segment_size(&self) -> u8 {
|
||||
self.segment_size
|
||||
}
|
||||
|
||||
/// Return the offset into the .debug_info section for this set of arange entries.
|
||||
#[inline]
|
||||
pub fn debug_info_offset(&self) -> DebugInfoOffset<Offset> {
|
||||
self.debug_info_offset
|
||||
}
|
||||
|
||||
/// Return the arange entries in this set.
|
||||
#[inline]
|
||||
pub fn entries(&self) -> ArangeEntryIter<R> {
|
||||
ArangeEntryIter {
|
||||
input: self.entries.clone(),
|
||||
encoding: self.encoding,
|
||||
segment_size: self.segment_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<R: Reader> {
|
||||
input: R,
|
||||
encoding: Encoding,
|
||||
segment_size: u8,
|
||||
}
|
||||
|
||||
impl<R: Reader> ArangeEntryIter<R> {
|
||||
/// 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<Option<ArangeEntry>> {
|
||||
if self.input.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
match ArangeEntry::parse(&mut self.input, self.encoding, self.segment_size) {
|
||||
Ok(Some(entry)) => Ok(Some(entry)),
|
||||
Ok(None) => {
|
||||
self.input.empty();
|
||||
Ok(None)
|
||||
}
|
||||
Err(e) => {
|
||||
self.input.empty();
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<R: Reader> fallible_iterator::FallibleIterator for ArangeEntryIter<R> {
|
||||
type Item = ArangeEntry;
|
||||
type Error = Error;
|
||||
|
||||
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
|
||||
ArangeEntryIter::next(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A single parsed arange.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ArangeEntry {
|
||||
segment: Option<u64>,
|
||||
address: u64,
|
||||
length: u64,
|
||||
}
|
||||
|
||||
impl ArangeEntry {
|
||||
/// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
|
||||
fn parse<R: Reader>(
|
||||
input: &mut R,
|
||||
encoding: Encoding,
|
||||
segment_size: u8,
|
||||
) -> Result<Option<Self>> {
|
||||
let address_size = encoding.address_size;
|
||||
|
||||
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) {
|
||||
// This is meant to be a null terminator, but in practice it can occur
|
||||
// before the end, possibly due to a linker omitting a function and
|
||||
// leaving an unrelocated entry.
|
||||
(0, 0, 0) => Self::parse(input, encoding, segment_size),
|
||||
_ => Ok(Some(ArangeEntry {
|
||||
segment: if segment_size != 0 {
|
||||
Some(segment)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
address,
|
||||
length,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the segment selector of this arange.
|
||||
#[inline]
|
||||
pub fn segment(&self) -> Option<u64> {
|
||||
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 range.
|
||||
#[inline]
|
||||
pub fn range(&self) -> Range {
|
||||
Range {
|
||||
begin: self.address,
|
||||
end: self.address.wrapping_add(self.length),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::common::{DebugInfoOffset, Format};
|
||||
use crate::endianity::LittleEndian;
|
||||
use crate::read::EndianSlice;
|
||||
|
||||
#[test]
|
||||
fn test_iterate_headers() {
|
||||
#[rustfmt::skip]
|
||||
let buf = [
|
||||
// 32-bit length = 28.
|
||||
0x1c, 0x00, 0x00, 0x00,
|
||||
// Version.
|
||||
0x02, 0x00,
|
||||
// Offset.
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
// Address size.
|
||||
0x04,
|
||||
// Segment size.
|
||||
0x00,
|
||||
// Dummy padding and arange tuples.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// 32-bit length = 36.
|
||||
0x24, 0x00, 0x00, 0x00,
|
||||
// Version.
|
||||
0x02, 0x00,
|
||||
// Offset.
|
||||
0x11, 0x12, 0x13, 0x14,
|
||||
// Address size.
|
||||
0x04,
|
||||
// Segment size.
|
||||
0x00,
|
||||
// Dummy padding and arange tuples.
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
let debug_aranges = DebugAranges::new(&buf, LittleEndian);
|
||||
let mut headers = debug_aranges.headers();
|
||||
|
||||
let header = headers
|
||||
.next()
|
||||
.expect("should parse header ok")
|
||||
.expect("should have a header");
|
||||
assert_eq!(header.offset(), DebugArangesOffset(0));
|
||||
assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x0403_0201));
|
||||
|
||||
let header = headers
|
||||
.next()
|
||||
.expect("should parse header ok")
|
||||
.expect("should have a header");
|
||||
assert_eq!(header.offset(), DebugArangesOffset(0x20));
|
||||
assert_eq!(header.debug_info_offset(), DebugInfoOffset(0x1413_1211));
|
||||
}
|
||||
|
||||
#[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 header =
|
||||
ArangeHeader::parse(rest, DebugArangesOffset(0x10)).expect("should parse header ok");
|
||||
|
||||
assert_eq!(
|
||||
*rest,
|
||||
EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
|
||||
);
|
||||
assert_eq!(
|
||||
header,
|
||||
ArangeHeader {
|
||||
offset: DebugArangesOffset(0x10),
|
||||
encoding: Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 2,
|
||||
address_size: 8,
|
||||
},
|
||||
length: 0x20,
|
||||
debug_info_offset: DebugInfoOffset(0x0403_0201),
|
||||
segment_size: 4,
|
||||
entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_header_overflow_error() {
|
||||
#[rustfmt::skip]
|
||||
let buf = [
|
||||
// 32-bit length = 32.
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// Version.
|
||||
0x02, 0x00,
|
||||
// Offset.
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
// Address size.
|
||||
0xff,
|
||||
// Segment size.
|
||||
0xff,
|
||||
// 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 error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
|
||||
.expect_err("should fail to parse header");
|
||||
assert_eq!(error, Error::InvalidAddressRange);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_header_div_by_zero_error() {
|
||||
#[rustfmt::skip]
|
||||
let buf = [
|
||||
// 32-bit length = 32.
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
// Version.
|
||||
0x02, 0x00,
|
||||
// Offset.
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
// Address size = 0. Could cause a division by zero if we aren't
|
||||
// careful.
|
||||
0x00,
|
||||
// Segment size.
|
||||
0x00,
|
||||
// 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 error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
|
||||
.expect_err("should fail to parse header");
|
||||
assert_eq!(error, Error::InvalidAddressRange);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_entry_ok() {
|
||||
let encoding = Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 2,
|
||||
address_size: 4,
|
||||
};
|
||||
let segment_size = 0;
|
||||
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
|
||||
let rest = &mut EndianSlice::new(&buf, LittleEndian);
|
||||
let entry =
|
||||
ArangeEntry::parse(rest, encoding, segment_size).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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_entry_segment() {
|
||||
let encoding = Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 2,
|
||||
address_size: 4,
|
||||
};
|
||||
let 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 =
|
||||
ArangeEntry::parse(rest, encoding, segment_size).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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_entry_zero() {
|
||||
let encoding = Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 2,
|
||||
address_size: 4,
|
||||
};
|
||||
let 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 =
|
||||
ArangeEntry::parse(rest, encoding, segment_size).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,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
7823
vendor/gimli/src/read/cfi.rs
vendored
Normal file
7823
vendor/gimli/src/read/cfi.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1210
vendor/gimli/src/read/dwarf.rs
vendored
Normal file
1210
vendor/gimli/src/read/dwarf.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
639
vendor/gimli/src/read/endian_reader.rs
vendored
Normal file
639
vendor/gimli/src/read/endian_reader.rs
vendored
Normal file
@ -0,0 +1,639 @@
|
||||
//! Defining custom `Reader`s quickly.
|
||||
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use core::fmt::Debug;
|
||||
use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
|
||||
use core::slice;
|
||||
use core::str;
|
||||
use stable_deref_trait::CloneStableDeref;
|
||||
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::{Error, Reader, ReaderOffsetId, Result};
|
||||
|
||||
/// A reference counted, non-thread-safe slice of bytes and associated
|
||||
/// endianity.
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "std")] {
|
||||
/// 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<Endian> = EndianReader<Endian, Rc<[u8]>>;
|
||||
|
||||
/// An atomically reference counted, thread-safe slice of bytes and associated
|
||||
/// endianity.
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "std")] {
|
||||
/// 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<Endian> = EndianReader<Endian, Arc<[u8]>>;
|
||||
|
||||
/// 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<Rc<MmapFile>>` or `EndianReader<Arc<MmapFile>>` 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<MmapFile> {
|
||||
/// // 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<MmapFile>);
|
||||
///
|
||||
/// // 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<Endian> = gimli::EndianReader<Endian, ArcMmapFile>;
|
||||
/// # fn test(_: &MmapFileReader<gimli::NativeEndian>) { }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, Hash)]
|
||||
pub struct EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
range: SubRange<T>,
|
||||
endian: Endian,
|
||||
}
|
||||
|
||||
impl<Endian, T1, T2> PartialEq<EndianReader<Endian, T2>> for EndianReader<Endian, T1>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T1: CloneStableDeref<Target = [u8]> + Debug,
|
||||
T2: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
fn eq(&self, rhs: &EndianReader<Endian, T2>) -> bool {
|
||||
self.bytes() == rhs.bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian, T> Eq for EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + 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<T>
|
||||
where
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
bytes: T,
|
||||
ptr: *const u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Send {}
|
||||
|
||||
unsafe impl<T> Sync for SubRange<T> where T: CloneStableDeref<Target = [u8]> + Debug + Sync {}
|
||||
|
||||
impl<T> SubRange<T>
|
||||
where
|
||||
T: CloneStableDeref<Target = [u8]> + 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<Endian, T> EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
/// Construct a new `EndianReader` with the given bytes.
|
||||
#[inline]
|
||||
pub fn new(bytes: T, endian: Endian) -> EndianReader<Endian, T> {
|
||||
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<Range<usize>>` to return a new `EndianReader` the way we
|
||||
/// would like to. Instead, we abandon fancy indexing operators and have these
|
||||
/// plain old methods.
|
||||
impl<Endian, T> EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
/// Take the given `start..end` range of the underlying buffer and return a
|
||||
/// new `EndianReader`.
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "std")] {
|
||||
/// 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<usize>) -> EndianReader<Endian, T> {
|
||||
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`.
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "std")] {
|
||||
/// 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<usize>) -> EndianReader<Endian, T> {
|
||||
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`.
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(feature = "std")] {
|
||||
/// 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<usize>) -> EndianReader<Endian, T> {
|
||||
let mut r = self.clone();
|
||||
r.range.truncate(idx.end);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian, T> Index<usize> for EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
type Output = u8;
|
||||
fn index(&self, idx: usize) -> &Self::Output {
|
||||
&self.bytes()[idx]
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian, T> Index<RangeFrom<usize>> for EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
type Output = [u8];
|
||||
fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
|
||||
&self.bytes()[idx]
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian, T> Deref for EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + Debug,
|
||||
{
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian, T> Reader for EndianReader<Endian, T>
|
||||
where
|
||||
Endian: Endianity,
|
||||
T: CloneStableDeref<Target = [u8]> + 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<Endian, T>) -> 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<Self::Offset> {
|
||||
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<usize> {
|
||||
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<Self> {
|
||||
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<Cow<[u8]>> {
|
||||
Ok(self.bytes().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_string(&self) -> Result<Cow<str>> {
|
||||
match str::from_utf8(self.bytes()) {
|
||||
Ok(s) => Ok(s.into()),
|
||||
_ => Err(Error::BadUtf8),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_string_lossy(&self) -> Result<Cow<str>> {
|
||||
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.copy_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<T: CloneStableDeref<Target = [u8]> + Debug>(
|
||||
bytes: T,
|
||||
) -> EndianReader<NativeEndian, T> {
|
||||
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("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>")));
|
||||
}
|
||||
|
||||
#[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..]);
|
||||
}
|
||||
}
|
360
vendor/gimli/src/read/endian_slice.rs
vendored
Normal file
360
vendor/gimli/src/read/endian_slice.rs
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
//! Working with byte slices that have an associated endianity.
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
use alloc::borrow::Cow;
|
||||
#[cfg(feature = "read")]
|
||||
use alloc::string::String;
|
||||
use core::fmt;
|
||||
use core::ops::{Deref, Range, RangeFrom, RangeTo};
|
||||
use core::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(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 occurrence of a byte in the slice, and return its index.
|
||||
#[inline]
|
||||
pub fn find(&self, byte: u8) -> Option<usize> {
|
||||
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`.
|
||||
#[cfg(feature = "read")]
|
||||
#[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<Range<usize>>` 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<usize>) -> 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<usize>) -> 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<usize>) -> EndianSlice<'input, Endian> {
|
||||
EndianSlice {
|
||||
slice: &self.slice[idx],
|
||||
endian: self.endian,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input, Endian> Deref for EndianSlice<'input, Endian>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.slice
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
|
||||
fmt.debug_tuple("EndianSlice")
|
||||
.field(&self.endian)
|
||||
.field(&DebugBytes(self.slice))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugBytes<'input>(&'input [u8]);
|
||||
|
||||
impl<'input> core::fmt::Debug for DebugBytes<'input> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
|
||||
let mut list = fmt.debug_list();
|
||||
list.entries(self.0.iter().take(8).copied().map(DebugByte));
|
||||
if self.0.len() > 8 {
|
||||
list.entry(&DebugLen(self.0.len()));
|
||||
}
|
||||
list.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugByte(u8);
|
||||
|
||||
impl fmt::Debug for DebugByte {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "0x{:02x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugLen(usize);
|
||||
|
||||
impl fmt::Debug for DebugLen {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "...; {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
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<Self::Offset> {
|
||||
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<usize> {
|
||||
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<Self> {
|
||||
let slice = self.read_slice(len)?;
|
||||
Ok(EndianSlice::new(slice, self.endian))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "read"))]
|
||||
fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
|
||||
super::reader::seal_if_no_alloc::Sealed
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
#[inline]
|
||||
fn to_slice(&self) -> Result<Cow<[u8]>> {
|
||||
Ok(self.slice.into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
#[inline]
|
||||
fn to_string(&self) -> Result<Cow<str>> {
|
||||
match str::from_utf8(self.slice) {
|
||||
Ok(s) => Ok(s.into()),
|
||||
_ => Err(Error::BadUtf8),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
#[inline]
|
||||
fn to_string_lossy(&self) -> Result<Cow<str>> {
|
||||
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.copy_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);
|
||||
}
|
||||
}
|
535
vendor/gimli/src/read/index.rs
vendored
Normal file
535
vendor/gimli/src/read/index.rs
vendored
Normal file
@ -0,0 +1,535 @@
|
||||
use core::slice;
|
||||
|
||||
use crate::common::SectionId;
|
||||
use crate::constants;
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section};
|
||||
|
||||
/// The data in the `.debug_cu_index` section of a `.dwp` file.
|
||||
///
|
||||
/// This section contains the compilation unit index.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugCuIndex<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugCuIndex<EndianSlice<'input, Endian>>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct a new `DebugCuIndex` instance from the data in the `.debug_cu_index`
|
||||
/// section.
|
||||
pub fn new(section: &'input [u8], endian: Endian) -> Self {
|
||||
Self::from(EndianSlice::new(section, endian))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugCuIndex<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugCuIndex
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugCuIndex<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugCuIndex { section }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugCuIndex<R> {
|
||||
/// Parse the index header.
|
||||
pub fn index(self) -> Result<UnitIndex<R>> {
|
||||
UnitIndex::parse(self.section)
|
||||
}
|
||||
}
|
||||
|
||||
/// The data in the `.debug_tu_index` section of a `.dwp` file.
|
||||
///
|
||||
/// This section contains the type unit index.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugTuIndex<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index`
|
||||
/// section.
|
||||
pub fn new(section: &'input [u8], endian: Endian) -> Self {
|
||||
Self::from(EndianSlice::new(section, endian))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugTuIndex<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugTuIndex
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugTuIndex<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugTuIndex { section }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugTuIndex<R> {
|
||||
/// Parse the index header.
|
||||
pub fn index(self) -> Result<UnitIndex<R>> {
|
||||
UnitIndex::parse(self.section)
|
||||
}
|
||||
}
|
||||
|
||||
const SECTION_COUNT_MAX: u8 = 8;
|
||||
|
||||
/// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnitIndex<R: Reader> {
|
||||
version: u16,
|
||||
section_count: u32,
|
||||
unit_count: u32,
|
||||
slot_count: u32,
|
||||
hash_ids: R,
|
||||
hash_rows: R,
|
||||
// Only `section_count` values are valid.
|
||||
sections: [SectionId; SECTION_COUNT_MAX as usize],
|
||||
offsets: R,
|
||||
sizes: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> UnitIndex<R> {
|
||||
fn parse(mut input: R) -> Result<UnitIndex<R>> {
|
||||
if input.is_empty() {
|
||||
return Ok(UnitIndex {
|
||||
version: 5,
|
||||
section_count: 0,
|
||||
unit_count: 0,
|
||||
slot_count: 0,
|
||||
hash_ids: input.clone(),
|
||||
hash_rows: input.clone(),
|
||||
sections: [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize],
|
||||
offsets: input.clone(),
|
||||
sizes: input.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// GNU split-dwarf extension to DWARF 4 uses a 32-bit version,
|
||||
// but DWARF 5 uses a 16-bit version followed by 16-bit padding.
|
||||
let mut original_input = input.clone();
|
||||
let version;
|
||||
if input.read_u32()? == 2 {
|
||||
version = 2
|
||||
} else {
|
||||
version = original_input.read_u16()?;
|
||||
if version != 5 {
|
||||
return Err(Error::UnknownVersion(version.into()));
|
||||
}
|
||||
}
|
||||
|
||||
let section_count = input.read_u32()?;
|
||||
let unit_count = input.read_u32()?;
|
||||
let slot_count = input.read_u32()?;
|
||||
if slot_count == 0 || slot_count & (slot_count - 1) != 0 || slot_count <= unit_count {
|
||||
return Err(Error::InvalidIndexSlotCount);
|
||||
}
|
||||
|
||||
let hash_ids = input.split(R::Offset::from_u64(u64::from(slot_count) * 8)?)?;
|
||||
let hash_rows = input.split(R::Offset::from_u64(u64::from(slot_count) * 4)?)?;
|
||||
|
||||
let mut sections = [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize];
|
||||
if section_count > SECTION_COUNT_MAX.into() {
|
||||
return Err(Error::InvalidIndexSectionCount);
|
||||
}
|
||||
for i in 0..section_count {
|
||||
let section = input.read_u32()?;
|
||||
sections[i as usize] = if version == 2 {
|
||||
match constants::DwSectV2(section) {
|
||||
constants::DW_SECT_V2_INFO => SectionId::DebugInfo,
|
||||
constants::DW_SECT_V2_TYPES => SectionId::DebugTypes,
|
||||
constants::DW_SECT_V2_ABBREV => SectionId::DebugAbbrev,
|
||||
constants::DW_SECT_V2_LINE => SectionId::DebugLine,
|
||||
constants::DW_SECT_V2_LOC => SectionId::DebugLoc,
|
||||
constants::DW_SECT_V2_STR_OFFSETS => SectionId::DebugStrOffsets,
|
||||
constants::DW_SECT_V2_MACINFO => SectionId::DebugMacinfo,
|
||||
constants::DW_SECT_V2_MACRO => SectionId::DebugMacro,
|
||||
_ => return Err(Error::UnknownIndexSection),
|
||||
}
|
||||
} else {
|
||||
match constants::DwSect(section) {
|
||||
constants::DW_SECT_INFO => SectionId::DebugInfo,
|
||||
constants::DW_SECT_ABBREV => SectionId::DebugAbbrev,
|
||||
constants::DW_SECT_LINE => SectionId::DebugLine,
|
||||
constants::DW_SECT_LOCLISTS => SectionId::DebugLocLists,
|
||||
constants::DW_SECT_STR_OFFSETS => SectionId::DebugStrOffsets,
|
||||
constants::DW_SECT_MACRO => SectionId::DebugMacro,
|
||||
constants::DW_SECT_RNGLISTS => SectionId::DebugRngLists,
|
||||
_ => return Err(Error::UnknownIndexSection),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let offsets = input.split(R::Offset::from_u64(
|
||||
u64::from(unit_count) * u64::from(section_count) * 4,
|
||||
)?)?;
|
||||
let sizes = input.split(R::Offset::from_u64(
|
||||
u64::from(unit_count) * u64::from(section_count) * 4,
|
||||
)?)?;
|
||||
|
||||
Ok(UnitIndex {
|
||||
version,
|
||||
section_count,
|
||||
unit_count,
|
||||
slot_count,
|
||||
hash_ids,
|
||||
hash_rows,
|
||||
sections,
|
||||
offsets,
|
||||
sizes,
|
||||
})
|
||||
}
|
||||
|
||||
/// Find `id` in the index hash table, and return the row index.
|
||||
///
|
||||
/// `id` may be a compilation unit ID if this index is from `.debug_cu_index`,
|
||||
/// or a type signature if this index is from `.debug_tu_index`.
|
||||
pub fn find(&self, id: u64) -> Option<u32> {
|
||||
if self.slot_count == 0 {
|
||||
return None;
|
||||
}
|
||||
let mask = u64::from(self.slot_count - 1);
|
||||
let mut hash1 = id & mask;
|
||||
let hash2 = ((id >> 32) & mask) | 1;
|
||||
for _ in 0..self.slot_count {
|
||||
// The length of these arrays was validated in `UnitIndex::parse`.
|
||||
let mut hash_ids = self.hash_ids.clone();
|
||||
hash_ids.skip(R::Offset::from_u64(hash1 * 8).ok()?).ok()?;
|
||||
let hash_id = hash_ids.read_u64().ok()?;
|
||||
if hash_id == id {
|
||||
let mut hash_rows = self.hash_rows.clone();
|
||||
hash_rows.skip(R::Offset::from_u64(hash1 * 4).ok()?).ok()?;
|
||||
let hash_row = hash_rows.read_u32().ok()?;
|
||||
return Some(hash_row);
|
||||
}
|
||||
if hash_id == 0 {
|
||||
return None;
|
||||
}
|
||||
hash1 = (hash1 + hash2) & mask;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Return the section offsets and sizes for the given row index.
|
||||
pub fn sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>> {
|
||||
if row == 0 {
|
||||
return Err(Error::InvalidIndexRow);
|
||||
}
|
||||
row -= 1;
|
||||
if row >= self.unit_count {
|
||||
return Err(Error::InvalidIndexRow);
|
||||
}
|
||||
let mut offsets = self.offsets.clone();
|
||||
offsets.skip(R::Offset::from_u64(
|
||||
u64::from(row) * u64::from(self.section_count) * 4,
|
||||
)?)?;
|
||||
let mut sizes = self.sizes.clone();
|
||||
sizes.skip(R::Offset::from_u64(
|
||||
u64::from(row) * u64::from(self.section_count) * 4,
|
||||
)?)?;
|
||||
Ok(UnitIndexSectionIterator {
|
||||
sections: self.sections[..self.section_count as usize].iter(),
|
||||
offsets,
|
||||
sizes,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the version.
|
||||
pub fn version(&self) -> u16 {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Return the number of sections.
|
||||
pub fn section_count(&self) -> u32 {
|
||||
self.section_count
|
||||
}
|
||||
|
||||
/// Return the number of units.
|
||||
pub fn unit_count(&self) -> u32 {
|
||||
self.unit_count
|
||||
}
|
||||
|
||||
/// Return the number of slots.
|
||||
pub fn slot_count(&self) -> u32 {
|
||||
self.slot_count
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the section offsets and sizes for a row in a `UnitIndex`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnitIndexSectionIterator<'index, R: Reader> {
|
||||
sections: slice::Iter<'index, SectionId>,
|
||||
offsets: R,
|
||||
sizes: R,
|
||||
}
|
||||
|
||||
impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> {
|
||||
type Item = UnitIndexSection;
|
||||
|
||||
fn next(&mut self) -> Option<UnitIndexSection> {
|
||||
let section = *self.sections.next()?;
|
||||
// The length of these arrays was validated in `UnitIndex::parse`.
|
||||
let offset = self.offsets.read_u32().ok()?;
|
||||
let size = self.sizes.read_u32().ok()?;
|
||||
Some(UnitIndexSection {
|
||||
section,
|
||||
offset,
|
||||
size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a unit's contribution to a section in a `.dwp` file.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct UnitIndexSection {
|
||||
/// The section kind.
|
||||
pub section: SectionId,
|
||||
/// The base offset of the unit's contribution to the section.
|
||||
pub offset: u32,
|
||||
/// The size of the unit's contribution to the section.
|
||||
pub size: u32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::endianity::BigEndian;
|
||||
use test_assembler::{Endian, Section};
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let buf = EndianSlice::new(&[], BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert!(index.find(0).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_2() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D32(2).D32(0).D32(0).D32(1)
|
||||
// Slots.
|
||||
.D64(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert_eq!(index.version, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_5() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D16(5).D16(0).D32(0).D32(0).D32(1)
|
||||
// Slots.
|
||||
.D64(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert_eq!(index.version, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_5_invalid() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D32(5).D32(0).D32(0).D32(1)
|
||||
// Slots.
|
||||
.D64(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
assert!(UnitIndex::parse(buf).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_2_sections() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D32(2).D32(8).D32(1).D32(2)
|
||||
// Slots.
|
||||
.D64(0).D64(0).D32(0).D32(0)
|
||||
// Sections.
|
||||
.D32(constants::DW_SECT_V2_INFO.0)
|
||||
.D32(constants::DW_SECT_V2_TYPES.0)
|
||||
.D32(constants::DW_SECT_V2_ABBREV.0)
|
||||
.D32(constants::DW_SECT_V2_LINE.0)
|
||||
.D32(constants::DW_SECT_V2_LOC.0)
|
||||
.D32(constants::DW_SECT_V2_STR_OFFSETS.0)
|
||||
.D32(constants::DW_SECT_V2_MACINFO.0)
|
||||
.D32(constants::DW_SECT_V2_MACRO.0)
|
||||
// Offsets.
|
||||
.D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18)
|
||||
// Sizes.
|
||||
.D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27).D32(28);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert_eq!(index.section_count, 8);
|
||||
assert_eq!(
|
||||
index.sections,
|
||||
[
|
||||
SectionId::DebugInfo,
|
||||
SectionId::DebugTypes,
|
||||
SectionId::DebugAbbrev,
|
||||
SectionId::DebugLine,
|
||||
SectionId::DebugLoc,
|
||||
SectionId::DebugStrOffsets,
|
||||
SectionId::DebugMacinfo,
|
||||
SectionId::DebugMacro,
|
||||
]
|
||||
);
|
||||
#[rustfmt::skip]
|
||||
let expect = [
|
||||
UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
|
||||
UnitIndexSection { section: SectionId::DebugTypes, offset: 12, size: 22 },
|
||||
UnitIndexSection { section: SectionId::DebugAbbrev, offset: 13, size: 23 },
|
||||
UnitIndexSection { section: SectionId::DebugLine, offset: 14, size: 24 },
|
||||
UnitIndexSection { section: SectionId::DebugLoc, offset: 15, size: 25 },
|
||||
UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 16, size: 26 },
|
||||
UnitIndexSection { section: SectionId::DebugMacinfo, offset: 17, size: 27 },
|
||||
UnitIndexSection { section: SectionId::DebugMacro, offset: 18, size: 28 },
|
||||
];
|
||||
let mut sections = index.sections(1).unwrap();
|
||||
for section in &expect {
|
||||
assert_eq!(*section, sections.next().unwrap());
|
||||
}
|
||||
assert!(sections.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_5_sections() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D16(5).D16(0).D32(7).D32(1).D32(2)
|
||||
// Slots.
|
||||
.D64(0).D64(0).D32(0).D32(0)
|
||||
// Sections.
|
||||
.D32(constants::DW_SECT_INFO.0)
|
||||
.D32(constants::DW_SECT_ABBREV.0)
|
||||
.D32(constants::DW_SECT_LINE.0)
|
||||
.D32(constants::DW_SECT_LOCLISTS.0)
|
||||
.D32(constants::DW_SECT_STR_OFFSETS.0)
|
||||
.D32(constants::DW_SECT_MACRO.0)
|
||||
.D32(constants::DW_SECT_RNGLISTS.0)
|
||||
// Offsets.
|
||||
.D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17)
|
||||
// Sizes.
|
||||
.D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert_eq!(index.section_count, 7);
|
||||
assert_eq!(
|
||||
index.sections[..7],
|
||||
[
|
||||
SectionId::DebugInfo,
|
||||
SectionId::DebugAbbrev,
|
||||
SectionId::DebugLine,
|
||||
SectionId::DebugLocLists,
|
||||
SectionId::DebugStrOffsets,
|
||||
SectionId::DebugMacro,
|
||||
SectionId::DebugRngLists,
|
||||
]
|
||||
);
|
||||
#[rustfmt::skip]
|
||||
let expect = [
|
||||
UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
|
||||
UnitIndexSection { section: SectionId::DebugAbbrev, offset: 12, size: 22 },
|
||||
UnitIndexSection { section: SectionId::DebugLine, offset: 13, size: 23 },
|
||||
UnitIndexSection { section: SectionId::DebugLocLists, offset: 14, size: 24 },
|
||||
UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 15, size: 25 },
|
||||
UnitIndexSection { section: SectionId::DebugMacro, offset: 16, size: 26 },
|
||||
UnitIndexSection { section: SectionId::DebugRngLists, offset: 17, size: 27 },
|
||||
];
|
||||
let mut sections = index.sections(1).unwrap();
|
||||
for section in &expect {
|
||||
assert_eq!(*section, sections.next().unwrap());
|
||||
}
|
||||
assert!(sections.next().is_none());
|
||||
|
||||
assert!(index.sections(0).is_err());
|
||||
assert!(index.sections(2).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D16(5).D16(0).D32(2).D32(3).D32(4)
|
||||
// Slots.
|
||||
.D64(0xffff_fff2_ffff_fff1)
|
||||
.D64(0xffff_fff0_ffff_fff1)
|
||||
.D64(0xffff_fff1_ffff_fff1)
|
||||
.D64(0)
|
||||
.D32(3).D32(1).D32(2).D32(0)
|
||||
// Sections.
|
||||
.D32(constants::DW_SECT_INFO.0)
|
||||
.D32(constants::DW_SECT_ABBREV.0)
|
||||
// Offsets.
|
||||
.D32(0).D32(0).D32(0).D32(0).D32(0).D32(0)
|
||||
// Sizes.
|
||||
.D32(0).D32(0).D32(0).D32(0).D32(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let buf = EndianSlice::new(&buf, BigEndian);
|
||||
let index = UnitIndex::parse(buf).unwrap();
|
||||
assert_eq!(index.version(), 5);
|
||||
assert_eq!(index.slot_count(), 4);
|
||||
assert_eq!(index.unit_count(), 3);
|
||||
assert_eq!(index.section_count(), 2);
|
||||
assert_eq!(index.find(0xffff_fff0_ffff_fff1), Some(1));
|
||||
assert_eq!(index.find(0xffff_fff1_ffff_fff1), Some(2));
|
||||
assert_eq!(index.find(0xffff_fff2_ffff_fff1), Some(3));
|
||||
assert_eq!(index.find(0xffff_fff3_ffff_fff1), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cu_index() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D16(5).D16(0).D32(0).D32(0).D32(1)
|
||||
// Slots.
|
||||
.D64(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let cu_index = DebugCuIndex::new(&buf, BigEndian);
|
||||
let index = cu_index.index().unwrap();
|
||||
assert_eq!(index.version, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tu_index() {
|
||||
#[rustfmt::skip]
|
||||
let section = Section::with_endian(Endian::Big)
|
||||
// Header.
|
||||
.D16(5).D16(0).D32(0).D32(0).D32(1)
|
||||
// Slots.
|
||||
.D64(0).D32(0);
|
||||
let buf = section.get_contents().unwrap();
|
||||
let tu_index = DebugTuIndex::new(&buf, BigEndian);
|
||||
let index = tu_index.index().unwrap();
|
||||
assert_eq!(index.version, 5);
|
||||
}
|
||||
}
|
3130
vendor/gimli/src/read/line.rs
vendored
Normal file
3130
vendor/gimli/src/read/line.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
vendor/gimli/src/read/lists.rs
vendored
Normal file
68
vendor/gimli/src/read/lists.rs
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
use crate::common::{Encoding, Format};
|
||||
use crate::read::{Error, Reader, Result};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct ListsHeader {
|
||||
encoding: Encoding,
|
||||
#[allow(dead_code)]
|
||||
offset_entry_count: u32,
|
||||
}
|
||||
|
||||
impl Default for ListsHeader {
|
||||
fn default() -> Self {
|
||||
ListsHeader {
|
||||
encoding: Encoding {
|
||||
format: Format::Dwarf32,
|
||||
version: 5,
|
||||
address_size: 0,
|
||||
},
|
||||
offset_entry_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ListsHeader {
|
||||
/// 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
|
||||
ListsHeader::size_for_encoding(self.encoding)
|
||||
}
|
||||
|
||||
/// Return the serialized size of the table header.
|
||||
#[inline]
|
||||
pub(crate) fn size_for_encoding(encoding: Encoding) -> u8 {
|
||||
// initial_length + version + address_size + segment_selector_size + offset_entry_count
|
||||
encoding.format.initial_length_size() + 2 + 1 + 1 + 4
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add an iterator over headers in the appropriate sections section
|
||||
#[allow(dead_code)]
|
||||
fn parse_header<R: Reader>(input: &mut R) -> Result<ListsHeader> {
|
||||
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(ListsHeader {
|
||||
encoding,
|
||||
offset_entry_count,
|
||||
})
|
||||
}
|
1627
vendor/gimli/src/read/loclists.rs
vendored
Normal file
1627
vendor/gimli/src/read/loclists.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
202
vendor/gimli/src/read/lookup.rs
vendored
Normal file
202
vendor/gimli/src/read/lookup.rs
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
use core::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<R: Reader> {
|
||||
/// 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<Option<Self::Entry>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DebugLookup<R, Parser>
|
||||
where
|
||||
R: Reader,
|
||||
Parser: LookupParser<R>,
|
||||
{
|
||||
input_buffer: R,
|
||||
phantom: PhantomData<Parser>,
|
||||
}
|
||||
|
||||
impl<R, Parser> From<R> for DebugLookup<R, Parser>
|
||||
where
|
||||
R: Reader,
|
||||
Parser: LookupParser<R>,
|
||||
{
|
||||
fn from(input_buffer: R) -> Self {
|
||||
DebugLookup {
|
||||
input_buffer,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, Parser> DebugLookup<R, Parser>
|
||||
where
|
||||
R: Reader,
|
||||
Parser: LookupParser<R>,
|
||||
{
|
||||
pub fn items(&self) -> LookupEntryIter<R, Parser> {
|
||||
LookupEntryIter {
|
||||
current_set: None,
|
||||
remaining_input: self.input_buffer.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reader(&self) -> &R {
|
||||
&self.input_buffer
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LookupEntryIter<R, Parser>
|
||||
where
|
||||
R: Reader,
|
||||
Parser: LookupParser<R>,
|
||||
{
|
||||
current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end.
|
||||
remaining_input: R,
|
||||
}
|
||||
|
||||
impl<R, Parser> LookupEntryIter<R, Parser>
|
||||
where
|
||||
R: Reader,
|
||||
Parser: LookupParser<R>,
|
||||
{
|
||||
/// 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<Option<Parser::Entry>> {
|
||||
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<T = usize> {
|
||||
format: Format,
|
||||
length: T,
|
||||
version: u16,
|
||||
unit_offset: DebugInfoOffset<T>,
|
||||
unit_length: T,
|
||||
}
|
||||
|
||||
pub trait PubStuffEntry<R: Reader> {
|
||||
fn new(
|
||||
die_offset: UnitOffset<R::Offset>,
|
||||
name: R,
|
||||
unit_header_offset: DebugInfoOffset<R::Offset>,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PubStuffParser<R, Entry>
|
||||
where
|
||||
R: Reader,
|
||||
Entry: PubStuffEntry<R>,
|
||||
{
|
||||
// This struct is never instantiated.
|
||||
phantom: PhantomData<(R, Entry)>,
|
||||
}
|
||||
|
||||
impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
|
||||
where
|
||||
R: Reader,
|
||||
Entry: PubStuffEntry<R>,
|
||||
{
|
||||
type Header = PubStuffHeader<R::Offset>;
|
||||
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<Option<Self::Entry>> {
|
||||
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,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
827
vendor/gimli/src/read/mod.rs
vendored
Normal file
827
vendor/gimli/src/read/mod.rs
vendored
Normal file
@ -0,0 +1,827 @@
|
||||
//! 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<R, gimli::Error> { unimplemented!() };
|
||||
//! # let get_sup_file_section_reader = |name| -> Result<R, gimli::Error> { 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 mut dwarf = gimli::Dwarf::load(loader)?;
|
||||
//! dwarf.load_sup(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/crates/examples/src/bin/simple.rs)
|
||||
//!
|
||||
//! * [A `dwarfdump`
|
||||
//! clone](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/dwarfdump.rs)
|
||||
//!
|
||||
//! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line)
|
||||
//!
|
||||
//! * [`ddbug`](https://github.com/gimli-rs/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`](https://github.com/gimli-rs/gimli/blob/master/crates/examples/src/bin/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.
|
||||
//!
|
||||
//! * [`DebugCuIndex`](./struct.DebugCuIndex.html): The `.debug_cu_index` section.
|
||||
//!
|
||||
//! * [`DebugTuIndex`](./struct.DebugTuIndex.html): The `.debug_tu_index` 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<T, E>`, 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:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "fallible-iterator")]
|
||||
//! # fn foo() {
|
||||
//! // 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<EndianSlice<LittleEndian>>)
|
||||
//! -> gimli::Result<u64>
|
||||
//! {
|
||||
//! // `DebugAranges::headers` returns a `FallibleIterator`!
|
||||
//! aranges.headers()
|
||||
//! // `flat_map` is provided by `FallibleIterator`!
|
||||
//! .flat_map(|header| Ok(header.entries()))
|
||||
//! // `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 core::fmt::{self, Debug};
|
||||
use core::result;
|
||||
#[cfg(feature = "std")]
|
||||
use std::{error, io};
|
||||
|
||||
use crate::common::{Register, SectionId};
|
||||
use crate::constants;
|
||||
|
||||
mod util;
|
||||
pub use util::*;
|
||||
|
||||
mod addr;
|
||||
pub use self::addr::*;
|
||||
|
||||
mod cfi;
|
||||
pub use self::cfi::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod dwarf;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::dwarf::*;
|
||||
|
||||
mod endian_slice;
|
||||
pub use self::endian_slice::*;
|
||||
|
||||
#[cfg(feature = "endian-reader")]
|
||||
mod endian_reader;
|
||||
#[cfg(feature = "endian-reader")]
|
||||
pub use self::endian_reader::*;
|
||||
|
||||
mod reader;
|
||||
pub use self::reader::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod abbrev;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::abbrev::*;
|
||||
|
||||
mod aranges;
|
||||
pub use self::aranges::*;
|
||||
|
||||
mod index;
|
||||
pub use self::index::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod line;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::line::*;
|
||||
|
||||
mod lists;
|
||||
|
||||
mod loclists;
|
||||
pub use self::loclists::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod lookup;
|
||||
|
||||
mod op;
|
||||
pub use self::op::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod pubnames;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::pubnames::*;
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod pubtypes;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::pubtypes::*;
|
||||
|
||||
mod rnglists;
|
||||
pub use self::rnglists::*;
|
||||
|
||||
mod str;
|
||||
pub use self::str::*;
|
||||
|
||||
/// An offset into the current compilation or type unit.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
pub struct UnitOffset<T = usize>(pub T);
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
mod unit;
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::unit::*;
|
||||
|
||||
mod value;
|
||||
pub use self::value::*;
|
||||
|
||||
/// Indicates that storage should be allocated on heap.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct StoreOnHeap;
|
||||
|
||||
/// `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),
|
||||
/// An unsupported operation was found while evaluating a DWARF expression.
|
||||
UnsupportedEvaluation,
|
||||
/// 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 or evaluation stack, but it was already
|
||||
/// at full capacity.
|
||||
StackFull,
|
||||
/// 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,
|
||||
/// `DW_FORM_implicit_const` used in an invalid context.
|
||||
InvalidImplicitConst,
|
||||
/// Invalid section count in `.dwp` index.
|
||||
InvalidIndexSectionCount,
|
||||
/// Invalid slot count in `.dwp` index.
|
||||
InvalidIndexSlotCount,
|
||||
/// Invalid hash row in `.dwp` index.
|
||||
InvalidIndexRow,
|
||||
/// Unknown section type in `.dwp` index.
|
||||
UnknownIndexSection,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> {
|
||||
write!(f, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
||||
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::UnsupportedEvaluation => "Unsupported operation when evaluating 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::StackFull => {
|
||||
"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."
|
||||
}
|
||||
Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.",
|
||||
Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.",
|
||||
Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.",
|
||||
Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.",
|
||||
Error::UnknownIndexSection => "Unknown section type in `.dwp` index.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for Error {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<io::Error> for Error {
|
||||
fn from(_: io::Error) -> Self {
|
||||
Error::Io
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a parse.
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
/// 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<R>: From<R> {
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// Returns the ELF section name (if any) for this type when used in a dwo
|
||||
/// file.
|
||||
fn dwo_section_name() -> Option<&'static str> {
|
||||
Self::id().dwo_name()
|
||||
}
|
||||
|
||||
/// Returns the XCOFF section name (if any) for this type when used in a XCOFF
|
||||
/// file.
|
||||
fn xcoff_section_name() -> Option<&'static str> {
|
||||
Self::id().xcoff_name()
|
||||
}
|
||||
|
||||
/// Try to load the section using the given loader function.
|
||||
fn load<F, E>(f: F) -> core::result::Result<Self, E>
|
||||
where
|
||||
F: FnOnce(SectionId) -> core::result::Result<R, E>,
|
||||
{
|
||||
f(Self::id()).map(From::from)
|
||||
}
|
||||
|
||||
/// Returns the `Reader` for this section.
|
||||
fn reader(&self) -> &R
|
||||
where
|
||||
R: Reader;
|
||||
|
||||
/// Returns the subrange of the section that is the contribution of
|
||||
/// a unit in a `.dwp` file.
|
||||
fn dwp_range(&self, offset: u32, size: u32) -> Result<Self>
|
||||
where
|
||||
R: Reader,
|
||||
{
|
||||
let mut data = self.reader().clone();
|
||||
data.skip(R::Offset::from_u32(offset))?;
|
||||
data.truncate(R::Offset::from_u32(size))?;
|
||||
Ok(data.into())
|
||||
}
|
||||
|
||||
/// 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<Register> {
|
||||
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),
|
||||
};
|
||||
}
|
||||
}
|
4140
vendor/gimli/src/read/op.rs
vendored
Normal file
4140
vendor/gimli/src/read/op.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
vendor/gimli/src/read/pubnames.rs
vendored
Normal file
141
vendor/gimli/src/read/pubnames.rs
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
use crate::common::{DebugInfoOffset, SectionId};
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser};
|
||||
use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset};
|
||||
|
||||
/// A single parsed pubname.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PubNamesEntry<R: Reader> {
|
||||
unit_header_offset: DebugInfoOffset<R::Offset>,
|
||||
die_offset: UnitOffset<R::Offset>,
|
||||
name: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> PubNamesEntry<R> {
|
||||
/// 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<R::Offset> {
|
||||
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<R::Offset> {
|
||||
self.die_offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> PubStuffEntry<R> for PubNamesEntry<R> {
|
||||
fn new(
|
||||
die_offset: UnitOffset<R::Offset>,
|
||||
name: R,
|
||||
unit_header_offset: DebugInfoOffset<R::Offset>,
|
||||
) -> 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<R: Reader>(DebugLookup<R, PubStuffParser<R, PubNamesEntry<R>>>);
|
||||
|
||||
impl<'input, Endian> DebugPubNames<EndianSlice<'input, Endian>>
|
||||
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 macOS, 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<R: Reader> DebugPubNames<R> {
|
||||
/// 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<R> {
|
||||
PubNamesEntryIter(self.0.items())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Section<R> for DebugPubNames<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugPubNames
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
self.0.reader()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> From<R> for DebugPubNames<R> {
|
||||
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<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubNamesEntry<R>>>);
|
||||
|
||||
impl<R: Reader> PubNamesEntryIter<R> {
|
||||
/// 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<Option<PubNamesEntry<R>>> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<R: Reader> fallible_iterator::FallibleIterator for PubNamesEntryIter<R> {
|
||||
type Item = PubNamesEntry<R>;
|
||||
type Error = crate::read::Error;
|
||||
|
||||
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
141
vendor/gimli/src/read/pubtypes.rs
vendored
Normal file
141
vendor/gimli/src/read/pubtypes.rs
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
use crate::common::{DebugInfoOffset, SectionId};
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::lookup::{DebugLookup, LookupEntryIter, PubStuffEntry, PubStuffParser};
|
||||
use crate::read::{EndianSlice, Reader, Result, Section, UnitOffset};
|
||||
|
||||
/// A single parsed pubtype.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PubTypesEntry<R: Reader> {
|
||||
unit_header_offset: DebugInfoOffset<R::Offset>,
|
||||
die_offset: UnitOffset<R::Offset>,
|
||||
name: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> PubTypesEntry<R> {
|
||||
/// 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<R::Offset> {
|
||||
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<R::Offset> {
|
||||
self.die_offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> PubStuffEntry<R> for PubTypesEntry<R> {
|
||||
fn new(
|
||||
die_offset: UnitOffset<R::Offset>,
|
||||
name: R,
|
||||
unit_header_offset: DebugInfoOffset<R::Offset>,
|
||||
) -> 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<R: Reader>(DebugLookup<R, PubStuffParser<R, PubTypesEntry<R>>>);
|
||||
|
||||
impl<'input, Endian> DebugPubTypes<EndianSlice<'input, Endian>>
|
||||
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 macOS, 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<R: Reader> DebugPubTypes<R> {
|
||||
/// 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<R> {
|
||||
PubTypesEntryIter(self.0.items())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Section<R> for DebugPubTypes<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugPubTypes
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
self.0.reader()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> From<R> for DebugPubTypes<R> {
|
||||
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<R: Reader>(LookupEntryIter<R, PubStuffParser<R, PubTypesEntry<R>>>);
|
||||
|
||||
impl<R: Reader> PubTypesEntryIter<R> {
|
||||
/// 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<Option<PubTypesEntry<R>>> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fallible-iterator")]
|
||||
impl<R: Reader> fallible_iterator::FallibleIterator for PubTypesEntryIter<R> {
|
||||
type Item = PubTypesEntry<R>;
|
||||
type Error = crate::read::Error;
|
||||
|
||||
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
502
vendor/gimli/src/read/reader.rs
vendored
Normal file
502
vendor/gimli/src/read/reader.rs
vendored
Normal file
@ -0,0 +1,502 @@
|
||||
#[cfg(feature = "read")]
|
||||
use alloc::borrow::Cow;
|
||||
use core::convert::TryInto;
|
||||
use core::fmt::Debug;
|
||||
use core::hash::Hash;
|
||||
use core::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<Output = Self> + AddAssign + Sub<Output = Self>
|
||||
{
|
||||
/// 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<Self>;
|
||||
|
||||
/// 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<Self>;
|
||||
}
|
||||
|
||||
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<Self> {
|
||||
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> {
|
||||
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<Self> {
|
||||
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> {
|
||||
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<Self> {
|
||||
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> {
|
||||
self.checked_sub(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "read"))]
|
||||
pub(crate) mod seal_if_no_alloc {
|
||||
#[derive(Debug)]
|
||||
pub struct Sealed;
|
||||
}
|
||||
|
||||
/// 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<T>`](./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<Self::Offset>;
|
||||
|
||||
/// Find the index of the first occurrence of the given byte.
|
||||
/// The offset of the reader is not changed.
|
||||
fn find(&self, byte: u8) -> Result<Self::Offset>;
|
||||
|
||||
/// 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<Self>;
|
||||
|
||||
/// This trait cannot be implemented if "read" feature is not enabled.
|
||||
///
|
||||
/// `Reader` trait has a few methods that depend on `alloc` crate.
|
||||
/// Disallowing `Reader` trait implementation prevents a crate that only depends on
|
||||
/// "read-core" from being broken if another crate depending on `gimli` enables
|
||||
/// "read" feature.
|
||||
#[cfg(not(feature = "read"))]
|
||||
fn cannot_implement() -> seal_if_no_alloc::Sealed;
|
||||
|
||||
/// 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.
|
||||
#[cfg(feature = "read")]
|
||||
fn to_slice(&self) -> Result<Cow<[u8]>>;
|
||||
|
||||
/// 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.
|
||||
#[cfg(feature = "read")]
|
||||
fn to_string(&self) -> Result<Cow<str>>;
|
||||
|
||||
/// 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.
|
||||
#[cfg(feature = "read")]
|
||||
fn to_string_lossy(&self) -> Result<Cow<str>>;
|
||||
|
||||
/// 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<A>(&mut self) -> Result<A>
|
||||
where
|
||||
A: Sized + Default + AsMut<[u8]>,
|
||||
{
|
||||
let mut val = Default::default();
|
||||
self.read_slice(<A as AsMut<[u8]>>::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<u8> {
|
||||
let a: [u8; 1] = self.read_u8_array()?;
|
||||
Ok(a[0])
|
||||
}
|
||||
|
||||
/// Read an i8.
|
||||
#[inline]
|
||||
fn read_i8(&mut self) -> Result<i8> {
|
||||
let a: [u8; 1] = self.read_u8_array()?;
|
||||
Ok(a[0] as i8)
|
||||
}
|
||||
|
||||
/// Read a u16.
|
||||
#[inline]
|
||||
fn read_u16(&mut self) -> Result<u16> {
|
||||
let a: [u8; 2] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_u16(&a))
|
||||
}
|
||||
|
||||
/// Read an i16.
|
||||
#[inline]
|
||||
fn read_i16(&mut self) -> Result<i16> {
|
||||
let a: [u8; 2] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_i16(&a))
|
||||
}
|
||||
|
||||
/// Read a u32.
|
||||
#[inline]
|
||||
fn read_u32(&mut self) -> Result<u32> {
|
||||
let a: [u8; 4] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_u32(&a))
|
||||
}
|
||||
|
||||
/// Read an i32.
|
||||
#[inline]
|
||||
fn read_i32(&mut self) -> Result<i32> {
|
||||
let a: [u8; 4] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_i32(&a))
|
||||
}
|
||||
|
||||
/// Read a u64.
|
||||
#[inline]
|
||||
fn read_u64(&mut self) -> Result<u64> {
|
||||
let a: [u8; 8] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_u64(&a))
|
||||
}
|
||||
|
||||
/// Read an i64.
|
||||
#[inline]
|
||||
fn read_i64(&mut self) -> Result<i64> {
|
||||
let a: [u8; 8] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_i64(&a))
|
||||
}
|
||||
|
||||
/// Read a f32.
|
||||
#[inline]
|
||||
fn read_f32(&mut self) -> Result<f32> {
|
||||
let a: [u8; 4] = self.read_u8_array()?;
|
||||
Ok(self.endian().read_f32(&a))
|
||||
}
|
||||
|
||||
/// Read a f64.
|
||||
#[inline]
|
||||
fn read_f64(&mut self) -> Result<f64> {
|
||||
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<u64> {
|
||||
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<Self> {
|
||||
let idx = self.find(0)?;
|
||||
let val = self.split(idx)?;
|
||||
self.skip(Self::Offset::from_u8(1))?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
/// Skip a LEB128 encoded integer.
|
||||
fn skip_leb128(&mut self) -> Result<()> {
|
||||
leb128::read::skip(self)
|
||||
}
|
||||
|
||||
/// Read an unsigned LEB128 encoded integer.
|
||||
fn read_uleb128(&mut self) -> Result<u64> {
|
||||
leb128::read::unsigned(self)
|
||||
}
|
||||
|
||||
/// Read an unsigned LEB128 encoded u32.
|
||||
fn read_uleb128_u32(&mut self) -> Result<u32> {
|
||||
leb128::read::unsigned(self)?
|
||||
.try_into()
|
||||
.map_err(|_| Error::BadUnsignedLeb128)
|
||||
}
|
||||
|
||||
/// Read an unsigned LEB128 encoded u16.
|
||||
fn read_uleb128_u16(&mut self) -> Result<u16> {
|
||||
leb128::read::u16(self)
|
||||
}
|
||||
|
||||
/// Read a signed LEB128 encoded integer.
|
||||
fn read_sleb128(&mut self) -> Result<i64> {
|
||||
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<u64> {
|
||||
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<Self::Offset> {
|
||||
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::Offset> {
|
||||
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::Offset> {
|
||||
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<Self::Offset> {
|
||||
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)
|
||||
}
|
||||
}
|
1458
vendor/gimli/src/read/rnglists.rs
vendored
Normal file
1458
vendor/gimli/src/read/rnglists.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
321
vendor/gimli/src/read/str.rs
vendored
Normal file
321
vendor/gimli/src/read/str.rs
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
use crate::common::{
|
||||
DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
|
||||
Encoding, 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<R> {
|
||||
debug_str_section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
|
||||
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 macOS, 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<R: Reader> DebugStr<R> {
|
||||
/// 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<R::Offset>) -> Result<R> {
|
||||
let input = &mut self.debug_str_section.clone();
|
||||
input.skip(offset.0)?;
|
||||
input.read_null_terminated_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugStr<T> {
|
||||
/// 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<Vec<u8>> = 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<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.debug_str_section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugStr<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugStr
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.debug_str_section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugStr<R> {
|
||||
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<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugStrOffsets<R> {
|
||||
// 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<R::Offset>,
|
||||
index: DebugStrOffsetsIndex<R::Offset>,
|
||||
) -> Result<DebugStrOffset<R::Offset>> {
|
||||
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<T> DebugStrOffsets<T> {
|
||||
/// 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<Vec<u8>> = 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<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugStrOffsets<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugStrOffsets
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugStrOffsets<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugStrOffsets { section }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Offset> DebugStrOffsetsBase<Offset>
|
||||
where
|
||||
Offset: ReaderOffset,
|
||||
{
|
||||
/// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
|
||||
/// for the given `Encoding` and `DwarfFileType`.
|
||||
pub fn default_for_encoding_and_file(
|
||||
encoding: Encoding,
|
||||
file_type: DwarfFileType,
|
||||
) -> DebugStrOffsetsBase<Offset> {
|
||||
if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
|
||||
// In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
|
||||
// only a single unit in the file) but we must skip past the header, which the attribute
|
||||
// would normally do for us.
|
||||
// initial_length_size + version + 2 bytes of padding.
|
||||
DebugStrOffsetsBase(Offset::from_u8(
|
||||
encoding.format.initial_length_size() + 2 + 2,
|
||||
))
|
||||
} else {
|
||||
DebugStrOffsetsBase(Offset::from_u8(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The `DebugLineStr` struct represents the DWARF strings
|
||||
/// found in the `.debug_line_str` section.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugLineStr<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str`
|
||||
/// section.
|
||||
///
|
||||
/// It is the caller's responsibility to read the `.debug_line_str` section and
|
||||
/// present it as a `&[u8]` slice. That means using some ELF loader on
|
||||
/// Linux, a Mach-O loader on macOS, etc.
|
||||
///
|
||||
/// ```
|
||||
/// use gimli::{DebugLineStr, LittleEndian};
|
||||
///
|
||||
/// # let buf = [0x00, 0x01, 0x02, 0x03];
|
||||
/// # let read_debug_line_str_section_somehow = || &buf;
|
||||
/// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian);
|
||||
/// ```
|
||||
pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
|
||||
Self::from(EndianSlice::new(debug_line_str_section, endian))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugLineStr<R> {
|
||||
/// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
|
||||
pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
|
||||
let input = &mut self.section.clone();
|
||||
input.skip(offset.0)?;
|
||||
input.read_null_terminated_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugLineStr<T> {
|
||||
/// 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<Vec<u8>> = 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<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugLineStr<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugLineStr
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugLineStr<R> {
|
||||
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))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
6139
vendor/gimli/src/read/unit.rs
vendored
Normal file
6139
vendor/gimli/src/read/unit.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
283
vendor/gimli/src/read/util.rs
vendored
Normal file
283
vendor/gimli/src/read/util.rs
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
#[cfg(feature = "read")]
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(feature = "read")]
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ops;
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
mod sealed {
|
||||
/// # Safety
|
||||
/// Implementer must not modify the content in storage.
|
||||
pub unsafe trait Sealed {
|
||||
type Storage;
|
||||
|
||||
fn new_storage() -> Self::Storage;
|
||||
|
||||
fn grow(_storage: &mut Self::Storage, _additional: usize) -> Result<(), CapacityFull> {
|
||||
Err(CapacityFull)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CapacityFull;
|
||||
}
|
||||
|
||||
use sealed::*;
|
||||
|
||||
/// Marker trait for types that can be used as backing storage when a growable array type is needed.
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside this crate.
|
||||
pub trait ArrayLike: Sealed {
|
||||
/// Type of the elements being stored.
|
||||
type Item;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<Self::Item>];
|
||||
|
||||
#[doc(hidden)]
|
||||
fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<Self::Item>];
|
||||
}
|
||||
|
||||
// Use macro since const generics can't be used due to MSRV.
|
||||
macro_rules! impl_array {
|
||||
() => {};
|
||||
($n:literal $($rest:tt)*) => {
|
||||
// SAFETY: does not modify the content in storage.
|
||||
unsafe impl<T> Sealed for [T; $n] {
|
||||
type Storage = [MaybeUninit<T>; $n];
|
||||
|
||||
fn new_storage() -> Self::Storage {
|
||||
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
|
||||
unsafe { MaybeUninit::uninit().assume_init() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArrayLike for [T; $n] {
|
||||
type Item = T;
|
||||
|
||||
fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
|
||||
storage
|
||||
}
|
||||
|
||||
fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
|
||||
storage
|
||||
}
|
||||
}
|
||||
|
||||
impl_array!($($rest)*);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
macro_rules! impl_box {
|
||||
() => {};
|
||||
($n:literal $($rest:tt)*) => {
|
||||
// SAFETY: does not modify the content in storage.
|
||||
unsafe impl<T> Sealed for Box<[T; $n]> {
|
||||
type Storage = Box<[MaybeUninit<T>; $n]>;
|
||||
|
||||
fn new_storage() -> Self::Storage {
|
||||
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
|
||||
Box::new(unsafe { MaybeUninit::uninit().assume_init() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArrayLike for Box<[T; $n]> {
|
||||
type Item = T;
|
||||
|
||||
fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
|
||||
&storage[..]
|
||||
}
|
||||
|
||||
fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
|
||||
&mut storage[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl_box!($($rest)*);
|
||||
}
|
||||
}
|
||||
|
||||
impl_array!(0 1 2 3 4 8 16 32 64 128 192);
|
||||
#[cfg(feature = "read")]
|
||||
impl_box!(0 1 2 3 4 8 16 32 64 128 192);
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
unsafe impl<T> Sealed for Vec<T> {
|
||||
type Storage = Box<[MaybeUninit<T>]>;
|
||||
|
||||
fn new_storage() -> Self::Storage {
|
||||
Box::new([])
|
||||
}
|
||||
|
||||
fn grow(storage: &mut Self::Storage, additional: usize) -> Result<(), CapacityFull> {
|
||||
let mut vec: Vec<_> = core::mem::replace(storage, Box::new([])).into();
|
||||
vec.reserve(additional);
|
||||
// SAFETY: This is a `Vec` of `MaybeUninit`.
|
||||
unsafe { vec.set_len(vec.capacity()) };
|
||||
*storage = vec.into_boxed_slice();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
impl<T> ArrayLike for Vec<T> {
|
||||
type Item = T;
|
||||
|
||||
fn as_slice(storage: &Self::Storage) -> &[MaybeUninit<T>] {
|
||||
storage
|
||||
}
|
||||
|
||||
fn as_mut_slice(storage: &mut Self::Storage) -> &mut [MaybeUninit<T>] {
|
||||
storage
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ArrayVec<A: ArrayLike> {
|
||||
storage: A::Storage,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> ArrayVec<A> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
storage: A::new_storage(),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
let ptr: *mut [A::Item] = &mut **self;
|
||||
// Set length first so the type invariant is upheld even if `drop_in_place` panicks.
|
||||
self.len = 0;
|
||||
// SAFETY: `ptr` contains valid elements only and we "forget" them by setting the length.
|
||||
unsafe { ptr::drop_in_place(ptr) };
|
||||
}
|
||||
|
||||
pub fn try_push(&mut self, value: A::Item) -> Result<(), CapacityFull> {
|
||||
let mut storage = A::as_mut_slice(&mut self.storage);
|
||||
if self.len >= storage.len() {
|
||||
A::grow(&mut self.storage, 1)?;
|
||||
storage = A::as_mut_slice(&mut self.storage);
|
||||
}
|
||||
|
||||
storage[self.len] = MaybeUninit::new(value);
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), CapacityFull> {
|
||||
assert!(index <= self.len);
|
||||
|
||||
let mut storage = A::as_mut_slice(&mut self.storage);
|
||||
if self.len >= storage.len() {
|
||||
A::grow(&mut self.storage, 1)?;
|
||||
storage = A::as_mut_slice(&mut self.storage);
|
||||
}
|
||||
|
||||
// SAFETY: storage[index] is filled later.
|
||||
unsafe {
|
||||
let p = storage.as_mut_ptr().add(index);
|
||||
core::ptr::copy(p as *const _, p.add(1), self.len - index);
|
||||
}
|
||||
storage[index] = MaybeUninit::new(element);
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<A::Item> {
|
||||
if self.len == 0 {
|
||||
None
|
||||
} else {
|
||||
self.len -= 1;
|
||||
// SAFETY: this element is valid and we "forget" it by setting the length.
|
||||
Some(unsafe { A::as_slice(&self.storage)[self.len].as_ptr().read() })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_remove(&mut self, index: usize) -> A::Item {
|
||||
assert!(self.len > 0);
|
||||
A::as_mut_slice(&mut self.storage).swap(index, self.len - 1);
|
||||
self.pop().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "read")]
|
||||
impl<T> ArrayVec<Vec<T>> {
|
||||
pub fn into_vec(mut self) -> Vec<T> {
|
||||
let len = core::mem::replace(&mut self.len, 0);
|
||||
let storage = core::mem::replace(&mut self.storage, Box::new([]));
|
||||
let slice = Box::leak(storage);
|
||||
debug_assert!(len <= slice.len());
|
||||
// SAFETY: valid elements.
|
||||
unsafe { Vec::from_raw_parts(slice.as_mut_ptr() as *mut T, len, slice.len()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> Drop for ArrayVec<A> {
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> Default for ArrayVec<A> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> ops::Deref for ArrayVec<A> {
|
||||
type Target = [A::Item];
|
||||
|
||||
fn deref(&self) -> &[A::Item] {
|
||||
let slice = &A::as_slice(&self.storage);
|
||||
debug_assert!(self.len <= slice.len());
|
||||
// SAFETY: valid elements.
|
||||
unsafe { slice::from_raw_parts(slice.as_ptr() as _, self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> ops::DerefMut for ArrayVec<A> {
|
||||
fn deref_mut(&mut self) -> &mut [A::Item] {
|
||||
let slice = &mut A::as_mut_slice(&mut self.storage);
|
||||
debug_assert!(self.len <= slice.len());
|
||||
// SAFETY: valid elements.
|
||||
unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as _, self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> Clone for ArrayVec<A>
|
||||
where
|
||||
A::Item: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
let mut new = Self::default();
|
||||
for value in &**self {
|
||||
new.try_push(value.clone()).unwrap();
|
||||
}
|
||||
new
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> PartialEq for ArrayVec<A>
|
||||
where
|
||||
A::Item: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ArrayLike> Eq for ArrayVec<A> where A::Item: Eq {}
|
||||
|
||||
impl<A: ArrayLike> fmt::Debug for ArrayVec<A>
|
||||
where
|
||||
A::Item: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
1621
vendor/gimli/src/read/value.rs
vendored
Normal file
1621
vendor/gimli/src/read/value.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
vendor/gimli/src/test_util.rs
vendored
Normal file
53
vendor/gimli/src/test_util.rs
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
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(mut self, mut val: i64) -> Self {
|
||||
while val & !0x3f != 0 && val | 0x3f != -1 {
|
||||
self = self.D8(val as u8 | 0x80);
|
||||
val >>= 7;
|
||||
}
|
||||
self.D8(val as u8 & 0x7f)
|
||||
}
|
||||
|
||||
fn uleb(mut self, mut val: u64) -> Self {
|
||||
while val & !0x7f != 0 {
|
||||
self = self.D8(val as u8 | 0x80);
|
||||
val >>= 7;
|
||||
}
|
||||
self.D8(val as u8)
|
||||
}
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
188
vendor/gimli/src/write/abbrev.rs
vendored
Normal file
188
vendor/gimli/src/write/abbrev.rs
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
use alloc::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<Abbreviation>,
|
||||
}
|
||||
|
||||
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<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> 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<AttributeSpecification>,
|
||||
}
|
||||
|
||||
impl Abbreviation {
|
||||
/// Construct a new `Abbreviation`.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
tag: constants::DwTag,
|
||||
has_children: bool,
|
||||
attributes: Vec<AttributeSpecification>,
|
||||
) -> Abbreviation {
|
||||
Abbreviation {
|
||||
tag,
|
||||
has_children,
|
||||
attributes,
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the abbreviation to the `.debug_abbrev` section.
|
||||
pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
|
||||
w.write_uleb128(self.tag.0.into())?;
|
||||
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<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
|
||||
w.write_uleb128(self.name.0.into())?;
|
||||
w.write_uleb128(self.form.0.into())
|
||||
}
|
||||
}
|
||||
|
||||
define_section!(
|
||||
DebugAbbrev,
|
||||
DebugAbbrevOffset,
|
||||
"A writable `.debug_abbrev` section."
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "read")]
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
1050
vendor/gimli/src/write/cfi.rs
vendored
Normal file
1050
vendor/gimli/src/write/cfi.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
138
vendor/gimli/src/write/dwarf.rs
vendored
Normal file
138
vendor/gimli/src/write/dwarf.rs
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
use alloc::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<LineProgram>,
|
||||
|
||||
/// 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<W: Writer>(&mut self, sections: &mut Sections<W>) -> 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<W: Writer>(&mut self, sections: &mut Sections<W>) -> 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();
|
||||
|
||||
self.unit.write(
|
||||
sections,
|
||||
abbrev_offset,
|
||||
&mut abbrevs,
|
||||
&line_strings,
|
||||
&strings,
|
||||
)?;
|
||||
// None should exist because we didn't give out any UnitId.
|
||||
assert!(sections.debug_info_refs.is_empty());
|
||||
assert!(sections.debug_loc_refs.is_empty());
|
||||
assert!(sections.debug_loclists_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<R: Reader<Offset = usize>>(
|
||||
dwarf: &read::Dwarf<R>,
|
||||
convert_address: &dyn Fn(u64) -> Option<Address>,
|
||||
) -> ConvertResult<Dwarf> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
117
vendor/gimli/src/write/endian_vec.rs
vendored
Normal file
117
vendor/gimli/src/write/endian_vec.rs
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
use alloc::vec::Vec;
|
||||
use std::mem;
|
||||
|
||||
use crate::endianity::Endianity;
|
||||
use crate::write::{Error, Result, Writer};
|
||||
|
||||
/// A `Vec<u8>` with endianity metadata.
|
||||
///
|
||||
/// This implements the `Writer` trait, which is used for all writing of DWARF sections.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EndianVec<Endian>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
vec: Vec<u8>,
|
||||
endian: Endian,
|
||||
}
|
||||
|
||||
impl<Endian> EndianVec<Endian>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct an empty `EndianVec` with the given endianity.
|
||||
pub fn new(endian: Endian) -> EndianVec<Endian> {
|
||||
EndianVec {
|
||||
vec: Vec::new(),
|
||||
endian,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a reference to the raw slice.
|
||||
pub fn slice(&self) -> &[u8] {
|
||||
&self.vec
|
||||
}
|
||||
|
||||
/// Convert into a `Vec<u8>`.
|
||||
pub fn into_vec(self) -> Vec<u8> {
|
||||
self.vec
|
||||
}
|
||||
|
||||
/// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place.
|
||||
pub fn take(&mut self) -> Vec<u8> {
|
||||
let mut vec = Vec::new();
|
||||
mem::swap(&mut self.vec, &mut vec);
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
impl<Endian> Writer for EndianVec<Endian>
|
||||
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]);
|
||||
}
|
||||
}
|
1957
vendor/gimli/src/write/line.rs
vendored
Normal file
1957
vendor/gimli/src/write/line.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
550
vendor/gimli/src/write/loc.rs
vendored
Normal file
550
vendor/gimli/src/write/loc.rs
vendored
Normal file
@ -0,0 +1,550 @@
|
||||
use alloc::vec::Vec;
|
||||
use indexmap::IndexSet;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::common::{Encoding, LocationListsOffset, SectionId};
|
||||
use crate::write::{
|
||||
Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets,
|
||||
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<LocationList>,
|
||||
}
|
||||
|
||||
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<W: Writer>(
|
||||
&self,
|
||||
sections: &mut Sections<W>,
|
||||
encoding: Encoding,
|
||||
unit_offsets: Option<&UnitOffsets>,
|
||||
) -> Result<LocationListOffsets> {
|
||||
if self.locations.is_empty() {
|
||||
return Ok(LocationListOffsets::none());
|
||||
}
|
||||
|
||||
match encoding.version {
|
||||
2..=4 => self.write_loc(
|
||||
&mut sections.debug_loc,
|
||||
&mut sections.debug_loc_refs,
|
||||
encoding,
|
||||
unit_offsets,
|
||||
),
|
||||
5 => self.write_loclists(
|
||||
&mut sections.debug_loclists,
|
||||
&mut sections.debug_loclists_refs,
|
||||
encoding,
|
||||
unit_offsets,
|
||||
),
|
||||
_ => Err(Error::UnsupportedVersion(encoding.version)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the location list table to the `.debug_loc` section.
|
||||
fn write_loc<W: Writer>(
|
||||
&self,
|
||||
w: &mut DebugLoc<W>,
|
||||
refs: &mut Vec<DebugInfoReference>,
|
||||
encoding: Encoding,
|
||||
unit_offsets: Option<&UnitOffsets>,
|
||||
) -> Result<LocationListOffsets> {
|
||||
let address_size = encoding.address_size;
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
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<W: Writer>(
|
||||
&self,
|
||||
w: &mut DebugLocLists<W>,
|
||||
refs: &mut Vec<DebugInfoReference>,
|
||||
encoding: Encoding,
|
||||
unit_offsets: Option<&UnitOffsets>,
|
||||
) -> Result<LocationListOffsets> {
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
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)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
Location::DefaultLocation { ref data } => {
|
||||
w.write_u8(crate::constants::DW_LLE_default_location.0)?;
|
||||
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Location>);
|
||||
|
||||
/// 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,
|
||||
},
|
||||
}
|
||||
|
||||
fn write_expression<W: Writer>(
|
||||
w: &mut W,
|
||||
refs: &mut Vec<DebugInfoReference>,
|
||||
encoding: Encoding,
|
||||
unit_offsets: Option<&UnitOffsets>,
|
||||
val: &Expression,
|
||||
) -> Result<()> {
|
||||
let size = val.size(encoding, unit_offsets) as u64;
|
||||
if encoding.version <= 4 {
|
||||
w.write_udata(size, 2)?;
|
||||
} else {
|
||||
w.write_uleb128(size)?;
|
||||
}
|
||||
val.write(w, Some(refs), encoding, unit_offsets)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[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<R: Reader<Offset = usize>>(
|
||||
mut from: read::RawLocListIter<R>,
|
||||
context: &ConvertUnitContext<R>,
|
||||
) -> ConvertResult<Self> {
|
||||
let mut have_base_address = context.base_address != Address::Constant(0);
|
||||
let convert_address =
|
||||
|x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress);
|
||||
let convert_expression = |x| {
|
||||
Expression::from(
|
||||
x,
|
||||
context.unit.encoding(),
|
||||
Some(context.dwarf),
|
||||
Some(context.unit),
|
||||
Some(context.entry_ids),
|
||||
context.convert_address,
|
||||
)
|
||||
};
|
||||
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 = convert_expression(data)?;
|
||||
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 = convert_expression(data)?;
|
||||
Location::StartEnd { begin, end, data }
|
||||
}
|
||||
read::RawLocListEntry::StartxLength {
|
||||
begin,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
|
||||
let data = convert_expression(data)?;
|
||||
Location::StartLength {
|
||||
begin,
|
||||
length,
|
||||
data,
|
||||
}
|
||||
}
|
||||
read::RawLocListEntry::OffsetPair { begin, end, data } => {
|
||||
let data = convert_expression(data)?;
|
||||
Location::OffsetPair { begin, end, data }
|
||||
}
|
||||
read::RawLocListEntry::StartEnd { begin, end, data } => {
|
||||
let begin = convert_address(begin)?;
|
||||
let end = convert_address(end)?;
|
||||
let data = convert_expression(data)?;
|
||||
Location::StartEnd { begin, end, data }
|
||||
}
|
||||
read::RawLocListEntry::StartLength {
|
||||
begin,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
let begin = convert_address(begin)?;
|
||||
let data = convert_expression(data)?;
|
||||
Location::StartLength {
|
||||
begin,
|
||||
length,
|
||||
data,
|
||||
}
|
||||
}
|
||||
read::RawLocListEntry::DefaultLocation { data } => {
|
||||
let data = convert_expression(data)?;
|
||||
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)]
|
||||
#[cfg(feature = "read")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::common::{
|
||||
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
|
||||
DebugStrOffsetsBase, Format,
|
||||
};
|
||||
use crate::read;
|
||||
use crate::write::{
|
||||
ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable,
|
||||
};
|
||||
use crate::LittleEndian;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn test_loc_list() {
|
||||
let mut line_strings = LineStringTable::default();
|
||||
let mut strings = StringTable::default();
|
||||
let mut expression = Expression::new();
|
||||
expression.op_constu(0);
|
||||
|
||||
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.clone(),
|
||||
},
|
||||
Location::StartEnd {
|
||||
begin: Address::Constant(4444),
|
||||
end: Address::Constant(5555),
|
||||
data: expression.clone(),
|
||||
},
|
||||
Location::BaseAddress {
|
||||
address: Address::Constant(1111),
|
||||
},
|
||||
Location::OffsetPair {
|
||||
begin: 2222,
|
||||
end: 3333,
|
||||
data: expression.clone(),
|
||||
},
|
||||
]);
|
||||
if version >= 5 {
|
||||
loc_list.0.push(Location::DefaultLocation {
|
||||
data: expression.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
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, None).unwrap();
|
||||
assert!(sections.debug_loc_refs.is_empty());
|
||||
assert!(sections.debug_loclists_refs.is_empty());
|
||||
|
||||
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 {
|
||||
header: read::UnitHeader::new(
|
||||
encoding,
|
||||
0,
|
||||
read::UnitType::Compilation,
|
||||
DebugAbbrevOffset(0),
|
||||
DebugInfoOffset(0).into(),
|
||||
read::EndianSlice::default(),
|
||||
),
|
||||
abbreviations: Arc::new(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,
|
||||
dwo_id: 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(),
|
||||
entry_ids: &HashMap::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.clone(),
|
||||
};
|
||||
}
|
||||
assert_eq!(loc_list, convert_loc_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
425
vendor/gimli/src/write/mod.rs
vendored
Normal file
425
vendor/gimli/src/write/mod.rs
vendored
Normal file
@ -0,0 +1,425 @@
|
||||
//! 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 loc;
|
||||
pub use self::loc::*;
|
||||
|
||||
mod op;
|
||||
pub use self::op::*;
|
||||
|
||||
mod range;
|
||||
pub use self::range::*;
|
||||
|
||||
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,
|
||||
/// The reference is invalid.
|
||||
InvalidReference,
|
||||
/// 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),
|
||||
/// Unsupported reference in CFI expression.
|
||||
UnsupportedCfiExpressionReference,
|
||||
/// Unsupported forward reference in expression.
|
||||
UnsupportedExpressionForwardReference,
|
||||
}
|
||||
|
||||
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::InvalidReference => write!(f, "The reference 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)
|
||||
}
|
||||
Error::UnsupportedCfiExpressionReference => {
|
||||
write!(f, "Unsupported reference in CFI expression.")
|
||||
}
|
||||
Error::UnsupportedExpressionForwardReference => {
|
||||
write!(f, "Unsupported forward reference in expression.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
|
||||
/// The result of a write.
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
/// 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,
|
||||
},
|
||||
}
|
||||
|
||||
/// A reference to a `.debug_info` entry.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Reference {
|
||||
/// An external symbol.
|
||||
///
|
||||
/// The meaning of this value is decided by the writer, but
|
||||
/// will typically be an index into a symbol table.
|
||||
Symbol(usize),
|
||||
/// An entry in the same section.
|
||||
///
|
||||
/// This only supports references in units that are emitted together.
|
||||
Entry(UnitId, UnitEntryId),
|
||||
}
|
||||
|
||||
// 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,
|
||||
/// A `.debug_info` unit entry reference is invalid.
|
||||
InvalidUnitRef,
|
||||
/// A `.debug_info` reference is invalid.
|
||||
InvalidDebugInfoRef,
|
||||
/// 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,
|
||||
/// Writing this expression operation is not implemented yet.
|
||||
UnsupportedOperation,
|
||||
/// Operation branch target is invalid.
|
||||
InvalidBranchTarget,
|
||||
/// Writing this unit type is not supported yet.
|
||||
UnsupportedUnitType,
|
||||
}
|
||||
|
||||
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."),
|
||||
InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."),
|
||||
InvalidDebugInfoRef => write!(f, "A `.debug_info` 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.")
|
||||
}
|
||||
UnsupportedOperation => write!(
|
||||
f,
|
||||
"Writing this expression operation is not implemented yet."
|
||||
),
|
||||
InvalidBranchTarget => write!(f, "Operation branch target is invalid."),
|
||||
UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ConvertError {}
|
||||
|
||||
impl From<read::Error> for ConvertError {
|
||||
fn from(e: read::Error) -> Self {
|
||||
ConvertError::Read(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a conversion.
|
||||
pub type ConvertResult<T> = result::Result<T, ConvertError>;
|
||||
}
|
||||
#[cfg(feature = "read")]
|
||||
pub use self::convert::*;
|
1618
vendor/gimli/src/write/op.rs
vendored
Normal file
1618
vendor/gimli/src/write/op.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
416
vendor/gimli/src/write/range.rs
vendored
Normal file
416
vendor/gimli/src/write/range.rs
vendored
Normal file
@ -0,0 +1,416 @@
|
||||
use alloc::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<RangeList>,
|
||||
}
|
||||
|
||||
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<W: Writer>(
|
||||
&self,
|
||||
sections: &mut Sections<W>,
|
||||
encoding: Encoding,
|
||||
) -> Result<RangeListOffsets> {
|
||||
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<W: Writer>(
|
||||
&self,
|
||||
w: &mut DebugRanges<W>,
|
||||
address_size: u8,
|
||||
) -> Result<RangeListOffsets> {
|
||||
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<W: Writer>(
|
||||
&self,
|
||||
w: &mut DebugRngLists<W>,
|
||||
encoding: Encoding,
|
||||
) -> Result<RangeListOffsets> {
|
||||
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<Range>);
|
||||
|
||||
/// 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<R: Reader<Offset = usize>>(
|
||||
mut from: read::RawRngListIter<R>,
|
||||
context: &ConvertUnitContext<R>,
|
||||
) -> ConvertResult<Self> {
|
||||
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)]
|
||||
#[cfg(feature = "read")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::common::{
|
||||
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
|
||||
DebugStrOffsetsBase, Format,
|
||||
};
|
||||
use crate::read;
|
||||
use crate::write::{
|
||||
ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable,
|
||||
StringTable,
|
||||
};
|
||||
use crate::LittleEndian;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[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 {
|
||||
header: read::UnitHeader::new(
|
||||
encoding,
|
||||
0,
|
||||
read::UnitType::Compilation,
|
||||
DebugAbbrevOffset(0),
|
||||
DebugInfoOffset(0).into(),
|
||||
read::EndianSlice::default(),
|
||||
),
|
||||
abbreviations: Arc::new(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,
|
||||
dwo_id: 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(),
|
||||
entry_ids: &HashMap::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
172
vendor/gimli/src/write/section.rs
vendored
Normal file
172
vendor/gimli/src/write/section.rs
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
use std::ops::DerefMut;
|
||||
use std::result;
|
||||
use std::vec::Vec;
|
||||
|
||||
use crate::common::SectionId;
|
||||
use crate::write::{
|
||||
DebugAbbrev, DebugFrame, DebugInfo, DebugInfoReference, DebugLine, DebugLineStr, DebugLoc,
|
||||
DebugLocLists, DebugRanges, DebugRngLists, DebugStr, EhFrame, Writer,
|
||||
};
|
||||
|
||||
macro_rules! define_section {
|
||||
($name:ident, $offset:ident, $docs:expr) => {
|
||||
#[doc=$docs]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct $name<W: Writer>(pub W);
|
||||
|
||||
impl<W: Writer> $name<W> {
|
||||
/// Return the offset of the next write.
|
||||
pub fn offset(&self) -> $offset {
|
||||
$offset(self.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> From<W> for $name<W> {
|
||||
#[inline]
|
||||
fn from(w: W) -> Self {
|
||||
$name(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> Deref for $name<W> {
|
||||
type Target = W;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &W {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> DerefMut for $name<W> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut W {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> Section<W> for $name<W> {
|
||||
#[inline]
|
||||
fn id(&self) -> SectionId {
|
||||
SectionId::$name
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Functionality common to all writable DWARF sections.
|
||||
pub trait Section<W: Writer>: DerefMut<Target = W> {
|
||||
/// 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<W: Writer> {
|
||||
/// The `.debug_abbrev` section.
|
||||
pub debug_abbrev: DebugAbbrev<W>,
|
||||
/// The `.debug_info` section.
|
||||
pub debug_info: DebugInfo<W>,
|
||||
/// The `.debug_line` section.
|
||||
pub debug_line: DebugLine<W>,
|
||||
/// The `.debug_line_str` section.
|
||||
pub debug_line_str: DebugLineStr<W>,
|
||||
/// The `.debug_ranges` section.
|
||||
pub debug_ranges: DebugRanges<W>,
|
||||
/// The `.debug_rnglists` section.
|
||||
pub debug_rnglists: DebugRngLists<W>,
|
||||
/// The `.debug_loc` section.
|
||||
pub debug_loc: DebugLoc<W>,
|
||||
/// The `.debug_loclists` section.
|
||||
pub debug_loclists: DebugLocLists<W>,
|
||||
/// The `.debug_str` section.
|
||||
pub debug_str: DebugStr<W>,
|
||||
/// The `.debug_frame` section.
|
||||
pub debug_frame: DebugFrame<W>,
|
||||
/// The `.eh_frame` section.
|
||||
pub eh_frame: EhFrame<W>,
|
||||
/// Unresolved references in the `.debug_info` section.
|
||||
pub(crate) debug_info_refs: Vec<DebugInfoReference>,
|
||||
/// Unresolved references in the `.debug_loc` section.
|
||||
pub(crate) debug_loc_refs: Vec<DebugInfoReference>,
|
||||
/// Unresolved references in the `.debug_loclists` section.
|
||||
pub(crate) debug_loclists_refs: Vec<DebugInfoReference>,
|
||||
}
|
||||
|
||||
impl<W: Writer + Clone> Sections<W> {
|
||||
/// 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()),
|
||||
debug_frame: DebugFrame(section.clone()),
|
||||
eh_frame: EhFrame(section),
|
||||
debug_info_refs: Vec::new(),
|
||||
debug_loc_refs: Vec::new(),
|
||||
debug_loclists_refs: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> Sections<W> {
|
||||
/// For each section, call `f` once with a shared reference.
|
||||
pub fn for_each<F, E>(&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)?;
|
||||
f!(self.debug_frame)?;
|
||||
f!(self.eh_frame)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// For each section, call `f` once with a mutable reference.
|
||||
pub fn for_each_mut<F, E>(&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)?;
|
||||
f!(self.debug_frame)?;
|
||||
f!(self.eh_frame)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
172
vendor/gimli/src/write/str.rs
vendored
Normal file
172
vendor/gimli/src/write/str.rs
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
use alloc::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<Vec<u8>>,
|
||||
}
|
||||
|
||||
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<T>(&mut self, bytes: T) -> $id
|
||||
where
|
||||
T: Into<Vec<u8>>,
|
||||
{
|
||||
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<W: Writer>(&self, w: &mut $section<W>) -> 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)]
|
||||
#[cfg(feature = "read")]
|
||||
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"[..]);
|
||||
}
|
||||
}
|
3152
vendor/gimli/src/write/unit.rs
vendored
Normal file
3152
vendor/gimli/src/write/unit.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
494
vendor/gimli/src/write/writer.rs
vendored
Normal file
494
vendor/gimli/src/write/writer.rs
vendored
Normal file
@ -0,0 +1,494 @@
|
||||
use 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.
|
||||
// TODO: use write_reference instead?
|
||||
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;
|
||||
val.wrapping_sub(offset)
|
||||
}
|
||||
_ => {
|
||||
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),
|
||||
_ => 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 reference to a symbol.
|
||||
///
|
||||
/// If the writer supports symbols, then it must provide its own implementation
|
||||
/// of this method.
|
||||
fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> {
|
||||
Err(Error::InvalidReference)
|
||||
}
|
||||
|
||||
/// 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<InitialLengthOffset> {
|
||||
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]
|
||||
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]
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user