2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/vm/pc-filter.h"
20 #include "hphp/runtime/vm/hhbc-codec.h"
24 TRACE_SET_MOD(debuggerflow
);
26 //////////////////////////////////////////////////////////////////////////
28 void PCFilter::PtrMapNode::clearImpl(unsigned short bits
) {
29 static_assert(sizeof(PCFilter::PtrMapNode
) == sizeof(PCFilter::PtrMap
) &&
30 sizeof(PCFilter::PtrMapNode
) == sizeof(void*),
31 "PtrMapNode and PtrMap must hold a single pointer");
33 // clear all the sub levels and mark all slots NULL
34 if (bits
<= PTRMAP_LEVEL_BITS
) {
35 assertx(bits
== PTRMAP_LEVEL_BITS
);
38 for (int i
= 0; i
< PTRMAP_LEVEL_ENTRIES
; i
++) {
39 if (m_entries
[i
].m_entries
) {
40 m_entries
[i
].clearImpl(bits
- PTRMAP_LEVEL_BITS
);
41 free(m_entries
[i
].m_entries
);
42 m_entries
[i
].m_entries
= nullptr;
47 auto PCFilter::PtrMap::makeNode() -> PtrMapNode
{
49 static_cast<PtrMapNode
*>(
50 calloc(PCFilter::PTRMAP_LEVEL_ENTRIES
, sizeof(PtrMapNode
))
55 void* PCFilter::PtrMap::getPointerImpl(void* ptr
) const {
56 auto current
= &m_root
;
57 assertx(current
->m_entries
);
58 unsigned short cursor
= PTRMAP_PTR_SIZE
;
60 cursor
-= PTRMAP_LEVEL_BITS
;
61 unsigned long index
= ((PTRMAP_LEVEL_MASK
<< cursor
) & (unsigned long)ptr
)
63 assertx(index
< PTRMAP_LEVEL_ENTRIES
);
64 current
= ¤t
->m_entries
[index
];
65 if (!cursor
) return current
->m_value
;
66 } while (current
->m_entries
);
70 void PCFilter::PtrMap::setPointer(void* ptr
, void* val
) {
71 if (!m_root
.m_entries
) {
76 auto current
= &m_root
;
77 unsigned short cursor
= PTRMAP_PTR_SIZE
;
79 cursor
-= PTRMAP_LEVEL_BITS
;
80 unsigned long index
= ((PTRMAP_LEVEL_MASK
<< cursor
) & (unsigned long)ptr
)
82 assertx(index
< PTRMAP_LEVEL_ENTRIES
);
84 current
->m_entries
[index
].m_value
= val
;
87 if (!current
->m_entries
[index
].m_entries
) {
88 current
->m_entries
[index
] = makeNode();
90 current
= ¤t
->m_entries
[index
];
94 void PCFilter::PtrMap::clear() {
95 if (m_root
.m_entries
) {
96 m_root
.clearImpl(PTRMAP_PTR_SIZE
);
97 free(m_root
.m_entries
);
98 m_root
.m_entries
= nullptr;
102 // Adds a range of PCs to the filter given a collection of offset ranges.
103 // Omit PCs which have opcodes that don't pass the given opcode filter.
104 void PCFilter::addRanges(const OffsetFuncRangeVec
& funcOffsets
,
105 OpcodeFilter isOpcodeAllowed
) {
106 for (auto offsets
: funcOffsets
) {
107 auto func
= offsets
.first
;
108 for (auto range
= offsets
.second
.cbegin(); range
!= offsets
.second
.cend(); ++range
) {
109 TRACE(3, "\toffsets [%d, %d)\n", range
->base
, range
->past
);
110 for (PC pc
= func
->at(range
->base
); pc
< func
->at(range
->past
);
111 pc
+= instrLen(pc
)) {
112 if (isOpcodeAllowed(peek_op(pc
))) {
113 TRACE(3, "\t\tpc %p\n", pc
);
116 TRACE(3, "\t\tpc %p -- skipping (offset %d)\n", pc
,
124 // Removes a range of PCs to the filter given a collection of offset ranges.
125 // Omit PCs which have opcodes that don't pass the given opcode filter.
126 void PCFilter::removeRanges(const OffsetFuncRangeVec
& funcOffsets
,
127 OpcodeFilter isOpcodeAllowed
) {
128 for (auto offsets
: funcOffsets
) {
129 auto func
= offsets
.first
;
130 for (auto range
= offsets
.second
.cbegin(); range
!= offsets
.second
.cend(); ++range
) {
131 TRACE(3, "\toffsets [%d, %d) (remove)\n", range
->base
, range
->past
);
132 for (PC pc
= func
->at(range
->base
); pc
< func
->at(range
->past
);
133 pc
+= instrLen(pc
)) {
134 if (isOpcodeAllowed(peek_op(pc
))) {
135 TRACE(3, "\t\tpc %p (remove)\n", pc
);
138 TRACE(3, "\t\tpc %p -- skipping (offset %d) (remove)\n", pc
,
146 void PCFilter::removeOffset(const Func
* func
, Offset offset
) {
147 removePC(func
->at(offset
));
150 ///////////////////////////////////////////////////////////////////////////////