text: #!/usr/bin/env vpython3
  # Copyright 2018 The Chromium Authors. All rights reserved.
  # Use of this source code is governed by a BSD-style license that can be
  # found in the LICENSE file.
  
  import collections
  import contextlib
  import logging
  import os
  import re
  import shutil
  import tempfile
  import unittest
  
  from pylib.symbols import apk_native_libs_unittest
  from pylib.symbols import mock_addr2line
  from pylib.symbols import symbol_utils
  
  _MOCK_ELF_DATA = apk_native_libs_unittest.MOCK_ELF_DATA
  
  _MOCK_A2L_PATH = os.path.join(os.path.dirname(mock_addr2line.__file__),
                                'mock_addr2line')
  
  
  # pylint: disable=line-too-long
  
  # list of (start_offset, end_offset, size, libpath) tuples corresponding
  # to the content of base.apk. This was taken from an x86 ChromeModern.apk
  # component build.
  _TEST_APK_LIBS = [
    (0x01331000, 0x013696bc, 0x000386bc, 'libaccessibility.cr.so'),
    (0x0136a000, 0x013779c4, 0x0000d9c4, 'libanimation.cr.so'),
    (0x01378000, 0x0137f7e8, 0x000077e8, 'libapdu.cr.so'),
    (0x01380000, 0x0155ccc8, 0x001dccc8, 'libbase.cr.so'),
    (0x0155d000, 0x015ab98c, 0x0004e98c, 'libbase_i18n.cr.so'),
    (0x015ac000, 0x015dff4c, 0x00033f4c, 'libbindings.cr.so'),
    (0x015e0000, 0x015f5a54, 0x00015a54, 'libbindings_base.cr.so'),
    (0x0160e000, 0x01731960, 0x00123960, 'libblink_common.cr.so'),
    (0x01732000, 0x0174ce54, 0x0001ae54, 'libblink_controller.cr.so'),
    (0x0174d000, 0x0318c528, 0x01a3f528, 'libblink_core.cr.so'),
    (0x0318d000, 0x03191700, 0x00004700, 'libblink_mojom_broadcastchannel_bindings_shared.cr.so'),
    (0x03192000, 0x03cd7918, 0x00b45918, 'libblink_modules.cr.so'),
    (0x03cd8000, 0x03d137d0, 0x0003b7d0, 'libblink_mojo_bindings_shared.cr.so'),
    (0x03d14000, 0x03d2670c, 0x0001270c, 'libblink_offscreen_canvas_mojo_bindings_shared.cr.so'),
    (0x03d27000, 0x046c7054, 0x009a0054, 'libblink_platform.cr.so'),
    (0x046c8000, 0x0473fbfc, 0x00077bfc, 'libbluetooth.cr.so'),
    (0x04740000, 0x04878f40, 0x00138f40, 'libboringssl.cr.so'),
    (0x04879000, 0x0498466c, 0x0010b66c, 'libc++_shared.so'),
    (0x04985000, 0x0498d93c, 0x0000893c, 'libcaptive_portal.cr.so'),
    (0x0498e000, 0x049947cc, 0x000067cc, 'libcapture_base.cr.so'),
    (0x04995000, 0x04b39f18, 0x001a4f18, 'libcapture_lib.cr.so'),
    (0x04b3a000, 0x04b488ec, 0x0000e8ec, 'libcbor.cr.so'),
    (0x04b49000, 0x04e9ea5c, 0x00355a5c, 'libcc.cr.so'),
    (0x04e9f000, 0x04ed6404, 0x00037404, 'libcc_animation.cr.so'),
    (0x04ed7000, 0x04ef5ab4, 0x0001eab4, 'libcc_base.cr.so'),
    (0x04ef6000, 0x04fd9364, 0x000e3364, 'libcc_blink.cr.so'),
    (0x04fda000, 0x04fe2758, 0x00008758, 'libcc_debug.cr.so'),
    (0x04fe3000, 0x0500ae0c, 0x00027e0c, 'libcc_ipc.cr.so'),
    (0x0500b000, 0x05078f38, 0x0006df38, 'libcc_paint.cr.so'),
    (0x05079000, 0x0507e734, 0x00005734, 'libcdm_manager.cr.so'),
    (0x0507f000, 0x06f4d744, 0x01ece744, 'libchrome.cr.so'),
    (0x06f54000, 0x06feb830, 0x00097830, 'libchromium_sqlite3.cr.so'),
    (0x06fec000, 0x0706f554, 0x00083554, 'libclient.cr.so'),
    (0x07070000, 0x0708da60, 0x0001da60, 'libcloud_policy_proto_generated_compile.cr.so'),
    (0x0708e000, 0x07121f28, 0x00093f28, 'libcodec.cr.so'),
    (0x07122000, 0x07134ab8, 0x00012ab8, 'libcolor_space.cr.so'),
    (0x07135000, 0x07138614, 0x00003614, 'libcommon.cr.so'),
    (0x07139000, 0x0717c938, 0x00043938, 'libcompositor.cr.so'),
    (0x0717d000, 0x0923d78c, 0x020c078c, 'libcontent.cr.so'),
    (0x0923e000, 0x092ae87c, 0x0007087c, 'libcontent_common_mojo_bindings_shared.cr.so'),
    (0x092af000, 0x092be718, 0x0000f718, 'libcontent_public_common_mojo_bindings_shared.cr.so'),
    (0x092bf000, 0x092d9a20, 0x0001aa20, 'libcrash_key.cr.so'),
    (0x092da000, 0x092eda58, 0x00013a58, 'libcrcrypto.cr.so'),
    (0x092ee000, 0x092f16e0, 0x000036e0, 'libdevice_base.cr.so'),
    (0x092f2000, 0x092fe8d8, 0x0000c8d8, 'libdevice_event_log.cr.so'),
    (0x092ff000, 0x093026a4, 0x000036a4, 'libdevice_features.cr.so'),
    (0x09303000, 0x093f1220, 0x000ee220, 'libdevice_gamepad.cr.so'),
    (0x093f2000, 0x09437f54, 0x00045f54, 'libdevice_vr_mojo_bindings.cr.so'),
    (0x09438000, 0x0954c168, 0x00114168, 'libdevice_vr_mojo_bindings_blink.cr.so'),
    (0x0954d000, 0x0955d720, 0x00010720, 'libdevice_vr_mojo_bindings_shared.cr.so'),
    (0x0955e000, 0x0956b9c0, 0x0000d9c0, 'libdevices.cr.so'),
    (0x0956c000, 0x0957cae8, 0x00010ae8, 'libdiscardable_memory_client.cr.so'),
    (0x0957d000, 0x09588854, 0x0000b854, 'libdiscardable_memory_common.cr.so'),
    (0x09589000, 0x0959cbb4, 0x00013bb4, 'libdiscardable_memory_service.cr.so'),
    (0x0959d000, 0x095b6b90, 0x00019b90, 'libdisplay.cr.so'),
    (0x095b7000, 0x095be930, 0x00007930, 'libdisplay_types.cr.so'),
    (0x095bf000, 0x095c46c4, 0x000056c4, 'libdisplay_util.cr.so'),
    (0x095c5000, 0x095f54a4, 0x000304a4, 'libdomain_reliability.cr.so'),
    (0x095f6000, 0x0966fe08, 0x00079e08, 'libembedder.cr.so'),
    (0x09670000, 0x096735f8, 0x000035f8, 'libembedder_switches.cr.so'),
    (0x09674000, 0x096a3460, 0x0002f460, 'libevents.cr.so'),
    (0x096a4000, 0x096b6d40, 0x00012d40, 'libevents_base.cr.so'),
    (0x096b7000, 0x0981a778, 0x00163778, 'libffmpeg.cr.so'),
    (0x0981b000, 0x09945c94, 0x0012ac94, 'libfido.cr.so'),
    (0x09946000, 0x09a330dc, 0x000ed0dc, 'libfingerprint.cr.so'),
    (0x09a34000, 0x09b53170, 0x0011f170, 'libfreetype_harfbuzz.cr.so'),
    (0x09b54000, 0x09bc5c5c, 0x00071c5c, 'libgcm.cr.so'),
    (0x09bc6000, 0x09cc8584, 0x00102584, 'libgeolocation.cr.so'),
    (0x09cc9000, 0x09cdc8d4, 0x000138d4, 'libgeometry.cr.so'),
    (0x09cdd000, 0x09cec8b4, 0x0000f8b4, 'libgeometry_skia.cr.so'),
    (0x09ced000, 0x09d10e14, 0x00023e14, 'libgesture_detection.cr.so'),
    (0x09d11000, 0x09d7595c, 0x0006495c, 'libgfx.cr.so'),
    (0x09d76000, 0x09d7d7cc, 0x000077cc, 'libgfx_ipc.cr.so'),
    (0x09d7e000, 0x09d82708, 0x00004708, 'libgfx_ipc_buffer_types.cr.so'),
    (0x09d83000, 0x09d89748, 0x00006748, 'libgfx_ipc_color.cr.so'),
    (0x09d8a000, 0x09d8f6f4, 0x000056f4, 'libgfx_ipc_geometry.cr.so'),
    (0x09d90000, 0x09d94754, 0x00004754, 'libgfx_ipc_skia.cr.so'),
    (0x09d95000, 0x09d9869c, 0x0000369c, 'libgfx_switches.cr.so'),
    (0x09d99000, 0x09dba0ac, 0x000210ac, 'libgin.cr.so'),
    (0x09dbb000, 0x09e0a8cc, 0x0004f8cc, 'libgl_in_process_context.cr.so'),
    (0x09e0b000, 0x09e17a18, 0x0000ca18, 'libgl_init.cr.so'),
    (0x09e18000, 0x09ee34e4, 0x000cb4e4, 'libgl_wrapper.cr.so'),
    (0x09ee4000, 0x0a1a2e00, 0x002bee00, 'libgles2.cr.so'),
    (0x0a1a3000, 0x0a24556c, 0x000a256c, 'libgles2_implementation.cr.so'),
    (0x0a246000, 0x0a267038, 0x00021038, 'libgles2_utils.cr.so'),
    (0x0a268000, 0x0a3288e4, 0x000c08e4, 'libgpu.cr.so'),
    (0x0a329000, 0x0a3627ec, 0x000397ec, 'libgpu_ipc_service.cr.so'),
    (0x0a363000, 0x0a388a18, 0x00025a18, 'libgpu_util.cr.so'),
    (0x0a389000, 0x0a506d8c, 0x0017dd8c, 'libhost.cr.so'),
    (0x0a507000, 0x0a6f0ec0, 0x001e9ec0, 'libicui18n.cr.so'),
    (0x0a6f1000, 0x0a83b4c8, 0x0014a4c8, 'libicuuc.cr.so'),
    (0x0a83c000, 0x0a8416e4, 0x000056e4, 'libinterfaces_shared.cr.so'),
    (0x0a842000, 0x0a87e2a0, 0x0003c2a0, 'libipc.cr.so'),
    (0x0a87f000, 0x0a88c98c, 0x0000d98c, 'libipc_mojom.cr.so'),
    (0x0a88d000, 0x0a8926e4, 0x000056e4, 'libipc_mojom_shared.cr.so'),
    (0x0a893000, 0x0a8a1e18, 0x0000ee18, 'libkeyed_service_content.cr.so'),
    (0x0a8a2000, 0x0a8b4a30, 0x00012a30, 'libkeyed_service_core.cr.so'),
    (0x0a8b5000, 0x0a930a80, 0x0007ba80, 'libleveldatabase.cr.so'),
    (0x0a931000, 0x0a9b3908, 0x00082908, 'libmanager.cr.so'),
    (0x0a9b4000, 0x0aea9bb4, 0x004f5bb4, 'libmedia.cr.so'),
    (0x0aeaa000, 0x0b08cb88, 0x001e2b88, 'libmedia_blink.cr.so'),
    (0x0b08d000, 0x0b0a4728, 0x00017728, 'libmedia_devices_mojo_bindings_shared.cr.so'),
    (0x0b0a5000, 0x0b1943ec, 0x000ef3ec, 'libmedia_gpu.cr.so'),
    (0x0b195000, 0x0b2d07d4, 0x0013b7d4, 'libmedia_mojo_services.cr.so'),
    (0x0b2d1000, 0x0b2d4760, 0x00003760, 'libmessage_center.cr.so'),
    (0x0b2d5000, 0x0b2e0938, 0x0000b938, 'libmessage_support.cr.so'),
    (0x0b2e1000, 0x0b2f3ad0, 0x00012ad0, 'libmetrics_cpp.cr.so'),
    (0x0b2f4000, 0x0b313bb8, 0x0001fbb8, 'libmidi.cr.so'),
    (0x0b314000, 0x0b31b848, 0x00007848, 'libmojo_base_lib.cr.so'),
    (0x0b31c000, 0x0b3329f8, 0x000169f8, 'libmojo_base_mojom.cr.so'),
    (0x0b333000, 0x0b34b98c, 0x0001898c, 'libmojo_base_mojom_blink.cr.so'),
    (0x0b34c000, 0x0b354700, 0x00008700, 'libmojo_base_mojom_shared.cr.so'),
    (0x0b355000, 0x0b3608b0, 0x0000b8b0, 'libmojo_base_shared_typemap_traits.cr.so'),
    (0x0b361000, 0x0b3ad454, 0x0004c454, 'libmojo_edk.cr.so'),
    (0x0b3ae000, 0x0b3c4a20, 0x00016a20, 'libmojo_edk_ports.cr.so'),
    (0x0b3c5000, 0x0b3d38a0, 0x0000e8a0, 'libmojo_mojom_bindings.cr.so'),
    (0x0b3d4000, 0x0b3da6e8, 0x000066e8, 'libmojo_mojom_bindings_shared.cr.so'),
    (0x0b3db000, 0x0b3e27f0, 0x000077f0, 'libmojo_public_system.cr.so'),
    (0x0b3e3000, 0x0b3fa9fc, 0x000179fc, 'libmojo_public_system_cpp.cr.so'),
    (0x0b3fb000, 0x0b407728, 0x0000c728, 'libmojom_core_shared.cr.so'),
    (0x0b408000, 0x0b421744, 0x00019744, 'libmojom_platform_shared.cr.so'),
    (0x0b422000, 0x0b43451c, 0x0001251c, 'libnative_theme.cr.so'),
    (0x0b435000, 0x0baaa1bc, 0x006751bc, 'libnet.cr.so'),
    (0x0bac4000, 0x0bb74670, 0x000b0670, 'libnetwork_cpp.cr.so'),
    (0x0bb75000, 0x0bbaee8c, 0x00039e8c, 'libnetwork_cpp_base.cr.so'),
    (0x0bbaf000, 0x0bd21844, 0x00172844, 'libnetwork_service.cr.so'),
    (0x0bd22000, 0x0bd256e4, 0x000036e4, 'libnetwork_session_configurator.cr.so'),
    (0x0bd26000, 0x0bd33734, 0x0000d734, 'libonc.cr.so'),
    (0x0bd34000, 0x0bd9ce18, 0x00068e18, 'libperfetto.cr.so'),
    (0x0bd9d000, 0x0bda4854, 0x00007854, 'libplatform.cr.so'),
    (0x0bda5000, 0x0bec5ce4, 0x00120ce4, 'libpolicy_component.cr.so'),
    (0x0bec6000, 0x0bf5ab58, 0x00094b58, 'libpolicy_proto.cr.so'),
    (0x0bf5b000, 0x0bf86fbc, 0x0002bfbc, 'libprefs.cr.so'),
    (0x0bf87000, 0x0bfa5d74, 0x0001ed74, 'libprinting.cr.so'),
    (0x0bfa6000, 0x0bfe0e80, 0x0003ae80, 'libprotobuf_lite.cr.so'),
    (0x0bfe1000, 0x0bff0a18, 0x0000fa18, 'libproxy_config.cr.so'),
    (0x0bff1000, 0x0c0f6654, 0x00105654, 'libpublic.cr.so'),
    (0x0c0f7000, 0x0c0fa6a4, 0x000036a4, 'librange.cr.so'),
    (0x0c0fb000, 0x0c118058, 0x0001d058, 'libraster.cr.so'),
    (0x0c119000, 0x0c133d00, 0x0001ad00, 'libresource_coordinator_cpp.cr.so'),
    (0x0c134000, 0x0c1396a0, 0x000056a0, 'libresource_coordinator_cpp_base.cr.so'),
    (0x0c13a000, 0x0c1973b8, 0x0005d3b8, 'libresource_coordinator_public_mojom.cr.so'),
    (0x0c198000, 0x0c2033e8, 0x0006b3e8, 'libresource_coordinator_public_mojom_blink.cr.so'),
    (0x0c204000, 0x0c219744, 0x00015744, 'libresource_coordinator_public_mojom_shared.cr.so'),
    (0x0c21a000, 0x0c21e700, 0x00004700, 'libsandbox.cr.so'),
    (0x0c21f000, 0x0c22f96c, 0x0001096c, 'libsandbox_services.cr.so'),
    (0x0c230000, 0x0c249d58, 0x00019d58, 'libseccomp_bpf.cr.so'),
    (0x0c24a000, 0x0c24e714, 0x00004714, 'libseccomp_starter_android.cr.so'),
    (0x0c24f000, 0x0c4ae9f0, 0x0025f9f0, 'libservice.cr.so'),
    (0x0c4af000, 0x0c4c3ae4, 0x00014ae4, 'libservice_manager_cpp.cr.so'),
    (0x0c4c4000, 0x0c4cb708, 0x00007708, 'libservice_manager_cpp_types.cr.so'),
    (0x0c4cc000, 0x0c4fbe30, 0x0002fe30, 'libservice_manager_mojom.cr.so'),
    (0x0c4fc000, 0x0c532e78, 0x00036e78, 'libservice_manager_mojom_blink.cr.so'),
    (0x0c533000, 0x0c53669c, 0x0000369c, 'libservice_manager_mojom_constants.cr.so'),
    (0x0c537000, 0x0c53e85c, 0x0000785c, 'libservice_manager_mojom_constants_blink.cr.so'),
    (0x0c53f000, 0x0c542668, 0x00003668, 'libservice_manager_mojom_constants_shared.cr.so'),
    (0x0c543000, 0x0c54d700, 0x0000a700, 'libservice_manager_mojom_shared.cr.so'),
    (0x0c54e000, 0x0c8fc6ec, 0x003ae6ec, 'libsessions.cr.so'),
    (0x0c8fd000, 0x0c90a924, 0x0000d924, 'libshared_memory_support.cr.so'),
    (0x0c90b000, 0x0c9148ec, 0x000098ec, 'libshell_dialogs.cr.so'),
    (0x0c915000, 0x0cf8de70, 0x00678e70, 'libskia.cr.so'),
    (0x0cf8e000, 0x0cf978bc, 0x000098bc, 'libsnapshot.cr.so'),
    (0x0cf98000, 0x0cfb7d9c, 0x0001fd9c, 'libsql.cr.so'),
    (0x0cfb8000, 0x0cfbe744, 0x00006744, 'libstartup_tracing.cr.so'),
    (0x0cfbf000, 0x0d19b4e4, 0x001dc4e4, 'libstorage_browser.cr.so'),
    (0x0d19c000, 0x0d2a773c, 0x0010b73c, 'libstorage_common.cr.so'),
    (0x0d2a8000, 0x0d2ac6fc, 0x000046fc, 'libsurface.cr.so'),
    (0x0d2ad000, 0x0d2baa98, 0x0000da98, 'libtracing.cr.so'),
    (0x0d2bb000, 0x0d2f36b0, 0x000386b0, 'libtracing_cpp.cr.so'),
    (0x0d2f4000, 0x0d326e70, 0x00032e70, 'libtracing_mojom.cr.so'),
    (0x0d327000, 0x0d33270c, 0x0000b70c, 'libtracing_mojom_shared.cr.so'),
    (0x0d333000, 0x0d46d804, 0x0013a804, 'libui_android.cr.so'),
    (0x0d46e000, 0x0d4cb3f8, 0x0005d3f8, 'libui_base.cr.so'),
    (0x0d4cc000, 0x0d4dbc40, 0x0000fc40, 'libui_base_ime.cr.so'),
    (0x0d4dc000, 0x0d4e58d4, 0x000098d4, 'libui_data_pack.cr.so'),
    (0x0d4e6000, 0x0d51d1e0, 0x000371e0, 'libui_devtools.cr.so'),
    (0x0d51e000, 0x0d52b984, 0x0000d984, 'libui_message_center_cpp.cr.so'),
    (0x0d52c000, 0x0d539a48, 0x0000da48, 'libui_touch_selection.cr.so'),
    (0x0d53a000, 0x0d55bc60, 0x00021c60, 'liburl.cr.so'),
    (0x0d55c000, 0x0d55f6b4, 0x000036b4, 'liburl_ipc.cr.so'),
    (0x0d560000, 0x0d5af110, 0x0004f110, 'liburl_matcher.cr.so'),
    (0x0d5b0000, 0x0d5e2fac, 0x00032fac, 'libuser_manager.cr.so'),
    (0x0d5e3000, 0x0d5e66e4, 0x000036e4, 'libuser_prefs.cr.so'),
    (0x0d5e7000, 0x0e3e1cc8, 0x00dfacc8, 'libv8.cr.so'),
    (0x0e3e2000, 0x0e400ae0, 0x0001eae0, 'libv8_libbase.cr.so'),
    (0x0e401000, 0x0e4d91d4, 0x000d81d4, 'libviz_common.cr.so'),
    (0x0e4da000, 0x0e4df7e4, 0x000057e4, 'libviz_resource_format.cr.so'),
    (0x0e4e0000, 0x0e5b7120, 0x000d7120, 'libweb_dialogs.cr.so'),
    (0x0e5b8000, 0x0e5c7a18, 0x0000fa18, 'libwebdata_common.cr.so'),
    (0x0e5c8000, 0x0e61bfe4, 0x00053fe4, 'libwtf.cr.so'),
  ]
  
  
  # A small memory map fragment extracted from a tombstone for a process that
  # had loaded the APK corresponding to _TEST_APK_LIBS above.
  _TEST_MEMORY_MAP = r'''memory map:
  12c00000-12ccafff rw-         0     cb000  /dev/ashmem/dalvik-main space (deleted)
  12ccb000-130cafff rw-     cb000    400000  /dev/ashmem/dalvik-main space (deleted)
  130cb000-32bfffff ---    4cb000  1fb35000  /dev/ashmem/dalvik-main space (deleted)
  32c00000-32c00fff rw-         0      1000  /dev/ashmem/dalvik-main space 1 (deleted)
  32c01000-52bfffff ---      1000  1ffff000  /dev/ashmem/dalvik-main space 1 (deleted)
  6f3b8000-6fd90fff rw-         0    9d9000  /data/dalvik-cache/x86/system@framework@boot.art
  6fd91000-71c42fff r--         0   1eb2000  /data/dalvik-cache/x86/system@framework@boot.oat
  71c43000-7393efff r-x   1eb2000   1cfc000  /data/dalvik-cache/x86/system@framework@boot.oat (load base 0x71c43000)
  7393f000-7393ffff rw-   3bae000      1000  /data/dalvik-cache/x86/system@framework@boot.oat
  73940000-73a1bfff rw-         0     dc000  /dev/ashmem/dalvik-zygote space (deleted)
  73a1c000-73a1cfff rw-         0      1000  /dev/ashmem/dalvik-non moving space (deleted)
  73a1d000-73a2dfff rw-      1000     11000  /dev/ashmem/dalvik-non moving space (deleted)
  73a2e000-77540fff ---     12000   3b13000  /dev/ashmem/dalvik-non moving space (deleted)
  77541000-7793ffff rw-   3b25000    3ff000  /dev/ashmem/dalvik-non moving space (deleted)
  923aa000-92538fff r--    8a9000    18f000  /data/app/com.example.app-2/base.apk
  92539000-9255bfff r--         0     23000  /data/data/com.example.app/app_data/paks/es.pak@162db1c6689
  9255c000-92593fff r--    213000     38000  /data/app/com.example.app-2/base.apk
  92594000-925c0fff r--    87d000     2d000  /data/app/com.example.app-2/base.apk
  925c1000-927d3fff r--    a37000    213000  /data/app/com.example.app-2/base.apk
  927d4000-92e07fff r--    24a000    634000  /data/app/com.example.app-2/base.apk
  92e08000-92e37fff r--   a931000     30000  /data/app/com.example.app-2/base.apk
  92e38000-92e86fff r-x   a961000     4f000  /data/app/com.example.app-2/base.apk
  92e87000-92e8afff rw-   a9b0000      4000  /data/app/com.example.app-2/base.apk
  92e8b000-92e8bfff rw-         0      1000
  92e8c000-92e9dfff r--   d5b0000     12000  /data/app/com.example.app-2/base.apk
  92e9e000-92ebcfff r-x   d5c2000     1f000  /data/app/com.example.app-2/base.apk
  92ebd000-92ebefff rw-   d5e1000      2000  /data/app/com.example.app-2/base.apk
  92ebf000-92ebffff rw-         0      1000
  '''
  
  # list of (address, size, path, offset)  tuples that must appear in
  # _TEST_MEMORY_MAP. Not all sections need to be listed.
  _TEST_MEMORY_MAP_SECTIONS = [
    (0x923aa000, 0x18f000, '/data/app/com.example.app-2/base.apk', 0x8a9000),
    (0x9255c000, 0x038000, '/data/app/com.example.app-2/base.apk', 0x213000),
    (0x92594000, 0x02d000, '/data/app/com.example.app-2/base.apk', 0x87d000),
    (0x925c1000, 0x213000, '/data/app/com.example.app-2/base.apk', 0xa37000),
  ]
  
  _EXPECTED_TEST_MEMORY_MAP = r'''memory map:
  12c00000-12ccafff rw-         0     cb000  /dev/ashmem/dalvik-main space (deleted)
  12ccb000-130cafff rw-     cb000    400000  /dev/ashmem/dalvik-main space (deleted)
  130cb000-32bfffff ---    4cb000  1fb35000  /dev/ashmem/dalvik-main space (deleted)
  32c00000-32c00fff rw-         0      1000  /dev/ashmem/dalvik-main space 1 (deleted)
  32c01000-52bfffff ---      1000  1ffff000  /dev/ashmem/dalvik-main space 1 (deleted)
  6f3b8000-6fd90fff rw-         0    9d9000  /data/dalvik-cache/x86/system@framework@boot.art
  6fd91000-71c42fff r--         0   1eb2000  /data/dalvik-cache/x86/system@framework@boot.oat
  71c43000-7393efff r-x   1eb2000   1cfc000  /data/dalvik-cache/x86/system@framework@boot.oat (load base 0x71c43000)
  7393f000-7393ffff rw-   3bae000      1000  /data/dalvik-cache/x86/system@framework@boot.oat
  73940000-73a1bfff rw-         0     dc000  /dev/ashmem/dalvik-zygote space (deleted)
  73a1c000-73a1cfff rw-         0      1000  /dev/ashmem/dalvik-non moving space (deleted)
  73a1d000-73a2dfff rw-      1000     11000  /dev/ashmem/dalvik-non moving space (deleted)
  73a2e000-77540fff ---     12000   3b13000  /dev/ashmem/dalvik-non moving space (deleted)
  77541000-7793ffff rw-   3b25000    3ff000  /dev/ashmem/dalvik-non moving space (deleted)
  923aa000-92538fff r--    8a9000    18f000  /data/app/com.example.app-2/base.apk
  92539000-9255bfff r--         0     23000  /data/data/com.example.app/app_data/paks/es.pak@162db1c6689
  9255c000-92593fff r--    213000     38000  /data/app/com.example.app-2/base.apk
  92594000-925c0fff r--    87d000     2d000  /data/app/com.example.app-2/base.apk
  925c1000-927d3fff r--    a37000    213000  /data/app/com.example.app-2/base.apk
  927d4000-92e07fff r--    24a000    634000  /data/app/com.example.app-2/base.apk
  92e08000-92e37fff r--   a931000     30000  /data/app/com.example.app-2/base.apk!lib/libmanager.cr.so (offset 0x0)
  92e38000-92e86fff r-x   a961000     4f000  /data/app/com.example.app-2/base.apk!lib/libmanager.cr.so (offset 0x30000)
  92e87000-92e8afff rw-   a9b0000      4000  /data/app/com.example.app-2/base.apk!lib/libmanager.cr.so (offset 0x7f000)
  92e8b000-92e8bfff rw-         0      1000
  92e8c000-92e9dfff r--   d5b0000     12000  /data/app/com.example.app-2/base.apk!lib/libuser_manager.cr.so (offset 0x0)
  92e9e000-92ebcfff r-x   d5c2000     1f000  /data/app/com.example.app-2/base.apk!lib/libuser_manager.cr.so (offset 0x12000)
  92ebd000-92ebefff rw-   d5e1000      2000  /data/app/com.example.app-2/base.apk!lib/libuser_manager.cr.so (offset 0x31000)
  92ebf000-92ebffff rw-         0      1000
  '''
  
  # Example stack section, taken from the same tombstone that _TEST_MEMORY_MAP
  # was extracted from.
  _TEST_STACK = r'''stack:
          bf89a070  b7439468  /system/lib/libc.so
          bf89a074  bf89a1e4  [stack]
          bf89a078  932d4000  /data/app/com.example.app-2/base.apk
          bf89a07c  b73bfbc9  /system/lib/libc.so (pthread_mutex_lock+65)
          bf89a080  00000000
          bf89a084  4000671c  /dev/ashmem/dalvik-main space 1 (deleted)
          bf89a088  932d1d86  /data/app/com.example.app-2/base.apk
          bf89a08c  b743671c  /system/lib/libc.so
          bf89a090  b77f8c00  /system/bin/linker
          bf89a094  b743cc90
          bf89a098  932d1d4a  /data/app/com.example.app-2/base.apk
          bf89a09c  b73bf271  /system/lib/libc.so (__pthread_internal_find(long)+65)
          bf89a0a0  b743cc90
          bf89a0a4  bf89a0b0  [stack]
          bf89a0a8  bf89a0b8  [stack]
          bf89a0ac  00000008
          ........  ........
    #00  bf89a0b0  00000006
          bf89a0b4  00000002
          bf89a0b8  b743671c  /system/lib/libc.so
          bf89a0bc  b73bf5d9  /system/lib/libc.so (pthread_kill+71)
    #01  bf89a0c0  00006937
          bf89a0c4  00006937
          bf89a0c8  00000006
          bf89a0cc  b77fd3a9  /system/bin/app_process32 (sigprocmask+141)
          bf89a0d0  00000002
          bf89a0d4  bf89a0ec  [stack]
          bf89a0d8  00000000
          bf89a0dc  b743671c  /system/lib/libc.so
          bf89a0e0  bf89a12c  [stack]
          bf89a0e4  bf89a1e4  [stack]
          bf89a0e8  932d1d4a  /data/app/com.example.app-2/base.apk
          bf89a0ec  b7365206  /system/lib/libc.so (raise+37)
    #02  bf89a0f0  b77f8c00  /system/bin/linker
          bf89a0f4  00000006
          bf89a0f8  b7439468  /system/lib/libc.so
          bf89a0fc  b743671c  /system/lib/libc.so
          bf89a100  bf89a12c  [stack]
          bf89a104  b743671c  /system/lib/libc.so
          bf89a108  bf89a12c  [stack]
          bf89a10c  b735e9e5  /system/lib/libc.so (abort+81)
    #03  bf89a110  00000006
          bf89a114  bf89a12c  [stack]
          bf89a118  00000000
          bf89a11c  b55a3d3b  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::DefaultLogHandler(google::protobuf::LogLevel, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+99)
          bf89a120  b7439468  /system/lib/libc.so
          bf89a124  b55ba38d  /system/lib/libprotobuf-cpp-lite.so
          bf89a128  b55ba408  /system/lib/libprotobuf-cpp-lite.so
          bf89a12c  ffffffdf
          bf89a130  0000003d
          bf89a134  adfedf00  [anon:libc_malloc]
          bf89a138  bf89a158  [stack]
    #04  bf89a13c  a0cee7f0  /data/app/com.example.app-2/base.apk
          bf89a140  b55c1cb0  /system/lib/libprotobuf-cpp-lite.so
          bf89a144  bf89a1e4  [stack]
  '''
  
  # Expected value of _TEST_STACK after translation of addresses in the APK
  # into offsets into libraries.
  _EXPECTED_STACK = r'''stack:
          bf89a070  b7439468  /system/lib/libc.so
          bf89a074  bf89a1e4  [stack]
          bf89a078  932d4000  /data/app/com.example.app-2/base.apk
          bf89a07c  b73bfbc9  /system/lib/libc.so (pthread_mutex_lock+65)
          bf89a080  00000000
          bf89a084  4000671c  /dev/ashmem/dalvik-main space 1 (deleted)
          bf89a088  932d1d86  /data/app/com.example.app-2/base.apk
          bf89a08c  b743671c  /system/lib/libc.so
          bf89a090  b77f8c00  /system/bin/linker
          bf89a094  b743cc90
          bf89a098  932d1d4a  /data/app/com.example.app-2/base.apk
          bf89a09c  b73bf271  /system/lib/libc.so (__pthread_internal_find(long)+65)
          bf89a0a0  b743cc90
          bf89a0a4  bf89a0b0  [stack]
          bf89a0a8  bf89a0b8  [stack]
          bf89a0ac  00000008
          ........  ........
    #00  bf89a0b0  00000006
          bf89a0b4  00000002
          bf89a0b8  b743671c  /system/lib/libc.so
          bf89a0bc  b73bf5d9  /system/lib/libc.so (pthread_kill+71)
    #01  bf89a0c0  00006937
          bf89a0c4  00006937
          bf89a0c8  00000006
          bf89a0cc  b77fd3a9  /system/bin/app_process32 (sigprocmask+141)
          bf89a0d0  00000002
          bf89a0d4  bf89a0ec  [stack]
          bf89a0d8  00000000
          bf89a0dc  b743671c  /system/lib/libc.so
          bf89a0e0  bf89a12c  [stack]
          bf89a0e4  bf89a1e4  [stack]
          bf89a0e8  932d1d4a  /data/app/com.example.app-2/base.apk
          bf89a0ec  b7365206  /system/lib/libc.so (raise+37)
    #02  bf89a0f0  b77f8c00  /system/bin/linker
          bf89a0f4  00000006
          bf89a0f8  b7439468  /system/lib/libc.so
          bf89a0fc  b743671c  /system/lib/libc.so
          bf89a100  bf89a12c  [stack]
          bf89a104  b743671c  /system/lib/libc.so
          bf89a108  bf89a12c  [stack]
          bf89a10c  b735e9e5  /system/lib/libc.so (abort+81)
    #03  bf89a110  00000006
          bf89a114  bf89a12c  [stack]
          bf89a118  00000000
          bf89a11c  b55a3d3b  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::DefaultLogHandler(google::protobuf::LogLevel, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+99)
          bf89a120  b7439468  /system/lib/libc.so
          bf89a124  b55ba38d  /system/lib/libprotobuf-cpp-lite.so
          bf89a128  b55ba408  /system/lib/libprotobuf-cpp-lite.so
          bf89a12c  ffffffdf
          bf89a130  0000003d
          bf89a134  adfedf00  [anon:libc_malloc]
          bf89a138  bf89a158  [stack]
    #04  bf89a13c  a0cee7f0  /data/app/com.example.app-2/base.apk
          bf89a140  b55c1cb0  /system/lib/libprotobuf-cpp-lite.so
          bf89a144  bf89a1e4  [stack]
  '''
  
  _TEST_BACKTRACE = r'''backtrace:
      #00 pc 00084126  /system/lib/libc.so (tgkill+22)
      #01 pc 000815d8  /system/lib/libc.so (pthread_kill+70)
      #02 pc 00027205  /system/lib/libc.so (raise+36)
      #03 pc 000209e4  /system/lib/libc.so (abort+80)
      #04 pc 0000cf73  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::LogMessage::Finish()+117)
      #05 pc 0000cf8e  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::LogFinisher::operator=(google::protobuf::internal::LogMessage&)+26)
      #06 pc 0000d27f  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::VerifyVersion(int, int, char const*)+574)
      #07 pc 007cd236  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #08 pc 000111a9  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0xbfc2000)
      #09 pc 00013228  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0xbfc2000)
      #10 pc 000131de  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0xbfc2000)
      #11 pc 007cd2d8  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #12 pc 007cd956  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #13 pc 007c2d4a  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #14 pc 009fc9f1  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #15 pc 009fc8ea  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #16 pc 00561c63  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #17 pc 0106fbdb  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #18 pc 004d7371  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #19 pc 004d8159  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #20 pc 004d7b96  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #21 pc 004da4b6  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #22 pc 005ab66c  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #23 pc 005afca2  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #24 pc 0000cae8  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x598d000)
      #25 pc 00ce864f  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #26 pc 00ce8dfa  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #27 pc 00ce74c6  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #28 pc 00004616  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x961e000)
      #29 pc 00ce8215  /data/app/com.google.android.apps.chrome-2/base.apk (offset 0x7daa000)
      #30 pc 0013d8c7  /system/lib/libart.so (art_quick_generic_jni_trampoline+71)
      #31 pc 00137c52  /system/lib/libart.so (art_quick_invoke_static_stub+418)
      #32 pc 00143651  /system/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+353)
      #33 pc 005e06ae  /system/lib/libart.so (artInterpreterToCompiledCodeBridge+190)
      #34 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #35 pc 0032cfc0  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)0, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+160)
      #36 pc 000fc703  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29891)
      #37 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #38 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #39 pc 0032cfc0  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)0, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+160)
      #40 pc 000fc703  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29891)
      #41 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #42 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #43 pc 0032ebf9  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)2, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+297)
      #44 pc 000fc955  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+30485)
      #45 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #46 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #47 pc 0033090c  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)4, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+636)
      #48 pc 000fc67f  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29759)
      #49 pc 00300700  /system/lib/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*)+128)
      #50 pc 00667c73  /system/lib/libart.so (artQuickToInterpreterBridge+808)
      #51 pc 0013d98d  /system/lib/libart.so (art_quick_to_interpreter_bridge+77)
      #52 pc 7264bc5b  /data/dalvik-cache/x86/system@framework@boot.oat (offset 0x1eb2000)
  '''
  
  _EXPECTED_BACKTRACE = r'''backtrace:
      #00 pc 00084126  /system/lib/libc.so (tgkill+22)
      #01 pc 000815d8  /system/lib/libc.so (pthread_kill+70)
      #02 pc 00027205  /system/lib/libc.so (raise+36)
      #03 pc 000209e4  /system/lib/libc.so (abort+80)
      #04 pc 0000cf73  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::LogMessage::Finish()+117)
      #05 pc 0000cf8e  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::LogFinisher::operator=(google::protobuf::internal::LogMessage&)+26)
      #06 pc 0000d27f  /system/lib/libprotobuf-cpp-lite.so (google::protobuf::internal::VerifyVersion(int, int, char const*)+574)
      #07 pc 007cd236  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #08 pc 000111a9  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libprotobuf_lite.cr.so (offset 0x1c000)
      #09 pc 00013228  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libprotobuf_lite.cr.so (offset 0x1c000)
      #10 pc 000131de  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libprotobuf_lite.cr.so (offset 0x1c000)
      #11 pc 007cd2d8  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #12 pc 007cd956  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #13 pc 007c2d4a  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #14 pc 009fc9f1  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #15 pc 009fc8ea  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #16 pc 00561c63  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #17 pc 0106fbdb  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #18 pc 004d7371  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #19 pc 004d8159  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #20 pc 004d7b96  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #21 pc 004da4b6  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #22 pc 005ab66c  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #23 pc 005afca2  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #24 pc 0000cae8  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so (offset 0x90e000)
      #25 pc 00ce864f  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #26 pc 00ce8dfa  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #27 pc 00ce74c6  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #28 pc 00004616  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libembedder.cr.so (offset 0x28000)
      #29 pc 00ce8215  /data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so (offset 0xc2d000)
      #30 pc 0013d8c7  /system/lib/libart.so (art_quick_generic_jni_trampoline+71)
      #31 pc 00137c52  /system/lib/libart.so (art_quick_invoke_static_stub+418)
      #32 pc 00143651  /system/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+353)
      #33 pc 005e06ae  /system/lib/libart.so (artInterpreterToCompiledCodeBridge+190)
      #34 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #35 pc 0032cfc0  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)0, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+160)
      #36 pc 000fc703  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29891)
      #37 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #38 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #39 pc 0032cfc0  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)0, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+160)
      #40 pc 000fc703  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29891)
      #41 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #42 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #43 pc 0032ebf9  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)2, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+297)
      #44 pc 000fc955  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+30485)
      #45 pc 00300af7  /system/lib/libart.so (artInterpreterToInterpreterBridge+188)
      #46 pc 00328b5d  /system/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+445)
      #47 pc 0033090c  /system/lib/libart.so (bool art::interpreter::DoInvoke<(art::InvokeType)4, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+636)
      #48 pc 000fc67f  /system/lib/libart.so (art::JValue art::interpreter::ExecuteGotoImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)+29759)
      #49 pc 00300700  /system/lib/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*)+128)
      #50 pc 00667c73  /system/lib/libart.so (artQuickToInterpreterBridge+808)
      #51 pc 0013d98d  /system/lib/libart.so (art_quick_to_interpreter_bridge+77)
      #52 pc 7264bc5b  /data/dalvik-cache/x86/system@framework@boot.oat (offset 0x1eb2000)
  '''
  
  _EXPECTED_BACKTRACE_OFFSETS_MAP = {
    '/data/app/com.google.android.apps.chrome-2/base.apk!lib/libprotobuf_lite.cr.so':
        set([
            0x1c000 + 0x111a9,
            0x1c000 + 0x13228,
            0x1c000 + 0x131de,
        ]),
  
    '/data/app/com.google.android.apps.chrome-2/base.apk!lib/libchrome.cr.so':
        set([
            0x90e000 + 0x7cd236,
            0x90e000 + 0x7cd2d8,
            0x90e000 + 0x7cd956,
            0x90e000 + 0x7c2d4a,
            0x90e000 + 0x9fc9f1,
            0x90e000 + 0x9fc8ea,
            0x90e000 + 0x561c63,
            0x90e000 + 0x106fbdb,
            0x90e000 + 0x4d7371,
            0x90e000 + 0x4d8159,
            0x90e000 + 0x4d7b96,
            0x90e000 + 0x4da4b6,
            0x90e000 + 0xcae8,
        ]),
    '/data/app/com.google.android.apps.chrome-2/base.apk!lib/libcontent.cr.so':
        set([
            0xc2d000 + 0x5ab66c,
            0xc2d000 + 0x5afca2,
            0xc2d000 + 0xce864f,
            0xc2d000 + 0xce8dfa,
            0xc2d000 + 0xce74c6,
            0xc2d000 + 0xce8215,
        ]),
    '/data/app/com.google.android.apps.chrome-2/base.apk!lib/libembedder.cr.so':
        set([
            0x28000 + 0x4616,
        ])
  }
  
  # pylint: enable=line-too-long
  
  _ONE_MB = 1024 * 1024
  _TEST_SYMBOL_DATA = {
    # Regular symbols
    0: 'mock_sym_for_addr_0 [mock_src/libmock1.so.c:0]',
    0x1000: 'mock_sym_for_addr_4096 [mock_src/libmock1.so.c:4096]',
  
    # Symbols without source file path.
    _ONE_MB: 'mock_sym_for_addr_1048576 [??:0]',
    _ONE_MB + 0x8234: 'mock_sym_for_addr_1081908 [??:0]',
  
    # Unknown symbol.
    2 * _ONE_MB: '?? [??:0]',
  
    # Inlined symbol.
    3 * _ONE_MB:
      'mock_sym_for_addr_3145728_inner [mock_src/libmock1.so.c:3145728]',
  }
  
  @contextlib.contextmanager
  def _TempDir():
    dirname = tempfile.mkdtemp()
    try:
      yield dirname
    finally:
      shutil.rmtree(dirname)
  
  
  def _TouchFile(path):
    # Create parent directories.
    try:
      os.makedirs(os.path.dirname(path))
    except OSError:
      pass
    with open(path, 'a'):
      os.utime(path, None)
  
  class MockApkTranslator(object):
    """A mock ApkLibraryPathTranslator object used for testing."""
  
    # Regex that matches the content of APK native library map files generated
    # with apk_lib_dump.py.
    _RE_MAP_FILE = re.compile(
        r'0x(?P<file_start>[0-9a-f]+)\s+' +
        r'0x(?P<file_end>[0-9a-f]+)\s+' +
        r'0x(?P<file_size>[0-9a-f]+)\s+' +
        r'0x(?P<lib_path>[0-9a-f]+)\s+')
  
    def __init__(self, test_apk_libs=None):
      """Initialize instance.
  
      Args:
        test_apk_libs: Optional list of (file_start, file_end, size, lib_path)
          tuples, like _TEST_APK_LIBS for example. This will be used to
          implement TranslatePath().
      """
      self._apk_libs = []
      if test_apk_libs:
        self._AddLibEntries(test_apk_libs)
  
    def _AddLibEntries(self, entries):
      self._apk_libs = sorted(self._apk_libs + entries, key=lambda x: x[0])
  
    def ReadMapFile(self, file_path):
      """Read an .apk.native-libs file that was produced with apk_lib_dump.py.
  
      Args:
        file_path: input path to .apk.native-libs file. Its format is
          essentially: 0x<start>  0x<end> 0x<size> <library-path>
      """
      new_libs = []
      with open(file_path) as f:
        for line in f.readlines():
          m = MockApkTranslator._RE_MAP_FILE.match(line)
          if m:
            file_start = int(m.group('file_start'), 16)
            file_end = int(m.group('file_end'), 16)
            file_size = int(m.group('file_size'), 16)
            lib_path = m.group('lib_path')
            # Sanity check
            if file_start + file_size != file_end:
              logging.warning('%s: Inconsistent (start, end, size) values '
                              '(0x%x, 0x%x, 0x%x)',
                              file_path, file_start, file_end, file_size)
            else:
              new_libs.append((file_start, file_end, file_size, lib_path))
  
      self._AddLibEntries(new_libs)
  
    def TranslatePath(self, lib_path, lib_offset):
      """Translate an APK file path + offset into a library path + offset."""
      min_pos = 0
      max_pos = len(self._apk_libs)
      while min_pos < max_pos:
        mid_pos = (min_pos + max_pos) // 2
        mid_entry = self._apk_libs[mid_pos]
        mid_offset = mid_entry[0]
        mid_size = mid_entry[2]
        if lib_offset < mid_offset:
          max_pos = mid_pos
        elif lib_offset >= mid_offset + mid_size:
          min_pos = mid_pos + 1
        else:
          # Found it
          new_path = '%s!lib/%s' % (lib_path, mid_entry[3])
          new_offset = lib_offset - mid_offset
          return (new_path, new_offset)
  
      return lib_path, lib_offset
  
  
  class HostLibraryFinderTest(unittest.TestCase):
  
    def testEmpty(self):
      finder = symbol_utils.HostLibraryFinder()
      self.assertIsNone(finder.Find('/data/data/com.example.app-1/lib/libfoo.so'))
      self.assertIsNone(
          finder.Find('/data/data/com.example.app-1/base.apk!lib/libfoo.so'))
  
  
    def testSimpleDirectory(self):
      finder = symbol_utils.HostLibraryFinder()
      with _TempDir() as tmp_dir:
        host_libfoo_path = os.path.join(tmp_dir, 'libfoo.so')
        host_libbar_path = os.path.join(tmp_dir, 'libbar.so')
        _TouchFile(host_libfoo_path)
        _TouchFile(host_libbar_path)
  
        finder.AddSearchDir(tmp_dir)
  
        # Regular library path (extracted at installation by the PackageManager).
        # Note that the extraction path has changed between Android releases,
        # i.e. it can be /data/app/, /data/data/ or /data/app-lib/ depending
        # on the system.
        self.assertEqual(
            host_libfoo_path,
            finder.Find('/data/app-lib/com.example.app-1/lib/libfoo.so'))
  
        # Verify that the path doesn't really matter
        self.assertEqual(
            host_libfoo_path,
            finder.Find('/whatever/what.apk!lib/libfoo.so'))
  
        self.assertEqual(
            host_libbar_path,
            finder.Find('/data/data/com.example.app-1/lib/libbar.so'))
  
        self.assertIsNone(
            finder.Find('/data/data/com.example.app-1/lib/libunknown.so'))
  
  
    def testMultipleDirectories(self):
      with _TempDir() as tmp_dir:
        # Create the following files:
        #   <tmp_dir>/aaa/
        #      libfoo.so
        #   <tmp_dir>/bbb/
        #      libbar.so
        #      libfoo.so    (this one should never be seen because 'aaa'
        #                    shall be first in the search path list).
        #
        aaa_dir = os.path.join(tmp_dir, 'aaa')
        bbb_dir = os.path.join(tmp_dir, 'bbb')
        os.makedirs(aaa_dir)
        os.makedirs(bbb_dir)
  
        host_libfoo_path = os.path.join(aaa_dir, 'libfoo.so')
        host_libbar_path = os.path.join(bbb_dir, 'libbar.so')
        host_libfoo2_path = os.path.join(bbb_dir, 'libfoo.so')
  
        _TouchFile(host_libfoo_path)
        _TouchFile(host_libbar_path)
        _TouchFile(host_libfoo2_path)
  
        finder = symbol_utils.HostLibraryFinder()
        finder.AddSearchDir(aaa_dir)
        finder.AddSearchDir(bbb_dir)
  
        self.assertEqual(
            host_libfoo_path,
            finder.Find('/data/data/com.example.app-1/lib/libfoo.so'))
  
        self.assertEqual(
            host_libfoo_path,
            finder.Find('/data/whatever/base.apk!lib/libfoo.so'))
  
        self.assertEqual(
            host_libbar_path,
            finder.Find('/data/data/com.example.app-1/lib/libbar.so'))
  
        self.assertIsNone(
            finder.Find('/data/data/com.example.app-1/lib/libunknown.so'))
  
  
  class ElfSymbolResolverTest(unittest.TestCase):
  
    def testCreation(self):
      resolver = symbol_utils.ElfSymbolResolver(
          addr2line_path_for_tests=_MOCK_A2L_PATH)
      self.assertTrue(resolver)
  
    def testWithSimpleOffsets(self):
      resolver = symbol_utils.ElfSymbolResolver(
          addr2line_path_for_tests=_MOCK_A2L_PATH)
      resolver.SetAndroidAbi('ignored-abi')
  
      for addr, expected_sym in _TEST_SYMBOL_DATA.items():
        self.assertEqual(resolver.FindSymbolInfo('/some/path/libmock1.so', addr),
                         expected_sym)
  
    def testWithPreResolvedSymbols(self):
      resolver = symbol_utils.ElfSymbolResolver(
          addr2line_path_for_tests=_MOCK_A2L_PATH)
      resolver.SetAndroidAbi('ignored-abi')
      resolver.AddLibraryOffsets('/some/path/libmock1.so',
                                 list(_TEST_SYMBOL_DATA.keys()))
  
      resolver.DisallowSymbolizerForTesting()
  
      for addr, expected_sym in _TEST_SYMBOL_DATA.items():
        sym_info = resolver.FindSymbolInfo('/some/path/libmock1.so', addr)
        self.assertIsNotNone(sym_info, 'None symbol info for addr %x' % addr)
        self.assertEqual(
            sym_info, expected_sym,
            'Invalid symbol info for addr %x [%s] expected [%s]' % (
                addr, sym_info, expected_sym))
  
  
  class MemoryMapTest(unittest.TestCase):
  
    def testCreation(self):
      mem_map = symbol_utils.MemoryMap('test-abi32')
      self.assertIsNone(mem_map.FindSectionForAddress(0))
  
    def testParseLines(self):
      mem_map = symbol_utils.MemoryMap('test-abi32')
      mem_map.ParseLines(_TEST_MEMORY_MAP.splitlines())
      for exp_addr, exp_size, exp_path, exp_offset in _TEST_MEMORY_MAP_SECTIONS:
        text = '(addr:%x, size:%x, path:%s, offset=%x)' % (
            exp_addr, exp_size, exp_path, exp_offset)
  
        t = mem_map.FindSectionForAddress(exp_addr)
        self.assertTrue(t, 'Could not find %s' % text)
        self.assertEqual(t.address, exp_addr)
        self.assertEqual(t.size, exp_size)
        self.assertEqual(t.offset, exp_offset)
        self.assertEqual(t.path, exp_path)
  
    def testTranslateLine(self):
      android_abi = 'test-abi'
      apk_translator = MockApkTranslator(_TEST_APK_LIBS)
      mem_map = symbol_utils.MemoryMap(android_abi)
      for line, expected_line in zip(_TEST_MEMORY_MAP.splitlines(),
                                     _EXPECTED_TEST_MEMORY_MAP.splitlines()):
        self.assertEqual(mem_map.TranslateLine(line, apk_translator),
                         expected_line)
  
  class StackTranslatorTest(unittest.TestCase):
  
    def testSimpleStack(self):
      android_abi = 'test-abi32'
      mem_map = symbol_utils.MemoryMap(android_abi)
      mem_map.ParseLines(_TEST_MEMORY_MAP)
      apk_translator = MockApkTranslator(_TEST_APK_LIBS)
      stack_translator = symbol_utils.StackTranslator(android_abi, mem_map,
                                                      apk_translator)
      input_stack = _TEST_STACK.splitlines()
      expected_stack = _EXPECTED_STACK.splitlines()
      self.assertEqual(len(input_stack), len(expected_stack))
      for stack_line, expected_line in zip(input_stack, expected_stack):
        new_line = stack_translator.TranslateLine(stack_line)
        self.assertEqual(new_line, expected_line)
  
  
  class MockSymbolResolver(symbol_utils.SymbolResolver):
  
    # A regex matching a symbol definition as it appears in a test symbol file.
    # Format is: <hex-offset> <whitespace> <symbol-string>
    _RE_SYMBOL_DEFINITION = re.compile(
        r'(?P<offset>[0-9a-f]+)\s+(?P<symbol>.*)')
  
    def __init__(self):
      super(MockSymbolResolver, self).__init__()
      self._map = collections.defaultdict(dict)
  
    def AddTestLibrarySymbols(self, lib_name, offsets_map):
      """Add a new test entry for a given library name.
  
      Args:
        lib_name: Library name (e.g. 'libfoo.so')
        offsets_map: A mapping from offsets to symbol info strings.
      """
      self._map[lib_name] = offsets_map
  
    def ReadTestFile(self, file_path, lib_name):
      """Read a single test symbol file, matching a given library.
  
      Args:
        file_path: Input file path.
        lib_name: Library name these symbols correspond to (e.g. 'libfoo.so')
      """
      with open(file_path) as f:
        for line in f.readlines():
          line = line.rstrip()
          m = MockSymbolResolver._RE_SYMBOL_DEFINITION.match(line)
          if m:
            offset = int(m.group('offset'))
            symbol = m.group('symbol')
            self._map[lib_name][offset] = symbol
  
    def ReadTestFilesInDir(self, dir_path, file_suffix):
      """Read all symbol test files in a given directory.
  
      Args:
        dir_path: Directory path.
        file_suffix: File suffix used to detect test symbol files.
      """
      for filename in os.listdir(dir_path):
        if filename.endswith(file_suffix):
          lib_name = filename[:-len(file_suffix)]
          self.ReadTestFile(os.path.join(dir_path, filename), lib_name)
  
    def FindSymbolInfo(self, device_path, device_offset):
      """Implement SymbolResolver.FindSymbolInfo."""
      lib_name = os.path.basename(device_path)
      offsets = self._map.get(lib_name)
      if not offsets:
        return None
  
      return offsets.get(device_offset)
  
  
  class BacktraceTranslatorTest(unittest.TestCase):
  
    def testEmpty(self):
      android_abi = 'test-abi'
      apk_translator = MockApkTranslator()
      backtrace_translator = symbol_utils.BacktraceTranslator(android_abi,
                                                              apk_translator)
      self.assertTrue(backtrace_translator)
  
    def testFindLibraryOffsets(self):
      android_abi = 'test-abi'
      apk_translator = MockApkTranslator(_TEST_APK_LIBS)
      backtrace_translator = symbol_utils.BacktraceTranslator(android_abi,
                                                              apk_translator)
      input_backtrace = _EXPECTED_BACKTRACE.splitlines()
      expected_lib_offsets_map = _EXPECTED_BACKTRACE_OFFSETS_MAP
      offset_map = backtrace_translator.FindLibraryOffsets(input_backtrace)
      for lib_path, offsets in offset_map.items():
        self.assertTrue(lib_path in expected_lib_offsets_map,
                        '%s is not in expected library-offsets map!' % lib_path)
        sorted_offsets = sorted(offsets)
        sorted_expected_offsets = sorted(expected_lib_offsets_map[lib_path])
        self.assertEqual(sorted_offsets, sorted_expected_offsets,
                         '%s has invalid offsets %s expected %s' % (
                            lib_path, sorted_offsets, sorted_expected_offsets))
  
    def testTranslateLine(self):
      android_abi = 'test-abi'
      apk_translator = MockApkTranslator(_TEST_APK_LIBS)
      backtrace_translator = symbol_utils.BacktraceTranslator(android_abi,
                                                              apk_translator)
      input_backtrace = _TEST_BACKTRACE.splitlines()
      expected_backtrace = _EXPECTED_BACKTRACE.splitlines()
      self.assertEqual(len(input_backtrace), len(expected_backtrace))
      for trace_line, expected_line in zip(input_backtrace, expected_backtrace):
        line = backtrace_translator.TranslateLine(trace_line,
                                                  MockSymbolResolver())
        self.assertEqual(line, expected_line)
  
  
  if __name__ == '__main__':
    unittest.main()
  