]> git.proxmox.com Git - rustc.git/blob - vendor/addr2line/examples/addr2line.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / vendor / addr2line / examples / addr2line.rs
1 extern crate addr2line;
2 extern crate clap;
3 extern crate fallible_iterator;
4 extern crate gimli;
5 extern crate memmap;
6 extern crate object;
7 extern crate typed_arena;
8
9 use std::borrow::Cow;
10 use std::fs::File;
11 use std::io::{BufRead, Lines, StdinLock, Write};
12 use std::path::Path;
13
14 use clap::{App, Arg, Values};
15 use fallible_iterator::FallibleIterator;
16 use object::{Object, ObjectSection};
17 use typed_arena::Arena;
18
19 use addr2line::{Context, Location};
20
21 fn parse_uint_from_hex_string(string: &str) -> u64 {
22 if string.len() > 2 && string.starts_with("0x") {
23 u64::from_str_radix(&string[2..], 16).expect("Failed to parse address")
24 } else {
25 u64::from_str_radix(string, 16).expect("Failed to parse address")
26 }
27 }
28
29 enum Addrs<'a> {
30 Args(Values<'a>),
31 Stdin(Lines<StdinLock<'a>>),
32 }
33
34 impl<'a> Iterator for Addrs<'a> {
35 type Item = u64;
36
37 fn next(&mut self) -> Option<u64> {
38 let text = match *self {
39 Addrs::Args(ref mut vals) => vals.next().map(Cow::from),
40 Addrs::Stdin(ref mut lines) => lines.next().map(Result::unwrap).map(Cow::from),
41 };
42 text.as_ref()
43 .map(Cow::as_ref)
44 .map(parse_uint_from_hex_string)
45 }
46 }
47
48 fn print_loc(loc: &Option<Location>, basenames: bool, llvm: bool) {
49 if let Some(ref loc) = *loc {
50 let file = loc.file.as_ref().unwrap();
51 let path = if basenames {
52 Path::new(Path::new(file).file_name().unwrap())
53 } else {
54 Path::new(file)
55 };
56 print!("{}:", path.display());
57 if llvm {
58 print!("{}:{}", loc.line.unwrap_or(0), loc.column.unwrap_or(0));
59 } else if let Some(line) = loc.line {
60 print!("{}", line);
61 } else {
62 print!("?");
63 }
64 println!();
65 } else if llvm {
66 println!("??:0:0");
67 } else {
68 println!("??:?");
69 }
70 }
71
72 fn print_function(name: &str, language: Option<gimli::DwLang>, demangle: bool) {
73 if demangle {
74 print!("{}", addr2line::demangle_auto(Cow::from(name), language));
75 } else {
76 print!("{}", name);
77 }
78 }
79
80 fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
81 id: gimli::SectionId,
82 file: &object::File<'input>,
83 endian: Endian,
84 arena_data: &'arena Arena<Cow<'input, [u8]>>,
85 ) -> Result<gimli::EndianSlice<'arena, Endian>, ()> {
86 // TODO: Unify with dwarfdump.rs in gimli.
87 let name = id.name();
88 match file.section_by_name(name) {
89 Some(section) => match section.uncompressed_data().unwrap() {
90 Cow::Borrowed(b) => Ok(gimli::EndianSlice::new(b, endian)),
91 Cow::Owned(b) => Ok(gimli::EndianSlice::new(arena_data.alloc(b.into()), endian)),
92 },
93 None => Ok(gimli::EndianSlice::new(&[][..], endian)),
94 }
95 }
96
97 fn main() {
98 let matches = App::new("hardliner")
99 .version("0.1")
100 .about("A fast addr2line clone")
101 .arg(
102 Arg::with_name("exe")
103 .short("e")
104 .long("exe")
105 .value_name("filename")
106 .help(
107 "Specify the name of the executable for which addresses should be translated.",
108 )
109 .required(true),
110 )
111 .arg(
112 Arg::with_name("sup")
113 .long("sup")
114 .value_name("filename")
115 .help("Path to supplementary object file."),
116 )
117 .arg(
118 Arg::with_name("functions")
119 .short("f")
120 .long("functions")
121 .help("Display function names as well as file and line number information."),
122 )
123 .arg(
124 Arg::with_name("pretty")
125 .short("p")
126 .long("pretty-print")
127 .help(
128 "Make the output more human friendly: each location are printed on \
129 one line.",
130 ),
131 )
132 .arg(Arg::with_name("inlines").short("i").long("inlines").help(
133 "If the address belongs to a function that was inlined, the source \
134 information for all enclosing scopes back to the first non-inlined \
135 function will also be printed.",
136 ))
137 .arg(
138 Arg::with_name("addresses")
139 .short("a")
140 .long("addresses")
141 .help(
142 "Display the address before the function name, file and line \
143 number information.",
144 ),
145 )
146 .arg(
147 Arg::with_name("basenames")
148 .short("s")
149 .long("basenames")
150 .help("Display only the base of each file name."),
151 )
152 .arg(Arg::with_name("demangle").short("C").long("demangle").help(
153 "Demangle function names. \
154 Specifying a specific demangling style (like GNU addr2line) \
155 is not supported. (TODO)",
156 ))
157 .arg(
158 Arg::with_name("llvm")
159 .long("llvm")
160 .help("Display output in the same format as llvm-symbolizer."),
161 )
162 .arg(
163 Arg::with_name("addrs")
164 .takes_value(true)
165 .multiple(true)
166 .help("Addresses to use instead of reading from stdin."),
167 )
168 .get_matches();
169
170 let arena_data = Arena::new();
171
172 let do_functions = matches.is_present("functions");
173 let do_inlines = matches.is_present("inlines");
174 let pretty = matches.is_present("pretty");
175 let print_addrs = matches.is_present("addresses");
176 let basenames = matches.is_present("basenames");
177 let demangle = matches.is_present("demangle");
178 let llvm = matches.is_present("llvm");
179 let path = matches.value_of("exe").unwrap();
180
181 let file = File::open(path).unwrap();
182 let map = unsafe { memmap::Mmap::map(&file).unwrap() };
183 let object = &object::File::parse(&*map).unwrap();
184
185 let endian = if object.is_little_endian() {
186 gimli::RunTimeEndian::Little
187 } else {
188 gimli::RunTimeEndian::Big
189 };
190
191 let mut load_section = |id: gimli::SectionId| -> Result<_, _> {
192 load_file_section(id, object, endian, &arena_data)
193 };
194
195 let sup_map;
196 let sup_object = if let Some(sup_path) = matches.value_of("sup") {
197 let sup_file = File::open(sup_path).unwrap();
198 sup_map = unsafe { memmap::Mmap::map(&sup_file).unwrap() };
199 Some(object::File::parse(&*sup_map).unwrap())
200 } else {
201 None
202 };
203
204 let symbols = object.symbol_map();
205 let mut dwarf = gimli::Dwarf::load(&mut load_section).unwrap();
206 if let Some(ref sup_object) = sup_object {
207 let mut load_sup_section = |id: gimli::SectionId| -> Result<_, _> {
208 load_file_section(id, sup_object, endian, &arena_data)
209 };
210 dwarf.load_sup(&mut load_sup_section).unwrap();
211 }
212
213 let ctx = Context::from_dwarf(dwarf).unwrap();
214
215 let stdin = std::io::stdin();
216 let addrs = matches
217 .values_of("addrs")
218 .map(Addrs::Args)
219 .unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()));
220
221 for probe in addrs {
222 if print_addrs {
223 if llvm {
224 print!("0x{:x}", probe);
225 } else {
226 print!("0x{:016x}", probe);
227 }
228 if pretty {
229 print!(": ");
230 } else {
231 println!();
232 }
233 }
234
235 if do_functions || do_inlines {
236 let mut printed_anything = false;
237 let mut frames = ctx.find_frames(probe).unwrap().enumerate();
238 while let Some((i, frame)) = frames.next().unwrap() {
239 if pretty && i != 0 {
240 print!(" (inlined by) ");
241 }
242
243 if do_functions {
244 if let Some(func) = frame.function {
245 print_function(&func.raw_name().unwrap(), func.language, demangle);
246 } else if let Some(name) = symbols.get(probe).map(|x| x.name()) {
247 print_function(name, None, demangle);
248 } else {
249 print!("??");
250 }
251
252 if pretty {
253 print!(" at ");
254 } else {
255 println!();
256 }
257 }
258
259 print_loc(&frame.location, basenames, llvm);
260
261 printed_anything = true;
262
263 if !do_inlines {
264 break;
265 }
266 }
267
268 if !printed_anything {
269 if do_functions {
270 if let Some(name) = symbols.get(probe).map(|x| x.name()) {
271 print_function(name, None, demangle);
272 } else {
273 print!("??");
274 }
275
276 if pretty {
277 print!(" at ");
278 } else {
279 println!();
280 }
281 }
282
283 if llvm {
284 println!("??:0:0");
285 } else {
286 println!("??:?");
287 }
288 }
289 } else {
290 let loc = ctx.find_location(probe).unwrap();
291 print_loc(&loc, basenames, llvm);
292 }
293
294 if llvm {
295 println!();
296 }
297 std::io::stdout().flush().unwrap();
298 }
299 }