blob: f222b214bba9e7c024ae6187c1048f564ef0935f [file] [log] [blame]
Gilad Arnold553b0ec2013-01-26 01:00:39 -08001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Tracing block data source through a Chrome OS update payload.
6
7This module is used internally by the main Payload class for tracing block
8content through an update payload. This is a useful feature in debugging
9payload applying functionality in this package. The interface for invoking the
10tracer is as follows:
11
12 tracer = PayloadBlockTracer(payload)
13 tracer.Run(...)
14
15"""
16
Gilad Arnold53b62272015-07-16 16:33:00 -070017from __future__ import print_function
18
Gilad Arnold553b0ec2013-01-26 01:00:39 -080019import common
20
21
22#
23# Payload block tracing.
24#
25class PayloadBlockTracer(object):
26 """Tracing the origin of block data through update instructions.
27
28 This is a short-lived object whose purpose is to isolate the logic used for
29 tracing the origin of destination partition blocks.
30
31 """
32
33 def __init__(self, payload):
34 assert payload.is_init, 'uninitialized update payload'
35 self.payload = payload
36
37 @staticmethod
38 def _TraceBlock(block, skip, trace_out_file, operations, base_name):
39 """Trace the origin of a given block through a sequence of operations.
40
41 This method tries to map the given dest block to the corresponding source
42 block from which its content originates in the course of an update. It
43 further tries to trace transitive origins through MOVE operations. It is
44 rather efficient, doing the actual tracing by means of a single reverse
45 sweep through the operation sequence. It dumps a log of operations and
46 source blocks responsible for the data in the given dest block to the
47 provided output file.
48
49 Args:
50 block: the block number to trace
51 skip: number of initial transitive origins to ignore
52 trace_out_file: a file object to dump the trace to
53 operations: the sequence of operations
54 base_name: name of the operation sequence
Gilad Arnold553b0ec2013-01-26 01:00:39 -080055 """
56 # Traverse operations backwards.
57 for op, op_name in common.OperationIter(operations, base_name,
58 reverse=True):
59 total_block_offset = 0
60 found = False
61
62 # Is the traced block mentioned in the dest extents?
63 for dst_ex, dst_ex_name in common.ExtentIter(op.dst_extents,
64 op_name + '.dst_extents'):
65 if (block >= dst_ex.start_block
66 and block < dst_ex.start_block + dst_ex.num_blocks):
67 if skip:
68 skip -= 1
69 else:
70 total_block_offset += block - dst_ex.start_block
71 trace_out_file.write(
Gilad Arnold53b62272015-07-16 16:33:00 -070072 '%d: %s: found %s (total block offset: %d)\n' %
73 (block, dst_ex_name, common.FormatExtent(dst_ex),
74 total_block_offset))
Gilad Arnold553b0ec2013-01-26 01:00:39 -080075 found = True
76 break
77
78 total_block_offset += dst_ex.num_blocks
79
80 if found:
81 # Don't trace further, unless it's a MOVE.
82 if op.type != common.OpType.MOVE:
83 break
84
85 # For MOVE, find corresponding source block and keep tracing.
86 for src_ex, src_ex_name in common.ExtentIter(op.src_extents,
87 op_name + '.src_extents'):
88 if total_block_offset < src_ex.num_blocks:
89 block = src_ex.start_block + total_block_offset
90 trace_out_file.write(
91 '%s: mapped to %s (%d)\n' %
92 (src_ex_name, common.FormatExtent(src_ex), block))
93 break
94
95 total_block_offset -= src_ex.num_blocks
96
97 def Run(self, block, skip, trace_out_file, is_kernel):
98 """Block tracer entry point, invoking the actual search.
99
100 Args:
101 block: the block number whose origin to trace
102 skip: the number of first origin mappings to skip
103 trace_out_file: file object to dump the trace to
104 is_kernel: trace through kernel (True) or rootfs (False) operations
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800105 """
106 if is_kernel:
Gilad Arnold53b62272015-07-16 16:33:00 -0700107 operations = self.payload.manifest.kernel_install_operations
108 base_name = 'kernel_install_operations'
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800109 else:
Gilad Arnold53b62272015-07-16 16:33:00 -0700110 operations = self.payload.manifest.install_operations
111 base_name = 'install_operations'
112
113 self._TraceBlock(block, skip, trace_out_file, operations, base_name)