You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
4.1 KiB
113 lines
4.1 KiB
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
|
# Use of this source code is governed by a BSD-style license that can be |
|
# found in the LICENSE file. |
|
|
|
"""Tracing block data source through a Chrome OS update payload. |
|
|
|
This module is used internally by the main Payload class for tracing block |
|
content through an update payload. This is a useful feature in debugging |
|
payload applying functionality in this package. The interface for invoking the |
|
tracer is as follows: |
|
|
|
tracer = PayloadBlockTracer(payload) |
|
tracer.Run(...) |
|
|
|
""" |
|
|
|
from __future__ import print_function |
|
|
|
import common |
|
|
|
|
|
# |
|
# Payload block tracing. |
|
# |
|
class PayloadBlockTracer(object): |
|
"""Tracing the origin of block data through update instructions. |
|
|
|
This is a short-lived object whose purpose is to isolate the logic used for |
|
tracing the origin of destination partition blocks. |
|
|
|
""" |
|
|
|
def __init__(self, payload): |
|
assert payload.is_init, 'uninitialized update payload' |
|
self.payload = payload |
|
|
|
@staticmethod |
|
def _TraceBlock(block, skip, trace_out_file, operations, base_name): |
|
"""Trace the origin of a given block through a sequence of operations. |
|
|
|
This method tries to map the given dest block to the corresponding source |
|
block from which its content originates in the course of an update. It |
|
further tries to trace transitive origins through MOVE operations. It is |
|
rather efficient, doing the actual tracing by means of a single reverse |
|
sweep through the operation sequence. It dumps a log of operations and |
|
source blocks responsible for the data in the given dest block to the |
|
provided output file. |
|
|
|
Args: |
|
block: the block number to trace |
|
skip: number of initial transitive origins to ignore |
|
trace_out_file: a file object to dump the trace to |
|
operations: the sequence of operations |
|
base_name: name of the operation sequence |
|
""" |
|
# Traverse operations backwards. |
|
for op, op_name in common.OperationIter(operations, base_name, |
|
reverse=True): |
|
total_block_offset = 0 |
|
found = False |
|
|
|
# Is the traced block mentioned in the dest extents? |
|
for dst_ex, dst_ex_name in common.ExtentIter(op.dst_extents, |
|
op_name + '.dst_extents'): |
|
if (block >= dst_ex.start_block |
|
and block < dst_ex.start_block + dst_ex.num_blocks): |
|
if skip: |
|
skip -= 1 |
|
else: |
|
total_block_offset += block - dst_ex.start_block |
|
trace_out_file.write( |
|
'%d: %s: found %s (total block offset: %d)\n' % |
|
(block, dst_ex_name, common.FormatExtent(dst_ex), |
|
total_block_offset)) |
|
found = True |
|
break |
|
|
|
total_block_offset += dst_ex.num_blocks |
|
|
|
if found: |
|
# Don't trace further, unless it's a MOVE. |
|
if op.type != common.OpType.MOVE: |
|
break |
|
|
|
# For MOVE, find corresponding source block and keep tracing. |
|
for src_ex, src_ex_name in common.ExtentIter(op.src_extents, |
|
op_name + '.src_extents'): |
|
if total_block_offset < src_ex.num_blocks: |
|
block = src_ex.start_block + total_block_offset |
|
trace_out_file.write( |
|
'%s: mapped to %s (%d)\n' % |
|
(src_ex_name, common.FormatExtent(src_ex), block)) |
|
break |
|
|
|
total_block_offset -= src_ex.num_blocks |
|
|
|
def Run(self, block, skip, trace_out_file, is_kernel): |
|
"""Block tracer entry point, invoking the actual search. |
|
|
|
Args: |
|
block: the block number whose origin to trace |
|
skip: the number of first origin mappings to skip |
|
trace_out_file: file object to dump the trace to |
|
is_kernel: trace through kernel (True) or rootfs (False) operations |
|
""" |
|
if is_kernel: |
|
operations = self.payload.manifest.kernel_install_operations |
|
base_name = 'kernel_install_operations' |
|
else: |
|
operations = self.payload.manifest.install_operations |
|
base_name = 'install_operations' |
|
|
|
self._TraceBlock(block, skip, trace_out_file, operations, base_name)
|
|
|