Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
2 /* libunwind - a platform-independent unwind library
3 Copyright 2011 Linaro Limited
5 This file is part of libunwind.
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26 // Copyright (c) 2010 Google Inc.
27 // All rights reserved.
28 //
29 // Redistribution and use in source and binary forms, with or without
30 // modification, are permitted provided that the following conditions are
31 // met:
32 //
33 // * Redistributions of source code must retain the above copyright
34 // notice, this list of conditions and the following disclaimer.
35 // * Redistributions in binary form must reproduce the above
36 // copyright notice, this list of conditions and the following disclaimer
37 // in the documentation and/or other materials provided with the
38 // distribution.
39 // * Neither the name of Google Inc. nor the names of its
40 // contributors may be used to endorse or promote products derived from
41 // this software without specific prior written permission.
42 //
43 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 // Derived from libunwind, with extensive modifications.
59 #include "common/arm_ex_reader.h"
60 #include "common/logging.h"
62 #include <assert.h>
64 // This file, in conjunction with arm_ex_to_module.cc, translates
65 // EXIDX unwind information into the same format that Breakpad uses
66 // for CFI information. Hence Breakpad's CFI unwinding abilities
67 // also become usable for EXIDX.
68 //
69 // See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A
70 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
72 // EXIDX data is presented in two parts:
73 //
74 // * an index table. This contains two words per routine,
75 // the first of which identifies the routine, and the second
76 // of which is a reference to the unwind bytecode. If the
77 // bytecode is very compact -- 3 bytes or less -- it can be
78 // stored directly in the second word.
79 //
80 // * an area containing the unwind bytecodes.
82 // General flow is: ExceptionTableInfo::Start iterates over all
83 // of the index table entries (pairs). For each entry, it:
84 //
85 // * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode
86 // out into an intermediate buffer.
88 // * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate
89 // buffer. Each bytecode instruction is bundled into a
90 // arm_ex_to_module::extab_data structure, and handed to ..
91 //
92 // * .. ARMExToModule::ImproveStackFrame, which in turn hands it to
93 // ARMExToModule::TranslateCmd, and that generates the pseudo-CFI
94 // records that Breakpad stores.
96 #define ARM_EXIDX_CANT_UNWIND 0x00000001
97 #define ARM_EXIDX_COMPACT 0x80000000
98 #define ARM_EXTBL_OP_FINISH 0xb0
99 #define ARM_EXIDX_TABLE_LIMIT (255*4)
101 namespace arm_ex_reader {
103 using arm_ex_to_module::ARM_EXIDX_CMD_FINISH;
104 using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP;
105 using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP;
106 using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP;
107 using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP;
108 using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP;
109 using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP;
110 using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP;
111 using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED;
112 using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED;
113 using arm_ex_to_module::exidx_entry;
114 using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16;
115 using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD;
116 using google_breakpad::MemoryRange;
119 static void* Prel31ToAddr(const void* addr)
120 {
121 uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr);
122 // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions
123 // 63:31 inclusive.
124 uint64_t offset64 = offset32;
125 if (offset64 & (1ULL << 30))
126 offset64 |= 0xFFFFFFFF80000000ULL;
127 else
128 offset64 &= 0x000000007FFFFFFFULL;
129 return ((char*)addr) + (uintptr_t)offset64;
130 }
133 // Extract unwind bytecode for the function denoted by |entry| into |buf|,
134 // and return the number of bytes of |buf| written, along with a code
135 // indicating the outcome.
137 ExceptionTableInfo::ExExtractResult
138 ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry,
139 uint8_t* buf, size_t buf_size,
140 /*OUT*/size_t* buf_used)
141 {
142 MemoryRange mr_out(buf, buf_size);
144 *buf_used = 0;
146 # define PUT_BUF_U8(_byte) \
147 do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \
148 buf[(*buf_used)++] = (_byte); } while (0)
150 # define GET_EX_U32(_lval, _addr, _sec_mr) \
151 do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \
152 - (_sec_mr).data(), 4)) \
153 return ExInBufOverflow; \
154 (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0)
156 # define GET_EXIDX_U32(_lval, _addr) \
157 GET_EX_U32(_lval, _addr, mr_exidx_)
158 # define GET_EXTAB_U32(_lval, _addr) \
159 GET_EX_U32(_lval, _addr, mr_extab_)
161 uint32_t data;
162 GET_EXIDX_U32(data, &entry->data);
164 // A function can be marked CANT_UNWIND if (eg) it is known to be
165 // at the bottom of the stack.
166 if (data == ARM_EXIDX_CANT_UNWIND)
167 return ExCantUnwind;
169 uint32_t pers; // personality number
170 uint32_t extra; // number of extra data words required
171 uint32_t extra_allowed; // number of extra data words allowed
172 uint32_t* extbl_data; // the handler entry, if not inlined
174 if (data & ARM_EXIDX_COMPACT) {
175 // The handler table entry has been inlined into the index table entry.
176 // In this case it can only be an ARM-defined compact model, since
177 // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the
178 // ARM compact model, but 1 and 2 are "Long format" and may require
179 // extra data words. Hence the allowable personalities here are:
180 // personality 0, in which case 'extra' has no meaning
181 // personality 1, with zero extra words
182 // personality 2, with zero extra words
183 extbl_data = NULL;
184 pers = (data >> 24) & 0x0F;
185 extra = (data >> 16) & 0xFF;
186 extra_allowed = 0;
187 }
188 else {
189 // The index table entry is a pointer to the handler entry. Note
190 // that Prel31ToAddr will read the given address, but we already
191 // range-checked above.
192 extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data));
193 GET_EXTAB_U32(data, extbl_data);
194 if (!(data & ARM_EXIDX_COMPACT)) {
195 // This denotes a "generic model" handler. That will involve
196 // executing arbitary machine code, which is something we
197 // can't represent here; hence reject it.
198 return ExCantRepresent;
199 }
200 // So we have a compact model representation. Again, 3 possible
201 // personalities, but this time up to 255 allowable extra words.
202 pers = (data >> 24) & 0x0F;
203 extra = (data >> 16) & 0xFF;
204 extra_allowed = 255;
205 extbl_data++;
206 }
208 // Now look at the the handler table entry. The first word is
209 // |data| and subsequent words start at |*extbl_data|. The number
210 // of extra words to use is |extra|, provided that the personality
211 // allows extra words. Even if it does, none may be available --
212 // extra_allowed is the maximum number of extra words allowed. */
213 if (pers == 0) {
214 // "Su16" in the documentation -- 3 unwinding insn bytes
215 // |extra| has no meaning here; instead that byte is an unwind-info byte
216 PUT_BUF_U8(data >> 16);
217 PUT_BUF_U8(data >> 8);
218 PUT_BUF_U8(data);
219 }
220 else if ((pers == 1 || pers == 2) && extra <= extra_allowed) {
221 // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes,
222 // and up to 255 extra words.
223 PUT_BUF_U8(data >> 8);
224 PUT_BUF_U8(data);
225 for (uint32_t j = 0; j < extra; j++) {
226 GET_EXTAB_U32(data, extbl_data);
227 extbl_data++;
228 PUT_BUF_U8(data >> 24);
229 PUT_BUF_U8(data >> 16);
230 PUT_BUF_U8(data >> 8);
231 PUT_BUF_U8(data >> 0);
232 }
233 }
234 else {
235 // The entry is invalid.
236 return ExInvalid;
237 }
239 // Make sure the entry is terminated with "FINISH"
240 if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH)
241 PUT_BUF_U8(ARM_EXTBL_OP_FINISH);
243 return ExSuccess;
245 # undef GET_EXTAB_U32
246 # undef GET_EXIDX_U32
247 # undef GET_U32
248 # undef PUT_BUF_U8
249 }
252 // Take the unwind information extracted by ExtabEntryExtract
253 // and parse it into frame-unwind instructions. These are as
254 // specified in "Table 4, ARM-defined frame-unwinding instructions"
255 // in the specification document detailed in comments at the top
256 // of this file.
257 //
258 // This reads from |buf[0, +data_size)|. It checks for overruns of
259 // the input buffer and returns a negative value if that happens, or
260 // for any other failure cases. It returns zero in case of success.
261 int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size)
262 {
263 if (buf == NULL || buf_size == 0)
264 return -1;
266 MemoryRange mr_in(buf, buf_size);
267 const uint8_t* buf_initially = buf;
269 # define GET_BUF_U8(_lval) \
270 do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \
271 (_lval) = *(buf++); } while (0)
273 const uint8_t* end = buf + buf_size;
275 while (buf < end) {
276 struct arm_ex_to_module::extab_data edata;
277 memset(&edata, 0, sizeof(edata));
279 uint8_t op;
280 GET_BUF_U8(op);
281 if ((op & 0xc0) == 0x00) {
282 // vsp = vsp + (xxxxxx << 2) + 4
283 edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
284 edata.data = (((int)op & 0x3f) << 2) + 4;
285 }
286 else if ((op & 0xc0) == 0x40) {
287 // vsp = vsp - (xxxxxx << 2) - 4
288 edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP;
289 edata.data = (((int)op & 0x3f) << 2) + 4;
290 }
291 else if ((op & 0xf0) == 0x80) {
292 uint8_t op2;
293 GET_BUF_U8(op2);
294 if (op == 0x80 && op2 == 0x00) {
295 // Refuse to unwind
296 edata.cmd = ARM_EXIDX_CMD_REFUSED;
297 } else {
298 // Pop up to 12 integer registers under masks {r15-r12},{r11-r4}
299 edata.cmd = ARM_EXIDX_CMD_REG_POP;
300 edata.data = ((op & 0xf) << 8) | op2;
301 edata.data = edata.data << 4;
302 }
303 }
304 else if ((op & 0xf0) == 0x90) {
305 if (op == 0x9d || op == 0x9f) {
306 // 9d: Reserved as prefix for ARM register to register moves
307 // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves
308 edata.cmd = ARM_EXIDX_CMD_RESERVED;
309 } else {
310 // Set vsp = r[nnnn]
311 edata.cmd = ARM_EXIDX_CMD_REG_TO_SP;
312 edata.data = op & 0x0f;
313 }
314 }
315 else if ((op & 0xf0) == 0xa0) {
316 // Pop r4 to r[4+nnn], or
317 // Pop r4 to r[4+nnn] and r14 or
318 unsigned end = (op & 0x07);
319 edata.data = (1 << (end + 1)) - 1;
320 edata.data = edata.data << 4;
321 if (op & 0x08) edata.data |= 1 << 14;
322 edata.cmd = ARM_EXIDX_CMD_REG_POP;
323 }
324 else if (op == ARM_EXTBL_OP_FINISH) {
325 // Finish
326 edata.cmd = ARM_EXIDX_CMD_FINISH;
327 buf = end;
328 }
329 else if (op == 0xb1) {
330 uint8_t op2;
331 GET_BUF_U8(op2);
332 if (op2 == 0 || (op2 & 0xf0)) {
333 // Spare
334 edata.cmd = ARM_EXIDX_CMD_RESERVED;
335 } else {
336 // Pop integer registers under mask {r3,r2,r1,r0}
337 edata.cmd = ARM_EXIDX_CMD_REG_POP;
338 edata.data = op2 & 0x0f;
339 }
340 }
341 else if (op == 0xb2) {
342 // vsp = vsp + 0x204 + (uleb128 << 2)
343 uint64_t offset = 0;
344 uint8_t byte, shift = 0;
345 do {
346 GET_BUF_U8(byte);
347 offset |= (byte & 0x7f) << shift;
348 shift += 7;
349 } while ((byte & 0x80) && buf < end);
350 edata.data = offset * 4 + 0x204;
351 edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
352 }
353 else if (op == 0xb3 || op == 0xc8 || op == 0xc9) {
354 // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly
355 // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly
356 // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly
357 edata.cmd = ARM_EXIDX_CMD_VFP_POP;
358 GET_BUF_U8(edata.data);
359 if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16;
360 if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD;
361 }
362 else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) {
363 // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly
364 // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly
365 edata.cmd = ARM_EXIDX_CMD_VFP_POP;
366 edata.data = 0x80 | (op & 0x07);
367 if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD;
368 }
369 else if (op >= 0xc0 && op <= 0xc5) {
370 // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7
371 edata.cmd = ARM_EXIDX_CMD_WREG_POP;
372 edata.data = 0xa0 | (op & 0x07);
373 }
374 else if (op == 0xc6) {
375 // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc]
376 edata.cmd = ARM_EXIDX_CMD_WREG_POP;
377 GET_BUF_U8(edata.data);
378 }
379 else if (op == 0xc7) {
380 uint8_t op2;
381 GET_BUF_U8(op2);
382 if (op2 == 0 || (op2 & 0xf0)) {
383 // Spare
384 edata.cmd = ARM_EXIDX_CMD_RESERVED;
385 } else {
386 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
387 edata.cmd = ARM_EXIDX_CMD_WCGR_POP;
388 edata.data = op2 & 0x0f;
389 }
390 }
391 else {
392 // Spare
393 edata.cmd = ARM_EXIDX_CMD_RESERVED;
394 }
396 int ret = handler_->ImproveStackFrame(&edata);
397 if (ret < 0) return ret;
398 }
399 return 0;
401 # undef GET_BUF_U8
402 }
404 void ExceptionTableInfo::Start()
405 {
406 const struct exidx_entry* start
407 = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data());
408 const struct exidx_entry* end
409 = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()
410 + mr_exidx_.length());
412 // Iterate over each of the EXIDX entries (pairs of 32-bit words).
413 // These occupy the entire .exidx section.
414 for (const struct exidx_entry* entry = start; entry < end; ++entry) {
416 // Figure out the code address range that this table entry is
417 // associated with.
418 uint32_t addr = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr))
419 - mapping_addr_ + loading_addr_) & 0x7fffffff;
420 uint32_t next_addr;
421 if (entry < end - 1)
422 next_addr = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr)))
423 - mapping_addr_ + loading_addr_) & 0x7fffffff;
424 else {
425 // This is the last EXIDX entry in the sequence, so we don't
426 // have an address for the start of the next function, to limit
427 // this one. Instead use the address of the last byte of the
428 // text section associated with this .exidx section, that we
429 // have been given. So as to avoid junking up the CFI unwind
430 // tables with absurdly large address ranges in the case where
431 // text_last_svma_ is wrong, only use the value if it is nonzero
432 // and within one page of |addr|. Otherwise assume a length of 1.
433 //
434 // In some cases, gcc has been observed to finish the exidx
435 // section with an entry of length 1 marked CANT_UNWIND,
436 // presumably exactly for the purpose of giving a definite
437 // length for the last real entry, without having to look at
438 // text segment boundaries.
439 bool plausible = false;
440 next_addr = addr + 1;
441 if (text_last_svma_ != 0) {
442 uint32_t maybe_next_addr = text_last_svma_ + 1;
443 if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) {
444 next_addr = maybe_next_addr;
445 plausible = true;
446 }
447 }
448 if (!plausible)
449 BPLOG(INFO) << "ExceptionTableInfo: implausible EXIDX last entry size "
450 << (int32_t)(text_last_svma_ - addr)
451 << "; using 1 instead.";
452 }
454 // Extract the unwind info into |buf|. This might fail for
455 // various reasons. It involves reading both the .exidx and
456 // .extab sections. All accesses to those sections are
457 // bounds-checked.
458 uint8_t buf[ARM_EXIDX_TABLE_LIMIT];
459 size_t buf_used = 0;
460 ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used);
461 if (res != ExSuccess) {
462 // Couldn't extract the unwind info, for some reason. Move on.
463 switch (res) {
464 case ExInBufOverflow:
465 BPLOG(INFO) << "ExtabEntryExtract: .exidx/.extab section overrun";
466 break;
467 case ExOutBufOverflow:
468 BPLOG(INFO) << "ExtabEntryExtract: bytecode buffer overflow";
469 break;
470 case ExCantUnwind:
471 BPLOG(INFO) << "ExtabEntryExtract: function is marked CANT_UNWIND";
472 break;
473 case ExCantRepresent:
474 BPLOG(INFO) << "ExtabEntryExtract: bytecode can't be represented";
475 break;
476 case ExInvalid:
477 BPLOG(INFO) << "ExtabEntryExtract: index table entry is invalid";
478 break;
479 default:
480 BPLOG(INFO) << "ExtabEntryExtract: unknown error: " << (int)res;
481 break;
482 }
483 continue;
484 }
486 // Finally, work through the unwind instructions in |buf| and
487 // create CFI entries that Breakpad can use. This can also fail.
488 // First, add a new stack frame entry, into which ExtabEntryDecode
489 // will write the CFI entries.
490 handler_->AddStackFrame(addr, next_addr - addr);
491 int ret = ExtabEntryDecode(buf, buf_used);
492 if (ret < 0) {
493 handler_->DeleteStackFrame();
494 BPLOG(INFO) << "ExtabEntryDecode: failed with error code: " << ret;
495 continue;
496 }
497 handler_->SubmitStackFrame();
499 } /* iterating over .exidx */
500 }
502 } // arm_ex_reader