/src/mozilla-central/tools/profiler/lul/LulDwarf.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | |
4 | | // Copyright (c) 2010 Google Inc. All Rights Reserved. |
5 | | // |
6 | | // Redistribution and use in source and binary forms, with or without |
7 | | // modification, are permitted provided that the following conditions are |
8 | | // met: |
9 | | // |
10 | | // * Redistributions of source code must retain the above copyright |
11 | | // notice, this list of conditions and the following disclaimer. |
12 | | // * Redistributions in binary form must reproduce the above |
13 | | // copyright notice, this list of conditions and the following disclaimer |
14 | | // in the documentation and/or other materials provided with the |
15 | | // distribution. |
16 | | // * Neither the name of Google Inc. nor the names of its |
17 | | // contributors may be used to endorse or promote products derived from |
18 | | // this software without specific prior written permission. |
19 | | // |
20 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | | |
32 | | // CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
33 | | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
34 | | |
35 | | // Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit, |
36 | | // and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details. |
37 | | |
38 | | // This file is derived from the following files in |
39 | | // toolkit/crashreporter/google-breakpad: |
40 | | // src/common/dwarf/bytereader.cc |
41 | | // src/common/dwarf/dwarf2reader.cc |
42 | | // src/common/dwarf_cfi_to_module.cc |
43 | | |
44 | | #include <stdint.h> |
45 | | #include <stdio.h> |
46 | | #include <string.h> |
47 | | #include <stdlib.h> |
48 | | |
49 | | #include <map> |
50 | | #include <stack> |
51 | | #include <string> |
52 | | |
53 | | #include "mozilla/Assertions.h" |
54 | | #include "mozilla/Sprintf.h" |
55 | | |
56 | | #include "LulCommonExt.h" |
57 | | #include "LulDwarfInt.h" |
58 | | |
59 | | |
60 | | // Set this to 1 for verbose logging |
61 | 0 | #define DEBUG_DWARF 0 |
62 | | |
63 | | |
64 | | namespace lul { |
65 | | |
66 | | using std::string; |
67 | | |
68 | | ByteReader::ByteReader(enum Endianness endian) |
69 | | :offset_reader_(NULL), address_reader_(NULL), endian_(endian), |
70 | | address_size_(0), offset_size_(0), |
71 | | have_section_base_(), have_text_base_(), have_data_base_(), |
72 | 0 | have_function_base_() { } |
73 | | |
74 | 0 | ByteReader::~ByteReader() { } |
75 | | |
76 | 0 | void ByteReader::SetOffsetSize(uint8 size) { |
77 | 0 | offset_size_ = size; |
78 | 0 | MOZ_ASSERT(size == 4 || size == 8); |
79 | 0 | if (size == 4) { |
80 | 0 | this->offset_reader_ = &ByteReader::ReadFourBytes; |
81 | 0 | } else { |
82 | 0 | this->offset_reader_ = &ByteReader::ReadEightBytes; |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | 0 | void ByteReader::SetAddressSize(uint8 size) { |
87 | 0 | address_size_ = size; |
88 | 0 | MOZ_ASSERT(size == 4 || size == 8); |
89 | 0 | if (size == 4) { |
90 | 0 | this->address_reader_ = &ByteReader::ReadFourBytes; |
91 | 0 | } else { |
92 | 0 | this->address_reader_ = &ByteReader::ReadEightBytes; |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | 0 | uint64 ByteReader::ReadInitialLength(const char* start, size_t* len) { |
97 | 0 | const uint64 initial_length = ReadFourBytes(start); |
98 | 0 | start += 4; |
99 | 0 |
|
100 | 0 | // In DWARF2/3, if the initial length is all 1 bits, then the offset |
101 | 0 | // size is 8 and we need to read the next 8 bytes for the real length. |
102 | 0 | if (initial_length == 0xffffffff) { |
103 | 0 | SetOffsetSize(8); |
104 | 0 | *len = 12; |
105 | 0 | return ReadOffset(start); |
106 | 0 | } else { |
107 | 0 | SetOffsetSize(4); |
108 | 0 | *len = 4; |
109 | 0 | } |
110 | 0 | return initial_length; |
111 | 0 | } |
112 | | |
113 | 0 | bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const { |
114 | 0 | if (encoding == DW_EH_PE_omit) return true; |
115 | 0 | if (encoding == DW_EH_PE_aligned) return true; |
116 | 0 | if ((encoding & 0x7) > DW_EH_PE_udata8) |
117 | 0 | return false; |
118 | 0 | if ((encoding & 0x70) > DW_EH_PE_funcrel) |
119 | 0 | return false; |
120 | 0 | return true; |
121 | 0 | } |
122 | | |
123 | | bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const { |
124 | | switch (encoding & 0x70) { |
125 | | case DW_EH_PE_absptr: return true; |
126 | | case DW_EH_PE_pcrel: return have_section_base_; |
127 | | case DW_EH_PE_textrel: return have_text_base_; |
128 | | case DW_EH_PE_datarel: return have_data_base_; |
129 | | case DW_EH_PE_funcrel: return have_function_base_; |
130 | | default: return false; |
131 | | } |
132 | | } |
133 | | |
134 | | uint64 ByteReader::ReadEncodedPointer(const char *buffer, |
135 | | DwarfPointerEncoding encoding, |
136 | 0 | size_t *len) const { |
137 | 0 | // UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't |
138 | 0 | // see it here. |
139 | 0 | MOZ_ASSERT(encoding != DW_EH_PE_omit); |
140 | 0 |
|
141 | 0 | // The Linux Standards Base 4.0 does not make this clear, but the |
142 | 0 | // GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c) |
143 | 0 | // agree that aligned pointers are always absolute, machine-sized, |
144 | 0 | // machine-signed pointers. |
145 | 0 | if (encoding == DW_EH_PE_aligned) { |
146 | 0 | MOZ_ASSERT(have_section_base_); |
147 | 0 |
|
148 | 0 | // We don't need to align BUFFER in *our* address space. Rather, we |
149 | 0 | // need to find the next position in our buffer that would be aligned |
150 | 0 | // when the .eh_frame section the buffer contains is loaded into the |
151 | 0 | // program's memory. So align assuming that buffer_base_ gets loaded at |
152 | 0 | // address section_base_, where section_base_ itself may or may not be |
153 | 0 | // aligned. |
154 | 0 |
|
155 | 0 | // First, find the offset to START from the closest prior aligned |
156 | 0 | // address. |
157 | 0 | uint64 skew = section_base_ & (AddressSize() - 1); |
158 | 0 | // Now find the offset from that aligned address to buffer. |
159 | 0 | uint64 offset = skew + (buffer - buffer_base_); |
160 | 0 | // Round up to the next boundary. |
161 | 0 | uint64 aligned = (offset + AddressSize() - 1) & -AddressSize(); |
162 | 0 | // Convert back to a pointer. |
163 | 0 | const char *aligned_buffer = buffer_base_ + (aligned - skew); |
164 | 0 | // Finally, store the length and actually fetch the pointer. |
165 | 0 | *len = aligned_buffer - buffer + AddressSize(); |
166 | 0 | return ReadAddress(aligned_buffer); |
167 | 0 | } |
168 | 0 |
|
169 | 0 | // Extract the value first, ignoring whether it's a pointer or an |
170 | 0 | // offset relative to some base. |
171 | 0 | uint64 offset; |
172 | 0 | switch (encoding & 0x0f) { |
173 | 0 | case DW_EH_PE_absptr: |
174 | 0 | // DW_EH_PE_absptr is weird, as it is used as a meaningful value for |
175 | 0 | // both the high and low nybble of encoding bytes. When it appears in |
176 | 0 | // the high nybble, it means that the pointer is absolute, not an |
177 | 0 | // offset from some base address. When it appears in the low nybble, |
178 | 0 | // as here, it means that the pointer is stored as a normal |
179 | 0 | // machine-sized and machine-signed address. A low nybble of |
180 | 0 | // DW_EH_PE_absptr does not imply that the pointer is absolute; it is |
181 | 0 | // correct for us to treat the value as an offset from a base address |
182 | 0 | // if the upper nybble is not DW_EH_PE_absptr. |
183 | 0 | offset = ReadAddress(buffer); |
184 | 0 | *len = AddressSize(); |
185 | 0 | break; |
186 | 0 |
|
187 | 0 | case DW_EH_PE_uleb128: |
188 | 0 | offset = ReadUnsignedLEB128(buffer, len); |
189 | 0 | break; |
190 | 0 |
|
191 | 0 | case DW_EH_PE_udata2: |
192 | 0 | offset = ReadTwoBytes(buffer); |
193 | 0 | *len = 2; |
194 | 0 | break; |
195 | 0 |
|
196 | 0 | case DW_EH_PE_udata4: |
197 | 0 | offset = ReadFourBytes(buffer); |
198 | 0 | *len = 4; |
199 | 0 | break; |
200 | 0 |
|
201 | 0 | case DW_EH_PE_udata8: |
202 | 0 | offset = ReadEightBytes(buffer); |
203 | 0 | *len = 8; |
204 | 0 | break; |
205 | 0 |
|
206 | 0 | case DW_EH_PE_sleb128: |
207 | 0 | offset = ReadSignedLEB128(buffer, len); |
208 | 0 | break; |
209 | 0 |
|
210 | 0 | case DW_EH_PE_sdata2: |
211 | 0 | offset = ReadTwoBytes(buffer); |
212 | 0 | // Sign-extend from 16 bits. |
213 | 0 | offset = (offset ^ 0x8000) - 0x8000; |
214 | 0 | *len = 2; |
215 | 0 | break; |
216 | 0 |
|
217 | 0 | case DW_EH_PE_sdata4: |
218 | 0 | offset = ReadFourBytes(buffer); |
219 | 0 | // Sign-extend from 32 bits. |
220 | 0 | offset = (offset ^ 0x80000000ULL) - 0x80000000ULL; |
221 | 0 | *len = 4; |
222 | 0 | break; |
223 | 0 |
|
224 | 0 | case DW_EH_PE_sdata8: |
225 | 0 | // No need to sign-extend; this is the full width of our type. |
226 | 0 | offset = ReadEightBytes(buffer); |
227 | 0 | *len = 8; |
228 | 0 | break; |
229 | 0 |
|
230 | 0 | default: |
231 | 0 | abort(); |
232 | 0 | } |
233 | 0 | |
234 | 0 | // Find the appropriate base address. |
235 | 0 | uint64 base; |
236 | 0 | switch (encoding & 0x70) { |
237 | 0 | case DW_EH_PE_absptr: |
238 | 0 | base = 0; |
239 | 0 | break; |
240 | 0 |
|
241 | 0 | case DW_EH_PE_pcrel: |
242 | 0 | MOZ_ASSERT(have_section_base_); |
243 | 0 | base = section_base_ + (buffer - buffer_base_); |
244 | 0 | break; |
245 | 0 |
|
246 | 0 | case DW_EH_PE_textrel: |
247 | 0 | MOZ_ASSERT(have_text_base_); |
248 | 0 | base = text_base_; |
249 | 0 | break; |
250 | 0 |
|
251 | 0 | case DW_EH_PE_datarel: |
252 | 0 | MOZ_ASSERT(have_data_base_); |
253 | 0 | base = data_base_; |
254 | 0 | break; |
255 | 0 |
|
256 | 0 | case DW_EH_PE_funcrel: |
257 | 0 | MOZ_ASSERT(have_function_base_); |
258 | 0 | base = function_base_; |
259 | 0 | break; |
260 | 0 |
|
261 | 0 | default: |
262 | 0 | abort(); |
263 | 0 | } |
264 | 0 | |
265 | 0 | uint64 pointer = base + offset; |
266 | 0 |
|
267 | 0 | // Remove inappropriate upper bits. |
268 | 0 | if (AddressSize() == 4) |
269 | 0 | pointer = pointer & 0xffffffff; |
270 | 0 | else |
271 | 0 | MOZ_ASSERT(AddressSize() == sizeof(uint64)); |
272 | 0 |
|
273 | 0 | return pointer; |
274 | 0 | } |
275 | | |
276 | | |
277 | | // A DWARF rule for recovering the address or value of a register, or |
278 | | // computing the canonical frame address. There is one subclass of this for |
279 | | // each '*Rule' member function in CallFrameInfo::Handler. |
280 | | // |
281 | | // It's annoying that we have to handle Rules using pointers (because |
282 | | // the concrete instances can have an arbitrary size). They're small, |
283 | | // so it would be much nicer if we could just handle them by value |
284 | | // instead of fretting about ownership and destruction. |
285 | | // |
286 | | // It seems like all these could simply be instances of std::tr1::bind, |
287 | | // except that we need instances to be EqualityComparable, too. |
288 | | // |
289 | | // This could logically be nested within State, but then the qualified names |
290 | | // get horrendous. |
291 | | class CallFrameInfo::Rule { |
292 | | public: |
293 | 0 | virtual ~Rule() { } |
294 | | |
295 | | // Tell HANDLER that, at ADDRESS in the program, REG can be |
296 | | // recovered using this rule. If REG is kCFARegister, then this rule |
297 | | // describes how to compute the canonical frame address. Return what the |
298 | | // HANDLER member function returned. |
299 | | virtual bool Handle(Handler *handler, uint64 address, int reg) const = 0; |
300 | | |
301 | | // Equality on rules. We use these to decide which rules we need |
302 | | // to report after a DW_CFA_restore_state instruction. |
303 | | virtual bool operator==(const Rule &rhs) const = 0; |
304 | | |
305 | 0 | bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } |
306 | | |
307 | | // Return a pointer to a copy of this rule. |
308 | | virtual Rule *Copy() const = 0; |
309 | | |
310 | | // If this is a base+offset rule, change its base register to REG. |
311 | | // Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.) |
312 | 0 | virtual void SetBaseRegister(unsigned reg) { } |
313 | | |
314 | | // If this is a base+offset rule, change its offset to OFFSET. Otherwise, |
315 | | // do nothing. (Ugly, but required for DW_CFA_def_cfa_offset.) |
316 | 0 | virtual void SetOffset(long long offset) { } |
317 | | |
318 | | // A RTTI workaround, to make it possible to implement equality |
319 | | // comparisons on classes derived from this one. |
320 | | enum CFIRTag { |
321 | | CFIR_UNDEFINED_RULE, |
322 | | CFIR_SAME_VALUE_RULE, |
323 | | CFIR_OFFSET_RULE, |
324 | | CFIR_VAL_OFFSET_RULE, |
325 | | CFIR_REGISTER_RULE, |
326 | | CFIR_EXPRESSION_RULE, |
327 | | CFIR_VAL_EXPRESSION_RULE |
328 | | }; |
329 | | |
330 | | // Produce the tag that identifies the child class of this object. |
331 | | virtual CFIRTag getTag() const = 0; |
332 | | }; |
333 | | |
334 | | // Rule: the value the register had in the caller cannot be recovered. |
335 | | class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { |
336 | | public: |
337 | 0 | UndefinedRule() { } |
338 | 0 | ~UndefinedRule() { } |
339 | 0 | CFIRTag getTag() const override { return CFIR_UNDEFINED_RULE; } |
340 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
341 | 0 | return handler->UndefinedRule(address, reg); |
342 | 0 | } |
343 | 0 | bool operator==(const Rule &rhs) const override { |
344 | 0 | if (rhs.getTag() != CFIR_UNDEFINED_RULE) return false; |
345 | 0 | return true; |
346 | 0 | } |
347 | 0 | Rule *Copy() const override { return new UndefinedRule(*this); } |
348 | | }; |
349 | | |
350 | | // Rule: the register's value is the same as that it had in the caller. |
351 | | class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { |
352 | | public: |
353 | 0 | SameValueRule() { } |
354 | 0 | ~SameValueRule() { } |
355 | 0 | CFIRTag getTag() const override { return CFIR_SAME_VALUE_RULE; } |
356 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
357 | 0 | return handler->SameValueRule(address, reg); |
358 | 0 | } |
359 | 0 | bool operator==(const Rule &rhs) const override { |
360 | 0 | if (rhs.getTag() != CFIR_SAME_VALUE_RULE) return false; |
361 | 0 | return true; |
362 | 0 | } |
363 | 0 | Rule *Copy() const override { return new SameValueRule(*this); } |
364 | | }; |
365 | | |
366 | | // Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER |
367 | | // may be CallFrameInfo::Handler::kCFARegister. |
368 | | class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { |
369 | | public: |
370 | | OffsetRule(int base_register, long offset) |
371 | 0 | : base_register_(base_register), offset_(offset) { } |
372 | 0 | ~OffsetRule() { } |
373 | 0 | CFIRTag getTag() const override { return CFIR_OFFSET_RULE; } |
374 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
375 | 0 | return handler->OffsetRule(address, reg, base_register_, offset_); |
376 | 0 | } |
377 | 0 | bool operator==(const Rule &rhs) const override { |
378 | 0 | if (rhs.getTag() != CFIR_OFFSET_RULE) return false; |
379 | 0 | const OffsetRule *our_rhs = static_cast<const OffsetRule *>(&rhs); |
380 | 0 | return (base_register_ == our_rhs->base_register_ && |
381 | 0 | offset_ == our_rhs->offset_); |
382 | 0 | } |
383 | 0 | Rule *Copy() const override { return new OffsetRule(*this); } |
384 | | // We don't actually need SetBaseRegister or SetOffset here, since they |
385 | | // are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it |
386 | | // doesn't make sense to use OffsetRule for computing the CFA: it |
387 | | // computes the address at which a register is saved, not a value. |
388 | | private: |
389 | | int base_register_; |
390 | | long offset_; |
391 | | }; |
392 | | |
393 | | // Rule: the value the register had in the caller is the value of |
394 | | // BASE_REGISTER plus offset. BASE_REGISTER may be |
395 | | // CallFrameInfo::Handler::kCFARegister. |
396 | | class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { |
397 | | public: |
398 | | ValOffsetRule(int base_register, long offset) |
399 | 0 | : base_register_(base_register), offset_(offset) { } |
400 | 0 | ~ValOffsetRule() { } |
401 | 0 | CFIRTag getTag() const override { return CFIR_VAL_OFFSET_RULE; } |
402 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
403 | 0 | return handler->ValOffsetRule(address, reg, base_register_, offset_); |
404 | 0 | } |
405 | 0 | bool operator==(const Rule &rhs) const override { |
406 | 0 | if (rhs.getTag() != CFIR_VAL_OFFSET_RULE) return false; |
407 | 0 | const ValOffsetRule *our_rhs = static_cast<const ValOffsetRule *>(&rhs); |
408 | 0 | return (base_register_ == our_rhs->base_register_ && |
409 | 0 | offset_ == our_rhs->offset_); |
410 | 0 | } |
411 | 0 | Rule *Copy() const override { return new ValOffsetRule(*this); } |
412 | 0 | void SetBaseRegister(unsigned reg) override { base_register_ = reg; } |
413 | 0 | void SetOffset(long long offset) override { offset_ = offset; } |
414 | | private: |
415 | | int base_register_; |
416 | | long offset_; |
417 | | }; |
418 | | |
419 | | // Rule: the register has been saved in another register REGISTER_NUMBER_. |
420 | | class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { |
421 | | public: |
422 | | explicit RegisterRule(int register_number) |
423 | 0 | : register_number_(register_number) { } |
424 | 0 | ~RegisterRule() { } |
425 | 0 | CFIRTag getTag() const override { return CFIR_REGISTER_RULE; } |
426 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
427 | 0 | return handler->RegisterRule(address, reg, register_number_); |
428 | 0 | } |
429 | 0 | bool operator==(const Rule &rhs) const override { |
430 | 0 | if (rhs.getTag() != CFIR_REGISTER_RULE) return false; |
431 | 0 | const RegisterRule *our_rhs = static_cast<const RegisterRule *>(&rhs); |
432 | 0 | return (register_number_ == our_rhs->register_number_); |
433 | 0 | } |
434 | 0 | Rule *Copy() const override { return new RegisterRule(*this); } |
435 | | private: |
436 | | int register_number_; |
437 | | }; |
438 | | |
439 | | // Rule: EXPRESSION evaluates to the address at which the register is saved. |
440 | | class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { |
441 | | public: |
442 | | explicit ExpressionRule(const string &expression) |
443 | 0 | : expression_(expression) { } |
444 | 0 | ~ExpressionRule() { } |
445 | 0 | CFIRTag getTag() const override { return CFIR_EXPRESSION_RULE; } |
446 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
447 | 0 | return handler->ExpressionRule(address, reg, expression_); |
448 | 0 | } |
449 | 0 | bool operator==(const Rule &rhs) const override { |
450 | 0 | if (rhs.getTag() != CFIR_EXPRESSION_RULE) return false; |
451 | 0 | const ExpressionRule *our_rhs = static_cast<const ExpressionRule *>(&rhs); |
452 | 0 | return (expression_ == our_rhs->expression_); |
453 | 0 | } |
454 | 0 | Rule *Copy() const override { return new ExpressionRule(*this); } |
455 | | private: |
456 | | string expression_; |
457 | | }; |
458 | | |
459 | | // Rule: EXPRESSION evaluates to the previous value of the register. |
460 | | class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { |
461 | | public: |
462 | | explicit ValExpressionRule(const string &expression) |
463 | 0 | : expression_(expression) { } |
464 | 0 | ~ValExpressionRule() { } |
465 | 0 | CFIRTag getTag() const override { return CFIR_VAL_EXPRESSION_RULE; } |
466 | 0 | bool Handle(Handler *handler, uint64 address, int reg) const override { |
467 | 0 | return handler->ValExpressionRule(address, reg, expression_); |
468 | 0 | } |
469 | 0 | bool operator==(const Rule &rhs) const override { |
470 | 0 | if (rhs.getTag() != CFIR_VAL_EXPRESSION_RULE) return false; |
471 | 0 | const ValExpressionRule *our_rhs = |
472 | 0 | static_cast<const ValExpressionRule *>(&rhs); |
473 | 0 | return (expression_ == our_rhs->expression_); |
474 | 0 | } |
475 | 0 | Rule *Copy() const override { return new ValExpressionRule(*this); } |
476 | | private: |
477 | | string expression_; |
478 | | }; |
479 | | |
480 | | // A map from register numbers to rules. |
481 | | class CallFrameInfo::RuleMap { |
482 | | public: |
483 | 0 | RuleMap() : cfa_rule_(NULL) { } |
484 | 0 | RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } |
485 | 0 | ~RuleMap() { Clear(); } |
486 | | |
487 | | RuleMap &operator=(const RuleMap &rhs); |
488 | | |
489 | | // Set the rule for computing the CFA to RULE. Take ownership of RULE. |
490 | 0 | void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; } |
491 | | |
492 | | // Return the current CFA rule. Unlike RegisterRule, this RuleMap retains |
493 | | // ownership of the rule. We use this for DW_CFA_def_cfa_offset and |
494 | | // DW_CFA_def_cfa_register, and for detecting references to the CFA before |
495 | | // a rule for it has been established. |
496 | 0 | Rule *CFARule() const { return cfa_rule_; } |
497 | | |
498 | | // Return the rule for REG, or NULL if there is none. The caller takes |
499 | | // ownership of the result. |
500 | | Rule *RegisterRule(int reg) const; |
501 | | |
502 | | // Set the rule for computing REG to RULE. Take ownership of RULE. |
503 | | void SetRegisterRule(int reg, Rule *rule); |
504 | | |
505 | | // Make all the appropriate calls to HANDLER as if we were changing from |
506 | | // this RuleMap to NEW_RULES at ADDRESS. We use this to implement |
507 | | // DW_CFA_restore_state, where lots of rules can change simultaneously. |
508 | | // Return true if all handlers returned true; otherwise, return false. |
509 | | bool HandleTransitionTo(Handler *handler, uint64 address, |
510 | | const RuleMap &new_rules) const; |
511 | | |
512 | | private: |
513 | | // A map from register numbers to Rules. |
514 | | typedef std::map<int, Rule *> RuleByNumber; |
515 | | |
516 | | // Remove all register rules and clear cfa_rule_. |
517 | | void Clear(); |
518 | | |
519 | | // The rule for computing the canonical frame address. This RuleMap owns |
520 | | // this rule. |
521 | | Rule *cfa_rule_; |
522 | | |
523 | | // A map from register numbers to postfix expressions to recover |
524 | | // their values. This RuleMap owns the Rules the map refers to. |
525 | | RuleByNumber registers_; |
526 | | }; |
527 | | |
528 | 0 | CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { |
529 | 0 | Clear(); |
530 | 0 | // Since each map owns the rules it refers to, assignment must copy them. |
531 | 0 | if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy(); |
532 | 0 | for (RuleByNumber::const_iterator it = rhs.registers_.begin(); |
533 | 0 | it != rhs.registers_.end(); it++) |
534 | 0 | registers_[it->first] = it->second->Copy(); |
535 | 0 | return *this; |
536 | 0 | } |
537 | | |
538 | 0 | CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { |
539 | 0 | MOZ_ASSERT(reg != Handler::kCFARegister); |
540 | 0 | RuleByNumber::const_iterator it = registers_.find(reg); |
541 | 0 | if (it != registers_.end()) |
542 | 0 | return it->second->Copy(); |
543 | 0 | else |
544 | 0 | return NULL; |
545 | 0 | } |
546 | | |
547 | 0 | void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { |
548 | 0 | MOZ_ASSERT(reg != Handler::kCFARegister); |
549 | 0 | MOZ_ASSERT(rule); |
550 | 0 | Rule **slot = ®isters_[reg]; |
551 | 0 | delete *slot; |
552 | 0 | *slot = rule; |
553 | 0 | } |
554 | | |
555 | | bool CallFrameInfo::RuleMap::HandleTransitionTo( |
556 | | Handler *handler, |
557 | | uint64 address, |
558 | 0 | const RuleMap &new_rules) const { |
559 | 0 | // Transition from cfa_rule_ to new_rules.cfa_rule_. |
560 | 0 | if (cfa_rule_ && new_rules.cfa_rule_) { |
561 | 0 | if (*cfa_rule_ != *new_rules.cfa_rule_ && |
562 | 0 | !new_rules.cfa_rule_->Handle(handler, address, Handler::kCFARegister)) |
563 | 0 | return false; |
564 | 0 | } else if (cfa_rule_) { |
565 | 0 | // this RuleMap has a CFA rule but new_rules doesn't. |
566 | 0 | // CallFrameInfo::Handler has no way to handle this --- and shouldn't; |
567 | 0 | // it's garbage input. The instruction interpreter should have |
568 | 0 | // detected this and warned, so take no action here. |
569 | 0 | } else if (new_rules.cfa_rule_) { |
570 | 0 | // This shouldn't be possible: NEW_RULES is some prior state, and |
571 | 0 | // there's no way to remove entries. |
572 | 0 | MOZ_ASSERT(0); |
573 | 0 | } else { |
574 | 0 | // Both CFA rules are empty. No action needed. |
575 | 0 | } |
576 | 0 |
|
577 | 0 | // Traverse the two maps in order by register number, and report |
578 | 0 | // whatever differences we find. |
579 | 0 | RuleByNumber::const_iterator old_it = registers_.begin(); |
580 | 0 | RuleByNumber::const_iterator new_it = new_rules.registers_.begin(); |
581 | 0 | while (old_it != registers_.end() && new_it != new_rules.registers_.end()) { |
582 | 0 | if (old_it->first < new_it->first) { |
583 | 0 | // This RuleMap has an entry for old_it->first, but NEW_RULES |
584 | 0 | // doesn't. |
585 | 0 | // |
586 | 0 | // This isn't really the right thing to do, but since CFI generally |
587 | 0 | // only mentions callee-saves registers, and GCC's convention for |
588 | 0 | // callee-saves registers is that they are unchanged, it's a good |
589 | 0 | // approximation. |
590 | 0 | if (!handler->SameValueRule(address, old_it->first)) |
591 | 0 | return false; |
592 | 0 | old_it++; |
593 | 0 | } else if (old_it->first > new_it->first) { |
594 | 0 | // NEW_RULES has entry for new_it->first, but this RuleMap |
595 | 0 | // doesn't. This shouldn't be possible: NEW_RULES is some prior |
596 | 0 | // state, and there's no way to remove entries. |
597 | 0 | MOZ_ASSERT(0); |
598 | 0 | } else { |
599 | 0 | // Both maps have an entry for this register. Report the new |
600 | 0 | // rule if it is different. |
601 | 0 | if (*old_it->second != *new_it->second && |
602 | 0 | !new_it->second->Handle(handler, address, new_it->first)) |
603 | 0 | return false; |
604 | 0 | new_it++; old_it++; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | // Finish off entries from this RuleMap with no counterparts in new_rules. |
608 | 0 | while (old_it != registers_.end()) { |
609 | 0 | if (!handler->SameValueRule(address, old_it->first)) |
610 | 0 | return false; |
611 | 0 | old_it++; |
612 | 0 | } |
613 | 0 | // Since we only make transitions from a rule set to some previously |
614 | 0 | // saved rule set, and we can only add rules to the map, NEW_RULES |
615 | 0 | // must have fewer rules than *this. |
616 | 0 | MOZ_ASSERT(new_it == new_rules.registers_.end()); |
617 | 0 |
|
618 | 0 | return true; |
619 | 0 | } |
620 | | |
621 | | // Remove all register rules and clear cfa_rule_. |
622 | 0 | void CallFrameInfo::RuleMap::Clear() { |
623 | 0 | delete cfa_rule_; |
624 | 0 | cfa_rule_ = NULL; |
625 | 0 | for (RuleByNumber::iterator it = registers_.begin(); |
626 | 0 | it != registers_.end(); it++) |
627 | 0 | delete it->second; |
628 | 0 | registers_.clear(); |
629 | 0 | } |
630 | | |
631 | | // The state of the call frame information interpreter as it processes |
632 | | // instructions from a CIE and FDE. |
633 | | class CallFrameInfo::State { |
634 | | public: |
635 | | // Create a call frame information interpreter state with the given |
636 | | // reporter, reader, handler, and initial call frame info address. |
637 | | State(ByteReader *reader, Handler *handler, Reporter *reporter, |
638 | | uint64 address) |
639 | | : reader_(reader), handler_(handler), reporter_(reporter), |
640 | | address_(address), entry_(NULL), cursor_(NULL), |
641 | 0 | saved_rules_(NULL) { } |
642 | | |
643 | 0 | ~State() { |
644 | 0 | if (saved_rules_) |
645 | 0 | delete saved_rules_; |
646 | 0 | } |
647 | | |
648 | | // Interpret instructions from CIE, save the resulting rule set for |
649 | | // DW_CFA_restore instructions, and return true. On error, report |
650 | | // the problem to reporter_ and return false. |
651 | | bool InterpretCIE(const CIE &cie); |
652 | | |
653 | | // Interpret instructions from FDE, and return true. On error, |
654 | | // report the problem to reporter_ and return false. |
655 | | bool InterpretFDE(const FDE &fde); |
656 | | |
657 | | private: |
658 | | // The operands of a CFI instruction, for ParseOperands. |
659 | | struct Operands { |
660 | | unsigned register_number; // A register number. |
661 | | uint64 offset; // An offset or address. |
662 | | long signed_offset; // A signed offset. |
663 | | string expression; // A DWARF expression. |
664 | | }; |
665 | | |
666 | | // Parse CFI instruction operands from STATE's instruction stream as |
667 | | // described by FORMAT. On success, populate OPERANDS with the |
668 | | // results, and return true. On failure, report the problem and |
669 | | // return false. |
670 | | // |
671 | | // Each character of FORMAT should be one of the following: |
672 | | // |
673 | | // 'r' unsigned LEB128 register number (OPERANDS->register_number) |
674 | | // 'o' unsigned LEB128 offset (OPERANDS->offset) |
675 | | // 's' signed LEB128 offset (OPERANDS->signed_offset) |
676 | | // 'a' machine-size address (OPERANDS->offset) |
677 | | // (If the CIE has a 'z' augmentation string, 'a' uses the |
678 | | // encoding specified by the 'R' argument.) |
679 | | // '1' a one-byte offset (OPERANDS->offset) |
680 | | // '2' a two-byte offset (OPERANDS->offset) |
681 | | // '4' a four-byte offset (OPERANDS->offset) |
682 | | // '8' an eight-byte offset (OPERANDS->offset) |
683 | | // 'e' a DW_FORM_block holding a (OPERANDS->expression) |
684 | | // DWARF expression |
685 | | bool ParseOperands(const char *format, Operands *operands); |
686 | | |
687 | | // Interpret one CFI instruction from STATE's instruction stream, update |
688 | | // STATE, report any rule changes to handler_, and return true. On |
689 | | // failure, report the problem and return false. |
690 | | bool DoInstruction(); |
691 | | |
692 | | // The following Do* member functions are subroutines of DoInstruction, |
693 | | // factoring out the actual work of operations that have several |
694 | | // different encodings. |
695 | | |
696 | | // Set the CFA rule to be the value of BASE_REGISTER plus OFFSET, and |
697 | | // return true. On failure, report and return false. (Used for |
698 | | // DW_CFA_def_cfa and DW_CFA_def_cfa_sf.) |
699 | | bool DoDefCFA(unsigned base_register, long offset); |
700 | | |
701 | | // Change the offset of the CFA rule to OFFSET, and return true. On |
702 | | // failure, report and return false. (Subroutine for |
703 | | // DW_CFA_def_cfa_offset and DW_CFA_def_cfa_offset_sf.) |
704 | | bool DoDefCFAOffset(long offset); |
705 | | |
706 | | // Specify that REG can be recovered using RULE, and return true. On |
707 | | // failure, report and return false. |
708 | | bool DoRule(unsigned reg, Rule *rule); |
709 | | |
710 | | // Specify that REG can be found at OFFSET from the CFA, and return true. |
711 | | // On failure, report and return false. (Subroutine for DW_CFA_offset, |
712 | | // DW_CFA_offset_extended, and DW_CFA_offset_extended_sf.) |
713 | | bool DoOffset(unsigned reg, long offset); |
714 | | |
715 | | // Specify that the caller's value for REG is the CFA plus OFFSET, |
716 | | // and return true. On failure, report and return false. (Subroutine |
717 | | // for DW_CFA_val_offset and DW_CFA_val_offset_sf.) |
718 | | bool DoValOffset(unsigned reg, long offset); |
719 | | |
720 | | // Restore REG to the rule established in the CIE, and return true. On |
721 | | // failure, report and return false. (Subroutine for DW_CFA_restore and |
722 | | // DW_CFA_restore_extended.) |
723 | | bool DoRestore(unsigned reg); |
724 | | |
725 | | // Return the section offset of the instruction at cursor. For use |
726 | | // in error messages. |
727 | 0 | uint64 CursorOffset() { return entry_->offset + (cursor_ - entry_->start); } |
728 | | |
729 | | // Report that entry_ is incomplete, and return false. For brevity. |
730 | 0 | bool ReportIncomplete() { |
731 | 0 | reporter_->Incomplete(entry_->offset, entry_->kind); |
732 | 0 | return false; |
733 | 0 | } |
734 | | |
735 | | // For reading multi-byte values with the appropriate endianness. |
736 | | ByteReader *reader_; |
737 | | |
738 | | // The handler to which we should report the data we find. |
739 | | Handler *handler_; |
740 | | |
741 | | // For reporting problems in the info we're parsing. |
742 | | Reporter *reporter_; |
743 | | |
744 | | // The code address to which the next instruction in the stream applies. |
745 | | uint64 address_; |
746 | | |
747 | | // The entry whose instructions we are currently processing. This is |
748 | | // first a CIE, and then an FDE. |
749 | | const Entry *entry_; |
750 | | |
751 | | // The next instruction to process. |
752 | | const char *cursor_; |
753 | | |
754 | | // The current set of rules. |
755 | | RuleMap rules_; |
756 | | |
757 | | // The set of rules established by the CIE, used by DW_CFA_restore |
758 | | // and DW_CFA_restore_extended. We set this after interpreting the |
759 | | // CIE's instructions. |
760 | | RuleMap cie_rules_; |
761 | | |
762 | | // A stack of saved states, for DW_CFA_remember_state and |
763 | | // DW_CFA_restore_state. |
764 | | std::stack<RuleMap>* saved_rules_; |
765 | | }; |
766 | | |
767 | 0 | bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { |
768 | 0 | entry_ = &cie; |
769 | 0 | cursor_ = entry_->instructions; |
770 | 0 | while (cursor_ < entry_->end) |
771 | 0 | if (!DoInstruction()) |
772 | 0 | return false; |
773 | 0 | // Note the rules established by the CIE, for use by DW_CFA_restore |
774 | 0 | // and DW_CFA_restore_extended. |
775 | 0 | cie_rules_ = rules_; |
776 | 0 | return true; |
777 | 0 | } |
778 | | |
779 | 0 | bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { |
780 | 0 | entry_ = &fde; |
781 | 0 | cursor_ = entry_->instructions; |
782 | 0 | while (cursor_ < entry_->end) |
783 | 0 | if (!DoInstruction()) |
784 | 0 | return false; |
785 | 0 | return true; |
786 | 0 | } |
787 | | |
788 | | bool CallFrameInfo::State::ParseOperands(const char *format, |
789 | 0 | Operands *operands) { |
790 | 0 | size_t len; |
791 | 0 | const char *operand; |
792 | 0 |
|
793 | 0 | for (operand = format; *operand; operand++) { |
794 | 0 | size_t bytes_left = entry_->end - cursor_; |
795 | 0 | switch (*operand) { |
796 | 0 | case 'r': |
797 | 0 | operands->register_number = reader_->ReadUnsignedLEB128(cursor_, &len); |
798 | 0 | if (len > bytes_left) return ReportIncomplete(); |
799 | 0 | cursor_ += len; |
800 | 0 | break; |
801 | 0 |
|
802 | 0 | case 'o': |
803 | 0 | operands->offset = reader_->ReadUnsignedLEB128(cursor_, &len); |
804 | 0 | if (len > bytes_left) return ReportIncomplete(); |
805 | 0 | cursor_ += len; |
806 | 0 | break; |
807 | 0 |
|
808 | 0 | case 's': |
809 | 0 | operands->signed_offset = reader_->ReadSignedLEB128(cursor_, &len); |
810 | 0 | if (len > bytes_left) return ReportIncomplete(); |
811 | 0 | cursor_ += len; |
812 | 0 | break; |
813 | 0 |
|
814 | 0 | case 'a': |
815 | 0 | operands->offset = |
816 | 0 | reader_->ReadEncodedPointer(cursor_, entry_->cie->pointer_encoding, |
817 | 0 | &len); |
818 | 0 | if (len > bytes_left) return ReportIncomplete(); |
819 | 0 | cursor_ += len; |
820 | 0 | break; |
821 | 0 |
|
822 | 0 | case '1': |
823 | 0 | if (1 > bytes_left) return ReportIncomplete(); |
824 | 0 | operands->offset = static_cast<unsigned char>(*cursor_++); |
825 | 0 | break; |
826 | 0 |
|
827 | 0 | case '2': |
828 | 0 | if (2 > bytes_left) return ReportIncomplete(); |
829 | 0 | operands->offset = reader_->ReadTwoBytes(cursor_); |
830 | 0 | cursor_ += 2; |
831 | 0 | break; |
832 | 0 |
|
833 | 0 | case '4': |
834 | 0 | if (4 > bytes_left) return ReportIncomplete(); |
835 | 0 | operands->offset = reader_->ReadFourBytes(cursor_); |
836 | 0 | cursor_ += 4; |
837 | 0 | break; |
838 | 0 |
|
839 | 0 | case '8': |
840 | 0 | if (8 > bytes_left) return ReportIncomplete(); |
841 | 0 | operands->offset = reader_->ReadEightBytes(cursor_); |
842 | 0 | cursor_ += 8; |
843 | 0 | break; |
844 | 0 |
|
845 | 0 | case 'e': { |
846 | 0 | size_t expression_length = reader_->ReadUnsignedLEB128(cursor_, &len); |
847 | 0 | if (len > bytes_left || expression_length > bytes_left - len) |
848 | 0 | return ReportIncomplete(); |
849 | 0 | cursor_ += len; |
850 | 0 | operands->expression = string(cursor_, expression_length); |
851 | 0 | cursor_ += expression_length; |
852 | 0 | break; |
853 | 0 | } |
854 | 0 |
|
855 | 0 | default: |
856 | 0 | MOZ_ASSERT(0); |
857 | 0 | } |
858 | 0 | } |
859 | 0 |
|
860 | 0 | return true; |
861 | 0 | } |
862 | | |
863 | 0 | bool CallFrameInfo::State::DoInstruction() { |
864 | 0 | CIE *cie = entry_->cie; |
865 | 0 | Operands ops; |
866 | 0 |
|
867 | 0 | // Our entry's kind should have been set by now. |
868 | 0 | MOZ_ASSERT(entry_->kind != kUnknown); |
869 | 0 |
|
870 | 0 | // We shouldn't have been invoked unless there were more |
871 | 0 | // instructions to parse. |
872 | 0 | MOZ_ASSERT(cursor_ < entry_->end); |
873 | 0 |
|
874 | 0 | unsigned opcode = *cursor_++; |
875 | 0 | if ((opcode & 0xc0) != 0) { |
876 | 0 | switch (opcode & 0xc0) { |
877 | 0 | // Advance the address. |
878 | 0 | case DW_CFA_advance_loc: { |
879 | 0 | size_t code_offset = opcode & 0x3f; |
880 | 0 | address_ += code_offset * cie->code_alignment_factor; |
881 | 0 | break; |
882 | 0 | } |
883 | 0 |
|
884 | 0 | // Find a register at an offset from the CFA. |
885 | 0 | case DW_CFA_offset: |
886 | 0 | if (!ParseOperands("o", &ops) || |
887 | 0 | !DoOffset(opcode & 0x3f, ops.offset * cie->data_alignment_factor)) |
888 | 0 | return false; |
889 | 0 | break; |
890 | 0 |
|
891 | 0 | // Restore the rule established for a register by the CIE. |
892 | 0 | case DW_CFA_restore: |
893 | 0 | if (!DoRestore(opcode & 0x3f)) return false; |
894 | 0 | break; |
895 | 0 |
|
896 | 0 | // The 'if' above should have excluded this possibility. |
897 | 0 | default: |
898 | 0 | MOZ_ASSERT(0); |
899 | 0 | } |
900 | 0 |
|
901 | 0 | // Return here, so the big switch below won't be indented. |
902 | 0 | return true; |
903 | 0 | } |
904 | 0 | |
905 | 0 | switch (opcode) { |
906 | 0 | // Set the address. |
907 | 0 | case DW_CFA_set_loc: |
908 | 0 | if (!ParseOperands("a", &ops)) return false; |
909 | 0 | address_ = ops.offset; |
910 | 0 | break; |
911 | 0 |
|
912 | 0 | // Advance the address. |
913 | 0 | case DW_CFA_advance_loc1: |
914 | 0 | if (!ParseOperands("1", &ops)) return false; |
915 | 0 | address_ += ops.offset * cie->code_alignment_factor; |
916 | 0 | break; |
917 | 0 |
|
918 | 0 | // Advance the address. |
919 | 0 | case DW_CFA_advance_loc2: |
920 | 0 | if (!ParseOperands("2", &ops)) return false; |
921 | 0 | address_ += ops.offset * cie->code_alignment_factor; |
922 | 0 | break; |
923 | 0 |
|
924 | 0 | // Advance the address. |
925 | 0 | case DW_CFA_advance_loc4: |
926 | 0 | if (!ParseOperands("4", &ops)) return false; |
927 | 0 | address_ += ops.offset * cie->code_alignment_factor; |
928 | 0 | break; |
929 | 0 |
|
930 | 0 | // Advance the address. |
931 | 0 | case DW_CFA_MIPS_advance_loc8: |
932 | 0 | if (!ParseOperands("8", &ops)) return false; |
933 | 0 | address_ += ops.offset * cie->code_alignment_factor; |
934 | 0 | break; |
935 | 0 |
|
936 | 0 | // Compute the CFA by adding an offset to a register. |
937 | 0 | case DW_CFA_def_cfa: |
938 | 0 | if (!ParseOperands("ro", &ops) || |
939 | 0 | !DoDefCFA(ops.register_number, ops.offset)) |
940 | 0 | return false; |
941 | 0 | break; |
942 | 0 |
|
943 | 0 | // Compute the CFA by adding an offset to a register. |
944 | 0 | case DW_CFA_def_cfa_sf: |
945 | 0 | if (!ParseOperands("rs", &ops) || |
946 | 0 | !DoDefCFA(ops.register_number, |
947 | 0 | ops.signed_offset * cie->data_alignment_factor)) |
948 | 0 | return false; |
949 | 0 | break; |
950 | 0 |
|
951 | 0 | // Change the base register used to compute the CFA. |
952 | 0 | case DW_CFA_def_cfa_register: { |
953 | 0 | Rule *cfa_rule = rules_.CFARule(); |
954 | 0 | if (!cfa_rule) { |
955 | 0 | reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); |
956 | 0 | return false; |
957 | 0 | } |
958 | 0 | if (!ParseOperands("r", &ops)) return false; |
959 | 0 | cfa_rule->SetBaseRegister(ops.register_number); |
960 | 0 | if (!cfa_rule->Handle(handler_, address_, Handler::kCFARegister)) |
961 | 0 | return false; |
962 | 0 | break; |
963 | 0 | } |
964 | 0 |
|
965 | 0 | // Change the offset used to compute the CFA. |
966 | 0 | case DW_CFA_def_cfa_offset: |
967 | 0 | if (!ParseOperands("o", &ops) || |
968 | 0 | !DoDefCFAOffset(ops.offset)) |
969 | 0 | return false; |
970 | 0 | break; |
971 | 0 |
|
972 | 0 | // Change the offset used to compute the CFA. |
973 | 0 | case DW_CFA_def_cfa_offset_sf: |
974 | 0 | if (!ParseOperands("s", &ops) || |
975 | 0 | !DoDefCFAOffset(ops.signed_offset * cie->data_alignment_factor)) |
976 | 0 | return false; |
977 | 0 | break; |
978 | 0 |
|
979 | 0 | // Specify an expression whose value is the CFA. |
980 | 0 | case DW_CFA_def_cfa_expression: { |
981 | 0 | if (!ParseOperands("e", &ops)) |
982 | 0 | return false; |
983 | 0 | Rule *rule = new ValExpressionRule(ops.expression); |
984 | 0 | rules_.SetCFARule(rule); |
985 | 0 | if (!rule->Handle(handler_, address_, Handler::kCFARegister)) |
986 | 0 | return false; |
987 | 0 | break; |
988 | 0 | } |
989 | 0 |
|
990 | 0 | // The register's value cannot be recovered. |
991 | 0 | case DW_CFA_undefined: { |
992 | 0 | if (!ParseOperands("r", &ops) || |
993 | 0 | !DoRule(ops.register_number, new UndefinedRule())) |
994 | 0 | return false; |
995 | 0 | break; |
996 | 0 | } |
997 | 0 |
|
998 | 0 | // The register's value is unchanged from its value in the caller. |
999 | 0 | case DW_CFA_same_value: { |
1000 | 0 | if (!ParseOperands("r", &ops) || |
1001 | 0 | !DoRule(ops.register_number, new SameValueRule())) |
1002 | 0 | return false; |
1003 | 0 | break; |
1004 | 0 | } |
1005 | 0 |
|
1006 | 0 | // Find a register at an offset from the CFA. |
1007 | 0 | case DW_CFA_offset_extended: |
1008 | 0 | if (!ParseOperands("ro", &ops) || |
1009 | 0 | !DoOffset(ops.register_number, |
1010 | 0 | ops.offset * cie->data_alignment_factor)) |
1011 | 0 | return false; |
1012 | 0 | break; |
1013 | 0 |
|
1014 | 0 | // The register is saved at an offset from the CFA. |
1015 | 0 | case DW_CFA_offset_extended_sf: |
1016 | 0 | if (!ParseOperands("rs", &ops) || |
1017 | 0 | !DoOffset(ops.register_number, |
1018 | 0 | ops.signed_offset * cie->data_alignment_factor)) |
1019 | 0 | return false; |
1020 | 0 | break; |
1021 | 0 |
|
1022 | 0 | // The register is saved at an offset from the CFA. |
1023 | 0 | case DW_CFA_GNU_negative_offset_extended: |
1024 | 0 | if (!ParseOperands("ro", &ops) || |
1025 | 0 | !DoOffset(ops.register_number, |
1026 | 0 | -ops.offset * cie->data_alignment_factor)) |
1027 | 0 | return false; |
1028 | 0 | break; |
1029 | 0 |
|
1030 | 0 | // The register's value is the sum of the CFA plus an offset. |
1031 | 0 | case DW_CFA_val_offset: |
1032 | 0 | if (!ParseOperands("ro", &ops) || |
1033 | 0 | !DoValOffset(ops.register_number, |
1034 | 0 | ops.offset * cie->data_alignment_factor)) |
1035 | 0 | return false; |
1036 | 0 | break; |
1037 | 0 |
|
1038 | 0 | // The register's value is the sum of the CFA plus an offset. |
1039 | 0 | case DW_CFA_val_offset_sf: |
1040 | 0 | if (!ParseOperands("rs", &ops) || |
1041 | 0 | !DoValOffset(ops.register_number, |
1042 | 0 | ops.signed_offset * cie->data_alignment_factor)) |
1043 | 0 | return false; |
1044 | 0 | break; |
1045 | 0 |
|
1046 | 0 | // The register has been saved in another register. |
1047 | 0 | case DW_CFA_register: { |
1048 | 0 | if (!ParseOperands("ro", &ops) || |
1049 | 0 | !DoRule(ops.register_number, new RegisterRule(ops.offset))) |
1050 | 0 | return false; |
1051 | 0 | break; |
1052 | 0 | } |
1053 | 0 |
|
1054 | 0 | // An expression yields the address at which the register is saved. |
1055 | 0 | case DW_CFA_expression: { |
1056 | 0 | if (!ParseOperands("re", &ops) || |
1057 | 0 | !DoRule(ops.register_number, new ExpressionRule(ops.expression))) |
1058 | 0 | return false; |
1059 | 0 | break; |
1060 | 0 | } |
1061 | 0 |
|
1062 | 0 | // An expression yields the caller's value for the register. |
1063 | 0 | case DW_CFA_val_expression: { |
1064 | 0 | if (!ParseOperands("re", &ops) || |
1065 | 0 | !DoRule(ops.register_number, new ValExpressionRule(ops.expression))) |
1066 | 0 | return false; |
1067 | 0 | break; |
1068 | 0 | } |
1069 | 0 |
|
1070 | 0 | // Restore the rule established for a register by the CIE. |
1071 | 0 | case DW_CFA_restore_extended: |
1072 | 0 | if (!ParseOperands("r", &ops) || |
1073 | 0 | !DoRestore( ops.register_number)) |
1074 | 0 | return false; |
1075 | 0 | break; |
1076 | 0 |
|
1077 | 0 | // Save the current set of rules on a stack. |
1078 | 0 | case DW_CFA_remember_state: |
1079 | 0 | if (!saved_rules_) { |
1080 | 0 | saved_rules_ = new std::stack<RuleMap>(); |
1081 | 0 | } |
1082 | 0 | saved_rules_->push(rules_); |
1083 | 0 | break; |
1084 | 0 |
|
1085 | 0 | // Pop the current set of rules off the stack. |
1086 | 0 | case DW_CFA_restore_state: { |
1087 | 0 | if (!saved_rules_ || saved_rules_->empty()) { |
1088 | 0 | reporter_->EmptyStateStack(entry_->offset, entry_->kind, |
1089 | 0 | CursorOffset()); |
1090 | 0 | return false; |
1091 | 0 | } |
1092 | 0 | const RuleMap &new_rules = saved_rules_->top(); |
1093 | 0 | if (rules_.CFARule() && !new_rules.CFARule()) { |
1094 | 0 | reporter_->ClearingCFARule(entry_->offset, entry_->kind, |
1095 | 0 | CursorOffset()); |
1096 | 0 | return false; |
1097 | 0 | } |
1098 | 0 | rules_.HandleTransitionTo(handler_, address_, new_rules); |
1099 | 0 | rules_ = new_rules; |
1100 | 0 | saved_rules_->pop(); |
1101 | 0 | break; |
1102 | 0 | } |
1103 | 0 |
|
1104 | 0 | // No operation. (Padding instruction.) |
1105 | 0 | case DW_CFA_nop: |
1106 | 0 | break; |
1107 | 0 |
|
1108 | 0 | // A SPARC register window save: Registers 8 through 15 (%o0-%o7) |
1109 | 0 | // are saved in registers 24 through 31 (%i0-%i7), and registers |
1110 | 0 | // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets |
1111 | 0 | // (0-15 * the register size). The register numbers must be |
1112 | 0 | // hard-coded. A GNU extension, and not a pretty one. |
1113 | 0 | case DW_CFA_GNU_window_save: { |
1114 | 0 | // Save %o0-%o7 in %i0-%i7. |
1115 | 0 | for (int i = 8; i < 16; i++) |
1116 | 0 | if (!DoRule(i, new RegisterRule(i + 16))) |
1117 | 0 | return false; |
1118 | 0 | // Save %l0-%l7 and %i0-%i7 at the CFA. |
1119 | 0 | for (int i = 16; i < 32; i++) |
1120 | 0 | // Assume that the byte reader's address size is the same as |
1121 | 0 | // the architecture's register size. !@#%*^ hilarious. |
1122 | 0 | if (!DoRule(i, new OffsetRule(Handler::kCFARegister, |
1123 | 0 | (i - 16) * reader_->AddressSize()))) |
1124 | 0 | return false; |
1125 | 0 | break; |
1126 | 0 | } |
1127 | 0 |
|
1128 | 0 | // I'm not sure what this is. GDB doesn't use it for unwinding. |
1129 | 0 | case DW_CFA_GNU_args_size: |
1130 | 0 | if (!ParseOperands("o", &ops)) return false; |
1131 | 0 | break; |
1132 | 0 |
|
1133 | 0 | // An opcode we don't recognize. |
1134 | 0 | default: { |
1135 | 0 | reporter_->BadInstruction(entry_->offset, entry_->kind, CursorOffset()); |
1136 | 0 | return false; |
1137 | 0 | } |
1138 | 0 | } |
1139 | 0 | |
1140 | 0 | return true; |
1141 | 0 | } |
1142 | | |
1143 | 0 | bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { |
1144 | 0 | Rule *rule = new ValOffsetRule(base_register, offset); |
1145 | 0 | rules_.SetCFARule(rule); |
1146 | 0 | return rule->Handle(handler_, address_, Handler::kCFARegister); |
1147 | 0 | } |
1148 | | |
1149 | 0 | bool CallFrameInfo::State::DoDefCFAOffset(long offset) { |
1150 | 0 | Rule *cfa_rule = rules_.CFARule(); |
1151 | 0 | if (!cfa_rule) { |
1152 | 0 | reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); |
1153 | 0 | return false; |
1154 | 0 | } |
1155 | 0 | cfa_rule->SetOffset(offset); |
1156 | 0 | return cfa_rule->Handle(handler_, address_, Handler::kCFARegister); |
1157 | 0 | } |
1158 | | |
1159 | 0 | bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { |
1160 | 0 | rules_.SetRegisterRule(reg, rule); |
1161 | 0 | return rule->Handle(handler_, address_, reg); |
1162 | 0 | } |
1163 | | |
1164 | 0 | bool CallFrameInfo::State::DoOffset(unsigned reg, long offset) { |
1165 | 0 | if (!rules_.CFARule()) { |
1166 | 0 | reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); |
1167 | 0 | return false; |
1168 | 0 | } |
1169 | 0 | return DoRule(reg, |
1170 | 0 | new OffsetRule(Handler::kCFARegister, offset)); |
1171 | 0 | } |
1172 | | |
1173 | 0 | bool CallFrameInfo::State::DoValOffset(unsigned reg, long offset) { |
1174 | 0 | if (!rules_.CFARule()) { |
1175 | 0 | reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); |
1176 | 0 | return false; |
1177 | 0 | } |
1178 | 0 | return DoRule(reg, |
1179 | 0 | new ValOffsetRule(Handler::kCFARegister, offset)); |
1180 | 0 | } |
1181 | | |
1182 | 0 | bool CallFrameInfo::State::DoRestore(unsigned reg) { |
1183 | 0 | // DW_CFA_restore and DW_CFA_restore_extended don't make sense in a CIE. |
1184 | 0 | if (entry_->kind == kCIE) { |
1185 | 0 | reporter_->RestoreInCIE(entry_->offset, CursorOffset()); |
1186 | 0 | return false; |
1187 | 0 | } |
1188 | 0 | Rule *rule = cie_rules_.RegisterRule(reg); |
1189 | 0 | if (!rule) { |
1190 | 0 | // This isn't really the right thing to do, but since CFI generally |
1191 | 0 | // only mentions callee-saves registers, and GCC's convention for |
1192 | 0 | // callee-saves registers is that they are unchanged, it's a good |
1193 | 0 | // approximation. |
1194 | 0 | rule = new SameValueRule(); |
1195 | 0 | } |
1196 | 0 | return DoRule(reg, rule); |
1197 | 0 | } |
1198 | | |
1199 | 0 | bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) { |
1200 | 0 | const char *buffer_end = buffer_ + buffer_length_; |
1201 | 0 |
|
1202 | 0 | // Initialize enough of ENTRY for use in error reporting. |
1203 | 0 | entry->offset = cursor - buffer_; |
1204 | 0 | entry->start = cursor; |
1205 | 0 | entry->kind = kUnknown; |
1206 | 0 | entry->end = NULL; |
1207 | 0 |
|
1208 | 0 | // Read the initial length. This sets reader_'s offset size. |
1209 | 0 | size_t length_size; |
1210 | 0 | uint64 length = reader_->ReadInitialLength(cursor, &length_size); |
1211 | 0 | if (length_size > size_t(buffer_end - cursor)) |
1212 | 0 | return ReportIncomplete(entry); |
1213 | 0 | cursor += length_size; |
1214 | 0 |
|
1215 | 0 | // In a .eh_frame section, a length of zero marks the end of the series |
1216 | 0 | // of entries. |
1217 | 0 | if (length == 0 && eh_frame_) { |
1218 | 0 | entry->kind = kTerminator; |
1219 | 0 | entry->end = cursor; |
1220 | 0 | return true; |
1221 | 0 | } |
1222 | 0 | |
1223 | 0 | // Validate the length. |
1224 | 0 | if (length > size_t(buffer_end - cursor)) |
1225 | 0 | return ReportIncomplete(entry); |
1226 | 0 | |
1227 | 0 | // The length is the number of bytes after the initial length field; |
1228 | 0 | // we have that position handy at this point, so compute the end |
1229 | 0 | // now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine, |
1230 | 0 | // and the length didn't fit in a size_t, we would have rejected it |
1231 | 0 | // above.) |
1232 | 0 | entry->end = cursor + length; |
1233 | 0 |
|
1234 | 0 | // Parse the next field: either the offset of a CIE or a CIE id. |
1235 | 0 | size_t offset_size = reader_->OffsetSize(); |
1236 | 0 | if (offset_size > size_t(entry->end - cursor)) return ReportIncomplete(entry); |
1237 | 0 | entry->id = reader_->ReadOffset(cursor); |
1238 | 0 |
|
1239 | 0 | // Don't advance cursor past id field yet; in .eh_frame data we need |
1240 | 0 | // the id's position to compute the section offset of an FDE's CIE. |
1241 | 0 |
|
1242 | 0 | // Now we can decide what kind of entry this is. |
1243 | 0 | if (eh_frame_) { |
1244 | 0 | // In .eh_frame data, an ID of zero marks the entry as a CIE, and |
1245 | 0 | // anything else is an offset from the id field of the FDE to the start |
1246 | 0 | // of the CIE. |
1247 | 0 | if (entry->id == 0) { |
1248 | 0 | entry->kind = kCIE; |
1249 | 0 | } else { |
1250 | 0 | entry->kind = kFDE; |
1251 | 0 | // Turn the offset from the id into an offset from the buffer's start. |
1252 | 0 | entry->id = (cursor - buffer_) - entry->id; |
1253 | 0 | } |
1254 | 0 | } else { |
1255 | 0 | // In DWARF CFI data, an ID of ~0 (of the appropriate width, given the |
1256 | 0 | // offset size for the entry) marks the entry as a CIE, and anything |
1257 | 0 | // else is the offset of the CIE from the beginning of the section. |
1258 | 0 | if (offset_size == 4) |
1259 | 0 | entry->kind = (entry->id == 0xffffffff) ? kCIE : kFDE; |
1260 | 0 | else { |
1261 | 0 | MOZ_ASSERT(offset_size == 8); |
1262 | 0 | entry->kind = (entry->id == 0xffffffffffffffffULL) ? kCIE : kFDE; |
1263 | 0 | } |
1264 | 0 | } |
1265 | 0 |
|
1266 | 0 | // Now advance cursor past the id. |
1267 | 0 | cursor += offset_size; |
1268 | 0 |
|
1269 | 0 | // The fields specific to this kind of entry start here. |
1270 | 0 | entry->fields = cursor; |
1271 | 0 |
|
1272 | 0 | entry->cie = NULL; |
1273 | 0 |
|
1274 | 0 | return true; |
1275 | 0 | } |
1276 | | |
1277 | 0 | bool CallFrameInfo::ReadCIEFields(CIE *cie) { |
1278 | 0 | const char *cursor = cie->fields; |
1279 | 0 | size_t len; |
1280 | 0 |
|
1281 | 0 | MOZ_ASSERT(cie->kind == kCIE); |
1282 | 0 |
|
1283 | 0 | // Prepare for early exit. |
1284 | 0 | cie->version = 0; |
1285 | 0 | cie->augmentation.clear(); |
1286 | 0 | cie->code_alignment_factor = 0; |
1287 | 0 | cie->data_alignment_factor = 0; |
1288 | 0 | cie->return_address_register = 0; |
1289 | 0 | cie->has_z_augmentation = false; |
1290 | 0 | cie->pointer_encoding = DW_EH_PE_absptr; |
1291 | 0 | cie->instructions = 0; |
1292 | 0 |
|
1293 | 0 | // Parse the version number. |
1294 | 0 | if (cie->end - cursor < 1) |
1295 | 0 | return ReportIncomplete(cie); |
1296 | 0 | cie->version = reader_->ReadOneByte(cursor); |
1297 | 0 | cursor++; |
1298 | 0 |
|
1299 | 0 | // If we don't recognize the version, we can't parse any more fields of the |
1300 | 0 | // CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a |
1301 | 0 | // version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well; |
1302 | 0 | // the difference between those versions seems to be the same as for |
1303 | 0 | // .debug_frame. |
1304 | 0 | if (cie->version < 1 || cie->version > 4) { |
1305 | 0 | reporter_->UnrecognizedVersion(cie->offset, cie->version); |
1306 | 0 | return false; |
1307 | 0 | } |
1308 | 0 | |
1309 | 0 | const char *augmentation_start = cursor; |
1310 | 0 | const void *augmentation_end = |
1311 | 0 | memchr(augmentation_start, '\0', cie->end - augmentation_start); |
1312 | 0 | if (! augmentation_end) return ReportIncomplete(cie); |
1313 | 0 | cursor = static_cast<const char *>(augmentation_end); |
1314 | 0 | cie->augmentation = string(augmentation_start, |
1315 | 0 | cursor - augmentation_start); |
1316 | 0 | // Skip the terminating '\0'. |
1317 | 0 | cursor++; |
1318 | 0 |
|
1319 | 0 | // Is this CFI augmented? |
1320 | 0 | if (!cie->augmentation.empty()) { |
1321 | 0 | // Is it an augmentation we recognize? |
1322 | 0 | if (cie->augmentation[0] == DW_Z_augmentation_start) { |
1323 | 0 | // Linux C++ ABI 'z' augmentation, used for exception handling data. |
1324 | 0 | cie->has_z_augmentation = true; |
1325 | 0 | } else { |
1326 | 0 | // Not an augmentation we recognize. Augmentations can have arbitrary |
1327 | 0 | // effects on the form of rest of the content, so we have to give up. |
1328 | 0 | reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); |
1329 | 0 | return false; |
1330 | 0 | } |
1331 | 0 | } |
1332 | 0 | |
1333 | 0 | if (cie->version >= 4) { |
1334 | 0 | // Check that the address_size and segment_size fields are plausible. |
1335 | 0 | if (cie->end - cursor < 2) { |
1336 | 0 | return ReportIncomplete(cie); |
1337 | 0 | } |
1338 | 0 | uint8_t address_size = reader_->ReadOneByte(cursor); |
1339 | 0 | cursor++; |
1340 | 0 | if (address_size != sizeof(void*)) { |
1341 | 0 | // This is not per-se invalid CFI. But we can reasonably expect to |
1342 | 0 | // be running on a target of the same word size as the CFI is for, |
1343 | 0 | // so we reject this case. |
1344 | 0 | reporter_->InvalidDwarf4Artefact(cie->offset, "Invalid address_size"); |
1345 | 0 | return false; |
1346 | 0 | } |
1347 | 0 | uint8_t segment_size = reader_->ReadOneByte(cursor); |
1348 | 0 | cursor++; |
1349 | 0 | if (segment_size != 0) { |
1350 | 0 | // This is also not per-se invalid CFI, but we don't currently handle |
1351 | 0 | // the case of non-zero |segment_size|. |
1352 | 0 | reporter_->InvalidDwarf4Artefact(cie->offset, "Invalid segment_size"); |
1353 | 0 | return false; |
1354 | 0 | } |
1355 | 0 | // We only continue parsing if |segment_size| is zero. If this routine |
1356 | 0 | // is ever changed to allow non-zero |segment_size|, then |
1357 | 0 | // ReadFDEFields() below will have to be changed to match, per comments |
1358 | 0 | // there. |
1359 | 0 | } |
1360 | 0 | |
1361 | 0 | // Parse the code alignment factor. |
1362 | 0 | cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len); |
1363 | 0 | if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); |
1364 | 0 | cursor += len; |
1365 | 0 |
|
1366 | 0 | // Parse the data alignment factor. |
1367 | 0 | cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len); |
1368 | 0 | if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); |
1369 | 0 | cursor += len; |
1370 | 0 |
|
1371 | 0 | // Parse the return address register. This is a ubyte in version 1, and |
1372 | 0 | // a ULEB128 in version 3. |
1373 | 0 | if (cie->version == 1) { |
1374 | 0 | if (cursor >= cie->end) return ReportIncomplete(cie); |
1375 | 0 | cie->return_address_register = uint8(*cursor++); |
1376 | 0 | } else { |
1377 | 0 | cie->return_address_register = reader_->ReadUnsignedLEB128(cursor, &len); |
1378 | 0 | if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); |
1379 | 0 | cursor += len; |
1380 | 0 | } |
1381 | 0 |
|
1382 | 0 | // If we have a 'z' augmentation string, find the augmentation data and |
1383 | 0 | // use the augmentation string to parse it. |
1384 | 0 | if (cie->has_z_augmentation) { |
1385 | 0 | uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &len); |
1386 | 0 | if (size_t(cie->end - cursor) < len + data_size) |
1387 | 0 | return ReportIncomplete(cie); |
1388 | 0 | cursor += len; |
1389 | 0 | const char *data = cursor; |
1390 | 0 | cursor += data_size; |
1391 | 0 | const char *data_end = cursor; |
1392 | 0 |
|
1393 | 0 | cie->has_z_lsda = false; |
1394 | 0 | cie->has_z_personality = false; |
1395 | 0 | cie->has_z_signal_frame = false; |
1396 | 0 |
|
1397 | 0 | // Walk the augmentation string, and extract values from the |
1398 | 0 | // augmentation data as the string directs. |
1399 | 0 | for (size_t i = 1; i < cie->augmentation.size(); i++) { |
1400 | 0 | switch (cie->augmentation[i]) { |
1401 | 0 | case DW_Z_has_LSDA: |
1402 | 0 | // The CIE's augmentation data holds the language-specific data |
1403 | 0 | // area pointer's encoding, and the FDE's augmentation data holds |
1404 | 0 | // the pointer itself. |
1405 | 0 | cie->has_z_lsda = true; |
1406 | 0 | // Fetch the LSDA encoding from the augmentation data. |
1407 | 0 | if (data >= data_end) return ReportIncomplete(cie); |
1408 | 0 | cie->lsda_encoding = DwarfPointerEncoding(*data++); |
1409 | 0 | if (!reader_->ValidEncoding(cie->lsda_encoding)) { |
1410 | 0 | reporter_->InvalidPointerEncoding(cie->offset, cie->lsda_encoding); |
1411 | 0 | return false; |
1412 | 0 | } |
1413 | 0 | // Don't check if the encoding is usable here --- we haven't |
1414 | 0 | // read the FDE's fields yet, so we're not prepared for |
1415 | 0 | // DW_EH_PE_funcrel, although that's a fine encoding for the |
1416 | 0 | // LSDA to use, since it appears in the FDE. |
1417 | 0 | break; |
1418 | 0 |
|
1419 | 0 | case DW_Z_has_personality_routine: |
1420 | 0 | // The CIE's augmentation data holds the personality routine |
1421 | 0 | // pointer's encoding, followed by the pointer itself. |
1422 | 0 | cie->has_z_personality = true; |
1423 | 0 | // Fetch the personality routine pointer's encoding from the |
1424 | 0 | // augmentation data. |
1425 | 0 | if (data >= data_end) return ReportIncomplete(cie); |
1426 | 0 | cie->personality_encoding = DwarfPointerEncoding(*data++); |
1427 | 0 | if (!reader_->ValidEncoding(cie->personality_encoding)) { |
1428 | 0 | reporter_->InvalidPointerEncoding(cie->offset, |
1429 | 0 | cie->personality_encoding); |
1430 | 0 | return false; |
1431 | 0 | } |
1432 | 0 | if (!reader_->UsableEncoding(cie->personality_encoding)) { |
1433 | 0 | reporter_->UnusablePointerEncoding(cie->offset, |
1434 | 0 | cie->personality_encoding); |
1435 | 0 | return false; |
1436 | 0 | } |
1437 | 0 | // Fetch the personality routine's pointer itself from the data. |
1438 | 0 | cie->personality_address = |
1439 | 0 | reader_->ReadEncodedPointer(data, cie->personality_encoding, |
1440 | 0 | &len); |
1441 | 0 | if (len > size_t(data_end - data)) |
1442 | 0 | return ReportIncomplete(cie); |
1443 | 0 | data += len; |
1444 | 0 | break; |
1445 | 0 |
|
1446 | 0 | case DW_Z_has_FDE_address_encoding: |
1447 | 0 | // The CIE's augmentation data holds the pointer encoding to use |
1448 | 0 | // for addresses in the FDE. |
1449 | 0 | if (data >= data_end) return ReportIncomplete(cie); |
1450 | 0 | cie->pointer_encoding = DwarfPointerEncoding(*data++); |
1451 | 0 | if (!reader_->ValidEncoding(cie->pointer_encoding)) { |
1452 | 0 | reporter_->InvalidPointerEncoding(cie->offset, |
1453 | 0 | cie->pointer_encoding); |
1454 | 0 | return false; |
1455 | 0 | } |
1456 | 0 | if (!reader_->UsableEncoding(cie->pointer_encoding)) { |
1457 | 0 | reporter_->UnusablePointerEncoding(cie->offset, |
1458 | 0 | cie->pointer_encoding); |
1459 | 0 | return false; |
1460 | 0 | } |
1461 | 0 | break; |
1462 | 0 |
|
1463 | 0 | case DW_Z_is_signal_trampoline: |
1464 | 0 | // Frames using this CIE are signal delivery frames. |
1465 | 0 | cie->has_z_signal_frame = true; |
1466 | 0 | break; |
1467 | 0 |
|
1468 | 0 | default: |
1469 | 0 | // An augmentation we don't recognize. |
1470 | 0 | reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); |
1471 | 0 | return false; |
1472 | 0 | } |
1473 | 0 | } |
1474 | 0 | } |
1475 | 0 |
|
1476 | 0 | // The CIE's instructions start here. |
1477 | 0 | cie->instructions = cursor; |
1478 | 0 |
|
1479 | 0 | return true; |
1480 | 0 | } |
1481 | | |
1482 | 0 | bool CallFrameInfo::ReadFDEFields(FDE *fde) { |
1483 | 0 | const char *cursor = fde->fields; |
1484 | 0 | size_t size; |
1485 | 0 |
|
1486 | 0 | // At this point, for Dwarf 4 and above, we are assuming that the |
1487 | 0 | // associated CIE has its |segment_size| field equal to zero. This is |
1488 | 0 | // checked for in ReadCIEFields() above. If ReadCIEFields() is ever |
1489 | 0 | // changed to allow non-zero |segment_size| CIEs then we will have to read |
1490 | 0 | // the segment_selector value at this point. |
1491 | 0 |
|
1492 | 0 | fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, |
1493 | 0 | &size); |
1494 | 0 | if (size > size_t(fde->end - cursor)) |
1495 | 0 | return ReportIncomplete(fde); |
1496 | 0 | cursor += size; |
1497 | 0 | reader_->SetFunctionBase(fde->address); |
1498 | 0 |
|
1499 | 0 | // For the length, we strip off the upper nybble of the encoding used for |
1500 | 0 | // the starting address. |
1501 | 0 | DwarfPointerEncoding length_encoding = |
1502 | 0 | DwarfPointerEncoding(fde->cie->pointer_encoding & 0x0f); |
1503 | 0 | fde->size = reader_->ReadEncodedPointer(cursor, length_encoding, &size); |
1504 | 0 | if (size > size_t(fde->end - cursor)) |
1505 | 0 | return ReportIncomplete(fde); |
1506 | 0 | cursor += size; |
1507 | 0 |
|
1508 | 0 | // If the CIE has a 'z' augmentation string, then augmentation data |
1509 | 0 | // appears here. |
1510 | 0 | if (fde->cie->has_z_augmentation) { |
1511 | 0 | uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &size); |
1512 | 0 | if (size_t(fde->end - cursor) < size + data_size) |
1513 | 0 | return ReportIncomplete(fde); |
1514 | 0 | cursor += size; |
1515 | 0 |
|
1516 | 0 | // In the abstract, we should walk the augmentation string, and extract |
1517 | 0 | // items from the FDE's augmentation data as we encounter augmentation |
1518 | 0 | // string characters that specify their presence: the ordering of items |
1519 | 0 | // in the augmentation string determines the arrangement of values in |
1520 | 0 | // the augmentation data. |
1521 | 0 | // |
1522 | 0 | // In practice, there's only ever one value in FDE augmentation data |
1523 | 0 | // that we support --- the LSDA pointer --- and we have to bail if we |
1524 | 0 | // see any unrecognized augmentation string characters. So if there is |
1525 | 0 | // anything here at all, we know what it is, and where it starts. |
1526 | 0 | if (fde->cie->has_z_lsda) { |
1527 | 0 | // Check whether the LSDA's pointer encoding is usable now: only once |
1528 | 0 | // we've parsed the FDE's starting address do we call reader_-> |
1529 | 0 | // SetFunctionBase, so that the DW_EH_PE_funcrel encoding becomes |
1530 | 0 | // usable. |
1531 | 0 | if (!reader_->UsableEncoding(fde->cie->lsda_encoding)) { |
1532 | 0 | reporter_->UnusablePointerEncoding(fde->cie->offset, |
1533 | 0 | fde->cie->lsda_encoding); |
1534 | 0 | return false; |
1535 | 0 | } |
1536 | 0 | |
1537 | 0 | fde->lsda_address = |
1538 | 0 | reader_->ReadEncodedPointer(cursor, fde->cie->lsda_encoding, &size); |
1539 | 0 | if (size > data_size) |
1540 | 0 | return ReportIncomplete(fde); |
1541 | 0 | // Ideally, we would also complain here if there were unconsumed |
1542 | 0 | // augmentation data. |
1543 | 0 | } |
1544 | 0 | |
1545 | 0 | cursor += data_size; |
1546 | 0 | } |
1547 | 0 |
|
1548 | 0 | // The FDE's instructions start after those. |
1549 | 0 | fde->instructions = cursor; |
1550 | 0 |
|
1551 | 0 | return true; |
1552 | 0 | } |
1553 | | |
1554 | 0 | bool CallFrameInfo::Start() { |
1555 | 0 | const char *buffer_end = buffer_ + buffer_length_; |
1556 | 0 | const char *cursor; |
1557 | 0 | bool all_ok = true; |
1558 | 0 | const char *entry_end; |
1559 | 0 | bool ok; |
1560 | 0 |
|
1561 | 0 | // Traverse all the entries in buffer_, skipping CIEs and offering |
1562 | 0 | // FDEs to the handler. |
1563 | 0 | for (cursor = buffer_; cursor < buffer_end; |
1564 | 0 | cursor = entry_end, all_ok = all_ok && ok) { |
1565 | 0 | FDE fde; |
1566 | 0 |
|
1567 | 0 | // Make it easy to skip this entry with 'continue': assume that |
1568 | 0 | // things are not okay until we've checked all the data, and |
1569 | 0 | // prepare the address of the next entry. |
1570 | 0 | ok = false; |
1571 | 0 |
|
1572 | 0 | // Read the entry's prologue. |
1573 | 0 | if (!ReadEntryPrologue(cursor, &fde)) { |
1574 | 0 | if (!fde.end) { |
1575 | 0 | // If we couldn't even figure out this entry's extent, then we |
1576 | 0 | // must stop processing entries altogether. |
1577 | 0 | all_ok = false; |
1578 | 0 | break; |
1579 | 0 | } |
1580 | 0 | entry_end = fde.end; |
1581 | 0 | continue; |
1582 | 0 | } |
1583 | 0 | |
1584 | 0 | // The next iteration picks up after this entry. |
1585 | 0 | entry_end = fde.end; |
1586 | 0 |
|
1587 | 0 | // Did we see an .eh_frame terminating mark? |
1588 | 0 | if (fde.kind == kTerminator) { |
1589 | 0 | // If there appears to be more data left in the section after the |
1590 | 0 | // terminating mark, warn the user. But this is just a warning; |
1591 | 0 | // we leave all_ok true. |
1592 | 0 | if (fde.end < buffer_end) reporter_->EarlyEHTerminator(fde.offset); |
1593 | 0 | break; |
1594 | 0 | } |
1595 | 0 |
|
1596 | 0 | // In this loop, we skip CIEs. We only parse them fully when we |
1597 | 0 | // parse an FDE that refers to them. This limits our memory |
1598 | 0 | // consumption (beyond the buffer itself) to that needed to |
1599 | 0 | // process the largest single entry. |
1600 | 0 | if (fde.kind != kFDE) { |
1601 | 0 | ok = true; |
1602 | 0 | continue; |
1603 | 0 | } |
1604 | 0 | |
1605 | 0 | // Validate the CIE pointer. |
1606 | 0 | if (fde.id > buffer_length_) { |
1607 | 0 | reporter_->CIEPointerOutOfRange(fde.offset, fde.id); |
1608 | 0 | continue; |
1609 | 0 | } |
1610 | 0 | |
1611 | 0 | CIE cie; |
1612 | 0 |
|
1613 | 0 | // Parse this FDE's CIE header. |
1614 | 0 | if (!ReadEntryPrologue(buffer_ + fde.id, &cie)) |
1615 | 0 | continue; |
1616 | 0 | // This had better be an actual CIE. |
1617 | 0 | if (cie.kind != kCIE) { |
1618 | 0 | reporter_->BadCIEId(fde.offset, fde.id); |
1619 | 0 | continue; |
1620 | 0 | } |
1621 | 0 | if (!ReadCIEFields(&cie)) |
1622 | 0 | continue; |
1623 | 0 | |
1624 | 0 | // We now have the values that govern both the CIE and the FDE. |
1625 | 0 | cie.cie = &cie; |
1626 | 0 | fde.cie = &cie; |
1627 | 0 |
|
1628 | 0 | // Parse the FDE's header. |
1629 | 0 | if (!ReadFDEFields(&fde)) |
1630 | 0 | continue; |
1631 | 0 | |
1632 | 0 | // Call Entry to ask the consumer if they're interested. |
1633 | 0 | if (!handler_->Entry(fde.offset, fde.address, fde.size, |
1634 | 0 | cie.version, cie.augmentation, |
1635 | 0 | cie.return_address_register)) { |
1636 | 0 | // The handler isn't interested in this entry. That's not an error. |
1637 | 0 | ok = true; |
1638 | 0 | continue; |
1639 | 0 | } |
1640 | 0 | |
1641 | 0 | if (cie.has_z_augmentation) { |
1642 | 0 | // Report the personality routine address, if we have one. |
1643 | 0 | if (cie.has_z_personality) { |
1644 | 0 | if (!handler_ |
1645 | 0 | ->PersonalityRoutine(cie.personality_address, |
1646 | 0 | IsIndirectEncoding(cie.personality_encoding))) |
1647 | 0 | continue; |
1648 | 0 | } |
1649 | 0 | |
1650 | 0 | // Report the language-specific data area address, if we have one. |
1651 | 0 | if (cie.has_z_lsda) { |
1652 | 0 | if (!handler_ |
1653 | 0 | ->LanguageSpecificDataArea(fde.lsda_address, |
1654 | 0 | IsIndirectEncoding(cie.lsda_encoding))) |
1655 | 0 | continue; |
1656 | 0 | } |
1657 | 0 | |
1658 | 0 | // If this is a signal-handling frame, report that. |
1659 | 0 | if (cie.has_z_signal_frame) { |
1660 | 0 | if (!handler_->SignalHandler()) |
1661 | 0 | continue; |
1662 | 0 | } |
1663 | 0 | } |
1664 | 0 | |
1665 | 0 | // Interpret the CIE's instructions, and then the FDE's instructions. |
1666 | 0 | State state(reader_, handler_, reporter_, fde.address); |
1667 | 0 | ok = state.InterpretCIE(cie) && state.InterpretFDE(fde); |
1668 | 0 |
|
1669 | 0 | // Tell the ByteReader that the function start address from the |
1670 | 0 | // FDE header is no longer valid. |
1671 | 0 | reader_->ClearFunctionBase(); |
1672 | 0 |
|
1673 | 0 | // Report the end of the entry. |
1674 | 0 | handler_->End(); |
1675 | 0 | } |
1676 | 0 |
|
1677 | 0 | return all_ok; |
1678 | 0 | } |
1679 | | |
1680 | 0 | const char *CallFrameInfo::KindName(EntryKind kind) { |
1681 | 0 | if (kind == CallFrameInfo::kUnknown) |
1682 | 0 | return "entry"; |
1683 | 0 | else if (kind == CallFrameInfo::kCIE) |
1684 | 0 | return "common information entry"; |
1685 | 0 | else if (kind == CallFrameInfo::kFDE) |
1686 | 0 | return "frame description entry"; |
1687 | 0 | else { |
1688 | 0 | MOZ_ASSERT (kind == CallFrameInfo::kTerminator); |
1689 | 0 | return ".eh_frame sequence terminator"; |
1690 | 0 | } |
1691 | 0 | } |
1692 | | |
1693 | 0 | bool CallFrameInfo::ReportIncomplete(Entry *entry) { |
1694 | 0 | reporter_->Incomplete(entry->offset, entry->kind); |
1695 | 0 | return false; |
1696 | 0 | } |
1697 | | |
1698 | | void CallFrameInfo::Reporter::Incomplete(uint64 offset, |
1699 | 0 | CallFrameInfo::EntryKind kind) { |
1700 | 0 | char buf[300]; |
1701 | 0 | SprintfLiteral(buf, |
1702 | 0 | "%s: CFI %s at offset 0x%llx in '%s': entry ends early\n", |
1703 | 0 | filename_.c_str(), CallFrameInfo::KindName(kind), offset, |
1704 | 0 | section_.c_str()); |
1705 | 0 | log_(buf); |
1706 | 0 | } |
1707 | | |
1708 | 0 | void CallFrameInfo::Reporter::EarlyEHTerminator(uint64 offset) { |
1709 | 0 | char buf[300]; |
1710 | 0 | SprintfLiteral(buf, |
1711 | 0 | "%s: CFI at offset 0x%llx in '%s': saw end-of-data marker" |
1712 | 0 | " before end of section contents\n", |
1713 | 0 | filename_.c_str(), offset, section_.c_str()); |
1714 | 0 | log_(buf); |
1715 | 0 | } |
1716 | | |
1717 | | void CallFrameInfo::Reporter::CIEPointerOutOfRange(uint64 offset, |
1718 | 0 | uint64 cie_offset) { |
1719 | 0 | char buf[300]; |
1720 | 0 | SprintfLiteral(buf, |
1721 | 0 | "%s: CFI frame description entry at offset 0x%llx in '%s':" |
1722 | 0 | " CIE pointer is out of range: 0x%llx\n", |
1723 | 0 | filename_.c_str(), offset, section_.c_str(), cie_offset); |
1724 | 0 | log_(buf); |
1725 | 0 | } |
1726 | | |
1727 | 0 | void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) { |
1728 | 0 | char buf[300]; |
1729 | 0 | SprintfLiteral(buf, |
1730 | 0 | "%s: CFI frame description entry at offset 0x%llx in '%s':" |
1731 | 0 | " CIE pointer does not point to a CIE: 0x%llx\n", |
1732 | 0 | filename_.c_str(), offset, section_.c_str(), cie_offset); |
1733 | 0 | log_(buf); |
1734 | 0 | } |
1735 | | |
1736 | 0 | void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) { |
1737 | 0 | char buf[300]; |
1738 | 0 | SprintfLiteral(buf, |
1739 | 0 | "%s: CFI frame description entry at offset 0x%llx in '%s':" |
1740 | 0 | " CIE specifies unrecognized version: %d\n", |
1741 | 0 | filename_.c_str(), offset, section_.c_str(), version); |
1742 | 0 | log_(buf); |
1743 | 0 | } |
1744 | | |
1745 | | void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset, |
1746 | 0 | const string &aug) { |
1747 | 0 | char buf[300]; |
1748 | 0 | SprintfLiteral(buf, |
1749 | 0 | "%s: CFI frame description entry at offset 0x%llx in '%s':" |
1750 | 0 | " CIE specifies unrecognized augmentation: '%s'\n", |
1751 | 0 | filename_.c_str(), offset, section_.c_str(), aug.c_str()); |
1752 | 0 | log_(buf); |
1753 | 0 | } |
1754 | | |
1755 | | void CallFrameInfo::Reporter::InvalidDwarf4Artefact(uint64 offset, |
1756 | 0 | const char* what) { |
1757 | 0 | char* what_safe = strndup(what, 100); |
1758 | 0 | char buf[300]; |
1759 | 0 | SprintfLiteral(buf, |
1760 | 0 | "%s: CFI frame description entry at offset 0x%llx in '%s':" |
1761 | 0 | " CIE specifies invalid Dwarf4 artefact: %s\n", |
1762 | 0 | filename_.c_str(), offset, section_.c_str(), what_safe); |
1763 | 0 | log_(buf); |
1764 | 0 | free(what_safe); |
1765 | 0 | } |
1766 | | |
1767 | | void CallFrameInfo::Reporter::InvalidPointerEncoding(uint64 offset, |
1768 | 0 | uint8 encoding) { |
1769 | 0 | char buf[300]; |
1770 | 0 | SprintfLiteral(buf, |
1771 | 0 | "%s: CFI common information entry at offset 0x%llx in '%s':" |
1772 | 0 | " 'z' augmentation specifies invalid pointer encoding: " |
1773 | 0 | "0x%02x\n", |
1774 | 0 | filename_.c_str(), offset, section_.c_str(), encoding); |
1775 | 0 | log_(buf); |
1776 | 0 | } |
1777 | | |
1778 | | void CallFrameInfo::Reporter::UnusablePointerEncoding(uint64 offset, |
1779 | 0 | uint8 encoding) { |
1780 | 0 | char buf[300]; |
1781 | 0 | SprintfLiteral(buf, |
1782 | 0 | "%s: CFI common information entry at offset 0x%llx in '%s':" |
1783 | 0 | " 'z' augmentation specifies a pointer encoding for which" |
1784 | 0 | " we have no base address: 0x%02x\n", |
1785 | 0 | filename_.c_str(), offset, section_.c_str(), encoding); |
1786 | 0 | log_(buf); |
1787 | 0 | } |
1788 | | |
1789 | 0 | void CallFrameInfo::Reporter::RestoreInCIE(uint64 offset, uint64 insn_offset) { |
1790 | 0 | char buf[300]; |
1791 | 0 | SprintfLiteral(buf, |
1792 | 0 | "%s: CFI common information entry at offset 0x%llx in '%s':" |
1793 | 0 | " the DW_CFA_restore instruction at offset 0x%llx" |
1794 | 0 | " cannot be used in a common information entry\n", |
1795 | 0 | filename_.c_str(), offset, section_.c_str(), insn_offset); |
1796 | 0 | log_(buf); |
1797 | 0 | } |
1798 | | |
1799 | | void CallFrameInfo::Reporter::BadInstruction(uint64 offset, |
1800 | | CallFrameInfo::EntryKind kind, |
1801 | 0 | uint64 insn_offset) { |
1802 | 0 | char buf[300]; |
1803 | 0 | SprintfLiteral(buf, |
1804 | 0 | "%s: CFI %s at offset 0x%llx in section '%s':" |
1805 | 0 | " the instruction at offset 0x%llx is unrecognized\n", |
1806 | 0 | filename_.c_str(), CallFrameInfo::KindName(kind), |
1807 | 0 | offset, section_.c_str(), insn_offset); |
1808 | 0 | log_(buf); |
1809 | 0 | } |
1810 | | |
1811 | | void CallFrameInfo::Reporter::NoCFARule(uint64 offset, |
1812 | | CallFrameInfo::EntryKind kind, |
1813 | 0 | uint64 insn_offset) { |
1814 | 0 | char buf[300]; |
1815 | 0 | SprintfLiteral(buf, |
1816 | 0 | "%s: CFI %s at offset 0x%llx in section '%s':" |
1817 | 0 | " the instruction at offset 0x%llx assumes that a CFA rule " |
1818 | 0 | "has been set, but none has been set\n", |
1819 | 0 | filename_.c_str(), CallFrameInfo::KindName(kind), offset, |
1820 | 0 | section_.c_str(), insn_offset); |
1821 | 0 | log_(buf); |
1822 | 0 | } |
1823 | | |
1824 | | void CallFrameInfo::Reporter::EmptyStateStack(uint64 offset, |
1825 | | CallFrameInfo::EntryKind kind, |
1826 | 0 | uint64 insn_offset) { |
1827 | 0 | char buf[300]; |
1828 | 0 | SprintfLiteral(buf, |
1829 | 0 | "%s: CFI %s at offset 0x%llx in section '%s':" |
1830 | 0 | " the DW_CFA_restore_state instruction at offset 0x%llx" |
1831 | 0 | " should pop a saved state from the stack, but the stack " |
1832 | 0 | "is empty\n", |
1833 | 0 | filename_.c_str(), CallFrameInfo::KindName(kind), offset, |
1834 | 0 | section_.c_str(), insn_offset); |
1835 | 0 | log_(buf); |
1836 | 0 | } |
1837 | | |
1838 | | void CallFrameInfo::Reporter::ClearingCFARule(uint64 offset, |
1839 | | CallFrameInfo::EntryKind kind, |
1840 | 0 | uint64 insn_offset) { |
1841 | 0 | char buf[300]; |
1842 | 0 | SprintfLiteral(buf, |
1843 | 0 | "%s: CFI %s at offset 0x%llx in section '%s':" |
1844 | 0 | " the DW_CFA_restore_state instruction at offset 0x%llx" |
1845 | 0 | " would clear the CFA rule in effect\n", |
1846 | 0 | filename_.c_str(), CallFrameInfo::KindName(kind), offset, |
1847 | 0 | section_.c_str(), insn_offset); |
1848 | 0 | log_(buf); |
1849 | 0 | } |
1850 | | |
1851 | | |
1852 | 0 | unsigned int DwarfCFIToModule::RegisterNames::I386() { |
1853 | 0 | /* |
1854 | 0 | 8 "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", |
1855 | 0 | 3 "$eip", "$eflags", "$unused1", |
1856 | 0 | 8 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", |
1857 | 0 | 2 "$unused2", "$unused3", |
1858 | 0 | 8 "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", |
1859 | 0 | 8 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", |
1860 | 0 | 3 "$fcw", "$fsw", "$mxcsr", |
1861 | 0 | 8 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", |
1862 | 0 | 2 "$tr", "$ldtr" |
1863 | 0 | */ |
1864 | 0 | return 8 + 3 + 8 + 2 + 8 + 8 + 3 + 8 + 2; |
1865 | 0 | } |
1866 | | |
1867 | 0 | unsigned int DwarfCFIToModule::RegisterNames::X86_64() { |
1868 | 0 | /* |
1869 | 0 | 8 "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", |
1870 | 0 | 8 "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", |
1871 | 0 | 1 "$rip", |
1872 | 0 | 8 "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", |
1873 | 0 | 8 "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", |
1874 | 0 | 8 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", |
1875 | 0 | 8 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", |
1876 | 0 | 1 "$rflags", |
1877 | 0 | 8 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", |
1878 | 0 | 4 "$fs.base", "$gs.base", "$unused3", "$unused4", |
1879 | 0 | 2 "$tr", "$ldtr", |
1880 | 0 | 3 "$mxcsr", "$fcw", "$fsw" |
1881 | 0 | */ |
1882 | 0 | return 8 + 8 + 1 + 8 + 8 + 8 + 8 + 1 + 8 + 4 + 2 + 3; |
1883 | 0 | } |
1884 | | |
1885 | | // Per ARM IHI 0040A, section 3.1 |
1886 | 0 | unsigned int DwarfCFIToModule::RegisterNames::ARM() { |
1887 | 0 | /* |
1888 | 0 | 8 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
1889 | 0 | 8 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", |
1890 | 0 | 8 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
1891 | 0 | 8 "fps", "cpsr", "", "", "", "", "", "", |
1892 | 0 | 8 "", "", "", "", "", "", "", "", |
1893 | 0 | 8 "", "", "", "", "", "", "", "", |
1894 | 0 | 8 "", "", "", "", "", "", "", "", |
1895 | 0 | 8 "", "", "", "", "", "", "", "", |
1896 | 0 | 8 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
1897 | 0 | 8 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", |
1898 | 0 | 8 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", |
1899 | 0 | 8 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", |
1900 | 0 | 8 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" |
1901 | 0 | */ |
1902 | 0 | return 13 * 8; |
1903 | 0 | } |
1904 | | |
1905 | | // Per ARM IHI 0057A, section 3.1 |
1906 | 0 | unsigned int DwarfCFIToModule::RegisterNames::ARM64() { |
1907 | 0 | /* |
1908 | 0 | 8 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", |
1909 | 0 | 8 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", |
1910 | 0 | 8 "x16" "x17", "x18", "x19", "x20", "x21", "x22", "x23", |
1911 | 0 | 8 "x24", "x25", "x26", "x27", "x28", "x29", "x30","sp", |
1912 | 0 | 8 "", "", "", "", "", "", "", "", |
1913 | 0 | 8 "", "", "", "", "", "", "", "", |
1914 | 0 | 8 "", "", "", "", "", "", "", "", |
1915 | 0 | 8 "", "", "", "", "", "", "", "", |
1916 | 0 | 8 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", |
1917 | 0 | 8 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", |
1918 | 0 | 8 "v16", "v17", "v18", "v19", "v20", "v21", "v22, "v23", |
1919 | 0 | 8 "v24", "x25", "x26, "x27", "v28", "v29", "v30", "v31", |
1920 | 0 | */ |
1921 | 0 | return 12 * 8; |
1922 | 0 | } |
1923 | | |
1924 | 0 | unsigned int DwarfCFIToModule::RegisterNames::MIPS() { |
1925 | 0 | /* |
1926 | 0 | 8 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", |
1927 | 0 | 8 "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", |
1928 | 0 | 8 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", |
1929 | 0 | 8 "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", |
1930 | 0 | 9 "$lo", "$hi", "$pc", "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", |
1931 | 0 | 8 "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", |
1932 | 0 | 7 "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", |
1933 | 0 | 7 "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", |
1934 | 0 | 6 "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir" |
1935 | 0 | */ |
1936 | 0 | return 8 + 8 + 8 + 8 + 9 + 8 + 7 + 7 + 6; |
1937 | 0 | } |
1938 | | |
1939 | | // See prototype for comments. |
1940 | | int32_t parseDwarfExpr(Summariser* summ, const ByteReader* reader, |
1941 | | string expr, bool debug, |
1942 | | bool pushCfaAtStart, bool derefAtEnd) |
1943 | 0 | { |
1944 | 0 | const char* cursor = expr.c_str(); |
1945 | 0 | const char* end1 = cursor + expr.length(); |
1946 | 0 |
|
1947 | 0 | char buf[100]; |
1948 | 0 | if (debug) { |
1949 | 0 | SprintfLiteral(buf, "LUL.DW << DwarfExpr, len is %d\n", |
1950 | 0 | (int)(end1 - cursor)); |
1951 | 0 | summ->Log(buf); |
1952 | 0 | } |
1953 | 0 |
|
1954 | 0 | // Add a marker for the start of this expression. In it, indicate |
1955 | 0 | // whether or not the CFA should be pushed onto the stack prior to |
1956 | 0 | // evaluation. |
1957 | 0 | int32_t start_ix |
1958 | 0 | = summ->AddPfxInstr(PfxInstr(PX_Start, pushCfaAtStart ? 1 : 0)); |
1959 | 0 | MOZ_ASSERT(start_ix >= 0); |
1960 | 0 |
|
1961 | 0 | while (cursor < end1) { |
1962 | 0 |
|
1963 | 0 | uint8 opc = reader->ReadOneByte(cursor); |
1964 | 0 | cursor++; |
1965 | 0 |
|
1966 | 0 | const char* nm = nullptr; |
1967 | 0 | PfxExprOp pxop = PX_End; |
1968 | 0 |
|
1969 | 0 | switch (opc) { |
1970 | 0 |
|
1971 | 0 | case DW_OP_lit0 ... DW_OP_lit31: { |
1972 | 0 | int32_t simm32 = (int32_t)(opc - DW_OP_lit0); |
1973 | 0 | if (debug) { |
1974 | 0 | SprintfLiteral(buf, "LUL.DW DW_OP_lit%d\n", (int)simm32); |
1975 | 0 | summ->Log(buf); |
1976 | 0 | } |
1977 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_SImm32, simm32)); |
1978 | 0 | break; |
1979 | 0 | } |
1980 | 0 |
|
1981 | 0 | case DW_OP_breg0 ... DW_OP_breg31: { |
1982 | 0 | size_t len; |
1983 | 0 | int64_t n = reader->ReadSignedLEB128(cursor, &len); |
1984 | 0 | cursor += len; |
1985 | 0 | DW_REG_NUMBER reg = (DW_REG_NUMBER)(opc - DW_OP_breg0); |
1986 | 0 | if (debug) { |
1987 | 0 | SprintfLiteral(buf, "LUL.DW DW_OP_breg%d %lld\n", |
1988 | 0 | (int)reg, (long long int)n); |
1989 | 0 | summ->Log(buf); |
1990 | 0 | } |
1991 | 0 | // PfxInstr only allows a 32 bit signed offset. So we |
1992 | 0 | // must fail if the immediate is out of range. |
1993 | 0 | if (n < INT32_MIN || INT32_MAX < n) |
1994 | 0 | goto fail; |
1995 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_DwReg, reg)); |
1996 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_SImm32, (int32_t)n)); |
1997 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_Add)); |
1998 | 0 | break; |
1999 | 0 | } |
2000 | 0 |
|
2001 | 0 | case DW_OP_const4s: { |
2002 | 0 | uint64_t u64 = reader->ReadFourBytes(cursor); |
2003 | 0 | cursor += 4; |
2004 | 0 | // u64 is guaranteed by |ReadFourBytes| to be in the |
2005 | 0 | // range 0 .. FFFFFFFF inclusive. But to be safe: |
2006 | 0 | uint32_t u32 = (uint32_t)(u64 & 0xFFFFFFFF); |
2007 | 0 | int32_t s32 = (int32_t)u32; |
2008 | 0 | if (debug) { |
2009 | 0 | SprintfLiteral(buf, "LUL.DW DW_OP_const4s %d\n", (int)s32); |
2010 | 0 | summ->Log(buf); |
2011 | 0 | } |
2012 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_SImm32, s32)); |
2013 | 0 | break; |
2014 | 0 | } |
2015 | 0 |
|
2016 | 0 | case DW_OP_deref: nm = "deref"; pxop = PX_Deref; goto no_operands; |
2017 | 0 | case DW_OP_and: nm = "and"; pxop = PX_And; goto no_operands; |
2018 | 0 | case DW_OP_plus: nm = "plus"; pxop = PX_Add; goto no_operands; |
2019 | 0 | case DW_OP_minus: nm = "minus"; pxop = PX_Sub; goto no_operands; |
2020 | 0 | case DW_OP_shl: nm = "shl"; pxop = PX_Shl; goto no_operands; |
2021 | 0 | case DW_OP_ge: nm = "ge"; pxop = PX_CmpGES; goto no_operands; |
2022 | 0 | no_operands: |
2023 | 0 | MOZ_ASSERT(nm && pxop != PX_End); |
2024 | 0 | if (debug) { |
2025 | 0 | SprintfLiteral(buf, "LUL.DW DW_OP_%s\n", nm); |
2026 | 0 | summ->Log(buf); |
2027 | 0 | } |
2028 | 0 | (void) summ->AddPfxInstr(PfxInstr(pxop)); |
2029 | 0 | break; |
2030 | 0 |
|
2031 | 0 | default: |
2032 | 0 | if (debug) { |
2033 | 0 | SprintfLiteral(buf, "LUL.DW unknown opc %d\n", (int)opc); |
2034 | 0 | summ->Log(buf); |
2035 | 0 | } |
2036 | 0 | goto fail; |
2037 | 0 |
|
2038 | 0 | } // switch (opc) |
2039 | 0 |
|
2040 | 0 | } // while (cursor < end1) |
2041 | 0 |
|
2042 | 0 | MOZ_ASSERT(cursor >= end1); |
2043 | 0 |
|
2044 | 0 | if (cursor > end1) { |
2045 | 0 | // We overran the Dwarf expression. Give up. |
2046 | 0 | goto fail; |
2047 | 0 | } |
2048 | 0 | |
2049 | 0 | // For DW_CFA_expression, what the expression denotes is the address |
2050 | 0 | // of where the previous value is located. The caller of this routine |
2051 | 0 | // may therefore request one last dereference before the end marker is |
2052 | 0 | // inserted. |
2053 | 0 | if (derefAtEnd) { |
2054 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_Deref)); |
2055 | 0 | } |
2056 | 0 |
|
2057 | 0 | // Insert an end marker, and declare success. |
2058 | 0 | (void) summ->AddPfxInstr(PfxInstr(PX_End)); |
2059 | 0 | if (debug) { |
2060 | 0 | SprintfLiteral(buf, "LUL.DW conversion of dwarf expression succeeded, " |
2061 | 0 | "ix = %d\n", (int)start_ix); |
2062 | 0 | summ->Log(buf); |
2063 | 0 | summ->Log("LUL.DW >>\n"); |
2064 | 0 | } |
2065 | 0 | return start_ix; |
2066 | 0 |
|
2067 | 0 | fail: |
2068 | 0 | if (debug) { |
2069 | 0 | summ->Log("LUL.DW conversion of dwarf expression failed\n"); |
2070 | 0 | summ->Log("LUL.DW >>\n"); |
2071 | 0 | } |
2072 | 0 | return -1; |
2073 | 0 | } |
2074 | | |
2075 | | |
2076 | | bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, |
2077 | | uint8 version, const string &augmentation, |
2078 | 0 | unsigned return_address) { |
2079 | 0 | if (DEBUG_DWARF) { |
2080 | 0 | char buf[100]; |
2081 | 0 | SprintfLiteral(buf, "LUL.DW DwarfCFIToModule::Entry 0x%llx,+%lld\n", |
2082 | 0 | address, length); |
2083 | 0 | summ_->Log(buf); |
2084 | 0 | } |
2085 | 0 |
|
2086 | 0 | summ_->Entry(address, length); |
2087 | 0 |
|
2088 | 0 | // If dwarf2reader::CallFrameInfo can handle this version and |
2089 | 0 | // augmentation, then we should be okay with that, so there's no |
2090 | 0 | // need to check them here. |
2091 | 0 |
|
2092 | 0 | // Get ready to collect entries. |
2093 | 0 | return_address_ = return_address; |
2094 | 0 |
|
2095 | 0 | // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI |
2096 | 0 | // may not establish any rule for .ra if the return address column |
2097 | 0 | // is an ordinary register, and that register holds the return |
2098 | 0 | // address on entry to the function. So establish an initial .ra |
2099 | 0 | // rule citing the return address register. |
2100 | 0 | if (return_address_ < num_dw_regs_) { |
2101 | 0 | summ_->Rule(address, return_address_, NODEREF, return_address, 0); |
2102 | 0 | } |
2103 | 0 |
|
2104 | 0 | return true; |
2105 | 0 | } |
2106 | | |
2107 | 0 | const UniqueString* DwarfCFIToModule::RegisterName(int i) { |
2108 | 0 | if (i < 0) { |
2109 | 0 | MOZ_ASSERT(i == kCFARegister); |
2110 | 0 | return usu_->ToUniqueString(".cfa"); |
2111 | 0 | } |
2112 | 0 | unsigned reg = i; |
2113 | 0 | if (reg == return_address_) |
2114 | 0 | return usu_->ToUniqueString(".ra"); |
2115 | 0 | |
2116 | 0 | char buf[30]; |
2117 | 0 | SprintfLiteral(buf, "dwarf_reg_%u", reg); |
2118 | 0 | return usu_->ToUniqueString(buf); |
2119 | 0 | } |
2120 | | |
2121 | 0 | bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { |
2122 | 0 | reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); |
2123 | 0 | // Treat this as a non-fatal error. |
2124 | 0 | return true; |
2125 | 0 | } |
2126 | | |
2127 | 0 | bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { |
2128 | 0 | if (DEBUG_DWARF) { |
2129 | 0 | char buf[100]; |
2130 | 0 | SprintfLiteral(buf, "LUL.DW 0x%llx: old r%d = Same\n", address, reg); |
2131 | 0 | summ_->Log(buf); |
2132 | 0 | } |
2133 | 0 | // reg + 0 |
2134 | 0 | summ_->Rule(address, reg, NODEREF, reg, 0); |
2135 | 0 | return true; |
2136 | 0 | } |
2137 | | |
2138 | | bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, |
2139 | 0 | int base_register, long offset) { |
2140 | 0 | if (DEBUG_DWARF) { |
2141 | 0 | char buf[100]; |
2142 | 0 | SprintfLiteral(buf, "LUL.DW 0x%llx: old r%d = *(r%d + %ld)\n", |
2143 | 0 | address, reg, base_register, offset); |
2144 | 0 | summ_->Log(buf); |
2145 | 0 | } |
2146 | 0 | // *(base_register + offset) |
2147 | 0 | summ_->Rule(address, reg, DEREF, base_register, offset); |
2148 | 0 | return true; |
2149 | 0 | } |
2150 | | |
2151 | | bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, |
2152 | 0 | int base_register, long offset) { |
2153 | 0 | if (DEBUG_DWARF) { |
2154 | 0 | char buf[100]; |
2155 | 0 | SprintfLiteral(buf, "LUL.DW 0x%llx: old r%d = r%d + %ld\n", |
2156 | 0 | address, reg, base_register, offset); |
2157 | 0 | summ_->Log(buf); |
2158 | 0 | } |
2159 | 0 | // base_register + offset |
2160 | 0 | summ_->Rule(address, reg, NODEREF, base_register, offset); |
2161 | 0 | return true; |
2162 | 0 | } |
2163 | | |
2164 | | bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, |
2165 | 0 | int base_register) { |
2166 | 0 | if (DEBUG_DWARF) { |
2167 | 0 | char buf[100]; |
2168 | 0 | SprintfLiteral(buf, "LUL.DW 0x%llx: old r%d = r%d\n", |
2169 | 0 | address, reg, base_register); |
2170 | 0 | summ_->Log(buf); |
2171 | 0 | } |
2172 | 0 | // base_register + 0 |
2173 | 0 | summ_->Rule(address, reg, NODEREF, base_register, 0); |
2174 | 0 | return true; |
2175 | 0 | } |
2176 | | |
2177 | | bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, |
2178 | | const string &expression) |
2179 | 0 | { |
2180 | 0 | bool debug = !!DEBUG_DWARF; |
2181 | 0 | int32_t start_ix = parseDwarfExpr(summ_, reader_, expression, debug, |
2182 | 0 | true/*pushCfaAtStart*/, |
2183 | 0 | true/*derefAtEnd*/); |
2184 | 0 | if (start_ix >= 0) { |
2185 | 0 | summ_->Rule(address, reg, PFXEXPR, 0, start_ix); |
2186 | 0 | } else { |
2187 | 0 | // Parsing of the Dwarf expression failed. Treat this as a |
2188 | 0 | // non-fatal error, hence return |true| even on this path. |
2189 | 0 | reporter_->ExpressionCouldNotBeSummarised(entry_offset_, RegisterName(reg)); |
2190 | 0 | } |
2191 | 0 | return true; |
2192 | 0 | } |
2193 | | |
2194 | | bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, |
2195 | | const string &expression) |
2196 | 0 | { |
2197 | 0 | bool debug = !!DEBUG_DWARF; |
2198 | 0 | int32_t start_ix = parseDwarfExpr(summ_, reader_, expression, debug, |
2199 | 0 | true/*pushCfaAtStart*/, |
2200 | 0 | false/*!derefAtEnd*/); |
2201 | 0 | if (start_ix >= 0) { |
2202 | 0 | summ_->Rule(address, reg, PFXEXPR, 0, start_ix); |
2203 | 0 | } else { |
2204 | 0 | // Parsing of the Dwarf expression failed. Treat this as a |
2205 | 0 | // non-fatal error, hence return |true| even on this path. |
2206 | 0 | reporter_->ExpressionCouldNotBeSummarised(entry_offset_, RegisterName(reg)); |
2207 | 0 | } |
2208 | 0 | return true; |
2209 | 0 | } |
2210 | | |
2211 | 0 | bool DwarfCFIToModule::End() { |
2212 | 0 | //module_->AddStackFrameEntry(entry_); |
2213 | 0 | if (DEBUG_DWARF) { |
2214 | 0 | summ_->Log("LUL.DW DwarfCFIToModule::End()\n"); |
2215 | 0 | } |
2216 | 0 | summ_->End(); |
2217 | 0 | return true; |
2218 | 0 | } |
2219 | | |
2220 | | void DwarfCFIToModule::Reporter::UndefinedNotSupported( |
2221 | | size_t offset, |
2222 | 0 | const UniqueString* reg) { |
2223 | 0 | char buf[300]; |
2224 | 0 | SprintfLiteral(buf, "DwarfCFIToModule::Reporter::UndefinedNotSupported()\n"); |
2225 | 0 | log_(buf); |
2226 | 0 | //BPLOG(INFO) << file_ << ", section '" << section_ |
2227 | 0 | // << "': the call frame entry at offset 0x" |
2228 | 0 | // << std::setbase(16) << offset << std::setbase(10) |
2229 | 0 | // << " sets the rule for register '" << FromUniqueString(reg) |
2230 | 0 | // << "' to 'undefined', but the Breakpad symbol file format cannot " |
2231 | 0 | // << " express this"; |
2232 | 0 | } |
2233 | | |
2234 | | // FIXME: move this somewhere sensible |
2235 | | static bool is_power_of_2(uint64_t n) |
2236 | 0 | { |
2237 | 0 | int i, nSetBits = 0; |
2238 | 0 | for (i = 0; i < 8*(int)sizeof(n); i++) { |
2239 | 0 | if ((n & ((uint64_t)1) << i) != 0) |
2240 | 0 | nSetBits++; |
2241 | 0 | } |
2242 | 0 | return nSetBits <= 1; |
2243 | 0 | } |
2244 | | |
2245 | | void DwarfCFIToModule::Reporter::ExpressionCouldNotBeSummarised( |
2246 | | size_t offset, |
2247 | 0 | const UniqueString* reg) { |
2248 | 0 | static uint64_t n_complaints = 0; // This isn't threadsafe |
2249 | 0 | n_complaints++; |
2250 | 0 | if (!is_power_of_2(n_complaints)) |
2251 | 0 | return; |
2252 | 0 | char buf[300]; |
2253 | 0 | SprintfLiteral(buf, |
2254 | 0 | "DwarfCFIToModule::Reporter::" |
2255 | 0 | "ExpressionCouldNotBeSummarised(shown %llu times)\n", |
2256 | 0 | (unsigned long long int)n_complaints); |
2257 | 0 | log_(buf); |
2258 | 0 | } |
2259 | | |
2260 | | } // namespace lul |