tracetool 0.4.0 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/tracetool/android.rb +2 -0
- data/lib/tracetool/android/java.rb +10 -6
- data/lib/tracetool/android/native.rb +19 -16
- data/lib/tracetool/ios.rb +1 -0
- data/lib/tracetool/ios/atos_context.rb +35 -0
- data/lib/tracetool/ios/parser.rb +2 -1
- data/lib/tracetool/ios/scanner.rb +20 -34
- data/lib/tracetool/utils/cli.rb +9 -8
- data/lib/tracetool/utils/parser.rb +50 -19
- data/lib/tracetool/utils/pipe.rb +6 -7
- data/lib/tracetool/utils/string.rb +24 -0
- data/lib/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7b0baff5d5f633d2474acf70b639fad429dd09b5b4cc4f80333ef55f72c1e5d8
|
4
|
+
data.tar.gz: 2851ab0c1b575429400937ad889b0a06fdce6f9ebaf550b05956b7879166d6f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba21b749c8875fec7e26c70da2899dfb89ea5c0fcfed2a7fc1233b34ee222d5de43cf630fc13998cf3e95335eee152e75e7fdfea8e998867ccfbd3c581eb3a1b
|
7
|
+
data.tar.gz: 7f0236c1c234fa42c8fc68874cbc63e0271c773078c64cf50a5bea4e1d6951757affb02064360590c5668e559633e85b6a237d6dff7d901edfe23fbf7a522888
|
data/lib/tracetool/android.rb
CHANGED
@@ -16,6 +16,7 @@ module Tracetool
|
|
16
16
|
# Find scanner which matches trace format
|
17
17
|
@scanner = SCANNERS.map { |s| s[trace] }.compact.first
|
18
18
|
raise(ArgumentError, "#{trace}\n not android trace?") unless @scanner
|
19
|
+
|
19
20
|
@scanner.process(context)
|
20
21
|
end
|
21
22
|
|
@@ -25,6 +26,7 @@ module Tracetool
|
|
25
26
|
# Or `nil`. If there was no scanning.
|
26
27
|
def parser(files)
|
27
28
|
return unless @scanner
|
29
|
+
|
28
30
|
@scanner.parser(files)
|
29
31
|
end
|
30
32
|
end
|
@@ -5,9 +5,9 @@ module Tracetool
|
|
5
5
|
# Parses java stack traces
|
6
6
|
class JavaTraceParser < Tracetool::BaseTraceParser
|
7
7
|
# Describes java stack entry
|
8
|
-
STACK_ENTRY_PATTERN = /^(\s+at (?<call_description>.+))|((?<error>.+?): (?<message>.+))
|
8
|
+
STACK_ENTRY_PATTERN = /^(\s+at (?<call_description>.+))|((?<error>.+?): (?<message>.+))$/.freeze
|
9
9
|
# Describes java method call
|
10
|
-
CALL_PATTERN = /(?<class>.+)\.(?<method>[^\(]+)\((((?<file>.+\.java):(?<line>\d+))|(?<location>.+))\)
|
10
|
+
CALL_PATTERN = /(?<class>.+)\.(?<method>[^\(]+)\((((?<file>.+\.java):(?<line>\d+))|(?<location>.+))\)$/.freeze
|
11
11
|
|
12
12
|
def initialize(files)
|
13
13
|
super(STACK_ENTRY_PATTERN, CALL_PATTERN, files, true)
|
@@ -15,8 +15,14 @@ module Tracetool
|
|
15
15
|
end
|
16
16
|
# Processes java traces
|
17
17
|
class JavaTraceScanner
|
18
|
-
|
19
|
-
|
18
|
+
# Usually java trace starts with
|
19
|
+
# com.something.SomeClass(: Some message)?
|
20
|
+
RX_FIRST_EXCEPTION_LINE = /^([a-zA-Z.]*)(:.*)?$/.freeze
|
21
|
+
|
22
|
+
# Rest is expanded as
|
23
|
+
# at com.other.OtherClass.someMethod(OtherClass.java:42)
|
24
|
+
# Source marker can be just "Native Method" or "Unknown Source"
|
25
|
+
RX_OTHER_EXCEPTION_LINE = /((at [a-zA-Z$.]+)|(Caused by:)|(\.\.\. [0-9]* more))(.+)?$/.freeze
|
20
26
|
|
21
27
|
def initialize(string)
|
22
28
|
@trace = string
|
@@ -38,8 +44,6 @@ module Tracetool
|
|
38
44
|
def match(string)
|
39
45
|
# Split into lines
|
40
46
|
first, *rest = string.split("\n")
|
41
|
-
|
42
|
-
return if rest.nil? || rest.empty?
|
43
47
|
return unless RX_FIRST_EXCEPTION_LINE.match(first)
|
44
48
|
|
45
49
|
rest.all? { |line| RX_OTHER_EXCEPTION_LINE.match(line) }
|
@@ -5,10 +5,15 @@ module Tracetool
|
|
5
5
|
# Android traces scanner and mapper
|
6
6
|
class NativeTraceParser < Tracetool::BaseTraceParser
|
7
7
|
# Describes android stack entry
|
8
|
+
# rubocop:disable Metrics/LineLength
|
8
9
|
STACK_ENTRY_PATTERN =
|
9
|
-
%r{Stack frame #(?<frame>\d+) (?<address>\w+ [a-f\d]+) (?<lib>[/\w\d
|
10
|
+
%r{Stack frame #(?<frame>\d+) (?<address>\w+ [a-f\d]+) (?<lib>[/\w\d\._!=-]+)( )?(:? (?<call_description>.+))?$}.freeze
|
11
|
+
# rubocop:enable Metrics/LineLength
|
10
12
|
# Describes android native method call (class::method and source file with line number)
|
11
|
-
CALL_PATTERN =
|
13
|
+
CALL_PATTERN = [
|
14
|
+
/((Routine )?(?<method>.+) ((in)|(at)) (?<file>.+):(?<line>\d+))/,
|
15
|
+
/(?<method>.+?) \d+/
|
16
|
+
].freeze
|
12
17
|
|
13
18
|
def initialize(files)
|
14
19
|
super(STACK_ENTRY_PATTERN, CALL_PATTERN, files, true)
|
@@ -30,7 +35,9 @@ module Tracetool
|
|
30
35
|
# @param [String] trace packed stack trace
|
31
36
|
# @return well formed stack trace
|
32
37
|
def unpack(trace)
|
33
|
-
dump_body = prepare(trace)
|
38
|
+
dump_body = prepare(trace)
|
39
|
+
.map
|
40
|
+
.with_index { |line, index| convert_line(line, index) }
|
34
41
|
add_header(dump_body.join("\n"))
|
35
42
|
end
|
36
43
|
|
@@ -48,8 +55,9 @@ module Tracetool
|
|
48
55
|
def convert_line(line, index)
|
49
56
|
frame = index
|
50
57
|
addr = line[/^(-?\d+) (.*)$/, 1]
|
51
|
-
lib = line[/^(-?\d+) (.*)$/, 2].strip
|
52
|
-
' #%
|
58
|
+
lib = (line[/^(-?\d+) (.*)$/, 2] || '').strip # nil safe
|
59
|
+
' #%02<frame>i pc %08<addr>x %<lib>s'
|
60
|
+
.format(frame: frame, addr: addr, lib: lib)
|
53
61
|
end
|
54
62
|
|
55
63
|
# If needed here we'll drop all unneeded leading characters from each
|
@@ -63,14 +71,15 @@ module Tracetool
|
|
63
71
|
# Processes native traces
|
64
72
|
class NativeTraceScanner
|
65
73
|
# Initial sequence of asterisks which marks begining of trace body
|
66
|
-
TRACE_DELIMETER =
|
67
|
-
|
74
|
+
TRACE_DELIMETER =
|
75
|
+
'*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***'.freeze
|
76
|
+
RX_INITIAL_ASTERISKS = /#{TRACE_DELIMETER.gsub('*', '\*')}/.freeze
|
68
77
|
# Contains address line like
|
69
78
|
#
|
70
79
|
# ```
|
71
80
|
# pc 00000000004321ec libfoo.so
|
72
81
|
# ```
|
73
|
-
RX_PC_ADDRESS = /pc \d
|
82
|
+
RX_PC_ADDRESS = /pc \d+/.freeze
|
74
83
|
|
75
84
|
# Format of packed trace.
|
76
85
|
# Consists of one or more trace blocks.
|
@@ -84,7 +93,7 @@ module Tracetool
|
|
84
93
|
# ** symbol offset `/\d+/`
|
85
94
|
#
|
86
95
|
# Last two entries can be missing.
|
87
|
-
RX_PACKED_FORMAT = /^(<<<(
|
96
|
+
RX_PACKED_FORMAT = /^(<<<([-?\d]+ [^ ]+ (.+)?;)+>>>)+$/.freeze
|
88
97
|
|
89
98
|
# @param [String] string well formed native android stack trace
|
90
99
|
# @see https://developer.android.com/ndk/guides/ndk-stack.html
|
@@ -96,13 +105,7 @@ module Tracetool
|
|
96
105
|
# path to symbols dir
|
97
106
|
# @return [String] desymbolicated stack trace
|
98
107
|
def process(ctx)
|
99
|
-
|
100
|
-
symbols = if ctx.arch
|
101
|
-
File.join(symbols, ctx.arch)
|
102
|
-
else
|
103
|
-
Dir[File.join(symbols, '*')].first || symbols
|
104
|
-
end
|
105
|
-
Pipe['ndk-stack', '-sym', symbols] << @trace
|
108
|
+
Pipe['ndk-stack', '-sym', ctx.symbols] << @trace
|
106
109
|
end
|
107
110
|
|
108
111
|
# Create parser for current trace format
|
data/lib/tracetool/ios.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Tracetool
|
2
|
+
module IOS
|
3
|
+
# Converts context to atos arguments
|
4
|
+
class AtosContext
|
5
|
+
# If no arch specified will use `arm64`
|
6
|
+
DEFAULT_ARCH = 'arm64'.freeze
|
7
|
+
|
8
|
+
# List of required argument names
|
9
|
+
REQUIRED_ARGUMENTS = %i[load_address xarchive module_name].freeze
|
10
|
+
|
11
|
+
def initialize(ctx)
|
12
|
+
check_arguments(ctx)
|
13
|
+
@load_address = ctx.load_address
|
14
|
+
@binary_path = module_binary(ctx.xarchive, ctx.module_name)
|
15
|
+
@arch = ctx.arch || 'arm64'
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_args
|
19
|
+
%w[-o -l -arch].zip([@binary_path, @load_address, @arch]).flatten
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def module_binary(xarchive, module_name)
|
25
|
+
File.join(xarchive, 'dSYMs', "#{module_name}.app.dSYM", 'Contents', 'Resources', 'DWARF', module_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_arguments(ctx)
|
29
|
+
REQUIRED_ARGUMENTS.each do |a|
|
30
|
+
ctx[a] || raise(ArgumentError, "Missing `#{a}` value")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/tracetool/ios/parser.rb
CHANGED
@@ -5,10 +5,11 @@ module Tracetool
|
|
5
5
|
# IOS traces scanner and source mapper
|
6
6
|
class IOSTraceParser < Tracetool::BaseTraceParser
|
7
7
|
# Describes IOS stack entry
|
8
|
-
STACK_ENTRY_PATTERN = /^(?<frame>\d+) (?<binary>[^ ]+) (?<call_description>.+)
|
8
|
+
STACK_ENTRY_PATTERN = /^(?<frame>\d+) (?<binary>[^ ]+) (?<call_description>.+)$/.freeze
|
9
9
|
# Describes source block
|
10
10
|
SOURCE_PATTERN =
|
11
11
|
/^((-?\[(?<class>[^ ]+) (?<method>.+)\])|(?<method>.+)) \(in (?<module>.+)\) \((?<file>.+):(?<line>\d+)\)$/
|
12
|
+
.freeze
|
12
13
|
|
13
14
|
def initialize(files)
|
14
15
|
super(STACK_ENTRY_PATTERN, SOURCE_PATTERN, files, true)
|
@@ -1,38 +1,5 @@
|
|
1
1
|
module Tracetool
|
2
2
|
module IOS
|
3
|
-
# Converts context to atos arguments
|
4
|
-
class AtosContext
|
5
|
-
# If no arch specified will use `arm64`
|
6
|
-
DEFAULT_ARCH = 'arm64'.freeze
|
7
|
-
|
8
|
-
# List of required argument names
|
9
|
-
REQUIRED_ARGUMENTS = %i[load_address xarchive module_name].freeze
|
10
|
-
|
11
|
-
#
|
12
|
-
def initialize(ctx)
|
13
|
-
check_arguments(ctx)
|
14
|
-
@load_address = ctx.load_address
|
15
|
-
@binary_path = module_binary(ctx.xarchive, ctx.module_name)
|
16
|
-
@arch = ctx.arch || 'arm64'
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_args
|
20
|
-
%w[-o -l -arch].zip([@binary_path, @load_address, @arch]).flatten
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def module_binary(xarchive, module_name)
|
26
|
-
File.join(xarchive, 'dSYMs', "#{module_name}.app.dSYM", 'Contents', 'Resources', 'DWARF', module_name)
|
27
|
-
end
|
28
|
-
|
29
|
-
def check_arguments(ctx)
|
30
|
-
REQUIRED_ARGUMENTS.each do |a|
|
31
|
-
ctx[a] || raise(ArgumentError, "Missing `#{a}` value")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
3
|
# launches atos
|
37
4
|
class IOSTraceScanner
|
38
5
|
# Stack trace line consists of numerous whitespace separated
|
@@ -45,10 +12,29 @@ module Tracetool
|
|
45
12
|
# @return [Array] containing (%binary_name%, %address%) pairs
|
46
13
|
def parse(trace)
|
47
14
|
trace.split("\n").map do |line|
|
48
|
-
line
|
15
|
+
parse_line(line)
|
49
16
|
end
|
50
17
|
end
|
51
18
|
|
19
|
+
# Parse trace line from trace. Which usualy looks like this:
|
20
|
+
# 3 My Module Name 0x0000000102d6e9f4 My Module Name + 5859828
|
21
|
+
# We need to fetch two values: 'My Module Name' and '0x0000000102d6e9f4'.
|
22
|
+
def parse_line(line)
|
23
|
+
parts = line.split(' ')
|
24
|
+
parts.shift # Frame number, not needed
|
25
|
+
|
26
|
+
module_name = ''
|
27
|
+
|
28
|
+
until parts.first.start_with?('0x')
|
29
|
+
module_name += parts.shift
|
30
|
+
module_name += ' '
|
31
|
+
end
|
32
|
+
|
33
|
+
address = parts.shift
|
34
|
+
|
35
|
+
[module_name.chop, address]
|
36
|
+
end
|
37
|
+
|
52
38
|
def process(trace, context)
|
53
39
|
trace = parse(trace)
|
54
40
|
desym = run_atos(context, trace.map(&:last))
|
data/lib/tracetool/utils/cli.rb
CHANGED
@@ -6,8 +6,8 @@ require_relative '../../version'
|
|
6
6
|
module Tracetool
|
7
7
|
# Tracetool cli args parser
|
8
8
|
class ParseArgs
|
9
|
-
# List of supported abis
|
10
|
-
ARCH_LIST = %i[
|
9
|
+
# List of supported abis. Only needed for iOS unpacking
|
10
|
+
ARCH_LIST = %i[arm arm64].freeze
|
11
11
|
#
|
12
12
|
# Return a structure describing the options.
|
13
13
|
#
|
@@ -19,24 +19,25 @@ module Tracetool
|
|
19
19
|
check(options)
|
20
20
|
check_ios(options)
|
21
21
|
options
|
22
|
-
rescue OptionParser::MissingArgument =>
|
23
|
-
io.write ["Error occurred: #{
|
22
|
+
rescue OptionParser::MissingArgument => e
|
23
|
+
io.write ["Error occurred: #{e.message}", '', opt_parser.help].join("\n")
|
24
24
|
io.write "\n"
|
25
|
-
raise(
|
25
|
+
raise(e)
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.check_ios(options)
|
29
29
|
return unless options.platform == :ios
|
30
|
+
|
30
31
|
{
|
31
32
|
'address' => options.address,
|
32
|
-
'module' =>
|
33
|
+
'module' => options.modulename,
|
34
|
+
'arch' => options.arch
|
33
35
|
}.each { |arg, check| raise(OptionParser::MissingArgument, arg) unless check }
|
34
36
|
end
|
35
37
|
|
36
38
|
def self.check(options)
|
37
39
|
{
|
38
|
-
'platform' => options.platform
|
39
|
-
'arch' => options.arch
|
40
|
+
'platform' => options.platform
|
40
41
|
}.each { |arg, check| raise(OptionParser::MissingArgument, arg) unless check }
|
41
42
|
end
|
42
43
|
|
@@ -1,12 +1,16 @@
|
|
1
|
+
require_relative 'string'
|
2
|
+
|
1
3
|
module Tracetool
|
2
4
|
# Base trace parser logic
|
3
5
|
class BaseTraceParser
|
6
|
+
include StringUtils
|
7
|
+
|
4
8
|
attr_reader :entry_pattern, :call_pattern
|
5
9
|
|
6
10
|
def initialize(entry_pattern, call_pattern, build_files, convert_numbers = false)
|
7
11
|
@build_files = build_files
|
8
12
|
@entry_pattern = entry_pattern
|
9
|
-
@call_pattern = call_pattern
|
13
|
+
@call_pattern = call_pattern.is_a?(Array) ? call_pattern : [call_pattern]
|
10
14
|
@convert_numbers = convert_numbers
|
11
15
|
end
|
12
16
|
|
@@ -54,36 +58,63 @@ module Tracetool
|
|
54
58
|
# * method
|
55
59
|
# * file
|
56
60
|
# * line number
|
57
|
-
def scan_call(
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
def scan_call(call_info)
|
62
|
+
call_description = call_info[:call_description]
|
63
|
+
# TODO: Lazy check
|
64
|
+
match = call_description && call_pattern.map { |p| p.match(call_description) }.compact.first
|
65
|
+
if match
|
66
|
+
call = extract_groups(match)
|
67
|
+
# Update file entry with expanded path
|
68
|
+
call[:file] = find_file(call[:file]) if call[:file]
|
69
|
+
|
70
|
+
call_info[:call] = call
|
66
71
|
end
|
67
72
|
|
68
|
-
|
73
|
+
call_info
|
69
74
|
end
|
70
75
|
|
71
76
|
# Find file with specified file name in symbols dir
|
72
|
-
# Can return multiple files if name was
|
77
|
+
# Can return multiple files if name was ambiguous
|
73
78
|
def find_file(file)
|
74
|
-
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
files =
|
79
|
+
file_name = File.basename(file)
|
80
|
+
# Firstly we'll drop obvious mismatches where basename of file differs
|
81
|
+
candidates = @build_files.select { |path| File.basename(path) == file_name }
|
82
|
+
# In case when got ambiguous files return all try to find closest match
|
83
|
+
files = find_closest_files(file, candidates)
|
79
84
|
|
80
85
|
# If has only option return first
|
81
86
|
return files.first if files.size == 1
|
82
87
|
# Return original file if files empty
|
83
88
|
return file if files.empty?
|
84
89
|
|
85
|
-
#
|
86
|
-
|
90
|
+
files # Return all files if many matched
|
91
|
+
end
|
92
|
+
|
93
|
+
# Select from candidates list such files
|
94
|
+
# that ends with maximum substring of file
|
95
|
+
# @param [String] file file path to match
|
96
|
+
# @param [Array<String>] candidates list of candidates path
|
97
|
+
# @return [Array<String>] list of files with maximum length matches
|
98
|
+
def find_closest_files(file, candidates)
|
99
|
+
candidates.inject([[], 0]) do |acc, elem|
|
100
|
+
# Current element score is length of longest common postfix
|
101
|
+
elem_score = file.longest_common_postfix(elem).length
|
102
|
+
|
103
|
+
# Unpack accumulator as (list_of_matched_files, max_score)
|
104
|
+
matched, score = acc
|
105
|
+
# Will update if only have better score
|
106
|
+
if elem_score >= score
|
107
|
+
# Current score more than last known score, so now
|
108
|
+
# we drop all previous results and replace them with
|
109
|
+
# current element
|
110
|
+
matched = [] if elem_score > score
|
111
|
+
score = elem_score
|
112
|
+
# Update list of matched
|
113
|
+
matched << elem
|
114
|
+
end
|
115
|
+
|
116
|
+
[matched, score]
|
117
|
+
end.first
|
87
118
|
end
|
88
119
|
|
89
120
|
def extract_groups(match)
|
data/lib/tracetool/utils/pipe.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'open3'
|
2
|
+
|
2
3
|
module Tracetool
|
3
|
-
#
|
4
|
+
# Helper module for launching commands
|
4
5
|
module Pipe
|
5
6
|
# Executes shell command
|
6
7
|
class Executor
|
@@ -14,12 +15,10 @@ module Tracetool
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def <<(args)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
io.read.chomp
|
22
|
-
end
|
18
|
+
out, err, status = Open3.capture3({}, *cmd, stdin_data: args)
|
19
|
+
raise "#{cmd.join(' ')} (exit: #{status.exitstatus}) #{err.chomp}" unless status.success?
|
20
|
+
|
21
|
+
out.chomp
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tracetool
|
2
|
+
# Set of utility methods for working with strings
|
3
|
+
module StringUtils
|
4
|
+
# Extended string class
|
5
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
6
|
+
class ::String
|
7
|
+
# Return longest common postfix
|
8
|
+
# @param [String] other other string to match
|
9
|
+
# @return [String] longest common postfix
|
10
|
+
def longest_common_postfix(other)
|
11
|
+
sidx = length - 1
|
12
|
+
oidx = other.length - 1
|
13
|
+
|
14
|
+
while sidx >= 0 && oidx >= 0 && (self[sidx] == other[oidx])
|
15
|
+
sidx -= 1
|
16
|
+
oidx -= 1
|
17
|
+
end
|
18
|
+
|
19
|
+
other[(oidx + 1)..-1]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
23
|
+
end
|
24
|
+
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracetool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ilya.arkhanhelsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: powerpack
|
@@ -37,12 +37,14 @@ files:
|
|
37
37
|
- lib/tracetool/android/java.rb
|
38
38
|
- lib/tracetool/android/native.rb
|
39
39
|
- lib/tracetool/ios.rb
|
40
|
+
- lib/tracetool/ios/atos_context.rb
|
40
41
|
- lib/tracetool/ios/parser.rb
|
41
42
|
- lib/tracetool/ios/scanner.rb
|
42
43
|
- lib/tracetool/utils/cli.rb
|
43
44
|
- lib/tracetool/utils/env.rb
|
44
45
|
- lib/tracetool/utils/parser.rb
|
45
46
|
- lib/tracetool/utils/pipe.rb
|
47
|
+
- lib/tracetool/utils/string.rb
|
46
48
|
- lib/tracetool_cli.rb
|
47
49
|
- lib/version.rb
|
48
50
|
homepage: https://github.com/vizor-games/tracetool
|
@@ -64,8 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
66
|
- !ruby/object:Gem::Version
|
65
67
|
version: '0'
|
66
68
|
requirements: []
|
67
|
-
|
68
|
-
rubygems_version: 2.6.13
|
69
|
+
rubygems_version: 3.1.2
|
69
70
|
signing_key:
|
70
71
|
specification_version: 4
|
71
72
|
summary: Tracetool
|