1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker *
16*795d594fSAndroid Build Coastguard Worker * Implementation file for control flow graph dumping for the dexdump utility.
17*795d594fSAndroid Build Coastguard Worker */
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "dexdump_cfg.h"
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include <map>
24*795d594fSAndroid Build Coastguard Worker #include <ostream>
25*795d594fSAndroid Build Coastguard Worker #include <set>
26*795d594fSAndroid Build Coastguard Worker #include <sstream>
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_exception_helpers.h"
32*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
33*795d594fSAndroid Build Coastguard Worker
34*795d594fSAndroid Build Coastguard Worker namespace art {
35*795d594fSAndroid Build Coastguard Worker
DumpMethodCFG(const ClassAccessor::Method & method,std::ostream & os)36*795d594fSAndroid Build Coastguard Worker void DumpMethodCFG(const ClassAccessor::Method& method, std::ostream& os) {
37*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = &method.GetDexFile();
38*795d594fSAndroid Build Coastguard Worker os << "digraph {\n";
39*795d594fSAndroid Build Coastguard Worker os << " # /* " << dex_file->PrettyMethod(method.GetIndex(), true) << " */\n";
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor accessor(method.GetInstructionsAndData());
42*795d594fSAndroid Build Coastguard Worker std::set<uint32_t> dex_pc_is_branch_target;
43*795d594fSAndroid Build Coastguard Worker {
44*795d594fSAndroid Build Coastguard Worker // Go and populate.
45*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : accessor) {
46*795d594fSAndroid Build Coastguard Worker const Instruction* inst = &pair.Inst();
47*795d594fSAndroid Build Coastguard Worker if (inst->IsBranch()) {
48*795d594fSAndroid Build Coastguard Worker dex_pc_is_branch_target.insert(pair.DexPc() + inst->GetTargetOffset());
49*795d594fSAndroid Build Coastguard Worker } else if (inst->IsSwitch()) {
50*795d594fSAndroid Build Coastguard Worker const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst);
51*795d594fSAndroid Build Coastguard Worker int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
52*795d594fSAndroid Build Coastguard Worker const uint16_t* switch_insns = insns + switch_offset;
53*795d594fSAndroid Build Coastguard Worker uint32_t switch_count = switch_insns[1];
54*795d594fSAndroid Build Coastguard Worker int32_t targets_offset;
55*795d594fSAndroid Build Coastguard Worker if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
56*795d594fSAndroid Build Coastguard Worker /* 0=sig, 1=count, 2/3=firstKey */
57*795d594fSAndroid Build Coastguard Worker targets_offset = 4;
58*795d594fSAndroid Build Coastguard Worker } else {
59*795d594fSAndroid Build Coastguard Worker /* 0=sig, 1=count, 2..count*2 = keys */
60*795d594fSAndroid Build Coastguard Worker targets_offset = 2 + 2 * switch_count;
61*795d594fSAndroid Build Coastguard Worker }
62*795d594fSAndroid Build Coastguard Worker for (uint32_t targ = 0; targ < switch_count; targ++) {
63*795d594fSAndroid Build Coastguard Worker int32_t offset =
64*795d594fSAndroid Build Coastguard Worker static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
65*795d594fSAndroid Build Coastguard Worker static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
66*795d594fSAndroid Build Coastguard Worker dex_pc_is_branch_target.insert(pair.DexPc() + offset);
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker // Create nodes for "basic blocks."
73*795d594fSAndroid Build Coastguard Worker std::map<uint32_t, uint32_t> dex_pc_to_node_id; // This only has entries for block starts.
74*795d594fSAndroid Build Coastguard Worker std::map<uint32_t, uint32_t> dex_pc_to_incl_id; // This has entries for all dex pcs.
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Worker {
77*795d594fSAndroid Build Coastguard Worker bool first_in_block = true;
78*795d594fSAndroid Build Coastguard Worker bool force_new_block = false;
79*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : accessor) {
80*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = pair.DexPc();
81*795d594fSAndroid Build Coastguard Worker if (dex_pc == 0 ||
82*795d594fSAndroid Build Coastguard Worker (dex_pc_is_branch_target.find(dex_pc) != dex_pc_is_branch_target.end()) ||
83*795d594fSAndroid Build Coastguard Worker force_new_block) {
84*795d594fSAndroid Build Coastguard Worker uint32_t id = dex_pc_to_node_id.size();
85*795d594fSAndroid Build Coastguard Worker if (id > 0) {
86*795d594fSAndroid Build Coastguard Worker // End last node.
87*795d594fSAndroid Build Coastguard Worker os << "}\"];\n";
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker // Start next node.
90*795d594fSAndroid Build Coastguard Worker os << " node" << id << " [shape=record,label=\"{";
91*795d594fSAndroid Build Coastguard Worker dex_pc_to_node_id.insert(std::make_pair(dex_pc, id));
92*795d594fSAndroid Build Coastguard Worker first_in_block = true;
93*795d594fSAndroid Build Coastguard Worker force_new_block = false;
94*795d594fSAndroid Build Coastguard Worker }
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker // Register instruction.
97*795d594fSAndroid Build Coastguard Worker dex_pc_to_incl_id.insert(std::make_pair(dex_pc, dex_pc_to_node_id.size() - 1));
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker // Print instruction.
100*795d594fSAndroid Build Coastguard Worker if (!first_in_block) {
101*795d594fSAndroid Build Coastguard Worker os << " | ";
102*795d594fSAndroid Build Coastguard Worker } else {
103*795d594fSAndroid Build Coastguard Worker first_in_block = false;
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker // Dump the instruction. Need to escape '"', '<', '>', '{' and '}'.
107*795d594fSAndroid Build Coastguard Worker os << "<" << "p" << dex_pc << ">";
108*795d594fSAndroid Build Coastguard Worker os << " 0x" << std::hex << dex_pc << std::dec << ": ";
109*795d594fSAndroid Build Coastguard Worker std::string inst_str = pair.Inst().DumpString(dex_file);
110*795d594fSAndroid Build Coastguard Worker size_t cur_start = 0; // It's OK to start at zero, instruction dumps don't start with chars
111*795d594fSAndroid Build Coastguard Worker // we need to escape.
112*795d594fSAndroid Build Coastguard Worker while (cur_start != std::string::npos) {
113*795d594fSAndroid Build Coastguard Worker size_t next_escape = inst_str.find_first_of("\"{}<>", cur_start + 1);
114*795d594fSAndroid Build Coastguard Worker if (next_escape == std::string::npos) {
115*795d594fSAndroid Build Coastguard Worker os << inst_str.substr(cur_start, inst_str.size() - cur_start);
116*795d594fSAndroid Build Coastguard Worker break;
117*795d594fSAndroid Build Coastguard Worker } else {
118*795d594fSAndroid Build Coastguard Worker os << inst_str.substr(cur_start, next_escape - cur_start);
119*795d594fSAndroid Build Coastguard Worker // Escape all necessary characters.
120*795d594fSAndroid Build Coastguard Worker while (next_escape < inst_str.size()) {
121*795d594fSAndroid Build Coastguard Worker char c = inst_str[next_escape];
122*795d594fSAndroid Build Coastguard Worker if (c == '"' || c == '{' || c == '}' || c == '<' || c == '>') {
123*795d594fSAndroid Build Coastguard Worker os << '\\' << c;
124*795d594fSAndroid Build Coastguard Worker } else {
125*795d594fSAndroid Build Coastguard Worker break;
126*795d594fSAndroid Build Coastguard Worker }
127*795d594fSAndroid Build Coastguard Worker next_escape++;
128*795d594fSAndroid Build Coastguard Worker }
129*795d594fSAndroid Build Coastguard Worker if (next_escape >= inst_str.size()) {
130*795d594fSAndroid Build Coastguard Worker next_escape = std::string::npos;
131*795d594fSAndroid Build Coastguard Worker }
132*795d594fSAndroid Build Coastguard Worker cur_start = next_escape;
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker // Force a new block for some fall-throughs and some instructions that terminate the "local"
137*795d594fSAndroid Build Coastguard Worker // control flow.
138*795d594fSAndroid Build Coastguard Worker force_new_block = pair.Inst().IsSwitch() || pair.Inst().IsBasicBlockEnd();
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker // Close last node.
141*795d594fSAndroid Build Coastguard Worker if (dex_pc_to_node_id.size() > 0) {
142*795d594fSAndroid Build Coastguard Worker os << "}\"];\n";
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker
146*795d594fSAndroid Build Coastguard Worker // Create edges between them.
147*795d594fSAndroid Build Coastguard Worker {
148*795d594fSAndroid Build Coastguard Worker std::ostringstream regular_edges;
149*795d594fSAndroid Build Coastguard Worker std::ostringstream taken_edges;
150*795d594fSAndroid Build Coastguard Worker std::ostringstream exception_edges;
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker // Common set of exception edges.
153*795d594fSAndroid Build Coastguard Worker std::set<uint32_t> exception_targets;
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker // These blocks (given by the first dex pc) need exception per dex-pc handling in a second
156*795d594fSAndroid Build Coastguard Worker // pass. In the first pass we try and see whether we can use a common set of edges.
157*795d594fSAndroid Build Coastguard Worker std::set<uint32_t> blocks_with_detailed_exceptions;
158*795d594fSAndroid Build Coastguard Worker
159*795d594fSAndroid Build Coastguard Worker {
160*795d594fSAndroid Build Coastguard Worker uint32_t last_node_id = std::numeric_limits<uint32_t>::max();
161*795d594fSAndroid Build Coastguard Worker uint32_t old_dex_pc = 0;
162*795d594fSAndroid Build Coastguard Worker uint32_t block_start_dex_pc = std::numeric_limits<uint32_t>::max();
163*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& pair : accessor) {
164*795d594fSAndroid Build Coastguard Worker const Instruction* inst = &pair.Inst();
165*795d594fSAndroid Build Coastguard Worker const uint32_t dex_pc = pair.DexPc();
166*795d594fSAndroid Build Coastguard Worker {
167*795d594fSAndroid Build Coastguard Worker auto it = dex_pc_to_node_id.find(dex_pc);
168*795d594fSAndroid Build Coastguard Worker if (it != dex_pc_to_node_id.end()) {
169*795d594fSAndroid Build Coastguard Worker if (!exception_targets.empty()) {
170*795d594fSAndroid Build Coastguard Worker // It seems the last block had common exception handlers. Add the exception edges now.
171*795d594fSAndroid Build Coastguard Worker uint32_t node_id = dex_pc_to_node_id.find(block_start_dex_pc)->second;
172*795d594fSAndroid Build Coastguard Worker for (uint32_t handler_pc : exception_targets) {
173*795d594fSAndroid Build Coastguard Worker auto node_id_it = dex_pc_to_incl_id.find(handler_pc);
174*795d594fSAndroid Build Coastguard Worker if (node_id_it != dex_pc_to_incl_id.end()) {
175*795d594fSAndroid Build Coastguard Worker exception_edges << " node" << node_id
176*795d594fSAndroid Build Coastguard Worker << " -> node" << node_id_it->second << ":p" << handler_pc
177*795d594fSAndroid Build Coastguard Worker << ";\n";
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker exception_targets.clear();
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker
183*795d594fSAndroid Build Coastguard Worker block_start_dex_pc = dex_pc;
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker // Seems to be a fall-through, connect to last_node_id. May be spurious edges for things
186*795d594fSAndroid Build Coastguard Worker // like switch data.
187*795d594fSAndroid Build Coastguard Worker uint32_t old_last = last_node_id;
188*795d594fSAndroid Build Coastguard Worker last_node_id = it->second;
189*795d594fSAndroid Build Coastguard Worker if (old_last != std::numeric_limits<uint32_t>::max()) {
190*795d594fSAndroid Build Coastguard Worker regular_edges << " node" << old_last << ":p" << old_dex_pc
191*795d594fSAndroid Build Coastguard Worker << " -> node" << last_node_id << ":p" << dex_pc
192*795d594fSAndroid Build Coastguard Worker << ";\n";
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker }
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker // Look at the exceptions of the first entry.
197*795d594fSAndroid Build Coastguard Worker CatchHandlerIterator catch_it(accessor, dex_pc);
198*795d594fSAndroid Build Coastguard Worker for (; catch_it.HasNext(); catch_it.Next()) {
199*795d594fSAndroid Build Coastguard Worker exception_targets.insert(catch_it.GetHandlerAddress());
200*795d594fSAndroid Build Coastguard Worker }
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker
203*795d594fSAndroid Build Coastguard Worker // Handle instruction.
204*795d594fSAndroid Build Coastguard Worker
205*795d594fSAndroid Build Coastguard Worker // Branch: something with at most two targets.
206*795d594fSAndroid Build Coastguard Worker if (inst->IsBranch()) {
207*795d594fSAndroid Build Coastguard Worker const int32_t offset = inst->GetTargetOffset();
208*795d594fSAndroid Build Coastguard Worker const bool conditional = !inst->IsUnconditional();
209*795d594fSAndroid Build Coastguard Worker
210*795d594fSAndroid Build Coastguard Worker auto target_it = dex_pc_to_node_id.find(dex_pc + offset);
211*795d594fSAndroid Build Coastguard Worker if (target_it != dex_pc_to_node_id.end()) {
212*795d594fSAndroid Build Coastguard Worker taken_edges << " node" << last_node_id << ":p" << dex_pc
213*795d594fSAndroid Build Coastguard Worker << " -> node" << target_it->second << ":p" << (dex_pc + offset)
214*795d594fSAndroid Build Coastguard Worker << ";\n";
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker if (!conditional) {
217*795d594fSAndroid Build Coastguard Worker // No fall-through.
218*795d594fSAndroid Build Coastguard Worker last_node_id = std::numeric_limits<uint32_t>::max();
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker } else if (inst->IsSwitch()) {
221*795d594fSAndroid Build Coastguard Worker // TODO: Iterate through all switch targets.
222*795d594fSAndroid Build Coastguard Worker const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst);
223*795d594fSAndroid Build Coastguard Worker /* make sure the start of the switch is in range */
224*795d594fSAndroid Build Coastguard Worker int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
225*795d594fSAndroid Build Coastguard Worker /* offset to switch table is a relative branch-style offset */
226*795d594fSAndroid Build Coastguard Worker const uint16_t* switch_insns = insns + switch_offset;
227*795d594fSAndroid Build Coastguard Worker uint32_t switch_count = switch_insns[1];
228*795d594fSAndroid Build Coastguard Worker int32_t targets_offset;
229*795d594fSAndroid Build Coastguard Worker if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
230*795d594fSAndroid Build Coastguard Worker /* 0=sig, 1=count, 2/3=firstKey */
231*795d594fSAndroid Build Coastguard Worker targets_offset = 4;
232*795d594fSAndroid Build Coastguard Worker } else {
233*795d594fSAndroid Build Coastguard Worker /* 0=sig, 1=count, 2..count*2 = keys */
234*795d594fSAndroid Build Coastguard Worker targets_offset = 2 + 2 * switch_count;
235*795d594fSAndroid Build Coastguard Worker }
236*795d594fSAndroid Build Coastguard Worker /* make sure the end of the switch is in range */
237*795d594fSAndroid Build Coastguard Worker /* verify each switch target */
238*795d594fSAndroid Build Coastguard Worker for (uint32_t targ = 0; targ < switch_count; targ++) {
239*795d594fSAndroid Build Coastguard Worker int32_t offset =
240*795d594fSAndroid Build Coastguard Worker static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
241*795d594fSAndroid Build Coastguard Worker static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
242*795d594fSAndroid Build Coastguard Worker int32_t abs_offset = dex_pc + offset;
243*795d594fSAndroid Build Coastguard Worker auto target_it = dex_pc_to_node_id.find(abs_offset);
244*795d594fSAndroid Build Coastguard Worker if (target_it != dex_pc_to_node_id.end()) {
245*795d594fSAndroid Build Coastguard Worker // TODO: value label.
246*795d594fSAndroid Build Coastguard Worker taken_edges << " node" << last_node_id << ":p" << dex_pc
247*795d594fSAndroid Build Coastguard Worker << " -> node" << target_it->second << ":p" << (abs_offset)
248*795d594fSAndroid Build Coastguard Worker << ";\n";
249*795d594fSAndroid Build Coastguard Worker }
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker }
252*795d594fSAndroid Build Coastguard Worker
253*795d594fSAndroid Build Coastguard Worker // Exception edges. If this is not the first instruction in the block
254*795d594fSAndroid Build Coastguard Worker if (block_start_dex_pc != dex_pc) {
255*795d594fSAndroid Build Coastguard Worker std::set<uint32_t> current_handler_pcs;
256*795d594fSAndroid Build Coastguard Worker CatchHandlerIterator catch_it(accessor, dex_pc);
257*795d594fSAndroid Build Coastguard Worker for (; catch_it.HasNext(); catch_it.Next()) {
258*795d594fSAndroid Build Coastguard Worker current_handler_pcs.insert(catch_it.GetHandlerAddress());
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker if (current_handler_pcs != exception_targets) {
261*795d594fSAndroid Build Coastguard Worker exception_targets.clear(); // Clear so we don't do something at the end.
262*795d594fSAndroid Build Coastguard Worker blocks_with_detailed_exceptions.insert(block_start_dex_pc);
263*795d594fSAndroid Build Coastguard Worker }
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker if (inst->IsReturn() ||
267*795d594fSAndroid Build Coastguard Worker (inst->Opcode() == Instruction::THROW) ||
268*795d594fSAndroid Build Coastguard Worker (inst->IsBranch() && inst->IsUnconditional())) {
269*795d594fSAndroid Build Coastguard Worker // No fall-through.
270*795d594fSAndroid Build Coastguard Worker last_node_id = std::numeric_limits<uint32_t>::max();
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker old_dex_pc = pair.DexPc();
273*795d594fSAndroid Build Coastguard Worker }
274*795d594fSAndroid Build Coastguard Worker // Finish up the last block, if it had common exceptions.
275*795d594fSAndroid Build Coastguard Worker if (!exception_targets.empty()) {
276*795d594fSAndroid Build Coastguard Worker // It seems the last block had common exception handlers. Add the exception edges now.
277*795d594fSAndroid Build Coastguard Worker uint32_t node_id = dex_pc_to_node_id.find(block_start_dex_pc)->second;
278*795d594fSAndroid Build Coastguard Worker for (uint32_t handler_pc : exception_targets) {
279*795d594fSAndroid Build Coastguard Worker auto node_id_it = dex_pc_to_incl_id.find(handler_pc);
280*795d594fSAndroid Build Coastguard Worker if (node_id_it != dex_pc_to_incl_id.end()) {
281*795d594fSAndroid Build Coastguard Worker exception_edges << " node" << node_id
282*795d594fSAndroid Build Coastguard Worker << " -> node" << node_id_it->second << ":p" << handler_pc
283*795d594fSAndroid Build Coastguard Worker << ";\n";
284*795d594fSAndroid Build Coastguard Worker }
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker exception_targets.clear();
287*795d594fSAndroid Build Coastguard Worker }
288*795d594fSAndroid Build Coastguard Worker }
289*795d594fSAndroid Build Coastguard Worker
290*795d594fSAndroid Build Coastguard Worker // Second pass for detailed exception blocks.
291*795d594fSAndroid Build Coastguard Worker // TODO
292*795d594fSAndroid Build Coastguard Worker // Exception edges. If this is not the first instruction in the block
293*795d594fSAndroid Build Coastguard Worker for (uint32_t dex_pc : blocks_with_detailed_exceptions) {
294*795d594fSAndroid Build Coastguard Worker const Instruction* inst = &accessor.InstructionAt(dex_pc);
295*795d594fSAndroid Build Coastguard Worker uint32_t this_node_id = dex_pc_to_incl_id.find(dex_pc)->second;
296*795d594fSAndroid Build Coastguard Worker while (true) {
297*795d594fSAndroid Build Coastguard Worker CatchHandlerIterator catch_it(accessor, dex_pc);
298*795d594fSAndroid Build Coastguard Worker if (catch_it.HasNext()) {
299*795d594fSAndroid Build Coastguard Worker std::set<uint32_t> handled_targets;
300*795d594fSAndroid Build Coastguard Worker for (; catch_it.HasNext(); catch_it.Next()) {
301*795d594fSAndroid Build Coastguard Worker uint32_t handler_pc = catch_it.GetHandlerAddress();
302*795d594fSAndroid Build Coastguard Worker auto it = handled_targets.find(handler_pc);
303*795d594fSAndroid Build Coastguard Worker if (it == handled_targets.end()) {
304*795d594fSAndroid Build Coastguard Worker auto node_id_it = dex_pc_to_incl_id.find(handler_pc);
305*795d594fSAndroid Build Coastguard Worker if (node_id_it != dex_pc_to_incl_id.end()) {
306*795d594fSAndroid Build Coastguard Worker exception_edges << " node" << this_node_id << ":p" << dex_pc
307*795d594fSAndroid Build Coastguard Worker << " -> node" << node_id_it->second << ":p" << handler_pc
308*795d594fSAndroid Build Coastguard Worker << ";\n";
309*795d594fSAndroid Build Coastguard Worker }
310*795d594fSAndroid Build Coastguard Worker
311*795d594fSAndroid Build Coastguard Worker // Mark as done.
312*795d594fSAndroid Build Coastguard Worker handled_targets.insert(handler_pc);
313*795d594fSAndroid Build Coastguard Worker }
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker }
316*795d594fSAndroid Build Coastguard Worker if (inst->IsBasicBlockEnd()) {
317*795d594fSAndroid Build Coastguard Worker break;
318*795d594fSAndroid Build Coastguard Worker }
319*795d594fSAndroid Build Coastguard Worker
320*795d594fSAndroid Build Coastguard Worker // Loop update. Have a break-out if the next instruction is a branch target and thus in
321*795d594fSAndroid Build Coastguard Worker // another block.
322*795d594fSAndroid Build Coastguard Worker dex_pc += inst->SizeInCodeUnits();
323*795d594fSAndroid Build Coastguard Worker if (dex_pc >= accessor.InsnsSizeInCodeUnits()) {
324*795d594fSAndroid Build Coastguard Worker break;
325*795d594fSAndroid Build Coastguard Worker }
326*795d594fSAndroid Build Coastguard Worker if (dex_pc_to_node_id.find(dex_pc) != dex_pc_to_node_id.end()) {
327*795d594fSAndroid Build Coastguard Worker break;
328*795d594fSAndroid Build Coastguard Worker }
329*795d594fSAndroid Build Coastguard Worker inst = inst->Next();
330*795d594fSAndroid Build Coastguard Worker }
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker // Write out the sub-graphs to make edges styled.
334*795d594fSAndroid Build Coastguard Worker os << "\n";
335*795d594fSAndroid Build Coastguard Worker os << " subgraph regular_edges {\n";
336*795d594fSAndroid Build Coastguard Worker os << " edge [color=\"#000000\",weight=.3,len=3];\n\n";
337*795d594fSAndroid Build Coastguard Worker os << " " << regular_edges.str() << "\n";
338*795d594fSAndroid Build Coastguard Worker os << " }\n\n";
339*795d594fSAndroid Build Coastguard Worker
340*795d594fSAndroid Build Coastguard Worker os << " subgraph taken_edges {\n";
341*795d594fSAndroid Build Coastguard Worker os << " edge [color=\"#00FF00\",weight=.3,len=3];\n\n";
342*795d594fSAndroid Build Coastguard Worker os << " " << taken_edges.str() << "\n";
343*795d594fSAndroid Build Coastguard Worker os << " }\n\n";
344*795d594fSAndroid Build Coastguard Worker
345*795d594fSAndroid Build Coastguard Worker os << " subgraph exception_edges {\n";
346*795d594fSAndroid Build Coastguard Worker os << " edge [color=\"#FF0000\",weight=.3,len=3];\n\n";
347*795d594fSAndroid Build Coastguard Worker os << " " << exception_edges.str() << "\n";
348*795d594fSAndroid Build Coastguard Worker os << " }\n\n";
349*795d594fSAndroid Build Coastguard Worker }
350*795d594fSAndroid Build Coastguard Worker
351*795d594fSAndroid Build Coastguard Worker os << "}\n";
352*795d594fSAndroid Build Coastguard Worker }
353*795d594fSAndroid Build Coastguard Worker
354*795d594fSAndroid Build Coastguard Worker
355*795d594fSAndroid Build Coastguard Worker } // namespace art
356