SlideShare a Scribd company logo
1 of 109
SOSCON 2018
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing the C/C++ open-sources for profit and fun
C/C++ 오픈소스를 Tracing 하면 얻을 수 있는 것들
HANBUM PARK
SOSCON 2018
SAMSUNG OPEN SOURCE CONFERENCE 2018
HANBUM PARK
KOSSLAB OPEN-FRONTIER
Uftrace Contributor
Reverse-Engineer
SOSCON 2018
SAMSUNG OPEN SOURCE CONFERENCE 2018
The stories I want to share.
• Introduction
• Motivation
• Uftrace
• Tracing for profit
– Android VM
• Tracing for fun
– Gcc
• Retrospect
• Conclusion
CONTENTS
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce
Tracing 사례 살펴보기
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Native 함수 호출을 통한 연산이 순수 Javascript보다 느린 경우
DOMMatrix perf (https://jsperf.com/dommatrix-perf/9)
JS Obj equivalent
JS equivalent
JS equivalent + DOM access
JS equivalent with floatArray
JS equivalent with floatArray + DOM access
JS with Native-Function call
55
Operation per second (higher is better)
44
43
5
14
32
Tracing case study – Node.js
Uftrace로 Tracing 한 후 결과 로그를 통해 이유를 확인할 수 있습니다
Jinho bang - chromium binding 기술을 node.js에 적용해보자 (DEVIEW 2017)
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Sum이란 함수로 배열 안의 값들의 합을 구한다고 가정합시다
let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]);
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
배열 안의 값들에 합을 구하는 Sum 함수 – Javascript
function sum(elements) {
let s = 0;
elements.forEach(element => { s += element; });
return s;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
배열 안의 값들에 합을 구하는 Sum 함수 – Node.js N-API
napi_value Sum(napi_env, napi_callback_info info) {
}
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
배열 안의 값들에 합을 구하는 Sum 함수는 두 부분으로 이뤄집니다
napi_value Sum(napi_env, napi_callback_info info) {
}
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
연산
반환
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Javascript 단에 저장된 값을 Native에서 사용하기 위해 읽어와야 합니다
napi_value Sum(napi_env, napi_callback_info info) {
}
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
Get Javascript value
napi_value element;
napi_get_element(env, i, &element);
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
이 과정에서 Javascript의 값에 대한 Type을 체크해야 합니다
napi_value Sum(napi_env, napi_callback_info info) {
}
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
Type checking
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Native에서 연산이 끝났으면, 결과 값을 Javascript에서 사용가능한 타입으로 바꿔야 합니다
napi_value Sum(napi_env, napi_callback_info info) {
}
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum; napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
Type converting
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Resolve : Chromium WebIDL to Node.js – automatic binding and checking
// WebIDL
[Constructor]
interface Calculator {
double sum(sequence<long> elements);
};
// Native Code
class Calculator {
public:
double Sum(std::vector<int> elements) {
int sum = 0;
for (int i = 0; I < elements.size(); i++)
sum += elements[i];
return sum;
}
};
// N-API
napi_value Sum(napi_env, napi_callback_info info) {
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Resolve : Chromium WebIDL to Node.js – ignore type checking
// WebIDL
[Constructor]
interface Calculator {
[NoTypeChecking] double sum(sequence<long> elements);
};
// Native Code
class Calculator {
public:
double Sum(std::vector<int> elements) {
int sum = 0;
for (int i = 0; I < elements.size(); i++)
sum += elements[i];
return sum;
}
};
// N-API
napi_value Sum(napi_env, napi_callback_info info) {
for (int i = 0; i < length; i++) {
napi_value element;
napi_get_element(env, i, &element);
napi_valuetype valuetype;
napi_typeof(env, element, &valuetype);
double value;
napi_get_value_double(env, element, &value);
sum += value;
}
napi_value js_sum;
napi_create_double(env, sum, &js_sum);
return js_sum;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
방진호님은 WebIDL을 Node.js에 제의하였으며 개발…
Project Bacardi
https://github.com/lunchclass/bacardi
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing case study – Node.js
Tracing, “프로그램의 실행 동안의 변화를 다각도로 기록하고 이를 검토하는 일”
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
시간은 금이라고 친구
Motivation
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
Android에서 새 App이 구동되는 순서
Zygote
Application
DalvikVM
Android OS
(Managers)
JNI_CreateJavaVM
2
ActivityThread
& Looper
3
attachApplication
4
bindApplication
5
Find Application Class
& Create new Instance
& Call attachBaseContext
6
Fork and Register
PID
1
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
Zygote
Android OS
(Managers)
ActivityThread
& Looper
3
attachApplication
4
bindApplication
5
Find Application Class
& Create new Instance
& Call attachBaseContext
6
Fork and Register
PID
1
Application
DalvikVM
JNI_CreateJavaVM
2
Resources
DEX
새 VM을 만들 때 APK가 인자로 전달
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
Zygote
Android OS
(Managers)
ActivityThread
& Looper
3
attachApplication
4
bindApplication
5
Find Application Class
& Create new Instance
& Call attachBaseContext
6
Fork and Register
PID
1
Application
DalvikVM
JNI_CreateJavaVM
2
Resources
method public static main([Ljava/lang/String;)V
.registers 3
.prologue
.line 19
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "Hello, world!"
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.line 20
return-void
.end method
DEX
DEX는 Bytecode로 코드로 이루어져 소스코드 노출이 쉽다!
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
Zygote
Android OS
(Managers)
ActivityThread
& Looper
3
attachApplication
4
bindApplication
5
Find Application Class
& Create new Instance
& Call attachBaseContext
6
Fork and Register
PID
1
Application
DalvikVM
JNI_CreateJavaVM
2
Resources
method public static main([Ljava/lang/String;)V
.registers 3
.prologue
.line 19
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "Hello, world!"
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.line 20
return-void
.end method
DEX
DEX의 보호 방안 찾기 대작전!
원본 DEX를 보호하는 메커니즘의 필요
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
You are right always
EntryPoint
Android
Open
Source
Project
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Language Files Blank Comment Code Line
C 708 22952 28339 95886
C++ 735 44751 49065 325759
Motivation
Everything grow up, except my salary
AOSP - art
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
분석의 시작은 CC 형제, Ctags + Cscope와 함께 시작했습니다만
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation
분석의 시작은 CC 형제, Ctags + Cscope와 함께 시작했습니다만
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
LookupClass
ResolveClass
FindClassNoInit
FindClass
DefineClass
LoadClass
LinkClass
ResolveClass
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation – time is gold, friends
You are right always, but need time
EntryPoint
Android
Open
Source
Project
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation – time is gold, friends
Reverse Engineer을 하는 일반적인 방식 #1
Process
Disk
Network
Memory
Binary
API
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation – time is gold, friends
Reverse Engineer을 하는 일반적인 방식 #2
Process
Disk
Network
Memory
Binary
API
Logging
Monitoring
Record
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation – time is gold, friends
Reverse Engineer을 하는 일반적인 방식 #3
Process
Disk
Network
Memory
API
Record
Binary
API
Catch
Event
Logging
Monitoring
FOUND
Logic
!!
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Motivation – time is gold, friends
프로그램의 실행을 흐름을 로깅하면 분석에 필요한 최소 로직을 추려낼 수 있습니다
Android
Open
Source
Project
Binary
API
dalvikvm
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Uftrace
Function tracer for user-space
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
일반적인 컴파일 결과
void bar() {
}
void foo() {
bar();
}
int main() {
foo();
}
<bar>:
ret
<foo>:
call <bar>
ret
<main>:
call <foo>
ret
$ gcc foobar.c
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
-pg 옵션으로 컴파일 했을 때의 결과
void bar() {
}
void foo() {
bar();
}
int main() {
foo();
}
<bar>:
call <mcount@plt>
ret
<foo>:
call <mcount@plt>
call <bar>
ret
<main>:
call <mcount@plt>
call <foo>
ret
$ gcc –pg foobar.c
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
-pg로 컴파일 하면 컴파일러가 mcount 호출을 생성해 줍니다
<bar>:
call <mcount@plt>
ret
<foo>:
call <mcount@plt>
call <bar>
ret
<main>:
call <mcount@plt>
call <foo>
ret
<mcount@plt>:
# record callee position
ret
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
함수 간에는 인자 값을 전달하는 방식은 약속되어 있습니다
void bar(int arg) {
}
void foo(int arg) {
bar(arg);
}
int main() {
foo(0x10);
}
<bar>:
# 인자 값 받기
ret
<foo>:
# 인자 값 받기
call <bar> #인자 보내기
ret
<main>:
call <foo> #인자 보내기
ret
$ gcc foobar.c -o output
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
함수 간에는 인자 값을 전달하는 방식은 약속되어 있습니다
void bar(int arg) {
}
void foo(int arg) {
bar(arg);
}
int main() {
foo(0x10);
}
<bar>:
# 인자 값 받기
ret
<foo>:
# 인자 값 받기
call <bar> #인자 보내기
ret
<main>:
call <foo> #인자 보내기
ret
$ gcc foobar.c -o output
Calling Convention
- 인자 값 전달
- 호출 지점으로 복귀
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Introduce UFTRACE
호출 규약에 지정된 레지스터, 메모리를 읽어 인자 값을 알아낼 수 있습니다
<bar>:
# 인자 값 받기
ret
<foo>:
# 인자 값 받기
call <bar> #인자 보내기
ret
<main>:
call <foo> #인자 보내기
ret
Call <mcount@plt>
Call <mcount@plt>
Uftrace
# 함수 호출 기록
# 인자 값 저장하기 대작전
$ gcc foobar.c -o output
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
LLDB with python script : 0.277480 sec
Uftrace record : 0.000532 sec
Compile with –pg : 0.000092 sec
Native : 0.000010 sec
Uftrace performance
동일 작업을 한다고 가정하면, Debugger보다 부하가 월등히 적습니다
Uftrace record with python script : 0.005210 sec
Appendix A. benchmark
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Uftrace visualization
$ uftrace dump --flame-graph -F clone_inlined_nodes > clone_inlined_nodes.flame
$ perl flamegraph.pl clone_inlined_nodes.flame > clone_inlined_nodes.svg
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Uftrace visualization support
$ uftrace dump --chrome -F clone_inlined_nodes > clone_inlined_nodes.json
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Uftrace visualization support
$ uftrace dump --graphviz -F clone_inlined_nodes > clone_inlined_nodes.dot
$ dot -Tpng clone_inlined_nodes.dot > clone_inlined_nodes.png
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Android VM
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Hello World를 출력하는 간단한 샘플 프로그램을 작성하여 Tracing!
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
$ javac Main.java
$ dx --dex --output=classes.dex Main.class
$ zip Main.apk classes.dex
$ uftrace record --auto-args `which dalvikvm64` –cp Main.apk Main
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Results : 1,144,484 lines function call record
1144476 0.088 us [ 99631] | art::FaultManager::~FaultManager();
1144477 0.055 us [ 99631] | std::__1::__vector_base::~__vector_base();
1144478 0.060 us [ 99631] | std::__1::__vector_base::~__vector_base();
1144479 0.054 us [ 99631] | art::JDWP::JdwpOptions::~JdwpOptions();
1144480 0.052 us [ 99631] | std::__1::__vector_base::~__vector_base();
1144481 0.078 us [ 99631] | std::__1::__vector_base::~__vector_base();
1144482 0.053 us [ 99631] | std::__1::unique_ptr::~unique_ptr();
1144483 0.063 us [ 99631] | std::__1::unique_ptr::~unique_ptr();
1144484 0.150 us [ 99631] | std::__1::unique_ptr::~unique_ptr();
1 # DURATION TID FUNCTION
2 [ 99631] | main(4, 0x7ffc2b7a7bb8) {
3 0.595 us [ 99631] | setvbuf();
4 0.922 us [ 99631] | operator new[](48) = 0x55b99858f5b0;
5 0.415 us [ 99631] | memset(0x55b99858f5b0, 0, 48) = 0x55b99858f5b0;
6 147.427 us [ 99631] | strncmp("-cp", "-XXlib:", 7) = 11;
7 0.305 us [ 99631] | strcmp("-cp", "-classpath") = 4;
8 0.166 us [ 99631] | strcmp("-cp", "-cp") = 0;
9 0.198 us [ 99631] | strncmp("Main.apk", "-XXlib:", 7) = 32;
10 0.146 us [ 99631] | strcmp("Main.apk", "-classpath") = 32;
11 0.111 us [ 99631] | strcmp("Main.apk", "-cp") = 32;
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Results : Chrome Tracing Viewer
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Results : Flamegraph
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
당황하지 마세요! 흔한 Interpreter 입니다.
Android VM
HEAP DATA
INTERPRETER
CLASSLOADER
Tables
INPUT
1
Execution
2
OUTPUT
3
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
“Hello world”의 출력은 – 56.6%의 Interpreting과 36.2%의 Class Load으로 이뤄집니다
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Flamegraph는 클릭된 지점에서의 호출 흐름을 보여줍니다
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
몇 번의 클릭으로 Interpreting이 이뤄지는 Path를 찾았습니다
MterpInvokeDirect
art::interpreter::Execute
art::interpreter::ArtInterpreterToInterpreterBridge
art::interpreter::DoCall
Interpreting Path
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Uftrace TUI를 통해 소스 브라우징을 할 수 있다는 것!
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
36.2%의 Class Load, Class 지옥의 주역
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Class가 로드되는 Path를 찾았습니다!
art::ClassLinker::LinkInterfaceMethods
art::ClassLinker::LinkMethods
art::ClassLinker::LinkClass
art::ClassLinker::DefineClass
art::ClassLinker::FindClass
Class Path
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Uftrace TUI를 통해 소스 브라우징! 어메이징!
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
FindClassNoInit
ResolveClass
FindSystemClassNoInit
FindClassNoInit
DexFindClass
LoadClassFromDex
AddClassToHash
LinkClass
LookupClass
Resolved Class
Class
Class
Linking
FindClass
Load Class from
Specific ClassLoader
Interpreter
DefineClass
From
DexFile
Find Class
from Dex
Directly
Tracing for profit
다양한 클래스 생성 과정
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Class를 로드하는 Path를 Tracing 해냈습니다!
INTERPRETER
CLASSLOADER
Android VM
HEAP DATA
Tables
Global Area
Class
Loader
Class
Loader
Loaded
Classes
Class
Loader
Find Class
From
Loaded Classes
1
vtable
ClassObject
static field
iftrable
directMethods
virtualMethods
Method Area
Method
Method
Dex Header
String_ids
Type_ids
Proto_ids
Field_ids
Method_ids
Class_defs
Data
DexFile
Format
Dex
OpenDex
2
DexParse
3
LoadClass
4
Add Class Hash
To
Loaded Classes
5
Parse ClassDef
Load Data
4-1
4-2
Method
Instructions
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for profit
Hello world!
# direct methods
method public constructor <init>()V
.registers 1
.prologue
.line 17
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
method public static main([Ljava/lang/String;)V
.registers 3
.prologue
.line 19
sget-object v0,
Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "Hello, world!"
invoke-virtual {v0, v1},
Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.line 20
return-void
.end method
ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
if (klass.get() == nullptr) {
fprintf(stderr, "Unable to locate class '%s'n", class_name.c_str());
env->ExceptionDescribe();
return EXIT_FAILURE;
}
jmethodID method = env->GetStaticMethodID(klass.get(), "main",
"([Ljava/lang/String;)V");
if (method == nullptr) {
fprintf(stderr, "Unable to find static main(String[]) in '%s'n",
class_name.c_str());
env->ExceptionDescribe();
return EXIT_FAILURE;
}
// Make sure the method is public. JNI doesn't prevent us from
// calling a private method, so we have to check it explicitly.
if (!IsMethodPublic(env, klass.get(), method)) {
fprintf(stderr, "Sorry, main() is not public in '%s'n",
class_name.c_str());
env->ExceptionDescribe();
return EXIT_FAILURE;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing for Fun
Gcc
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
Gcc를 사용해 컴파일 했는데 의도한 대로 동작하지 않는 상황
static inline __attribute__((always_inline)) char *get_msg()
{
char str[64] = "Hello worldn";
return (char *)str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
$ ./compile_by_clang
Hello world
$ ./compile_by_gcc
Segmentation fault (core dumped)
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
push %rbp
mov %rsp,%rbp
sub $0x60,%rsp
lea -0x40(%rbp),%rax
movl $0x0,-0x44(%rbp)
mov %rax,%rcx
movaps 0x103(%rip),%xmm0 # 0x400650
movaps %xmm0,0x30(%rcx)
movaps 0xe8(%rip),%xmm0 # 0x400640
movaps %xmm0,0x20(%rcx)
movaps 0xcd(%rip),%xmm0 # 0x400630
movaps %xmm0,0x10(%rcx)
movaps 0xb2(%rip),%xmm0 # 0x400620
movaps %xmm0,(%rcx)
mov %rax,-0x50(%rbp)
mov -0x50(%rbp),%rdi
mov $0x0,%al
callq 0x400410 <puts@plt>
xor %edx,%edx
mov %eax,-0x54(%rbp)
mov %edx,%eax
add $0x60,%rsp
pop %rbp
retq
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
Tracing For Fun
Clang과 비교해봤습니다
Gcc Clang
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
Gcc 넌 나에게 0을 줬어…
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
Why?
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
코드를 변경해야 하나? #1 – 문자열 포인터 반환으로 변경
static inline __attribute__((always_inline)) char *get_msg()
{
char *str = "Hello worldn";
return str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
코드를 변경해야 하나? #1 – 문자열 포인터를 반환하게 바꾸면 내용을 수정 못함
static inline __attribute__((always_inline)) char *get_msg()
{
char *str = "Hello worldn";
return str;
}
int main()
{
char *p;
p = get_msg();
p[1] = 'a';
puts(p);
return 0;
}
$ ./compile_by_clang
Segmentation fault (core dumped)
$ ./compile_by_gcc
Segmentation fault (core dumped)
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
코드를 변경해야 하나? #1 – “Hallo world”를 출력하고 싶은데요...
static inline __attribute__((always_inline)) char *get_msg()
{
char *str = "Hello worldn";
return str;
}
int main()
{
char *p;
p = get_msg();
p[1] = 'a';
puts(p);
return 0;
}
p[1] = 'a';
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
static inline __attribute__((always_inline)) char *get_msg()
{
char *str = "Hello worldn";
return str;
}
int main()
{
char *p;
p = get_msg();
p[1] = 'a';
puts(p);
return 0;
}
Tracing For Fun
코드를 변경해야 하나? #1 – 문자열은 Const Char * 형으로 Data Section에 저장
$ objdump -s compile_by_gcc
...
Contents of section .rodata:
4005f0 01000200 48656c6c 6f20776f 726c640a ....Hello world.
400600 00
…
Const char *
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
static inline __attribute__((always_inline)) char *get_msg()
{
const char *str = "Hello worldn";
char *p = malloc(strlen(str));
strcpy(p, str);
return p;
}
int main()
{
char *p;
p = get_msg();
puts(p);
free(p);
return 0;
}
Tracing For Fun
코드를 변경해야 하나? #2 – 동적 할당
동적 할당으로 변경하면
해제를 해줘야...
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
재미로 원인 추적하기 - Warning 메시지를 따라가보자
$ gcc inline.c
inline.c: In function ‘get_msg:
inline.c:6:9: warning: function returns address of local variable [-Wreturn-local-addr]
return (char *)str;
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
I love warning message.
10105 tree
10106 c_finish_return (location_t loc, tree retval, tree origtype)
...
10227 case ADDR_EXPR:
10228 inner = TREE_OPERAND (inner, 0);
10229
10230 while (REFERENCE_CLASS_P (inner)
10231 && !INDIRECT_REF_P (inner))
10232 inner = TREE_OPERAND (inner, 0);
10233
10234 if (DECL_P (inner)
10235 && !DECL_EXTERNAL (inner)
10236 && !TREE_STATIC (inner)
10237 && DECL_CONTEXT (inner) == current_function_decl)
10238 {
10239 if (TREE_CODE (inner) == LABEL_DECL)
10240 warning_at (loc, OPT_Wreturn_local_addr,
10241 "function returns address of label");
10242 else
10243 {
10244 warning_at (loc, OPT_Wreturn_local_addr,
10245 "function returns address of local variable");
10246 tree zero = build_zero_cst (TREE_TYPE (res));
10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
10248 }
10249 }
10250 break;
...
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
static inline __attribute__((always_inline))
char *get_msg()
{
char str[64] = "Hello worldn";
}
return
return statement
(char *)str;
operand
Address
Expression?
Valid
Declaration?
!External?
!Static?
Local?
이건 0이 딱이네!
Tracing For Fun
str이 return 시 0이 되는 이유가 이렇습니다.
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
I love warning message.
10105 tree
10106 c_finish_return (location_t loc, tree retval, tree origtype)
...
10227 case ADDR_EXPR:
10228 inner = TREE_OPERAND (inner, 0);
10229
10230 while (REFERENCE_CLASS_P (inner)
10231 && !INDIRECT_REF_P (inner))
10232 inner = TREE_OPERAND (inner, 0);
10233
10234 if (DECL_P (inner)
10235 && !DECL_EXTERNAL (inner)
10236 && !TREE_STATIC (inner)
10237 && DECL_CONTEXT (inner) == current_function_decl)
10238 {
10239 if (TREE_CODE (inner) == LABEL_DECL)
10240 warning_at (loc, OPT_Wreturn_local_addr,
10241 "function returns address of label");
10242 else
10243 {
10244 warning_at (loc, OPT_Wreturn_local_addr,
10245 "function returns address of local variable");
10246 tree zero = build_zero_cst (TREE_TYPE (res));
10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
10248 }
10249 }
10250 break;
...
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
왜 inline function 체크를 하지 않을까요?
(gdb) ptype tree
tree_node {
tree_base base;
tree_typed typed;
tree_common common;
tree_int_cst int_cst;
tree_poly_int_cst poly_int_cst;
tree_real_cst real_cst;
tree_fixed_cst fixed_cst;
tree_vector vector;
tree_string string;
tree_complex complex;
tree_identifier identifier;
tree_decl_minimal decl_minimal;
tree_decl_common decl_common;
tree_decl_with_rtl decl_with_rtl;
tree_decl_non_common decl_non_common;
tree_parm_decl parm_decl;
tree_decl_with_vis decl_with_vis;
tree_var_decl var_decl;
tree_field_decl field_decl;
tree_label_decl label_decl;
tree_result_decl result_decl;
tree_const_decl const_decl;
tree_type_decl type_decl;
tree_function_decl function_decl;
tree_translation_unit_decl translation_unit_decl;
tree_type_common type_common;
tree_type_with_lang_specific type_with_lang_specific;
tree_type_non_common type_non_common;
tree_list list;
tree_vec vec;
tree_exp exp;
tree_ssa_name ssa_name;
tree_block block;
tree_binfo binfo;
tree_statement_list stmt_list;
tree_constructor constructor;
tree_omp_clause omp_clause;
tree_optimization_option optimization;
tree_target_option target_option;
} *
tree_function_decl
function_base
Tree_node 중
function을 관장하는 구조체
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
static inline __attribute__((always_inline))
char *get_msg()
{
char str[64] = "Hello worldn";
}
declared_inline_flag = 1
static_flag = 1
Current_function_decl.function_decl
Tracing For Fun
str이 속한 함수 get_msg에는 inline_flag가 set되어 있습니다
return
return statement
(char *)str;
operand
Address
Expression?
Valid
Declaration?
!External?
!Static?
Local?
이건 0이 딱이네!
static_flag = 0
tree_base base;
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
그래서 한번 바꿔봤습니다!
10227 case ADDR_EXPR:
10228 inner = TREE_OPERAND (inner, 0);
10229
10230 while (REFERENCE_CLASS_P (inner)
10231 && !INDIRECT_REF_P (inner))
10232 inner = TREE_OPERAND (inner, 0);
10233
10234 if (DECL_P (inner)
10235 && !DECL_EXTERNAL (inner)
10237 && !DECL_DECLARED_INLINE_P(current_function_decl)
10236 && !TREE_STATIC (inner)
10237 && DECL_CONTEXT (inner) == current_function_decl)
10238 {
10239 if (TREE_CODE (inner) == LABEL_DECL)
10240 warning_at (loc, OPT_Wreturn_local_addr,
10241 "function returns address of label");
10242 else
10243 {
10244 warning_at (loc, OPT_Wreturn_local_addr,
10245 "function returns address of local variable");
10246 tree zero = build_zero_cst (TREE_TYPE (res));
10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
10248 }
10249 }
10250 break;
if (DECL_P (inner)
&& !DECL_EXTERNAL (inner)
&& !TREE_STATIC (inner)
&& !DECL_DECLARED_INLINE_P(current_function_decl)
&& DECL_CONTEXT (inner) == current_function_decl)
return 될 tree가 속한 함수가
inline 으로 선언되어 있으면
0으로 바꾸지 마세요!
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
이런? 최적화 옵션을 주면 “Hello world”가 출력이 안됩니다!
$ gcc inline.c -o 1st_code_modify
$ ./1st_code_modify
Hello world
$ gcc -O1 inline.c 1st_code_modify
$ ./1st_code_modify
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
sub $0x48,%rsp
mov %rsp,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
add $0x48,%rsp
retq
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
lea -0x50(%rbp),%rax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
Tracing For Fun
디스어셈블을 통해 문제를 파악해 봅시다
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
sub $0x48,%rsp
mov %rsp,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
add $0x48,%rsp
retq
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
lea -0x50(%rbp),%rax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
mov $0x0,%eax lea -0x50(%rbp),%rax
Tracing For Fun
0 이 되버리던 str을 제대로 반환하게 하는데 성공했지만
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
mov $0x0,%eax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
sub $0x48,%rsp
mov %rsp,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
add $0x48,%rsp
retq
push %rbp
mov %rsp,%rbp
sub $0x50,%rsp
movabs $0x6f77206f6c6c6548,%rax
mov $0xa646c72,%edx
mov %rax,-0x50(%rbp)
mov %rdx,-0x48(%rbp)
movq $0x0,-0x40(%rbp)
movq $0x0,-0x38(%rbp)
movq $0x0,-0x30(%rbp)
movq $0x0,-0x28(%rbp)
movq $0x0,-0x20(%rbp)
movq $0x0,-0x18(%rbp)
lea -0x50(%rbp),%rax
mov %rax,-0x8(%rbp)
mov -0x8(%rbp),%rax
mov %rax,%rdi
callq 0x400430 <puts@plt>
mov $0x0,%eax
leaveq
retq
mov $0x0,%eax lea -0x50(%rbp),%rax
int main()
{
char *p;
p = nullptr;
puts(p);
return 0;
}
int main()
{
char str[64] = "Hello worldn";
char *p = str;
puts(p);
return 0;
}
int main()
{
char str[64];
puts(str);
return 0;
}
무슨 일이 벌어진거야?
Tracing For Fun
최적화 옵션을 주면 “Hello world”가 아예 증발됩니다
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
$ gcc –O1 –fdump-tree-all-details inline.c
;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0)
Deleted dead store: str = "Hello worldn";
__attribute__((always_inline)) get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return &str;
}
;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1)
main ()
{
char str[64];
char * D.1810;
char * p;
<bb 2> [100.00%]:
str ={v} {CLOBBER};
puts (&str);
return 0;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0)
Deleted dead store: str = "Hello worldn";
__attribute__((always_inline)) get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return &str;
}
;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1)
main ()
{
char str[64];
char * D.1810;
char * p;
<bb 2> [100.00%]:
str ={v} {CLOBBER};
puts (&str);
return 0;
}
Tracing For Fun
$ gcc –O1 –fdump-tree-all-details inline.c
inline.c.040t.dse1
Deleted dead store: str = "Hello worldn";
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
함수 인자 값을 함께 기록하도록 옵션을 지정하여 Tracing 해봅니다
$ uftrace record --auto-args -A fwrite@arg1/s 
`which gcc` -O1 -fdump-tree-all-details 
inline.c
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
Tracing 결과에서 Deleted dead store 검색하면 위치를 찾을 수 있습니다
$ uftrace replay > replay.log
$ wc -lc replay.log
4157866 line 392760323 charater replay.log
$ grep "Deleted" -B2 replay.log
[110797] | delete_dead_assignment(0x7ffe0825b230) {
[110797] | gsi_stmt();
[110797] | fwrite(" Deleted dead store: ") = 22;
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
Uftrace TUI를 통한 소스 브라우징! - delete_dead_assignment 검색
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
delete_dead_assignment 를 찾았습니다
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
소스코드를 찾을 수 있을 때 까지 U키를 눌러 상위 함수로 이동합니다
dse_dom_walker::dse_optimize_stmt
delete_dead_assignment
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
한 번 더 하면, pass_dse 에 도달하게 됩니다
_GLOBAL__N_1::pass_dse::execute
dse_dom_walker::dse_optimize_stmt
delete_dead_assignment
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
/* This file implements dead store elimination.
A dead store is a store into a memory location which will later be
overwritten by another store without any intervening loads. In this
case the earlier store can be deleted.
In our SSA + virtual operand world we use immediate uses of virtual
operands to detect dead stores. If a store's virtual definition
is used precisely once by a later store to the same location which
post dominates the first store, then the first store is dead.
The single use of the store's virtual definition ensures that
there are no intervening aliased loads and the requirement that
the second load post dominate the first ensures that if the earlier
store executes, then the later stores will execute before the function
exits.
It may help to think of this as first moving the earlier store to
the point immediately before the later store. Again, the single
use of the virtual definition and the post-dominance relationship
ensure that such movement would be safe. Clearly if there are
back to back stores, then the second is redundant.
Reviewing section 10.7.2 in Morgan's "Building an Optimizing Compiler"
may also help in understanding this code since it discusses the
relationship between dead store and redundant load elimination. In
fact, they are the same transformation applied to different views of
the CFG. */
tree-ssa-dse.c
DSE(Dead Store Elimination)
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
최적화 때문이라면 최적화를 하지 못하게 강제하고 비교/확인해 볼까요?
static char *get_msg()
{
char str[64] = "Hello worldn";
return (char *)str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
최적화 때문이라면 최적화를 하지 못하게 강제하고 비교/확인해 볼까요?
static char *get_msg()
{
volatile char str[64] = "Hello worldn";
return (char *)str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
static char *get_msg()
{
char str[64] = "Hello worldn";
return (char *)str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
volatile
메모리 최적화 방지 메모리 최적화
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
$ gcc –O1 –fdump-tree-all-details inline.c
;; Function get_msg (get_msg, funcdef_no=0)
get_msg ()
{
volatile char str[64];
<bb 2> [0.00%]:
str ={v} "Hello worldn";
return 0B;
}
;; Function main (main, funcdef_no=1)
main ()
{
char * p;
<bb 2> [0.00%]:
p_3 = get_msg ();
puts (p_3);
return 0;
}
;; Function get_msg (get_msg, funcdef_no=0)
Deleted dead store: str = "Hello worldn";
get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return 0B;
}
;; Function main (main, funcdef_no=1)
main ()
{
char * p;
<bb 2> [0.00%]:
p_3 = get_msg ();
puts (p_3);
return 0;
}
메모리 최적화 방지 메모리 최적화
inline.c.040t.dse1
Deleted dead store: str = "Hello worldn";
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
$ uftrace graph -D 2 -F dse_dom_walker::dse_optimize_stmt -f none
메모리 최적화 방지 메모리 최적화
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
10227 case ADDR_EXPR:
10228 inner = TREE_OPERAND (inner, 0);
10229
10230 while (REFERENCE_CLASS_P (inner)
10231 && !INDIRECT_REF_P (inner))
10232 inner = TREE_OPERAND (inner, 0);
10233
10234 if (DECL_P (inner)
10235 && !DECL_EXTERNAL (inner)
10236 && !TREE_STATIC (inner)
10237 && DECL_CONTEXT (inner) == current_function_decl)
10238 {
10239 if (TREE_CODE (inner) == LABEL_DECL)
10240 warning_at (loc, OPT_Wreturn_local_addr,
10241 "function returns address of label");
10242 else if (DECL_DECLARED_INLINE_P(current_function_decl))
10243 inner->base.volatile_flag = true;
10244 else
10245 {
10246 warning_at (loc, OPT_Wreturn_local_addr,
10247 "function returns address of local variable");
10248 tree zero = build_zero_cst (TREE_TYPE (res));
10249 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero);
10250 }
10251 }
10252 break;
else if (DECL_DECLARED_INLINE_P(current_function_decl))
inner->base.volatile_flag = true;
return 될 tree가 속한 함수가
inline 으로 선언되어 있으면
0으로 바꾸지 마세요!
+ volatile_flag true set
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Tracing For Fun
실종됐던 Hello world를 되찾았습니다
$ cat inline.c
static inline __attribute__((always_inline))
char *get_msg()
{
char str[64] = "Hello worldn";
return (char *)str;
}
int main()
{
char *p;
p = get_msg();
puts(p);
return 0;
}
$ gcc -O2 inline.c
$ ./a.out
Hello world
Dump of assembler code for function main:
<+4>: movdqa 0x1b4(%rip),%xmm0
<+12>: mov %rsp,%rdi
<+15>: movaps %xmm0,(%rsp)
<+19>: pxor %xmm0,%xmm0
<+23>: movaps %xmm0,0x10(%rsp)
<+28>: movaps %xmm0,0x20(%rsp)
<+33>: movaps %xmm0,0x30(%rsp)
<+38>: callq 0x400400 <puts@plt>
Dump of assembler code for function main:
<+4>: movabs $0x6f77206f6c6c6548,%rax
<+14>: mov $0xa646c72,%edx
<+19>: mov %rax,(%rsp)
<+23>: mov %rdx,0x8(%rsp)
<+28>: movq $0x0,0x10(%rsp)
<+37>: movq $0x0,0x18(%rsp)
<+46>: movq $0x0,0x20(%rsp)
<+55>: movq $0x0,0x28(%rsp)
<+64>: movq $0x0,0x30(%rsp)
<+73>: movq $0x0,0x38(%rsp)
<+82>: mov %rsp,%rdi
<+85>: callq 0x400400 <puts@plt>
-O1
-O2
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
회고
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
문외한도 아는 척 할 수 있는 핵심은 – 가독성!
;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0)
Deleted dead store: str = "Hello worldn";
__attribute__((always_inline)) get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return &str;
}
;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1)
main ()
{
char str[64];
char * D.1810;
char * p;
<bb 2> [100.00%]:
str ={v} {CLOBBER};
puts (&str);
return 0;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0)
Deleted dead store: str = "Hello worldn";
__attribute__((always_inline)) get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return &str;
}
;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1)
main ()
{
char str[64];
char * D.1810;
char * p;
<bb 2> [100.00%]:
str ={v} {CLOBBER};
puts (&str);
return 0;
}
Retrospect
문외한도 아는 척 할 수 있는 핵심은 – 가독성!
(gdb) p *gsi->ptr
$4 = {code = GIMPLE_ASSIGN, no_warning = 0, visited = 0, nontemporal_move = 0, plf
= 1, modified = 0, has_volatile_ops = 0, pad = 0, subcode = 32, uid = 0,
location = 2147483655, num_ops = 2, bb = 0x7ffff6ede478, next = 0x7ffff702d190,
prev = 0x7ffff702d140}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
Gcc를 수정하는 과정에서 관련 지식도 조금 습득했습니다
else if (DECL_DECLARED_INLINE_P(current_function_decl))
inner->base.volatile_flag = true;
GIMPLE RTL
TREE
Abstract IR
Front-End Back-End
Front-end Optimize Pass :
DSE
Volatile
CLOBBER
CONSTRUCOR
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
Android VM에 대한 부분 부분의 지식들이
VM
Interpreter
Bytecode
동작 방식에
대한 이해
DEX 파일
포맷에
대한 지식
Bytecode에
대한 지식
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
Tracing의 과정을 거치면서 연결되게 되면
VM
Interpreter
Bytecode
동작 방식에
대한 이해
DEX 파일
포맷에
대한 지식
Bytecode에
대한 지식
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Retrospect
답답하기만 했던 코드가 이해되는 시원함을 느끼게 됩니다
VM
Interpreter
Bytecode
동작 방식에
대한 이해
DEX 파일
포맷에
대한 지식
Bytecode에
대한 지식
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Conclusion
오픈소스의 접근성을 올려주는 요소
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Conclusion
오픈소스의 역설
AOSP
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Conclusion
오픈소스의 접근성 올리기
Open-source tracing data
API
정보 #1
정보 #2
정보 #3
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Conclusion
오픈소스의 접근성 올리기
Global Declared Classes
Optimization step The actual step to run dse.
The optimization is actually performed when this function is called
A dead store is a store into a memory location which will later be
overwritten by another store without any intervening loads. In this
case the earlier store can be deleted.
=====================================================
[ 32314] | _GLOBAL__N_1::pass_dse::pass_dse() {
29.798 us [ 32314] | } /* _GLOBAL__N_1::pass_dse::pass_dse */
$ uftrace record -S clarity_gcc_opt_path.py `which gcc` -O1 inline.c
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
[ 32314] | _GLOBAL__N_1::pass_dse::pass_dse() {
[ 32314] | } /* _GLOBAL__N_1::pass_dse::pass_dse */
Conclusion
오픈소스의 접근성 올리기
;; Function main (main, funcdef_no=1, decl_uid=1796,
cgraph_uid=1, symbol_order=1)
main ()
{
char str[64];
char * D.1810;
char * p;
<bb 2> [100.00%]:
str ={v} {CLOBBER};
puts (&str);
return 0;
}
;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792,
cgraph_uid=0, symbol_order=0)
Deleted dead store: str = "Hello worldn";
__attribute__((always_inline)) get_msg ()
{
char str[64];
<bb 2> [0.00%]:
str ={v} {CLOBBER};
return &str;
}
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Conclusion
똑같은 장벽을 올라야 하더라도…
AOSP
SOSCON 2018
SAMSUNG OPEN SOURCE CONFERENCE 2018
THANK YOU
Uftrace repository
https://github.com/namhyung/uftrace
SOSCON 2018
SAMSUNG OPEN SOURCE CONFERENCE 2018
Any Question?
Uftrace repository
https://github.com/namhyung/uftrace
SOSCON
SAMSUNG OPEN SOURCE CONFERENCE 2018
Appendix A. benchmark
#include <stdio.h>
#include <time.h>
void callme(int *r)
{
(*r)++;
}
int main()
{
clock_t begin = clock();
for(int i=0;i<0xFFF;)
{
callme(&i);
}
clock_t end = clock();
printf("Elapsed: %lf secondsn", (double)(end - begin) / CLOCKS_PER_SEC);
return 0;
}
Target Source LLDB python script
https://github.com/ParkHanbum/lldb_tracer

More Related Content

What's hot

The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196Mahmoud Samir Fayed
 
Pads lab manual final
Pads lab manual finalPads lab manual final
Pads lab manual finalAhalyaR
 
Global Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the SealGlobal Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the SealTzung-Bi Shih
 
Network lap pgms 7th semester
Network lap pgms 7th semesterNetwork lap pgms 7th semester
Network lap pgms 7th semesterDOSONKA Group
 
Network lab manual
Network lab manualNetwork lab manual
Network lab manualPrabhu D
 
Inheritance and polymorphism
Inheritance and polymorphismInheritance and polymorphism
Inheritance and polymorphismmohamed sikander
 
What's New In C# 5.0 - Rumos InsideOut
What's New In C# 5.0 - Rumos InsideOutWhat's New In C# 5.0 - Rumos InsideOut
What's New In C# 5.0 - Rumos InsideOutPaulo Morgado
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesAndrey Karpov
 
C++ Programming - 11th Study
C++ Programming - 11th StudyC++ Programming - 11th Study
C++ Programming - 11th StudyChris Ohk
 
Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Miłosz Sobczak
 

What's hot (20)

Clang tidy
Clang tidyClang tidy
Clang tidy
 
C++ file
C++ fileC++ file
C++ file
 
Joel Falcou, Boost.SIMD
Joel Falcou, Boost.SIMDJoel Falcou, Boost.SIMD
Joel Falcou, Boost.SIMD
 
The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196
 
Pads lab manual final
Pads lab manual finalPads lab manual final
Pads lab manual final
 
Global Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the SealGlobal Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the Seal
 
informatics practices practical file
informatics practices practical fileinformatics practices practical file
informatics practices practical file
 
C++ aptitude
C++ aptitudeC++ aptitude
C++ aptitude
 
Network lap pgms 7th semester
Network lap pgms 7th semesterNetwork lap pgms 7th semester
Network lap pgms 7th semester
 
Network lab manual
Network lab manualNetwork lab manual
Network lab manual
 
Inheritance and polymorphism
Inheritance and polymorphismInheritance and polymorphism
Inheritance and polymorphism
 
C&cpu
C&cpuC&cpu
C&cpu
 
C++ manual Report Full
C++ manual Report FullC++ manual Report Full
C++ manual Report Full
 
C programs
C programsC programs
C programs
 
C++17 now
C++17 nowC++17 now
C++17 now
 
What's New In C# 5.0 - Rumos InsideOut
What's New In C# 5.0 - Rumos InsideOutWhat's New In C# 5.0 - Rumos InsideOut
What's New In C# 5.0 - Rumos InsideOut
 
C program
C programC program
C program
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
 
C++ Programming - 11th Study
C++ Programming - 11th StudyC++ Programming - 11th Study
C++ Programming - 11th Study
 
Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()Ecmascript 2015 – best of new features()
Ecmascript 2015 – best of new features()
 

Similar to soscon2018 - Tracing for fun and profit

"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav DukhinFwdays
 
MunichJS - node.js - from the beginning
MunichJS - node.js - from the beginningMunichJS - node.js - from the beginning
MunichJS - node.js - from the beginningRobert Prediger
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaBabacar NIANG
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every dayVadym Khondar
 
node.js - Eventful JavaScript on the Server
node.js - Eventful JavaScript on the Servernode.js - Eventful JavaScript on the Server
node.js - Eventful JavaScript on the ServerDavid Ruiz
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
E.D.D.I - Open Source Chatbot Platform
E.D.D.I - Open Source Chatbot PlatformE.D.D.I - Open Source Chatbot Platform
E.D.D.I - Open Source Chatbot PlatformGregor Jarisch
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0Eugenio Romano
 
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswanivvaswani
 
High Performance NodeJS
High Performance NodeJSHigh Performance NodeJS
High Performance NodeJSDicoding
 
The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...Karthik Murugesan
 
Timings API: Performance Assertion during the functional testing
 Timings API: Performance Assertion during the functional testing Timings API: Performance Assertion during the functional testing
Timings API: Performance Assertion during the functional testingPetrosPlakogiannis
 
React Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsMatteo Manchi
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP AnywayI Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP AnywayAll Things Open
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...Codemotion
 

Similar to soscon2018 - Tracing for fun and profit (20)

"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
 
MunichJS - node.js - from the beginning
MunichJS - node.js - from the beginningMunichJS - node.js - from the beginning
MunichJS - node.js - from the beginning
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux Saga
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Hexagonal architecture
Hexagonal architectureHexagonal architecture
Hexagonal architecture
 
Nativescript with angular 2
Nativescript with angular 2Nativescript with angular 2
Nativescript with angular 2
 
node.js - Eventful JavaScript on the Server
node.js - Eventful JavaScript on the Servernode.js - Eventful JavaScript on the Server
node.js - Eventful JavaScript on the Server
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
E.D.D.I - Open Source Chatbot Platform
E.D.D.I - Open Source Chatbot PlatformE.D.D.I - Open Source Chatbot Platform
E.D.D.I - Open Source Chatbot Platform
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
 
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
 
High Performance NodeJS
High Performance NodeJSHigh Performance NodeJS
High Performance NodeJS
 
The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...
 
Android development
Android developmentAndroid development
Android development
 
Timings API: Performance Assertion during the functional testing
 Timings API: Performance Assertion during the functional testing Timings API: Performance Assertion during the functional testing
Timings API: Performance Assertion during the functional testing
 
Mobile optimization
Mobile optimizationMobile optimization
Mobile optimization
 
React Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applications
 
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP AnywayI Know It Was MEAN, But I Cut the Cord to LAMP Anyway
I Know It Was MEAN, But I Cut the Cord to LAMP Anyway
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
 

More from hanbeom Park

DEVIEW-FULL-감독판.pptx
DEVIEW-FULL-감독판.pptxDEVIEW-FULL-감독판.pptx
DEVIEW-FULL-감독판.pptxhanbeom Park
 
Android Native Module 안정적으로 개발하기
Android Native Module 안정적으로 개발하기Android Native Module 안정적으로 개발하기
Android Native Module 안정적으로 개발하기hanbeom Park
 
Deview 2019 눈발자국
Deview 2019 눈발자국Deview 2019 눈발자국
Deview 2019 눈발자국hanbeom Park
 
Project turtle ship
Project turtle shipProject turtle ship
Project turtle shiphanbeom Park
 
가상화와 보안 발표자료
가상화와 보안 발표자료가상화와 보안 발표자료
가상화와 보안 발표자료hanbeom Park
 
Virtualization technology for security
Virtualization technology for securityVirtualization technology for security
Virtualization technology for securityhanbeom Park
 

More from hanbeom Park (6)

DEVIEW-FULL-감독판.pptx
DEVIEW-FULL-감독판.pptxDEVIEW-FULL-감독판.pptx
DEVIEW-FULL-감독판.pptx
 
Android Native Module 안정적으로 개발하기
Android Native Module 안정적으로 개발하기Android Native Module 안정적으로 개발하기
Android Native Module 안정적으로 개발하기
 
Deview 2019 눈발자국
Deview 2019 눈발자국Deview 2019 눈발자국
Deview 2019 눈발자국
 
Project turtle ship
Project turtle shipProject turtle ship
Project turtle ship
 
가상화와 보안 발표자료
가상화와 보안 발표자료가상화와 보안 발표자료
가상화와 보안 발표자료
 
Virtualization technology for security
Virtualization technology for securityVirtualization technology for security
Virtualization technology for security
 

Recently uploaded

SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 

Recently uploaded (20)

SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 

soscon2018 - Tracing for fun and profit

  • 1. SOSCON 2018 SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing the C/C++ open-sources for profit and fun C/C++ 오픈소스를 Tracing 하면 얻을 수 있는 것들 HANBUM PARK
  • 2. SOSCON 2018 SAMSUNG OPEN SOURCE CONFERENCE 2018 HANBUM PARK KOSSLAB OPEN-FRONTIER Uftrace Contributor Reverse-Engineer
  • 3. SOSCON 2018 SAMSUNG OPEN SOURCE CONFERENCE 2018 The stories I want to share. • Introduction • Motivation • Uftrace • Tracing for profit – Android VM • Tracing for fun – Gcc • Retrospect • Conclusion CONTENTS
  • 4. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce Tracing 사례 살펴보기
  • 5. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Native 함수 호출을 통한 연산이 순수 Javascript보다 느린 경우 DOMMatrix perf (https://jsperf.com/dommatrix-perf/9) JS Obj equivalent JS equivalent JS equivalent + DOM access JS equivalent with floatArray JS equivalent with floatArray + DOM access JS with Native-Function call 55 Operation per second (higher is better) 44 43 5 14 32
  • 6. Tracing case study – Node.js Uftrace로 Tracing 한 후 결과 로그를 통해 이유를 확인할 수 있습니다 Jinho bang - chromium binding 기술을 node.js에 적용해보자 (DEVIEW 2017)
  • 7. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Sum이란 함수로 배열 안의 값들의 합을 구한다고 가정합시다 let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]);
  • 8. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js 배열 안의 값들에 합을 구하는 Sum 함수 – Javascript function sum(elements) { let s = 0; elements.forEach(element => { s += element; }); return s; }
  • 9. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js 배열 안의 값들에 합을 구하는 Sum 함수 – Node.js N-API napi_value Sum(napi_env, napi_callback_info info) { } for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum;
  • 10. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js 배열 안의 값들에 합을 구하는 Sum 함수는 두 부분으로 이뤄집니다 napi_value Sum(napi_env, napi_callback_info info) { } for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; 연산 반환
  • 11. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Javascript 단에 저장된 값을 Native에서 사용하기 위해 읽어와야 합니다 napi_value Sum(napi_env, napi_callback_info info) { } for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; Get Javascript value napi_value element; napi_get_element(env, i, &element);
  • 12. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js 이 과정에서 Javascript의 값에 대한 Type을 체크해야 합니다 napi_value Sum(napi_env, napi_callback_info info) { } for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; Type checking napi_valuetype valuetype; napi_typeof(env, element, &valuetype);
  • 13. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Native에서 연산이 끝났으면, 결과 값을 Javascript에서 사용가능한 타입으로 바꿔야 합니다 napi_value Sum(napi_env, napi_callback_info info) { } for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; napi_valuetype valuetype; napi_typeof(env, element, &valuetype); Type converting
  • 14. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Resolve : Chromium WebIDL to Node.js – automatic binding and checking // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); }; // Native Code class Calculator { public: double Sum(std::vector<int> elements) { int sum = 0; for (int i = 0; I < elements.size(); i++) sum += elements[i]; return sum; } }; // N-API napi_value Sum(napi_env, napi_callback_info info) { for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; }
  • 15. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Resolve : Chromium WebIDL to Node.js – ignore type checking // WebIDL [Constructor] interface Calculator { [NoTypeChecking] double sum(sequence<long> elements); }; // Native Code class Calculator { public: double Sum(std::vector<int> elements) { int sum = 0; for (int i = 0; I < elements.size(); i++) sum += elements[i]; return sum; } }; // N-API napi_value Sum(napi_env, napi_callback_info info) { for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; }
  • 16. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js 방진호님은 WebIDL을 Node.js에 제의하였으며 개발… Project Bacardi https://github.com/lunchclass/bacardi
  • 17. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing case study – Node.js Tracing, “프로그램의 실행 동안의 변화를 다각도로 기록하고 이를 검토하는 일”
  • 18. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 시간은 금이라고 친구 Motivation
  • 19. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation Android에서 새 App이 구동되는 순서 Zygote Application DalvikVM Android OS (Managers) JNI_CreateJavaVM 2 ActivityThread & Looper 3 attachApplication 4 bindApplication 5 Find Application Class & Create new Instance & Call attachBaseContext 6 Fork and Register PID 1
  • 20. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation Zygote Android OS (Managers) ActivityThread & Looper 3 attachApplication 4 bindApplication 5 Find Application Class & Create new Instance & Call attachBaseContext 6 Fork and Register PID 1 Application DalvikVM JNI_CreateJavaVM 2 Resources DEX 새 VM을 만들 때 APK가 인자로 전달
  • 21. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation Zygote Android OS (Managers) ActivityThread & Looper 3 attachApplication 4 bindApplication 5 Find Application Class & Create new Instance & Call attachBaseContext 6 Fork and Register PID 1 Application DalvikVM JNI_CreateJavaVM 2 Resources method public static main([Ljava/lang/String;)V .registers 3 .prologue .line 19 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "Hello, world!" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V .line 20 return-void .end method DEX DEX는 Bytecode로 코드로 이루어져 소스코드 노출이 쉽다!
  • 22. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation Zygote Android OS (Managers) ActivityThread & Looper 3 attachApplication 4 bindApplication 5 Find Application Class & Create new Instance & Call attachBaseContext 6 Fork and Register PID 1 Application DalvikVM JNI_CreateJavaVM 2 Resources method public static main([Ljava/lang/String;)V .registers 3 .prologue .line 19 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "Hello, world!" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V .line 20 return-void .end method DEX DEX의 보호 방안 찾기 대작전! 원본 DEX를 보호하는 메커니즘의 필요
  • 23. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation You are right always EntryPoint Android Open Source Project
  • 24. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Language Files Blank Comment Code Line C 708 22952 28339 95886 C++ 735 44751 49065 325759 Motivation Everything grow up, except my salary AOSP - art
  • 25. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation 분석의 시작은 CC 형제, Ctags + Cscope와 함께 시작했습니다만 LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass
  • 26. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation 분석의 시작은 CC 형제, Ctags + Cscope와 함께 시작했습니다만 LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass LookupClass ResolveClass FindClassNoInit FindClass DefineClass LoadClass LinkClass ResolveClass
  • 27. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation – time is gold, friends You are right always, but need time EntryPoint Android Open Source Project
  • 28. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation – time is gold, friends Reverse Engineer을 하는 일반적인 방식 #1 Process Disk Network Memory Binary API
  • 29. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation – time is gold, friends Reverse Engineer을 하는 일반적인 방식 #2 Process Disk Network Memory Binary API Logging Monitoring Record
  • 30. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation – time is gold, friends Reverse Engineer을 하는 일반적인 방식 #3 Process Disk Network Memory API Record Binary API Catch Event Logging Monitoring FOUND Logic !!
  • 31. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Motivation – time is gold, friends 프로그램의 실행을 흐름을 로깅하면 분석에 필요한 최소 로직을 추려낼 수 있습니다 Android Open Source Project Binary API dalvikvm
  • 32. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Uftrace Function tracer for user-space
  • 33. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE 일반적인 컴파일 결과 void bar() { } void foo() { bar(); } int main() { foo(); } <bar>: ret <foo>: call <bar> ret <main>: call <foo> ret $ gcc foobar.c
  • 34. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE -pg 옵션으로 컴파일 했을 때의 결과 void bar() { } void foo() { bar(); } int main() { foo(); } <bar>: call <mcount@plt> ret <foo>: call <mcount@plt> call <bar> ret <main>: call <mcount@plt> call <foo> ret $ gcc –pg foobar.c
  • 35. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE -pg로 컴파일 하면 컴파일러가 mcount 호출을 생성해 줍니다 <bar>: call <mcount@plt> ret <foo>: call <mcount@plt> call <bar> ret <main>: call <mcount@plt> call <foo> ret <mcount@plt>: # record callee position ret
  • 36. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE 함수 간에는 인자 값을 전달하는 방식은 약속되어 있습니다 void bar(int arg) { } void foo(int arg) { bar(arg); } int main() { foo(0x10); } <bar>: # 인자 값 받기 ret <foo>: # 인자 값 받기 call <bar> #인자 보내기 ret <main>: call <foo> #인자 보내기 ret $ gcc foobar.c -o output
  • 37. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE 함수 간에는 인자 값을 전달하는 방식은 약속되어 있습니다 void bar(int arg) { } void foo(int arg) { bar(arg); } int main() { foo(0x10); } <bar>: # 인자 값 받기 ret <foo>: # 인자 값 받기 call <bar> #인자 보내기 ret <main>: call <foo> #인자 보내기 ret $ gcc foobar.c -o output Calling Convention - 인자 값 전달 - 호출 지점으로 복귀
  • 38. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Introduce UFTRACE 호출 규약에 지정된 레지스터, 메모리를 읽어 인자 값을 알아낼 수 있습니다 <bar>: # 인자 값 받기 ret <foo>: # 인자 값 받기 call <bar> #인자 보내기 ret <main>: call <foo> #인자 보내기 ret Call <mcount@plt> Call <mcount@plt> Uftrace # 함수 호출 기록 # 인자 값 저장하기 대작전 $ gcc foobar.c -o output
  • 39. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 LLDB with python script : 0.277480 sec Uftrace record : 0.000532 sec Compile with –pg : 0.000092 sec Native : 0.000010 sec Uftrace performance 동일 작업을 한다고 가정하면, Debugger보다 부하가 월등히 적습니다 Uftrace record with python script : 0.005210 sec Appendix A. benchmark
  • 40. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Uftrace visualization $ uftrace dump --flame-graph -F clone_inlined_nodes > clone_inlined_nodes.flame $ perl flamegraph.pl clone_inlined_nodes.flame > clone_inlined_nodes.svg
  • 41. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Uftrace visualization support $ uftrace dump --chrome -F clone_inlined_nodes > clone_inlined_nodes.json
  • 42. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Uftrace visualization support $ uftrace dump --graphviz -F clone_inlined_nodes > clone_inlined_nodes.dot $ dot -Tpng clone_inlined_nodes.dot > clone_inlined_nodes.png
  • 43. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Android VM
  • 44. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Hello World를 출력하는 간단한 샘플 프로그램을 작성하여 Tracing! public class Main { public static void main(String[] args) { System.out.println("Hello World!"); } } $ javac Main.java $ dx --dex --output=classes.dex Main.class $ zip Main.apk classes.dex $ uftrace record --auto-args `which dalvikvm64` –cp Main.apk Main
  • 45. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Results : 1,144,484 lines function call record 1144476 0.088 us [ 99631] | art::FaultManager::~FaultManager(); 1144477 0.055 us [ 99631] | std::__1::__vector_base::~__vector_base(); 1144478 0.060 us [ 99631] | std::__1::__vector_base::~__vector_base(); 1144479 0.054 us [ 99631] | art::JDWP::JdwpOptions::~JdwpOptions(); 1144480 0.052 us [ 99631] | std::__1::__vector_base::~__vector_base(); 1144481 0.078 us [ 99631] | std::__1::__vector_base::~__vector_base(); 1144482 0.053 us [ 99631] | std::__1::unique_ptr::~unique_ptr(); 1144483 0.063 us [ 99631] | std::__1::unique_ptr::~unique_ptr(); 1144484 0.150 us [ 99631] | std::__1::unique_ptr::~unique_ptr(); 1 # DURATION TID FUNCTION 2 [ 99631] | main(4, 0x7ffc2b7a7bb8) { 3 0.595 us [ 99631] | setvbuf(); 4 0.922 us [ 99631] | operator new[](48) = 0x55b99858f5b0; 5 0.415 us [ 99631] | memset(0x55b99858f5b0, 0, 48) = 0x55b99858f5b0; 6 147.427 us [ 99631] | strncmp("-cp", "-XXlib:", 7) = 11; 7 0.305 us [ 99631] | strcmp("-cp", "-classpath") = 4; 8 0.166 us [ 99631] | strcmp("-cp", "-cp") = 0; 9 0.198 us [ 99631] | strncmp("Main.apk", "-XXlib:", 7) = 32; 10 0.146 us [ 99631] | strcmp("Main.apk", "-classpath") = 32; 11 0.111 us [ 99631] | strcmp("Main.apk", "-cp") = 32;
  • 46. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Results : Chrome Tracing Viewer
  • 47. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Results : Flamegraph
  • 48. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit 당황하지 마세요! 흔한 Interpreter 입니다. Android VM HEAP DATA INTERPRETER CLASSLOADER Tables INPUT 1 Execution 2 OUTPUT 3
  • 49. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit “Hello world”의 출력은 – 56.6%의 Interpreting과 36.2%의 Class Load으로 이뤄집니다
  • 50. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Flamegraph는 클릭된 지점에서의 호출 흐름을 보여줍니다
  • 51. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit 몇 번의 클릭으로 Interpreting이 이뤄지는 Path를 찾았습니다 MterpInvokeDirect art::interpreter::Execute art::interpreter::ArtInterpreterToInterpreterBridge art::interpreter::DoCall Interpreting Path
  • 52. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Uftrace TUI를 통해 소스 브라우징을 할 수 있다는 것!
  • 53. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit 36.2%의 Class Load, Class 지옥의 주역
  • 54. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Class가 로드되는 Path를 찾았습니다! art::ClassLinker::LinkInterfaceMethods art::ClassLinker::LinkMethods art::ClassLinker::LinkClass art::ClassLinker::DefineClass art::ClassLinker::FindClass Class Path
  • 55. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Uftrace TUI를 통해 소스 브라우징! 어메이징!
  • 56. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 FindClassNoInit ResolveClass FindSystemClassNoInit FindClassNoInit DexFindClass LoadClassFromDex AddClassToHash LinkClass LookupClass Resolved Class Class Class Linking FindClass Load Class from Specific ClassLoader Interpreter DefineClass From DexFile Find Class from Dex Directly Tracing for profit 다양한 클래스 생성 과정
  • 57. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Class를 로드하는 Path를 Tracing 해냈습니다! INTERPRETER CLASSLOADER Android VM HEAP DATA Tables Global Area Class Loader Class Loader Loaded Classes Class Loader Find Class From Loaded Classes 1 vtable ClassObject static field iftrable directMethods virtualMethods Method Area Method Method Dex Header String_ids Type_ids Proto_ids Field_ids Method_ids Class_defs Data DexFile Format Dex OpenDex 2 DexParse 3 LoadClass 4 Add Class Hash To Loaded Classes 5 Parse ClassDef Load Data 4-1 4-2 Method Instructions
  • 58. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for profit Hello world! # direct methods method public constructor <init>()V .registers 1 .prologue .line 17 invoke-direct {p0}, Ljava/lang/Object;-><init>()V return-void .end method method public static main([Ljava/lang/String;)V .registers 3 .prologue .line 19 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; const-string v1, "Hello, world!" invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V .line 20 return-void .end method ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str())); if (klass.get() == nullptr) { fprintf(stderr, "Unable to locate class '%s'n", class_name.c_str()); env->ExceptionDescribe(); return EXIT_FAILURE; } jmethodID method = env->GetStaticMethodID(klass.get(), "main", "([Ljava/lang/String;)V"); if (method == nullptr) { fprintf(stderr, "Unable to find static main(String[]) in '%s'n", class_name.c_str()); env->ExceptionDescribe(); return EXIT_FAILURE; } // Make sure the method is public. JNI doesn't prevent us from // calling a private method, so we have to check it explicitly. if (!IsMethodPublic(env, klass.get(), method)) { fprintf(stderr, "Sorry, main() is not public in '%s'n", class_name.c_str()); env->ExceptionDescribe(); return EXIT_FAILURE; }
  • 59. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing for Fun Gcc
  • 60. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun Gcc를 사용해 컴파일 했는데 의도한 대로 동작하지 않는 상황 static inline __attribute__((always_inline)) char *get_msg() { char str[64] = "Hello worldn"; return (char *)str; } int main() { char *p; p = get_msg(); puts(p); return 0; } $ ./compile_by_clang Hello world $ ./compile_by_gcc Segmentation fault (core dumped)
  • 61. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 push %rbp mov %rsp,%rbp sub $0x60,%rsp lea -0x40(%rbp),%rax movl $0x0,-0x44(%rbp) mov %rax,%rcx movaps 0x103(%rip),%xmm0 # 0x400650 movaps %xmm0,0x30(%rcx) movaps 0xe8(%rip),%xmm0 # 0x400640 movaps %xmm0,0x20(%rcx) movaps 0xcd(%rip),%xmm0 # 0x400630 movaps %xmm0,0x10(%rcx) movaps 0xb2(%rip),%xmm0 # 0x400620 movaps %xmm0,(%rcx) mov %rax,-0x50(%rbp) mov -0x50(%rbp),%rdi mov $0x0,%al callq 0x400410 <puts@plt> xor %edx,%edx mov %eax,-0x54(%rbp) mov %edx,%eax add $0x60,%rsp pop %rbp retq push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq Tracing For Fun Clang과 비교해봤습니다 Gcc Clang
  • 62. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun Gcc 넌 나에게 0을 줬어… push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi Why?
  • 63. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 코드를 변경해야 하나? #1 – 문자열 포인터 반환으로 변경 static inline __attribute__((always_inline)) char *get_msg() { char *str = "Hello worldn"; return str; } int main() { char *p; p = get_msg(); puts(p); return 0; }
  • 64. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 코드를 변경해야 하나? #1 – 문자열 포인터를 반환하게 바꾸면 내용을 수정 못함 static inline __attribute__((always_inline)) char *get_msg() { char *str = "Hello worldn"; return str; } int main() { char *p; p = get_msg(); p[1] = 'a'; puts(p); return 0; } $ ./compile_by_clang Segmentation fault (core dumped) $ ./compile_by_gcc Segmentation fault (core dumped)
  • 65. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 코드를 변경해야 하나? #1 – “Hallo world”를 출력하고 싶은데요... static inline __attribute__((always_inline)) char *get_msg() { char *str = "Hello worldn"; return str; } int main() { char *p; p = get_msg(); p[1] = 'a'; puts(p); return 0; } p[1] = 'a';
  • 66. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 static inline __attribute__((always_inline)) char *get_msg() { char *str = "Hello worldn"; return str; } int main() { char *p; p = get_msg(); p[1] = 'a'; puts(p); return 0; } Tracing For Fun 코드를 변경해야 하나? #1 – 문자열은 Const Char * 형으로 Data Section에 저장 $ objdump -s compile_by_gcc ... Contents of section .rodata: 4005f0 01000200 48656c6c 6f20776f 726c640a ....Hello world. 400600 00 … Const char *
  • 67. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 static inline __attribute__((always_inline)) char *get_msg() { const char *str = "Hello worldn"; char *p = malloc(strlen(str)); strcpy(p, str); return p; } int main() { char *p; p = get_msg(); puts(p); free(p); return 0; } Tracing For Fun 코드를 변경해야 하나? #2 – 동적 할당 동적 할당으로 변경하면 해제를 해줘야...
  • 68. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 재미로 원인 추적하기 - Warning 메시지를 따라가보자 $ gcc inline.c inline.c: In function ‘get_msg: inline.c:6:9: warning: function returns address of local variable [-Wreturn-local-addr] return (char *)str;
  • 69. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun I love warning message. 10105 tree 10106 c_finish_return (location_t loc, tree retval, tree origtype) ... 10227 case ADDR_EXPR: 10228 inner = TREE_OPERAND (inner, 0); 10229 10230 while (REFERENCE_CLASS_P (inner) 10231 && !INDIRECT_REF_P (inner)) 10232 inner = TREE_OPERAND (inner, 0); 10233 10234 if (DECL_P (inner) 10235 && !DECL_EXTERNAL (inner) 10236 && !TREE_STATIC (inner) 10237 && DECL_CONTEXT (inner) == current_function_decl) 10238 { 10239 if (TREE_CODE (inner) == LABEL_DECL) 10240 warning_at (loc, OPT_Wreturn_local_addr, 10241 "function returns address of label"); 10242 else 10243 { 10244 warning_at (loc, OPT_Wreturn_local_addr, 10245 "function returns address of local variable"); 10246 tree zero = build_zero_cst (TREE_TYPE (res)); 10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); 10248 } 10249 } 10250 break; ...
  • 70. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 static inline __attribute__((always_inline)) char *get_msg() { char str[64] = "Hello worldn"; } return return statement (char *)str; operand Address Expression? Valid Declaration? !External? !Static? Local? 이건 0이 딱이네! Tracing For Fun str이 return 시 0이 되는 이유가 이렇습니다.
  • 71. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun I love warning message. 10105 tree 10106 c_finish_return (location_t loc, tree retval, tree origtype) ... 10227 case ADDR_EXPR: 10228 inner = TREE_OPERAND (inner, 0); 10229 10230 while (REFERENCE_CLASS_P (inner) 10231 && !INDIRECT_REF_P (inner)) 10232 inner = TREE_OPERAND (inner, 0); 10233 10234 if (DECL_P (inner) 10235 && !DECL_EXTERNAL (inner) 10236 && !TREE_STATIC (inner) 10237 && DECL_CONTEXT (inner) == current_function_decl) 10238 { 10239 if (TREE_CODE (inner) == LABEL_DECL) 10240 warning_at (loc, OPT_Wreturn_local_addr, 10241 "function returns address of label"); 10242 else 10243 { 10244 warning_at (loc, OPT_Wreturn_local_addr, 10245 "function returns address of local variable"); 10246 tree zero = build_zero_cst (TREE_TYPE (res)); 10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); 10248 } 10249 } 10250 break; ... mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi
  • 72. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 왜 inline function 체크를 하지 않을까요? (gdb) ptype tree tree_node { tree_base base; tree_typed typed; tree_common common; tree_int_cst int_cst; tree_poly_int_cst poly_int_cst; tree_real_cst real_cst; tree_fixed_cst fixed_cst; tree_vector vector; tree_string string; tree_complex complex; tree_identifier identifier; tree_decl_minimal decl_minimal; tree_decl_common decl_common; tree_decl_with_rtl decl_with_rtl; tree_decl_non_common decl_non_common; tree_parm_decl parm_decl; tree_decl_with_vis decl_with_vis; tree_var_decl var_decl; tree_field_decl field_decl; tree_label_decl label_decl; tree_result_decl result_decl; tree_const_decl const_decl; tree_type_decl type_decl; tree_function_decl function_decl; tree_translation_unit_decl translation_unit_decl; tree_type_common type_common; tree_type_with_lang_specific type_with_lang_specific; tree_type_non_common type_non_common; tree_list list; tree_vec vec; tree_exp exp; tree_ssa_name ssa_name; tree_block block; tree_binfo binfo; tree_statement_list stmt_list; tree_constructor constructor; tree_omp_clause omp_clause; tree_optimization_option optimization; tree_target_option target_option; } * tree_function_decl function_base Tree_node 중 function을 관장하는 구조체
  • 73. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 static inline __attribute__((always_inline)) char *get_msg() { char str[64] = "Hello worldn"; } declared_inline_flag = 1 static_flag = 1 Current_function_decl.function_decl Tracing For Fun str이 속한 함수 get_msg에는 inline_flag가 set되어 있습니다 return return statement (char *)str; operand Address Expression? Valid Declaration? !External? !Static? Local? 이건 0이 딱이네! static_flag = 0 tree_base base;
  • 74. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 그래서 한번 바꿔봤습니다! 10227 case ADDR_EXPR: 10228 inner = TREE_OPERAND (inner, 0); 10229 10230 while (REFERENCE_CLASS_P (inner) 10231 && !INDIRECT_REF_P (inner)) 10232 inner = TREE_OPERAND (inner, 0); 10233 10234 if (DECL_P (inner) 10235 && !DECL_EXTERNAL (inner) 10237 && !DECL_DECLARED_INLINE_P(current_function_decl) 10236 && !TREE_STATIC (inner) 10237 && DECL_CONTEXT (inner) == current_function_decl) 10238 { 10239 if (TREE_CODE (inner) == LABEL_DECL) 10240 warning_at (loc, OPT_Wreturn_local_addr, 10241 "function returns address of label"); 10242 else 10243 { 10244 warning_at (loc, OPT_Wreturn_local_addr, 10245 "function returns address of local variable"); 10246 tree zero = build_zero_cst (TREE_TYPE (res)); 10247 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); 10248 } 10249 } 10250 break; if (DECL_P (inner) && !DECL_EXTERNAL (inner) && !TREE_STATIC (inner) && !DECL_DECLARED_INLINE_P(current_function_decl) && DECL_CONTEXT (inner) == current_function_decl) return 될 tree가 속한 함수가 inline 으로 선언되어 있으면 0으로 바꾸지 마세요!
  • 75. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 이런? 최적화 옵션을 주면 “Hello world”가 출력이 안됩니다! $ gcc inline.c -o 1st_code_modify $ ./1st_code_modify Hello world $ gcc -O1 inline.c 1st_code_modify $ ./1st_code_modify
  • 76. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq sub $0x48,%rsp mov %rsp,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax add $0x48,%rsp retq push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) lea -0x50(%rbp),%rax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq Tracing For Fun 디스어셈블을 통해 문제를 파악해 봅시다
  • 77. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq sub $0x48,%rsp mov %rsp,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax add $0x48,%rsp retq push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) lea -0x50(%rbp),%rax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq mov $0x0,%eax lea -0x50(%rbp),%rax Tracing For Fun 0 이 되버리던 str을 제대로 반환하게 하는데 성공했지만
  • 78. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) mov $0x0,%eax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq sub $0x48,%rsp mov %rsp,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax add $0x48,%rsp retq push %rbp mov %rsp,%rbp sub $0x50,%rsp movabs $0x6f77206f6c6c6548,%rax mov $0xa646c72,%edx mov %rax,-0x50(%rbp) mov %rdx,-0x48(%rbp) movq $0x0,-0x40(%rbp) movq $0x0,-0x38(%rbp) movq $0x0,-0x30(%rbp) movq $0x0,-0x28(%rbp) movq $0x0,-0x20(%rbp) movq $0x0,-0x18(%rbp) lea -0x50(%rbp),%rax mov %rax,-0x8(%rbp) mov -0x8(%rbp),%rax mov %rax,%rdi callq 0x400430 <puts@plt> mov $0x0,%eax leaveq retq mov $0x0,%eax lea -0x50(%rbp),%rax int main() { char *p; p = nullptr; puts(p); return 0; } int main() { char str[64] = "Hello worldn"; char *p = str; puts(p); return 0; } int main() { char str[64]; puts(str); return 0; } 무슨 일이 벌어진거야? Tracing For Fun 최적화 옵션을 주면 “Hello world”가 아예 증발됩니다
  • 79. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun $ gcc –O1 –fdump-tree-all-details inline.c ;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0) Deleted dead store: str = "Hello worldn"; __attribute__((always_inline)) get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return &str; } ;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1) main () { char str[64]; char * D.1810; char * p; <bb 2> [100.00%]: str ={v} {CLOBBER}; puts (&str); return 0; }
  • 80. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 ;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0) Deleted dead store: str = "Hello worldn"; __attribute__((always_inline)) get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return &str; } ;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1) main () { char str[64]; char * D.1810; char * p; <bb 2> [100.00%]: str ={v} {CLOBBER}; puts (&str); return 0; } Tracing For Fun $ gcc –O1 –fdump-tree-all-details inline.c inline.c.040t.dse1 Deleted dead store: str = "Hello worldn";
  • 81. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 함수 인자 값을 함께 기록하도록 옵션을 지정하여 Tracing 해봅니다 $ uftrace record --auto-args -A fwrite@arg1/s `which gcc` -O1 -fdump-tree-all-details inline.c
  • 82. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun Tracing 결과에서 Deleted dead store 검색하면 위치를 찾을 수 있습니다 $ uftrace replay > replay.log $ wc -lc replay.log 4157866 line 392760323 charater replay.log $ grep "Deleted" -B2 replay.log [110797] | delete_dead_assignment(0x7ffe0825b230) { [110797] | gsi_stmt(); [110797] | fwrite(" Deleted dead store: ") = 22;
  • 83. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun Uftrace TUI를 통한 소스 브라우징! - delete_dead_assignment 검색
  • 84. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun delete_dead_assignment 를 찾았습니다
  • 85. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 소스코드를 찾을 수 있을 때 까지 U키를 눌러 상위 함수로 이동합니다 dse_dom_walker::dse_optimize_stmt delete_dead_assignment
  • 86. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 한 번 더 하면, pass_dse 에 도달하게 됩니다 _GLOBAL__N_1::pass_dse::execute dse_dom_walker::dse_optimize_stmt delete_dead_assignment
  • 87. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun /* This file implements dead store elimination. A dead store is a store into a memory location which will later be overwritten by another store without any intervening loads. In this case the earlier store can be deleted. In our SSA + virtual operand world we use immediate uses of virtual operands to detect dead stores. If a store's virtual definition is used precisely once by a later store to the same location which post dominates the first store, then the first store is dead. The single use of the store's virtual definition ensures that there are no intervening aliased loads and the requirement that the second load post dominate the first ensures that if the earlier store executes, then the later stores will execute before the function exits. It may help to think of this as first moving the earlier store to the point immediately before the later store. Again, the single use of the virtual definition and the post-dominance relationship ensure that such movement would be safe. Clearly if there are back to back stores, then the second is redundant. Reviewing section 10.7.2 in Morgan's "Building an Optimizing Compiler" may also help in understanding this code since it discusses the relationship between dead store and redundant load elimination. In fact, they are the same transformation applied to different views of the CFG. */ tree-ssa-dse.c DSE(Dead Store Elimination)
  • 88. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 최적화 때문이라면 최적화를 하지 못하게 강제하고 비교/확인해 볼까요? static char *get_msg() { char str[64] = "Hello worldn"; return (char *)str; } int main() { char *p; p = get_msg(); puts(p); return 0; }
  • 89. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 최적화 때문이라면 최적화를 하지 못하게 강제하고 비교/확인해 볼까요? static char *get_msg() { volatile char str[64] = "Hello worldn"; return (char *)str; } int main() { char *p; p = get_msg(); puts(p); return 0; } static char *get_msg() { char str[64] = "Hello worldn"; return (char *)str; } int main() { char *p; p = get_msg(); puts(p); return 0; } volatile 메모리 최적화 방지 메모리 최적화
  • 90. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun $ gcc –O1 –fdump-tree-all-details inline.c ;; Function get_msg (get_msg, funcdef_no=0) get_msg () { volatile char str[64]; <bb 2> [0.00%]: str ={v} "Hello worldn"; return 0B; } ;; Function main (main, funcdef_no=1) main () { char * p; <bb 2> [0.00%]: p_3 = get_msg (); puts (p_3); return 0; } ;; Function get_msg (get_msg, funcdef_no=0) Deleted dead store: str = "Hello worldn"; get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return 0B; } ;; Function main (main, funcdef_no=1) main () { char * p; <bb 2> [0.00%]: p_3 = get_msg (); puts (p_3); return 0; } 메모리 최적화 방지 메모리 최적화 inline.c.040t.dse1 Deleted dead store: str = "Hello worldn";
  • 91. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun $ uftrace graph -D 2 -F dse_dom_walker::dse_optimize_stmt -f none 메모리 최적화 방지 메모리 최적화
  • 92. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 10227 case ADDR_EXPR: 10228 inner = TREE_OPERAND (inner, 0); 10229 10230 while (REFERENCE_CLASS_P (inner) 10231 && !INDIRECT_REF_P (inner)) 10232 inner = TREE_OPERAND (inner, 0); 10233 10234 if (DECL_P (inner) 10235 && !DECL_EXTERNAL (inner) 10236 && !TREE_STATIC (inner) 10237 && DECL_CONTEXT (inner) == current_function_decl) 10238 { 10239 if (TREE_CODE (inner) == LABEL_DECL) 10240 warning_at (loc, OPT_Wreturn_local_addr, 10241 "function returns address of label"); 10242 else if (DECL_DECLARED_INLINE_P(current_function_decl)) 10243 inner->base.volatile_flag = true; 10244 else 10245 { 10246 warning_at (loc, OPT_Wreturn_local_addr, 10247 "function returns address of local variable"); 10248 tree zero = build_zero_cst (TREE_TYPE (res)); 10249 t = build2 (COMPOUND_EXPR, TREE_TYPE (res), t, zero); 10250 } 10251 } 10252 break; else if (DECL_DECLARED_INLINE_P(current_function_decl)) inner->base.volatile_flag = true; return 될 tree가 속한 함수가 inline 으로 선언되어 있으면 0으로 바꾸지 마세요! + volatile_flag true set
  • 93. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Tracing For Fun 실종됐던 Hello world를 되찾았습니다 $ cat inline.c static inline __attribute__((always_inline)) char *get_msg() { char str[64] = "Hello worldn"; return (char *)str; } int main() { char *p; p = get_msg(); puts(p); return 0; } $ gcc -O2 inline.c $ ./a.out Hello world Dump of assembler code for function main: <+4>: movdqa 0x1b4(%rip),%xmm0 <+12>: mov %rsp,%rdi <+15>: movaps %xmm0,(%rsp) <+19>: pxor %xmm0,%xmm0 <+23>: movaps %xmm0,0x10(%rsp) <+28>: movaps %xmm0,0x20(%rsp) <+33>: movaps %xmm0,0x30(%rsp) <+38>: callq 0x400400 <puts@plt> Dump of assembler code for function main: <+4>: movabs $0x6f77206f6c6c6548,%rax <+14>: mov $0xa646c72,%edx <+19>: mov %rax,(%rsp) <+23>: mov %rdx,0x8(%rsp) <+28>: movq $0x0,0x10(%rsp) <+37>: movq $0x0,0x18(%rsp) <+46>: movq $0x0,0x20(%rsp) <+55>: movq $0x0,0x28(%rsp) <+64>: movq $0x0,0x30(%rsp) <+73>: movq $0x0,0x38(%rsp) <+82>: mov %rsp,%rdi <+85>: callq 0x400400 <puts@plt> -O1 -O2
  • 94. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect 회고
  • 95. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect 문외한도 아는 척 할 수 있는 핵심은 – 가독성! ;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0) Deleted dead store: str = "Hello worldn"; __attribute__((always_inline)) get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return &str; } ;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1) main () { char str[64]; char * D.1810; char * p; <bb 2> [100.00%]: str ={v} {CLOBBER}; puts (&str); return 0; }
  • 96. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 ;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0) Deleted dead store: str = "Hello worldn"; __attribute__((always_inline)) get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return &str; } ;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1) main () { char str[64]; char * D.1810; char * p; <bb 2> [100.00%]: str ={v} {CLOBBER}; puts (&str); return 0; } Retrospect 문외한도 아는 척 할 수 있는 핵심은 – 가독성! (gdb) p *gsi->ptr $4 = {code = GIMPLE_ASSIGN, no_warning = 0, visited = 0, nontemporal_move = 0, plf = 1, modified = 0, has_volatile_ops = 0, pad = 0, subcode = 32, uid = 0, location = 2147483655, num_ops = 2, bb = 0x7ffff6ede478, next = 0x7ffff702d190, prev = 0x7ffff702d140}
  • 97. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect Gcc를 수정하는 과정에서 관련 지식도 조금 습득했습니다 else if (DECL_DECLARED_INLINE_P(current_function_decl)) inner->base.volatile_flag = true; GIMPLE RTL TREE Abstract IR Front-End Back-End Front-end Optimize Pass : DSE Volatile CLOBBER CONSTRUCOR
  • 98. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect Android VM에 대한 부분 부분의 지식들이 VM Interpreter Bytecode 동작 방식에 대한 이해 DEX 파일 포맷에 대한 지식 Bytecode에 대한 지식
  • 99. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect Tracing의 과정을 거치면서 연결되게 되면 VM Interpreter Bytecode 동작 방식에 대한 이해 DEX 파일 포맷에 대한 지식 Bytecode에 대한 지식
  • 100. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Retrospect 답답하기만 했던 코드가 이해되는 시원함을 느끼게 됩니다 VM Interpreter Bytecode 동작 방식에 대한 이해 DEX 파일 포맷에 대한 지식 Bytecode에 대한 지식
  • 101. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Conclusion 오픈소스의 접근성을 올려주는 요소
  • 102. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Conclusion 오픈소스의 역설 AOSP
  • 103. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Conclusion 오픈소스의 접근성 올리기 Open-source tracing data API 정보 #1 정보 #2 정보 #3
  • 104. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Conclusion 오픈소스의 접근성 올리기 Global Declared Classes Optimization step The actual step to run dse. The optimization is actually performed when this function is called A dead store is a store into a memory location which will later be overwritten by another store without any intervening loads. In this case the earlier store can be deleted. ===================================================== [ 32314] | _GLOBAL__N_1::pass_dse::pass_dse() { 29.798 us [ 32314] | } /* _GLOBAL__N_1::pass_dse::pass_dse */ $ uftrace record -S clarity_gcc_opt_path.py `which gcc` -O1 inline.c
  • 105. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 [ 32314] | _GLOBAL__N_1::pass_dse::pass_dse() { [ 32314] | } /* _GLOBAL__N_1::pass_dse::pass_dse */ Conclusion 오픈소스의 접근성 올리기 ;; Function main (main, funcdef_no=1, decl_uid=1796, cgraph_uid=1, symbol_order=1) main () { char str[64]; char * D.1810; char * p; <bb 2> [100.00%]: str ={v} {CLOBBER}; puts (&str); return 0; } ;; Function get_msg (get_msg, funcdef_no=0, decl_uid=1792, cgraph_uid=0, symbol_order=0) Deleted dead store: str = "Hello worldn"; __attribute__((always_inline)) get_msg () { char str[64]; <bb 2> [0.00%]: str ={v} {CLOBBER}; return &str; }
  • 106. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Conclusion 똑같은 장벽을 올라야 하더라도… AOSP
  • 107. SOSCON 2018 SAMSUNG OPEN SOURCE CONFERENCE 2018 THANK YOU Uftrace repository https://github.com/namhyung/uftrace
  • 108. SOSCON 2018 SAMSUNG OPEN SOURCE CONFERENCE 2018 Any Question? Uftrace repository https://github.com/namhyung/uftrace
  • 109. SOSCON SAMSUNG OPEN SOURCE CONFERENCE 2018 Appendix A. benchmark #include <stdio.h> #include <time.h> void callme(int *r) { (*r)++; } int main() { clock_t begin = clock(); for(int i=0;i<0xFFF;) { callme(&i); } clock_t end = clock(); printf("Elapsed: %lf secondsn", (double)(end - begin) / CLOCKS_PER_SEC); return 0; } Target Source LLDB python script https://github.com/ParkHanbum/lldb_tracer

Editor's Notes

  1. 특기 리버스엔지니어링
  2. 제가 공유하고 싶은 이야기는 tracing에 대한 소개와 제가 어쩐 연유로 tracing에 관심을 갖게 됐는지를 말씀드리고 트레이싱 툴로서 Uftrace를 간단히 소개드린 다음 Uftrace를 활용해 트레이싱했던 경험을 공유하고 그를 고찰하여 내린 결론을 말씀드리는 순서로 진행될겁니다.
  3. Javascript 엔진들은 여러 이유가 있겠지만 그 중 특히 성능 상의 이점 때문에 C나 C++로 짜여진 네이티브 함수를 호출하는 인터페이스를 제공합니다. 근데 특정 경우에는 네이티브 함수를 호출하는 것 보다 순수 자바스크립트에서 연산하는게 오히려 더 빠를 때가 있다는 겁니다.
  4. 왜 네이티브 함수 호출을 통한 연산이 순수 자바스크립트보다 느릴 수가 있냐면 자바스크립트에서 네이티브 함수 호출을 하기 위한 몇 가지 절차가 함수 호출 때마다 일어나 성능을 저하시키기 때문입니다. 그림은 그를 트레이싱한 결과인데요, Native Type으로의 전환을 위해 타입 체킹이 반복적으로 일어나는 것을 확인 하실 수 있으실 겁니다. IsNumber라는 텍스트가 보이시죠?
  5. 한번 배열 안의 값들을 구하는 sum이란 함수를 구한다고 예를 들어보겠습니다.
  6. 자바스크립트로 작성한 코드입니다. 더 설명할 것도 없겠죠?
  7. 근데 이를 Native에서 연산하기 위해 Node.js의 N-API를 활용해 코드를 작성하면 꽤나 설명이 필요해질 것 같습니다.
  8. 이 코드는 크게 연산이 이뤄지는 부분과 반환하는 부분으로 나눠 볼 수 있는데요
  9. 연산하는 부분에서 호출한 자바스크립트가 넘겨준 값을 읽어와야하구요
  10. 값의 타입이 무엇인지 확인을 해야합니다.
  11. 확인된 타입으로 타입을 변환도 해줘야 하죠. 이런 과정을 거치고 나서야 합을 구할 수 있고, 마찬가지로 반환을 해줄 수 있는 겁니다. 이런 절차가 자바스크립트에서 네이티브 함수 호출을 하는 경우에 반복적으로 일어나기 때문에 자바스크립트에서 연산하는게 더 빠른 경우도 발생하는 겁니다.
  12. 이 문제를 파악한 코스랩에서 활동하시는 방진호님은 크로미움에 WebIDL이라는 기술을 Node.js에서 제안했구요. 이 기술은 자동으로 javascript 값의 타입을 검사하고 IDL에 기술된 타입으로 전환해주기 때문에 코드가 좀더 간결해집니다.
  13. 필요하지 않은 경우에 타입을 검사하지 않아서 그만큼의 성능상 이점을 가져갈 수 있게 됩니다.
  14. 현재 node.js에 제안이 받아들여져 bacardi라는 이름으로 개발 하시는 것으로 알고 있습니다.
  15. 이제 트레이싱이 무엇인지 감이 오시나요? 트레이싱이라는 것은 프로그램이 실행되는 동안의 변화를 다각도록 기록하고 이를 검토하는 것을 말합니다. 이번 예에서 방진호님은 트레이싱을 통해 문제를 파악하고 해결방안을 제시하실 수 있었죠.
  16. 이제 제 경험을 소개드릴텐데 앞서 보신 것보다 좀더 친숙하게 느껴지실 거라고 기대합니다. 제가 왜 Tracing에 관심을 갖게 되었냐면, 사실 앞서 소개드린 케이스를 먼저 접했지만 그때는 크게 와닿지는 않았었거든요. 근데 회사에서 안드로이드 가상머신을 분석하게 되버린거죠.
  17. 안드로이드에서 새 앱이 구동되는 순서는 대략 이렇습니다.
  18. 새 앱이 구동 될 때마다 가상 머신을 만들면서 APK라는 안드로이드 패키지를 인자로 전달하게 됩니다.
  19. 이 APK는 DEX라는 안드로이드 실행파일과 기타 리소스로 구성되어 있는데 문제는 DEX라는 안드로이드 실행파일 포맷이 너무 쉽게 리버싱되서 원본 소스를 복원해내기 쉽다는 겁니다. 여러분이 보시는 코드는 스몰리라고 DEX가 바이트코드로 이루어져 있는데 바이트코드를 사람이 읽을 수 있는 텍스트로 출력을 해준 것 뿐입니다. 그럼에도 불구하고 대충 뭔지 알 수 있지 않나요? 헬로 월드를 출력해주는 프로그램 입니다.
  20. 그런 이유로 DEX를 보호하는 방안이 필요했고, 저희는 경쟁사보다 우위를 점하기 위해 향상된 기법을 찾고자 했습니다. 그런 이유로 제가 안드로이드 가상머신을 분석하게 되버린거죠.
  21. 만약 누가 여러분에게 월급을 주면서 오픈소스를 분석 해달라고 하면 하시겠습니까? 당시의 저는 하고 싶었습니다. 과거의 저에게 stay라고 말해주고 싶네요. 당시에는 오픈소스 분석이 뭐… 어려워봐야 얼마나 어렵겠냐는 생각이었습니다. 시작지점부터 분석해가면 끝나긴 할거 아닌가? 라고 생각했죠.
  22. 하지만 어리석은 생각이더군요. 모든 것이 성장합니다. 오픈소스도 마찬가지구요. 제 월급만 빼구요. 안드로이드 소스코드도 양이 40만 라인정도로 상당했습니다.
  23. 안드로이드 가상머신 분석에 돌입하여 ctags, cscope를 활용해 시작지점부터 분석해 들어가면서 호출 흐름을 이면지에 적어 기록하기 시작했습니다.
  24. 그렇게 적기 시작한 이면지가 책상에 점점 쌓여가는데요. 보시다시피 특정 지점 이후로 어디를 분석해야 할지 갈피를 잡지 못하는 상황에 직면했습니다.
  25. 시작지점부터 분석해 들어가는 것이 꼭 나쁜 것은 아닙니다. 다만 시간이 좀 필요했을 뿐이고 저한테는 없을 뿐인거죠.
  26. 이런 방식으로는 끝이 없겠다는 생각이 들어 소스코드의 정적 분석을 끝내고 다른 방식으로 접근해보기 위해 역공학을 했던 기억을 되살려 봤습니다. 역공학은 주로 바이너리를 대상으로 하기 때문에 분석이 필요한 지점을 찾아 범위를 한정하는데 많은 공을 들입니다.
  27. 어떤 방식으로 범위를 줄일 수 있느냐면, 바이너리의 API호출을 후킹등의 방법을 통해 기록하고, 동시에 시스템 자원들의 실시간 모니터링 내용을 함께 기록하면서 특이한 사항이 있는지 분석할 필요가 있는지를 추려내는 것이죠. 트레이싱과 많이 유사합니다. 다만, 역공학을 통해 주로 찾고자 하는 것은 프로그램의 이상 동작이라는 차이가 있습니다.
  28. 하지만 원하는 로직을 찾아서 분석해야 할 작업의 양을 줄이는 것은 트레이싱과 동일한 목표입니다.
  29. 다시 말해 바이너리의 실행을 로깅하여 이를 추적하면, 우선적으로 실행에 필요한 소스와 로직을 추릴 수 있을거라 생각이 들었습니다.
  30. 그래서, 트레이싱을 해줄 적절한 툴 부터 찾았는데요, 저는 Uftrace를 사용하였습니다. Uftrace는 트레이싱에 좋은 기능들이 많습니다. 아주 빠르고 간단하게 uftrace에 대해 설명드리겠습니다.
  31. 먼저 Uftrace가 tracing을 하는 메커니즘을 설명드릴건데요. 예를 들어 왼쪽 소스코드를 컴파일 하면 함수 호출이 오른쪽처럼 call과 ret이라는 어셈블리 코드로 컴파일 될 겁니다.
  32. 여기서 –pg 옵션을 줘서 컴파일하면 컴파일러가 각 함수마다 시작지점에 Mcount라는 이름의 함수를 호출하도록 코드를 삽입 해놓습니다.
  33. 그러면 각 함수 호출시마다 함수의 시작 지점에서 mcount가 우선적으로 호출하게 되니 mcount라는 함수에서는 이를 기록하면 함수들의 호출 순서를 기록할 수 있게 되는 겁니다.
  34. 여기에 추가로 함수를 호출할 때는 정해진 규칙이 몇 가지 있는데요. 그 중에 인자 값을 전달하는 규칙이 있습니다.
  35. 이것을 콜링 컨벤션, 함수 호출 규칙이라고 부르며 정해진 방식으로 인자를 전달하고 받을 수 있도록 상호간에 약속된 규칙입니다.
  36. Uftrace에서는 함수 호출 규칙을 활용하여 함수 호출 뿐 아니라 함수에 전달되는 인자도 함께 기록하는 기능이 있습니다.
  37. 이런 방식은 Native하게 이뤄지기 때문에 동일한 방식을 디버거로 구현했을 때에 비해 부하가 적다는 장점이 있습니다.
  38. Uftrace는 트레이싱 된 결과에 대해서 시각적 가공도 지원하는데요, 보시는 그림은 flamegraph라고 부릅니다. 커널에서는 perf 라는 성능 측정을 위한 기능이 있는데 perf를 통해 나온 결과를 시각화 해서 보고자 할 때 많이 사용되는 그래프 입니다.
  39. Chromium에도 자체 프로파일링 및 트레이싱 기능이 있고 트레이싱 데이터를 시각화 해서 볼 수 있는 트레이싱 뷰어도 제공합니다. Uftrace에서도 해당 데이터 포맷을 지원하기 때문에 chrome tracing 뷰어에서 볼 수 있도록 데이터 가공할 수 있습니다.
  40. DOT는 graph를 표현하기 위한 언어인데 이를 기반으로 graph를 그려주는 툴들이 많습니다. Uftrace는 DOT형태로도 데이터를 가공해줍니다.
  41. 이제 Uftrace로 Android 가상머신을 트레이싱 해본 내용을 말씀드리려고 합니다
  42. 안드로이드 소스를 다운 받아 컴파일하면 Dalvikvm이라는 이름의 빌드 환경에서 실행할 수 있는 바이너리가 생성됩니다. 이를 통해 uftrace로 안드로이드 가상머신을 트레이싱 해볼 수 있습니다. 트레이싱을 해보기 위해 간단히 Hello world를 출력해주는 프로그램을 작성하여 DX라는 안드로이드 유틸을 사용하여 DEX포맷으로 변환하고 이를 Main.apk로 압축하면 준비는 끝입니다. 마지막 줄처럼 uftrace로 dalvikvm을 실행하면 트레이싱을 하게 되는거죠.
  43. 트레이싱 해보면 약 100만줄 정도의 함수 호출 기록을 얻을 수 있구요.
  44. 이를 시각화하면 chrome tracing 뷰어는 보시는 것처럼 보여줍니다. 아무래도 chrome 트레이싱 뷰어로 보기는 좀 별로일것 같죠?
  45. 다음으로 flamegraph를 통해 결과를 확인해봤습니다. 텍스트가 좀 보이는게 마음이 편해지지 않나요?
  46. 이렇게 많은 트레이싱 결과가 나오더라도 당황할 필요가 없습니다. 어차피 중요 로직들은 반복적으로 호출되기 때문에 DEX라는 실행파일을 입력받아 DEX에 들어있는 Hello world를 출력하는 과정은 분명 찾을 수 있을 것이기 때문입니다.
  47. 플레임 그래프를 쭉 훑어보면, 동일한 함수 이름이 반복해서 보이는데요 혹시 확인하실 수 있는지 모르겠는데, FindClass나 interpreter가 들어가는 함수들이 그렇습니다. FindClass와 Interpreter로 검색을 해보면 Interpreter가 56%, find class가 36%의 지분을 가지고 있다는 걸 알 수 있습니다.
  48. 플레임 그래프는 특정 노드를 클릭하면 클릭 지점 “하”에서 발생하는 호출 흐름으로 축소해서 보여줍니다. 이제 좀더 자세히 보이실테니 몇 개의 텍스트가 반복 된다는걸 유심히 보시면 아실 수 있으실 겁니다.
  49. 이렇게 플레임그래프를 탐색하고 클릭 몇 번을 하여 특정 호출 흐름을 추려낼 수 있습니다. 추려낸 함수는 MterpInvokeDirect라는 이름의 Interpreter가 인스트럭션을 처리하는 함수 중에 하나입니다.
  50. Uftrace의 기능 중에 tui를 사용하면 터미널 환경에서 함수 호출 흐름을 그래프로 확인할 수 있습니다. 또한 소스 브라우징도 할 수 있습니다. MterpInvokeDirect 함수를 검색해보면, 소스를 추적해 들어가면 이는 super를 호출했을 때 즉, 부모 클래스의 메소드를 호출하는 함수라는 것을 알 수 있습니다. 이런식으로 MterpInvoke 명령어를 몇 개 찾아보면 인터프리팅이 바이트코드와 매핑되어 바이트코드마다 호출되게 되어 있는 MterpInvoke로 시작하는 함수들이 있다는 것을 확인할 수 있었습니다.
  51. 이번에는 자바 기반 가상 머신에서 핵심인 class가 로드되는 구간을 찾아보겠습니다.
  52. 마찬가지로 플레임 그래프에서 FindClass를 검색 후 클릭해가며 호출 범위를 좁히면 클래스를 로드하는 구간을 추려서 볼 수 있습니다.
  53. 인터프리터의 경우와 마찬가지로 tui를 통해 콜 그래프를 보면 좀더 상세한 정보를 한 눈에 확인 할 수 있습니다. 트레이싱을 통해 생성한 함수와 호출 흐름이 있으므로, 그 순서에 맞춰 소스코드를 분석 해들어가면 됩니다. 네비가 따로없죠.
  54. 클래스 관련 부분을 분석하기 어려웠던 이유가 여기서 나옵니다. 클래스는 자바 기반 가상머신의 핵심 중에 핵심이기 때문에 클래스를 다양한 방법으로 자주 로드합니다. 또한 클래스는 상속이라는 특징이 있어 하나의 클래스를 생성하기 위해 몇 번이고 상위 클래스들이 로드됐는지 확인하고 로드되지 않았다면 로드하는 작업을 반복하게 됩니다. 하지만 Hello world를 출력하는 과정를 트레이싱 한 결과를 통해서는 시작과 끝을 명확하게 알 수 있었기에 호출 흐름을 정리하는데 큰 도움이 됐습니다.
  55. 클래스가 로드되고 클래스의 메소드에 존재하는 바이트코드들이 인터프리터의 MterpInvoke로 시작하는 함수들과 매핑되어 실행되는 동작 원리를 파악하고 나자 나머지는 어렵지 않게 진행되었고, 소기의 목적을 달성할 수 있었습니다.
  56. 참고로 좌측이 바이트코드를 사람이 읽을 수 있게 텍스트화 한 스몰리 코드이고 우측이 DEX의 로드가 끝난 이후에 Main Class의 init을 호출하여 Main Class의 인스턴스를 생성하고 해당 인스턴스에서 public static void main 함수를 찾아 직접적으로 호출함으로서 실행 파일의 시작지점부터 실행을 하게 만들어주는 코드입니다. 혹시 궁금하신 분이 있으실까 해서 덧붙여 봤습니다.
  57. 이번에는 Gcc를 트레이싱 했던 경험을 공유해보려고 합니다. Gcc의 경우는 특정 문제의 원인을 찾았던 경험인데요.
  58. C로 코딩을 하던 중에 목적한 대로 코드가 동작하지 않는 경우에 직면해서 문제가 발생하는 부분만을 추려낸 소스코드를 작성한 뒤에 Gcc와 Clang 각각 컴파일하여 실행해봤습니다. Gcc와 clang의 결과가 다르게 출력이 되어서 이상하다는 생각이 들었습니다.
  59. Gcc와 clang으로 컴파일한 바이너리를 각각 디스어셈블 해봤는데요. 큰 차이가 있습니다.
  60. 코드가 의도한 바는 get_msg 함수의 리턴 값을 char *p에 저장하는 것인데 Get_msg함수의 리턴 값이 p로 전달되기 직전에 갑자기 0으로 바꿔버리는겁니다. 0이 p에 전달되니 puts는 NULL을 받은 것과 마찬가지고 segment fault가 날 수 밖에 없죠.
  61. 그냥 코드를 변경할까 하는 생각이 들어, 반환하는 문자열을 캐릭터 배열이 아닌 캐릭터 포인터로 변경해봤습니다.
  62. 당연히 출력은 정상적으로 나오겠죠. 하지만 제가 이 코드에서 의도했던 바는 특정 문자열을 가져다가 수정하려는 것인데 캐릭터 포인터로 변경하면 수정을 할 수가 없습니다.
  63. 보시는 바와 마찬가지로. 헬로 월드가 아니라 할로 월드를 출력하려고 하면 문제가 발생합니다.
  64. 문제의 원인은 컴파일러가 문자열을 저장하는 공간이 쓰기 불가 영역이기 때문입니다. 변경이 안되는거죠.
  65. 그럼 동적 할당으로 바꿀까? 했지만 동적할당으로 바꾸면 문자를 수정할 수 있는 대신 매번 해제를 해줘야 하죠.
  66. 그래서 한번 문제가 뭔지나 알아보자고 생각을 했습니다. 예제를 컴파일해보면, gcc가 워닝 메시지로 함수가 지역 변수 주소를 리턴한다고 알려줍니다
  67. Gcc 소스코드를 다운받아 검색을 하면 출력 지점을 찾을 수 있습니다.
  68. get_msg 함수의 반환 값이 0이 되버리는 이유는 함수의 리턴 값이 주소 표현인데 , 외부 변수나 정적 변수가 아니고, 로컬 변수면 0으로 바꿔버리고 있었기 때문입니다.
  69. 아까 디스어셈블했던, 리턴 값을 0으로 만드는 어셈블리 코드는 바로 여기서 나온거죠!
  70. 일반적인 함수의 로컬 변수라면 모르겠지만, 인라인 함수는 인라인 되는 함수 스택에 할당되니 굳이 0으로 바꿔줘야 할 필요가 있을까? 사실상 리턴을 하는 것도 아니고 인라인 되는 함수 내에서 동작하는 코드와 동일한데 말이죠? 인라인 함수인 경우에는 여기를 거르면 될지 않을까? 하는 생각도 들구요.
  71. 혹시나 해서 디버거로 확인해보니 get_msg 함수의 inline_flag는 1로 셋이 되어 있었습니다.
  72. 그래서 한번 inline 함수인 경우에는 로컬 스택을 반환해도 허용해주게 바꿔봤습니다.
  73. 동작을 하긴 하는데… 추가적으로 최적화 옵션을 줬을 때 아무 출력도 되지 않는 문제가 발생했습니다.
  74. 이건 또 왜이러는거지? 다시 디스어셈블 했습니다. 마지막에는 갑자기 뭐가 많이 없어졌는데요?
  75. 처음 발생한 문제인 리턴 값을 무조건 0 으로 바꾸던 문제는 최적화 옵션을 안주면 발생하지 않는 것은 확인할 수 있습니다.
  76. 지금까지의 변화를 C로 한번 표현해봤습니다. 최적화 옵션을 주게 되면, C로 표현한 것처럼 헬로 월드라는 문자열이 증발 되버리는 겁니다.
  77. 왜 그런지 추적하기에는 단순 트레이싱만으론 중과부족이었구요. Gcc에서는 최적화 과정의 변화를 dump해서 볼 수 있는 옵션을 지원하는데요. 이를 이용하면 트레이싱 할 수 있었습니다.
  78. 덤프 옵션으로 생성된 파일 중에 40t dse1에서 문자열을 지웠다는 메시지를 출력한걸 확인한 뒤에
  79. 어디서 문자열을 지우는지 찾기 위해 트레이싱을 시도했습니다.
  80. 400만 줄 정도의 기록이 남지만, 이미 덤프로 Deleted dead store라는 키워드를 확보했으니 이걸로 검색해보면 로그를 남기는 함수를 쉽게 찾을 수 있었습니다. Delete_dead_assignment 가 그 함수네요.
  81. 좀더 편하게 찾기 위해 소스 브라우징이 되는 tui를 다시 띄웠습니다.
  82. Delete_dead_assignment를 검색해서 위치를 찾은 다음에
  83. U키를 눌러서 소스코드가 표시되는 함수까지 찾아갑니다.
  84. Dse_dom_Walker::dse_optimize_stmt 함수가 위치한 소스코드가 표시되는게 보입니다.
  85. Tree-ssa-dse.c 소스의 최상단에는 여기서 하는 작업에 대해 상세한 설명이 주석으로 적혀 있습니다. 다 이해는 못하더라도, 여기서 참조되지 않는 메모리를 삭제한다는 것은 알겠더라구요.
  86. 최적화 할 때 문자열을 삭제하는 것인지를 확인해보기 위해 최적화 한 경우와 아닌 경우를 비교해보려고 합니다.
  87. 비교하기 위해 한쪽 str에만 메모리 최적화 방지 키워드인 volatile을 지정했습니다.
  88. 최적화 1 옵션을 주고 dump를 출력하도록 옵션을 주고 컴파일 합니다. 생각했던 것처럼 volatile 키워드를 줬을 경우 “Hello world”가 지워지지 않는것을 확인했습니다.
  89. 그러면 트레이싱한 결과를 uftrace를 통해 그래프로 시각화를 하면서 , 동시에 “Hello world”를 삭제하는 함수 delete_dead_assignment의 부모 함수, “dse_dom_walker::dse_optimize_stmt”로 필터링 옵션을 줘서 이 구간이 volatile을 준 코드를 컴파일 한 경우와 그렇지 않은 경우에 호출 흐름이 서로 다른지 비교해봅시다. 비교는 winmerge로 했습니다. , 눈으로 확인할 수 있는 것처럼 volatile을 주지 않으면 최적화가 이뤄지는 과정에서 몇 개의 함수를 추가로 호출한 뒤에 delete_dead_assignment를 호출하여 “Hello world”를 삭제한다는 확신을 할 수 있습니다.
  90. 이런 비교 결과를 토대로, “Hello world”라는 문자열은 컴파일러가, 최적화 과정 중에 지워버린다는 것을 확인 할 수 있었습니다. 그렇다면 “Hello world”가 최적화가 되지 않도록 하면 되지 않을까요? 소스코드를 좀더 수정하여, “Hello world”라는 지역변수 tree를 반환할 때 함수가 Inline으로 선언된 경우는 0으로 바뀌지 않으면서 동시에 최적화 하지 않도록 volatile_flag를 1로 셋 하도록 바꿔봤습니다.
  91. 예상했던 대로 이제 최적화를 해도 “Hello world”가 제대로 출력됩니다. 최적화 1단계와 2단계 모두 정상 동작하네요!
  92. 지금까지 제가 Tracing을 했던 경험을 소개 드렸는데요. 이 과정에서 느낀 바를 공유하고자 하고 싶어서 앞선 사례들을 먼저 장황하게 설명한 겁니다.
  93. 물론 트레이싱의 도움도 받았지만, 가장 크게 도움을 받은 것은 보시는 Gcc에서 텍스트로 출력해주는 덤프 정보였습니다. 텍스트로 출력해준다는 것은 당장 gcc에 대한 지식이 전무한 상황이었던 제가 Gcc에서 이뤄지는 작업의 각 단계에 대한 동작과, 원리의 이해가 없이도 전과 후에 대한 비교만으로 문제가 발현되는 지점을 찾는데 큰 도움이 됐습니다.
  94. 만약에 이런 정보가 없이, 보시는 것과 같은 본래 GIMPLE 구조체가 저장하는 데이터를 가지고 문제를 추적하려고 했다면 훨씬 많은 시간과 도전이 필요했을 거라는 것은 분명하다는 거죠.
  95. 원하는 아웃풋을 얻기 위해 GCC에 두 줄의 코드를 추가하였는데 위의 작업을 진행하며 GCC에 대한 몇 가지 정보도 함께 습득할 수 있었습니다. 대략 4일 정도의 작업으로는 GCC에서 문제를 트레이싱 하면서 느낀 것은 안드로이드를 할 때와 같은 시원함을 느낄 수 없었다는 것인데요.
  96. 그래서 왜인지를 생각해보니, 안드로이드 가상머신을 분석하기 전에 이미 안드로이드 플랫폼에서, 만들어진 앱을 분석하거나 솔루션을 만들거나 하면서 부분적인 정보를 습득하고 있었던 것 같습니다.
  97. 그래서 안드로이드 가상머신을 tracing 할 때는 단순히 분석해야 할 양을 줄여주거나, 분석 지점을 찾는 것을 넘어서,
  98. 지식이 부분적이라 유기적으로 연결되지 못한 상태가, 유기적인 시스템 전체 그림을 그릴 수 있도록 Tracing이 도움을 줬던 겁니다. 그래서 어느 순간 코드가 이해되기 시작하는 시원함을 느낄 수 있었던 겁니다.
  99. 오픈소스의 접근성을 올려주는 방법을 찾고 싶기 때문입니다. 그래서 그 중 하나라고 생각하는 트레이싱을 도와주는 도구인 Uftrace에 기여하고 있습니다.
  100. 오픈소스는 오픈되어 있어, 다수의 참여로 꾸준히 성장하는데, 이런 점이 역설적으로 오픈소스로 가는 장벽이 되버립니다.
  101. 안드로이드에서의 경우처럼 부분적 정보들을 트레이싱 데이터를 가공하는 과정에서 함께 볼 수 있다면 오픈소스의 접근성을 올릴 수 있지 않겠어요?
  102. 트레이싱 데이터를 가공할 때 함수의 설명에 대한 정보를 함께 보여주면 함수의 역할에 대해 트레이싱 결과만으로도 이해할 수 있겠죠?
  103. Gcc에서 Gimple을 dump해서 보여주는 것처럼 트레이싱 결과를 가공할 때 복합 데이터 타입을 Text로 치환된 가독성이 높은 형태로 가공해서 보여주는 접근성을 높일 수 있습니다.
  104. 이런 생각을 하는 것도 사실은 오픈소스에 대한 접근성을 높여, 저 자신이 오픈소스에 대한 분석을 효율적으로 해보고 싶기 때문입니다.
  105. 이상 부족한 발표를 경청해 주셔서 감사합니다.
  106. 혹시 질문 있으신가요?