itsukichang

フロントエンドが得意なエンジニア.ダーツと旅行とギターが好き

セキュリティ&プログラミングキャンプ2011 に参加してきた.

セキュリティ&プログラミングキャンプ2011 に参加してきた.

詳細 → セキュリティ&プログラミングキャンプ2011

言語組で参加してきましたー

もう何から書いていいのか分からないぐらい濃い5日間だったんですが,とにかく刺激的で楽しかったです.

参加者

井の中の蛙感を存分に味わいました.
世の中広い.みんなすげぇ

講義,演習

キャンプの中での講義,演習はどれも新鮮...未知なものばっかりでした.
自分は普段,どちらかというと用意された環境でコンテンツを作るタイプで,言語の処理系や構成を学ぶだとか.それの性能改善,デバッグ,向上技法なんてものはまったく触れた事がない世界でした.
つまり講義や演習について行くのが大変だったわけです><
でも多少の興味は持っていたためか新しい知識を得るのを楽しんでいた気がします.

講師,チューター

「聞くは一時の恥.聞かぬは一生の恥」
まさにこの通り.
個別演習とかデバッグ演習とかは本当にチューターや講師の方にお世話になりました,
講師とかチューターとか凄い人達ばかりで一瞬怯んだりもしますが,敵ではありません.
個別演習とか,もう本当なにもわからない自分を導いてくれた西尾さんと須永さんに感謝してもしきれないくらいです.

できたの

とりあえずスライド

せつめい

個別演習で,Rubyの可視化/可聴化を選択し,.rbファイルから使用されているメソッドの定義元(ファイル名,関数名)を可視化すると行ったものを作成しました.
まず,メソッドが定義されるタイミングでメソッド名と,それが定義されている関数名,その関数ポインタを出力するようにRubyソースコードを変更
次にメソッドが呼び出されるタイミングで,どの関数を呼び出そうとしているのか,それを判別する関数ポインタを出力するようにする.
これによって,rubyを実行した際に,すべてのメソッドのメソッド名,定義されている関数名,そのポインタが出力されると同時に,
使用されている関数ポインタ一覧も出力されます.

これをtxtに吐き出したものが以下.

rb_define_method: name===, funcname=rb_obj_equal, funcaddr=0x4ad350
rb_define_method: name=equal?, funcname=rb_obj_equal, funcaddr=0x4ad350
rb_define_method: name=!, funcname=rb_obj_not, funcaddr=0x4ad360
rb_define_method: name=!=, funcname=rb_obj_not_equal, funcaddr=0x4adca0
rb_define_method: name=nil?, funcname=rb_false, funcaddr=0x4ad4b0
rb_define_method: name====, funcname=rb_equal, funcaddr=0x4adcd0
rb_define_method: name==~, funcname=rb_obj_match, funcaddr=0x4ad4c0
rb_define_method: name=!~, funcname=rb_obj_not_match, funcaddr=0x4adc50
rb_define_method: name=eql?, funcname=rb_obj_equal, funcaddr=0x4ad350
rb_define_method: name=hash, funcname=rb_obj_hash, funcaddr=0x4ae160
rb_define_method: name=<=>, funcname=rb_obj_cmp, funcaddr=0x4ae660
rb_define_method: name=class, funcname=rb_obj_class, funcaddr=0x4aebb0
.
.
.
(1600行ほどあるので省略)
.
.
.
address::0x5892f0
address::0x4aeda0
address::0x589280
address::0x530660
address::0x4908e0

rb_define_method: ~で出力されているのがrubyで定義されている全てのメソッド
address:: ~で出力されているのが,適当な.rbファイルで使用されているメソッドのポインタ一覧です.
ここで使用した.rbは以下

#test.rb
s = "hogehoge"
s.capitalize
p s + "!!"

capitalizeだとかpだとかのメソッドを使用していますね.

これをrubyで良い感じに文字列処理を行って,address:: ~部分の16進数だけ取り除きます.
つまり

0x5892f0
0x4aeda0
0x589280
0x530660
0x4908e0

こんな感じのファイルができる訳です.
これをlinuxコマンドの addr2lineに渡してやると,渡されたアドレス...つまりrubyのあるメソッドの定義が行われている関数の場所 がどのファイルの何行目にあたるのか.を教えてくれます.

../ruby/load.c:502
../ruby/regexec.c:2204
../ruby/load.c:496
../ruby/vm.c:1003
../ruby/rational.c:273

こんな感じ.
あとはこれらのデータをもとにActionScriptを使って可視化を行っています.


こんな感じ.

つくったやつの考察とか

自動化

手動作業多いので,自動化したい.
ASでnativeprocess APIを使ったらシェルスクリプトとか実行できて自動で色々できるんじゃねーのとか思ったけど,
なぜかnativeprocessAPIがうまく動かない. 設定ファイルとかもちゃんと記述したのに><
これはあとで要調査.

もっときれいに

とりあえずやっつけな感じでas部分を作ったので,UIがダサい.
もっと見せ方を工夫したい.

正確に

メソッド名,関数名は完璧に表示されるんだけど、ファイル名が若干違うときがある.
たぶんaddr2lineの段階で何かが起きているはず...
これも要調査.

とりあえず

動くものができてよかった><
本当,rubyソースコードいじって,関数ポインタとか吐き出すようにする部分は講師の方に超お世話になりましたorz
ありがとうありがとう.

あとasのコード

なんか無駄に長々となってしまた.
文字列処理周りがかなり変態的.やっつけすぐる.

  • Main.as
//Main.as 主に文字列処理とか.ボタン表示とか.アニメーションとか
package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLVariables;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import caurina.transitions.Tweener;
	
	public class Main extends Sprite {
		
		private const RESOUCE_CNT = 2
		private var _txt:URLLoader;
		private var _txt2:URLLoader;
		
		private var _s:Array; //とりあえずtxtからログを1行ずつ配列に格納
		private var _fileName:Array;
		private var _line:Array;
		
		private var _define:Array;
		private var _addArray:Array;
		private var _instName:Array;
		private var _funcName:Array;
		private var _flag:Boolean;
		private var _nowTarget:int;
		private var _boxArray:Array;
		private var _box:Box;
		private var _next:Button;
		private var _prev:Button;
		private var _auto:AutoButton;
		private var _autoFlg:Boolean;
		
		private var _rsrcCnt = 0;
		
		
		private var _timer:Timer;
		public function Main() {
			_s = new Array();
			_fileName = new Array();
			_line = new Array();
			_boxArray = new Array();
			_define = new Array();
			_addArray = new Array();
			_instName = new Array();
			_funcName = new Array();
			
			_txt = new URLLoader();
			_txt.load(new URLRequest("filenames.txt")); //パスと行数が書いてあるテキスト
			_txt.addEventListener(Event.COMPLETE, onComp); 
			
			_txt2 = new URLLoader();
			_txt2.load(new URLRequest("log.txt")); //defineログがいっぱい書いてあるテキスト
			_txt2.addEventListener(Event.COMPLETE,onComp2);
		}
		
		private function onComp(e:Event):void {
			
			var my_str:String = e.target.data;
  			var aLoad:Array = my_str.split("\n");
  			aLoad.forEach(myTrace1);
  			///var myVars:URLVariables = new URLVariables(my_str);
  			
  			/*
  			for (var name_str:String in myVars){
  				trace(my_str + "hogehoge");
  				/*
    			if ( my_str.indexOf("ruby/") != 1) {
    				trace(my_str + "hoge");
    				//trace(my_str.indexOf("ruby/"));
    				trace("hoge");
    			}
    			*/
    			//trace([name_str, myVars[name_str]]);
    		if (++_rsrcCnt == RESOUCE_CNT)	compInit();
  		} 
  		
  		private function onComp2(e:Event):void {
			var my_str:String = e.target.data;
  			var aLoad:Array = my_str.split("\n");
  			aLoad.forEach(myTrace2);
  			///var myVars:URLVariables = new URLVariables(my_str);
  			
  			/*
  			for (var name_str:String in myVars){
  				trace(my_str + "hogehoge");
  				/*
    			if ( my_str.indexOf("ruby/") != 1) {
    				trace(my_str + "hoge");
    				//trace(my_str.indexOf("ruby/"));
    				trace("hoge");
    			}
    			*/
    			//trace([name_str, myVars[name_str]]);
    		if (++_rsrcCnt == RESOUCE_CNT)	compInit();
    		
  		}
  		
  		private function compInit():void {
  			traceArray();
  		}
  			

		
		private function myTrace1(item:*, index:int, array:Array):void { //ただのアドレスだけ格納
 			 //trace(index + "/" + String(item).replace("\n","") );
 			 _s.push(item);
		}
		
		private function myTrace2(item:*, index:int, array:Array):void { //defineマクロで出力されてるやつ格納
 			 //trace(index + "/" + String(item).replace("\n","") );
 			 _define.push(item);
		}
		
		
		private function traceArray():void { //arraycheck
			trace("lenght = " + _s.length);
			trace("dfineLenght = " + _define.length);

			
				
			
			for (var i:uint = 0; i < _s.length; i++) {
				var n:uint = _s[i].indexOf("ruby/") + 5;
				var ln:uint = (_s[i].substring(n)).indexOf(":") ; //コロン後が何文字目か
				
				var fn:String = _s[i].substring(n); //ファイル名からの文字列
				var fns:String = fn.substr(0,ln); //ファイル名のみ
				var line = fn.substring(ln+1); //行数
				
				trace(fn); //ファイル名&行数
				trace("hogeファイル" + fns);	
				trace("n行目" + line);
				
				//結局使うもの 
				_fileName.push(fns);
				
				_line.push(line);
			}
			
			//こっからでふぁいん
			trace("---define---");
			for (var i:uint = 0; i < _define.length; i++) {
				var n:uint = _define[i].indexOf("address::") + 8;
				//trace(n);
				if (n != 7) {
					var addName:String = _define[i].substring(n+1);
					_addArray.push(addName); //どんだけアドレスが登録されてるか
					//trace(addName);
				}
			}
			
			trace("---addarry---");
			for (var i:uint = 0; i < _addArray.length; i++) {
				trace(_addArray[i]);
				//_instName[i] = 0;
				//_funcName[i] = 0;
			}
			
			for (var i:uint = 0; i < _define.length - _addArray.length; i++) {
				if( _define[i].charAt() == "r") {
					var n:uint = _define[i].indexOf("funcaddr=") + 8;
					var s:String = _define[i].substring(n+1);
					//trace(s);
					for (var j:uint = 1; j < _addArray.length; j++) {
						if ( s == _addArray[j]) {
							//trace("def" + s);
							var nn:uint = _define[i].indexOf("name=") + 5;
							var nnn:uint = _define[i].indexOf(",",0);
							var ss:String = _define[i].substr(nn,nnn-nn);
							//trace("ss = "  +ss);
							_instName[j] = ss;
							
							nn = _define[i].indexOf("funcname=") + 9;
							nnn = _define[i].indexOf(", funcaddr=",0);
							ss = _define[i].substr(nn,nnn-nn);
							_funcName[j] = ss;

						}
					}
				}
			}
			
			for (var i:uint = 0; i < _addArray.length; i++) {
				trace("inst= " + _instName[i]);
				trace("func= " + _funcName[i]);
			}
			makeBox();
		}
		
		private function makeBox():void {
			//testMake();
			for (var i:uint = 1; i < _line.length; i++) {
				_box = new Box(_line[i], _fileName[i], _instName[i], _funcName[i]);
				_box.name = i.toString();
				_box.x = 550;
				_box.y = 120;
				_box.alpha = 0;
				_boxArray.push(_box);
	
			}
			initView();
		}
		
		private function testMake():void {
			
			_box = new Box(_line[3], _fileName[3]);
			addChild(_box);
			_box.x = stage.stageWidth / 2 - _box.width / 2;
			_box.y = 120;	
		}
		
		private function initView():void {
			initButton();
			addChild(_boxArray[0]);
			_nowTarget = 0;
			_boxArray[0].alpha = 1;
			_boxArray[0].x =  stage.stageWidth / 2 - _box.width / 2;
			_boxArray[0].y = 120;
		}
		
		private function initButton():void {
			_next = new Button("next");
			_prev = new Button("prev");
			_next.x = stage.stageWidth - 80;
			_prev.x = 80;
			_next.y = stage.stageHeight - 80;
			_prev.y = stage.stageHeight - 80;	
			addChild(_next);
			addChild(_prev);
			_next.buttonMode = true;
			_prev.buttonMode = true;
			_next.addEventListener(MouseEvent.CLICK, onClickNext);
			_prev.addEventListener(MouseEvent.CLICK, onClickPrev);
			
			_auto = new AutoButton();
			_auto.buttonMode = true;
			_auto.x = stage.stageWidth / 2 - 100 / 2 ;
			_auto.y = 330;
			addChild(_auto);
			_auto.addEventListener(MouseEvent.CLICK, onClickAuto);
		}
		
		private function onClickNext(e:MouseEvent):void {
			toNext();
		}
		
		private function onClickPrev(e:MouseEvent):void {
			toPrev();
			
		}
		
		private function onClickAuto(e:MouseEvent):void {
			_autoFlg = true;
			_timer = new Timer(1500);
			_timer.addEventListener(TimerEvent.TIMER, onTimer);
			_timer.start();
		}
		
		private function onTimer(e:TimerEvent):void {
			toNext();
		}
		
		private function toNext():void {
			trace(_nowTarget);
			if (_nowTarget+1 > _line.length-3) {
				trace("これ以上ないよ")
				if (_autoFlg) {
					trace("hoge");
					removeEventListener(TimerEvent.TIMER, onTimer);
					_autoFlg = false;
					_timer.stop();
				}

			} else {
				_nowTarget++;
				addChild(_boxArray[_nowTarget]);
				Tweener.addTween(_boxArray[_nowTarget-1], {x:-550, alpha:0, onComplete:removedNext, transition:"easeInSine", time:0.5});
									 
				Tweener.addTween(_boxArray[_nowTarget], {x:stage.stageWidth / 2 - _box.width / 2, alpha:1, 
								 						onComplete:moved ,transition:"easeInSine", time:0.5});
			}	
		}
		
		private function toPrev():void {
			trace(_nowTarget);
			if (_nowTarget-1 < 0) {
				trace("これ以上ないよ")
			} else {
				_nowTarget--;
				addChild(_boxArray[_nowTarget]);
				Tweener.addTween(_boxArray[_nowTarget+1], {x:550, alpha:0, onComplete:removedPrev, transition:"easeInSine", time:0.5});
									 
				Tweener.addTween(_boxArray[_nowTarget], {x:stage.stageWidth / 2 - _box.width / 2, alpha:1, 
								 						onComplete:moved ,transition:"easeInSine", time:0.5});
			}			
		}
		
		private function removedNext():void {
			removeChild(_boxArray[_nowTarget-1]);	
		}
		
		private function removedPrev():void {
			removeChild(_boxArray[_nowTarget+1]);	
		}
		
		private function moved():void {
			
		}
	}
}
  • Button.as
//Button.as ぼたんです!!!11

package {
	
	import flash.display.Sprite;
	import flash.display.Sprite;
	import flash.geom.*
 	import flash.display.*
 	import flash.text.TextField;
 	import flash.text.TextFormat;
 	
 	public class Button extends Sprite {
		
		private var _sp:Sprite;
		private var _tags:String;
		
		private var _tagTxt:TextField;
		public function Button(tag:String = "hoge") {
			_tags = tag			
			init();
		}
		
		private function init():void {
			var fillType:String = GradientType.RADIAL;
			
			var colors:Array = [0xeeeeee, 0xaaaaaa];
			var alphas:Array = [1, 1];
			var ratios:Array = [0x00, 0xFF];
			var matr:Matrix = new Matrix();
			matr.createGradientBox(0, 0, 0 , 100, 100);
			var spreadMethod:String = SpreadMethod.PAD;
			_sp = new Sprite();
			_sp.graphics.lineStyle(5, 0xf0f0f0);
			_sp.graphics.beginFill(0xcccccc)
			_sp.graphics.drawCircle(0,0,30);
			_sp.graphics.endFill();
			_sp.x = 0;
			_sp.y = 0;
			addChild(_sp);
			
			_tagTxt = new TextField();
			_tagTxt.defaultTextFormat = new TextFormat("",20,0x0,true);
			_tagTxt.text = _tags;
			addChild(_tagTxt);
			_tagTxt.x = _sp.x - 20;
			_tagTxt.y = _sp.y + _sp.height /2+ 5;
		}
	}
}
  • Box.as
//Box.as なんかファイル名とかを表示するやつです!!1
package {
	
	import flash.display.Sprite;
	import flash.geom.*
 	import flash.display.*
 	import flash.text.TextField;
 	import flash.text.TextFormat;
 	
	public class Box extends Sprite {
		
		private var _sp:Sprite;
		/*可視化に関する情報*/
		private var _instName:String;
		private var _fileName:String;
		private var _line:String;
		private var _funcName:String;
		
		private var _s1:String;
		private var _s2:String;
		private var _txtFld1:TextField;
		private var _txtFld2:TextField;
		
		public function Box(line:String, file:String, inst:String = "non", func:String = "non") {
			_instName = inst; //命令名
			_funcName = func; //実行関数
			_line = line; //何行目か
			_fileName = file; //何のファイルか
			trace("box" + _fileName);
			init();
		}
		
		private function init():void {
			
			boxInit();
			txtInit();
			
		}
		
		private function boxInit():void {
			var fillType:String = GradientType.LINEAR;
			
			var colors:Array = [0xffffff, 0xBBBBBB];
			var alphas:Array = [1, 1];
			var ratios:Array = [0x00, 0xFF];
			var matr:Matrix = new Matrix();
			matr.createGradientBox(400, 200, Math.PI / 2, 100, 0);
			var spreadMethod:String = SpreadMethod.PAD;
			
			_sp = new Sprite();
			//_sp.graphics.
			_sp.graphics.lineStyle(5, 0xf0f0f0);
			_sp.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod)
			_sp.graphics.drawRoundRect(0,0,520,150,30,30);
			_sp.graphics.endFill();
			addChild(_sp);	
		}
		
		private function txtInit():void {
			_s1 = "命令名: " + _instName; 
			_s2 = _fileName + "  の  " + _line + "  行目  " +  "\n" + _funcName + "  に定義されています. ";
			_txtFld1 = new TextField();
			_txtFld1.defaultTextFormat = new TextFormat("", 25, 0x0, true);
			
			_txtFld2 = new TextField();
			_txtFld2.defaultTextFormat = new TextFormat("", 30, 0x0, true);	
			
			_sp.addChild(_txtFld1);
			_sp.addChild(_txtFld2);
			_txtFld1.width = 500;
			_txtFld2.width = 500;
			_txtFld1.text = _s1;
			
			//_txtFld1.x = 200 - (_txtFld1.width / 2);
			_txtFld1.x = 20;
			_txtFld1.y = 20;
			
			_txtFld2.text = _s2;
			_txtFld2.x = 20;
			_txtFld2.y = 60;
			
		}
	}
}
  • AutoButton
//AutoButon.as AutoButton用のクラスらしい.なぜButtonと分けたのか謎なので,徹夜明けの僕にでも聞いてください.
package {
	
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFormat;
	public class AutoButton extends Sprite {
		
		private var _sp:Sprite;
		private var _tagTxt:TextField;

		public function AutoButton() {
			init();
		}
		
		private function init():void {
			_sp = new Sprite();
			_sp.graphics.lineStyle(5, 0xf0f0f0);
			_sp.graphics.beginFill(0xcccccc);
			_sp.graphics.drawRoundRect(0,0,100,30,20,20);
			_sp.graphics.endFill();
			addChild(_sp);
			
			_tagTxt = new TextField();
			_tagTxt.defaultTextFormat = new TextFormat("",20,0x0,true);
			_tagTxt.text = "Auto";
			addChild(_tagTxt);
			_tagTxt.x = _sp.x + 25;
			_tagTxt.y = _sp.y + _sp.height /2+ 15;
		}
	}
}

まとめ

とても勉強になったし,楽しかったし,仲間が増えたし,視野が広がったし,知識が増えたし,超有意義に過ごせました!
来年があるない云々言われてますが,あったら皆参加しよう!!!
ぼくみたいに全然できない子でもどうにかなったので,どうにかなるでしょう!たぶん!