Alpacius / arachne-pl

A tool for visualization of C runtime call graphs from call logs.
MIT License
2 stars 0 forks source link

[compatible] support macOS atos #1

Open meritozh opened 5 years ago

meritozh commented 5 years ago

In macOS, addr2line built from binutils cannot works fine.

References

  1. atos manpage
  2. atos for linux
meritozh commented 5 years ago
diff --git a/CallLogDrawer_LogIter.pm b/CallLogDrawer_LogIter.pm
index 5af3272..a2454e8 100644
--- a/CallLogDrawer_LogIter.pm
+++ b/CallLogDrawer_LogIter.pm
@@ -19,7 +19,7 @@ sub new {
         open($fh, "<", $infpath) or die "Failed to open $infpath: $!";
     }
     my ($ana_in, $ana_out);
-    my $pid = open2($ana_out, $ana_in, "LANG=c addr2line -fps -e $bin");
+    my $pid = open2($ana_out, $ana_in, "LANG=c atos -o $bin");
     my $iter = { in => $fh, bin => $bin, pid => $pid, ana_out => $ana_out, ana_in => $ana_in };
     bless $iter, $class;
     $iter
@@ -31,7 +31,7 @@ sub funcinfo_from_addr {
     print $chld_in sprintf("0x%x\n", $ptr);
     my $res = <$chld_out>;
     chomp $res;
-    if ($res =~ /\s*([_A-Za-z][_A-Za-z0-9]*)\s*at\s*([^:]+?):([0-9]+)/) {
+    if ($res =~ /\s*([_a-zA-Z][_a-zA-Z0-9]*)\s+\(.+?\)\s+\((.+):([0-9]+)\)/) {
         return { func => $1, srcfile => $2, lineno => $3, site => $ptr };
     } else {
         return { func => '#', srcfile => '#', lineno => '#', site => $ptr };
diff --git a/CallLogDrawer_LogIterConf.pm b/CallLogDrawer_LogIterConf.pm
index 05f162f..1f6700d 100644
--- a/CallLogDrawer_LogIterConf.pm
+++ b/CallLogDrawer_LogIterConf.pm
@@ -7,6 +7,7 @@ our @EXPORT_OK = qw( callptrs_from_logline );

 sub callptrs_from_logline {
     my ($logline) = @_;
+    print "content: $logline\n";
     ($logline =~ /e\s+(0x[0-9a-f]+)\s+(0x[0-9a-f]+)/) ? (hex($1), hex($2)) : (0, 0)
 }
→ head ../trace.out        
x 0x100002850 0x10888ccc8
e 0x1000029a0 0x10888ccc8
x 0x1000029a0 0x10888ccc8
e 0x1000011a0 0x7fff695dc08d
e 0x10000f270 0x1000014f4
x 0x10000f270 0x1000014f4
e 0x100011e20 0x1000014f9
e 0x100011e90 0x100011e47
e 0x100013f70 0x100011ec0
x 0x100013f70 0x100011ec0
→ ./rtcalls_draw.pl -f ../trace.out -e ../metal
content: x 0x100002850 0x10888ccc8
digraph runtime_calls { 
}

It just parse the first line?


But

→ echo '0x10001a190 0x10001a890' | atos -o metal
casino_timerwheel_get_expired (in metal) (timewheel.c:288)
casino_linklist_init_anchor (in metal) (linklist.h:73)

Works well.

Alpacius commented 5 years ago
  • diff file:
diff --git a/CallLogDrawer_LogIter.pm b/CallLogDrawer_LogIter.pm
index 5af3272..a2454e8 100644
--- a/CallLogDrawer_LogIter.pm
+++ b/CallLogDrawer_LogIter.pm
@@ -19,7 +19,7 @@ sub new {
         open($fh, "<", $infpath) or die "Failed to open $infpath: $!";
     }
     my ($ana_in, $ana_out);
-    my $pid = open2($ana_out, $ana_in, "LANG=c addr2line -fps -e $bin");
+    my $pid = open2($ana_out, $ana_in, "LANG=c atos -o $bin");
     my $iter = { in => $fh, bin => $bin, pid => $pid, ana_out => $ana_out, ana_in => $ana_in };
     bless $iter, $class;
     $iter
@@ -31,7 +31,7 @@ sub funcinfo_from_addr {
     print $chld_in sprintf("0x%x\n", $ptr);
     my $res = <$chld_out>;
     chomp $res;
-    if ($res =~ /\s*([_A-Za-z][_A-Za-z0-9]*)\s*at\s*([^:]+?):([0-9]+)/) {
+    if ($res =~ /\s*([_a-zA-Z][_a-zA-Z0-9]*)\s+\(.+?\)\s+\((.+):([0-9]+)\)/) {
         return { func => $1, srcfile => $2, lineno => $3, site => $ptr };
     } else {
         return { func => '#', srcfile => '#', lineno => '#', site => $ptr };
diff --git a/CallLogDrawer_LogIterConf.pm b/CallLogDrawer_LogIterConf.pm
index 05f162f..1f6700d 100644
--- a/CallLogDrawer_LogIterConf.pm
+++ b/CallLogDrawer_LogIterConf.pm
@@ -7,6 +7,7 @@ our @EXPORT_OK = qw( callptrs_from_logline );

 sub callptrs_from_logline {
     my ($logline) = @_;
+    print "content: $logline\n";
     ($logline =~ /e\s+(0x[0-9a-f]+)\s+(0x[0-9a-f]+)/) ? (hex($1), hex($2)) : (0, 0)
 }
  • trace.out:
→ head ../trace.out        
x 0x100002850 0x10888ccc8
e 0x1000029a0 0x10888ccc8
x 0x1000029a0 0x10888ccc8
e 0x1000011a0 0x7fff695dc08d
e 0x10000f270 0x1000014f4
x 0x10000f270 0x1000014f4
e 0x100011e20 0x1000014f9
e 0x100011e90 0x100011e47
e 0x100013f70 0x100011ec0
x 0x100013f70 0x100011ec0
  • output:
→ ./rtcalls_draw.pl -f ../trace.out -e ../metal
content: x 0x100002850 0x10888ccc8
digraph runtime_calls { 
}

It just parse the first line?

But

→ echo '0x10001a190 0x10001a890' | atos -o metal
casino_timerwheel_get_expired (in metal) (timewheel.c:288)
casino_linklist_init_anchor (in metal) (linklist.h:73)

Works well.

Call graph construction needs log entries from the enter hook only -- "x" entries may produce empty call instances and could be easily filtered. According to this line, any failure of pattern matching in iteration over the log causes the log iterator to return undef, which shall cause the main loop of the analyzer to recognize an End-of-Input and stop immediately.

Removing all "x" entries, leaving only "e" entries, may produce some correct output.

Should the log iterator die croaking loud when any pattern mismatch occurs?

meritozh commented 5 years ago

How to just ignore "x" entries? I need a .diff ...

Alpacius commented 5 years ago

How to just ignore "x" entries? I need a .diff ...

For now,

perl -e 'while (<>) { print if (/^e/); }' < trace.out >trace_filtered.out

should work -- at least we'll have some cleaner trace log. Filter code would be added later as a patch.

Alpacius commented 5 years ago

Currently I'll keep this issue held (but still open). Branch mac-atos-support shall be merged into master as a minor refactor, featuring separation of log iteration and symbol lookup, with addr2line as the only analysis program available.