読者です 読者をやめる 読者になる 読者になる

Segmentation Fault

コアダンプの数だけ強くなれるよ、IT企業で働くエンジニアのように。

gdbで絶対秒を日付で表示する

gdbデバッグ時に、対象のプログラムが内部で持っている絶対秒(Unix時間)を
日付に変換して表示する方法。

バグ等でcoreファイルから原因を調査する際に欲しくなったので作ってみた。
具体的には~/.gdbinitにユーザ定義のコマンドを作って実現する。

#普通にgdbでプログラムを動かしている場合は、glibcの関数等を呼び出して変換できるはず。

coreファイル出力用のソースコード

解析用のソースコードとcoreファイルが必要なので、
グローバル変数に時刻と項番を書き込んだらabort()で自爆する単純なプログラムを作る。

printime.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define ENTRY_MAX 10

typedef struct {
    struct timeval tv;
    int entno;
} entry_t;

static entry_t ent[ENTRY_MAX];

int main(int argc, char* argv[])
{
    int i = 0;
    for(i = 0; i < ENTRY_MAX; i++) {
        gettimeofday(&ent[i].tv, NULL);
        ent[i].entno = i;
    }

    abort();

    return 0;
}

~/.gdbinitの作成

gdbinitにユーザコマンドを定義する際のフォーマットは次の通り。

define <コマンド名>
    #実行したい処理
    <処理1>
    <処理2>
    ...
end

↓みたいな秒とマイクロ秒の引数を渡すと日付で表示してくれるコマンドを作る。

(gdb) ShowClock <sec> <usec>
2017/04/14 00:45:12.246025(JST)




実際に作成したgdbinitは下記。
Unix時間から表示する各要素を求めるのがとっても面倒だった。

~/.gdbinit

#
# Convert Unix-Time (tv_sec, tv_usec) to date(yy/mm/dd hh:mm:ss)
#
define ConvertUnixTime2Date
    set $__acdays1  = 31
    set $__acdays2  = 59
    set $__acdays3  = 90
    set $__acdays4  = 120
    set $__acdays5  = 151
    set $__acdays6  = 181
    set $__acdays7  = 212
    set $__acdays8  = 243
    set $__acdays9  = 273
    set $__acdays10 = 304
    set $__acdays11 = 334
    set $__acdays12 = 365

    set $__leapdays = ((($__year-1)/4) - (($__year-1)/100) + (($__year-1)/400)) - 477
    set $__year = 1970 + (($__daycount - $__leapdays)/365)
    set $__restdays = $__daycount - ((($__year - 1970) * 365) + $__leapdays)

    if (($__year % 400 == 0) || (($__year % 4 == 0) && ($__year % 100 !=0 )))
        set $__acdays2++
        set $__acdays3++
        set $__acdays4++
        set $__acdays5++
        set $__acdays6++
        set $__acdays7++
        set $__acdays8++
        set $__acdays9++
        set $__acdays10++
        set $__acdays11++
        set $__acdays12++
    end

    if ($__restdays <= $__acdays1)
        set $__mon = 1
        set $__day = $__restdays
    end

    if ($__acdays1 < $__restdays && $__restdays <= $__acdays2)
        set $__mon = 2
        set $__day = $__restdays - $__acdays1
    end

    if ($__acdays2 < $__restdays && $__restdays <= $__acdays3)
        set $__mon = 3
        set $__day = $__restdays - $__acdays2
    end

    if ($__acdays3 < $__restdays && $__restdays <= $__acdays4)
        set $__mon = 4
        set $__day = $__restdays - $__acdays3
    end

    if ($__acdays4 < $__restdays && $__restdays <= $__acdays5)
        set $__mon = 5
        set $__day = $__restdays - $__acdays4
    end

    if ($__acdays5 < $__restdays && $__restdays <= $__acdays6)
        set $__mon = 6
        set $__day = $__restdays - $__acdays5
    end

    if ($__acdays6 < $__restdays && $__restdays <= $__acdays7)
        set $__mon = 7
        set $__day = $__restdays - $__acdays6
    end

    if ($__acdays7 < $__restdays && $__restdays <= $__acdays8)
        set $__mon = 8
        set $__day = $__restdays - $__acdays7
    end

    if ($__acdays8 < $__restdays && $__restdays <= $__acdays9)
        set $__mon = 9
        set $__day = $__restdays - $__acdays8
    end

    if ($__acdays9 < $__restdays && $__restdays <= $__acdays10)
        set $__mon = 10
        set $__day = $__restdays - $__acdays9
    end

    if ($__acdays10 < $__restdays && $__restdays <= $__acdays11)
        set $__mon = 11
        set $__day = $__restdays - $__acdays10
    end

    if ($__acdays11 < $__restdays && $__restdays <= $__acdays12)
        set $__mon = 12
        set $__day = $__restdays - $__acdays11
    end

end

#
# Show clock form Unix-Time
# This command requires 2 arguments (tv_sec, tv_usec)
#
define ShowClock

    set $__tv_sec = $arg0
    set $__tv_usec = $arg1

    # Set Time-Zone(JST)
    set $__timezone = 9
    set $__tv_sec = $__tv_sec + ($__timezone * 60 * 60)

    set $__mon        = 0
    set $__day      = 0
    set $__daycount = ($__tv_sec / 86400) + 1
    set $__year     = (1970 + ($__daycount / 365))
    set $__hour     = (($__tv_sec % 86400) / 3600)
    set $__min        = ((($__tv_sec % 86400) / 60) % 60)
    set $__sec        = (($__tv_sec % 86400) % 60)

    ConvertUnixTime2Date

    if ($__timezone == 0)
        printf "%04d/%02d/%02d %02d:%02d:%02d.%06d(UTC)  ", \
               $__year, $__mon, $__day, $__hour, $__min, $__sec, $__tv_usec
    end

    if ($__timezone == 9)
        printf "%04d/%02d/%02d %02d:%02d:%02d.%06d(JST)  ", \
               $__year, $__mon, $__day, $__hour, $__min, $__sec, $__tv_usec
    end
end


define ShowEntryDump

    set $__index = 0

    while ($__index < 10)
        set $__ent = &ent[$__index]
        ShowClock $__ent->tv.tv_sec $__ent->tv.tv_usec
        printf "entno=%d\n", $__ent->entno
        set $__index++
    end
end

実行結果

$ ulimit -c unlimited
$ ./printime
$ gdb printime corefile
$ (gdb) showentrydump



f:id:segmentation-fault:20170414005018p:plain




すごく処理が重いけどいい感じ。

Javascriptでオセロ(その2)


前回に引き続き、不足していた機能を追加してみた。



























----------------------------------
こんな感じのオセロが完成。申し訳程度の対AIもサポート。


ソースコード

下記で公開。

github.com


このページには下記で埋め込んで実行させている。

<body>
    <link rel="stylesheet" type="text/css" href="https://rawgit.com/ke1suke/othello/master/css/board.css">
    <script type="text/javascript" src="https://rawgit.com/ke1suke/othello/master/js/othello.js"></script>
    
    <div style="display:none">
        <div id="none"  class="square"><img class="block" src="https://raw.githubusercontent.com/ke1suke/othello/master/img/none.png" ></img></div>
        <div id="black" class="square"><img class="block" src="https://raw.githubusercontent.com/ke1suke/othello/master/img/black.png"></img></div>
        <div id="white" class="square"><img class="block" src="https://raw.githubusercontent.com/ke1suke/othello/master/img/white.png"></img></div>
    </div>

    <div id="board"></div>
    <div id="msg" class="message"></div>
    
    <form name="form1" style="display:block; position: relative; top:230px" action="">
        <label><input type="checkbox"  name="check[]" id="Computer" value="1" autocomplete="off"/> Computer</label>
        <label><input type="checkbox" name="check[]" id="First" value="2" autocomplete="off" checked="checked"/> Bat First</label>
        <p>
            <input type="button" value="Play" onclick="OnClickButton();"/>
        </p>
    </form>

</body>

Javascriptでオセロ(その1)

HTML+JavaScriptでブラウザで動くオセロを実装してみる。
制限付き(*1)で動いたところまで。

ソースコードはほとんど参考(*2)のまま。


(*1) 機能制限

  • AIなし(人間vs人間だけ)
  • 黒が先行
  • パス不可
  • 勝利判定なし

ソースコード

html

othello.html

<html>
<head>
	<title>Othello</title>
	<link rel="stylesheet" type="text/css" href="css/board.css">
</head>

<body>
	<script type="text/javascript" src="js/othello.js"></script>
	
	<!-- 盤面の要素定義 -->
	<div style="display:none">
		<div id="cell" class="square"><div class="cell"></div></div>
		<div id="black" class="square"><img class="block" src="img/black.png"></img></div>
		<div id="white" class="square"><img class="block" src="img/white.png"></img></div>
	</div>

	<div id="board"></div>


</body>
</html>
javascript

othello.js

(function() {
    // 変数定義
    var BOARD_TYPE = {
        'WIDTH' :8,
        'HEIGHT':8,
    };

    var PIECE_TYPE = {
        'NONE'   : 0,
        'BLACK'  : 1,
        'WHITE'  : 2,
        'MAX'    : 3,
    };

    var stone;
    var board = [];

    var turn = PIECE_TYPE.BLACK;
    var checkTurnOver = function(x, y, flip) {
    
        var ret = 0;
        
        for (var dx = -1; dx <= 1; dx++) {
            for(var dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) {
                    continue;
                }
            
                var nx = x + dx;
                var ny = y + dy;
                var n = 0;
                while(board[nx][ny] == PIECE_TYPE.MAX - turn) {
                    n++;
                    nx += dx;
                    ny += dy;
                }
                
                if (n > 0 && board[nx][ny] == turn) {
                    ret += n;
                    
                    if (flip) {
                        nx = x + dx;
                        ny = y + dy;
                        
                        while(board[nx][ny] == PIECE_TYPE.MAX - turn) {
                            board[nx][ny] = turn;
                            nx += dx;
                            ny += dy;
                        }
                        
                        
                    }
                }
            }
        }
        
        return ret;
    };
    
    var showBoard = function() {
    
        var b = document.getElementById("board");
        
        while(b.firstChild) {
            b.removeChild(b.firstChild);
        }
        
        for(var y = 1; y <= BOARD_TYPE.HEIGHT; y++) {
            for(var x = 1; x <= BOARD_TYPE.WIDTH; x++) {
                var cell = stone[board[x][y]].cloneNode(true);
                
                cell.style.left = ((x - 1) * 31) + "px"; 
                cell.style.top = ((y - 1) * 31) + "px"; 
                b.appendChild(cell);
                
                if (board[x][y] == PIECE_TYPE.NONE) {
                    (function() {
                        var _x = x;
                        var _y = y;
                        //alert("break point")
                        cell.onclick = function() {
                            if (checkTurnOver(_x, _y, true) > 0) {
                                board[_x][_y] = turn;
                                showBoard();
                                turn = PIECE_TYPE.MAX - turn;
                            }
                            
                        };
                    })();
                }
            }
        }
        
    };

    onload = function() {
        
        // 0:石無し, 1:黒, 2:白
        stone = [
            document.getElementById("cell"),
            document.getElementById("black"),
            document.getElementById("white")
        ];
        
        // PIECE種別の凍結(念のため)
        Object.freeze(PIECE_TYPE);
        
        // 盤面を初期化
        for (var i = 0; i < 10; i++) {
            board[i] = [];
            for (var j = 0; j < 10; j++) {
                board[i][j] = PIECE_TYPE.NONE;
            }
        }
        
        // 黒白の初期配置
        board[4][5] = PIECE_TYPE.BLACK;
        board[5][4] = PIECE_TYPE.BLACK;
        board[4][4] = PIECE_TYPE.WHITE;
        board[5][5] = PIECE_TYPE.WHITE;
        
        // 盤面表示
        showBoard();
    };
})();
css
#board{
    position            : relative;
}

.cell
{
    position            : relative;
    top                 : 1px;
    left                : 1px;
    width               : 31px;
    height              : 31px;
    background-color    : #00ff00;
}

.square
{
    position            : absolute;
    width               : 33px;
    height              : 33px;
    background-color    : #000000;
}

.block
{
    display             : block;
    position            : relative;
    top                 : 1px;
    left                : 1px;
    width               : 31px;
    height              : 31px;
}
その他

black.png
f:id:segmentation-fault:20170320225002p:plain

white.png
f:id:segmentation-fault:20170320225005p:plain

実行結果

f:id:segmentation-fault:20170320225855p:plain


次回は下記を目標に作業。


(*2 参考)
【プログラミング】オセロを1時間で作ってみた【実況解説】 by t-kihira ニコニコ技術部/動画 - ニコニコ動画

ソースコードでよく使う英単語

ソースコード書くときによく使う英単語(と対義語)。

動詞系

  • add/del
  • create/destory
  • start/stop
  • allow/deny
  • enqueue/dequeue
  • get/put
  • push/pop
  • write/read
  • send[snd]/recv[rcv]
  • lock/unlock
  • import/export

その他

  • head/tail
  • prev/next
  • old/new


deleteなのかeraseなのか、lastなのかendなのかは曖昧だったりする。
Linuxカーネルソースコードとか、ソフトウェアのコンフィグで使われてる実例から一覧を作ろうかな。

kivyで始めるGUIプログラミング

kivyを使ってpythonでサクッと簡単(*1)にGUIプログラミングを試してみる。

(*1)環境構築はあまりサクッとは行かない模様


[実行環境]

いつものLinux側でプログラムを実行してWindows側で表示するスタイル。

事前準備

$ python --version
Python 3.5.1
$ sudo yum install python-pip 
$ pip install cython==0.23
$ pip install pygame
$ pip install kivy

プログラム作成

本家サイトのサンプルそのまま。

test.py

from kivy.app import App
from kivy.uix.button import Button

class TestApp(App):
    def build(self):
        return Button(text='Hello World')

TestApp().run()

実行結果

$ python test.py


f:id:segmentation-fault:20170308215016p:plain

XORで暗号化&複合化

最も簡単な暗号化/複合化を試してみる。
任意のデータとある定数値の排他的論理和(XOR)を2回とると元のデータに戻る性質を利用する。

例)

任意のデータ : 10101010
XORをとる定数: 11110000

1回目
    10101010
XOR 11110000
-------------
    01011010

2回目
    01011010
XOR 11110000
-------------
    10101010 ★

ソースコード

1byte単位で暗号/複合キーとのXORをとりファイルへ書き出す。

xor.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#define XOR_KEY 0xE5

int main(int argc, char* argv[])
{

    if (argc != 3) {
        printf("usage : %s <src file> <dst file> \n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE* srcfp = fopen(argv[1], "rb");
    if (NULL == srcfp) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    FILE* dstfp = fopen(argv[2], "w+b");
    if (NULL == dstfp) {
        perror("fopen");
        fclose(srcfp);
        exit(EXIT_FAILURE);
    }

    while(0 == feof(srcfp)) {
        uint8_t dat = 0x00;
        size_t rs = fread(&dat, sizeof(dat), 1, srcfp);
        if (rs == 0) {
            break;
        }

        /* 暗号化 or 複合化 */
        dat ^= XOR_KEY;

        fwrite(&dat, sizeof(dat), 1, dstfp);
    }

    fclose(dstfp);
    fclose(srcfp);

    return 0;
}

暗号化対象のデータ

file1.txt

$ cat file1.txt
abcdefghijklmnopqrstuvwxyz
$
$ hexdump -C file1.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b

実行結果

$ gcc -o xor xor.c
$ ./xor file1.txt file2.txt
$ ./xor file2.txt file3.txt
$
$ hexdump -C file1.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b
$ hexdump -C file2.txt
00000000  84 87 86 81 80 83 82 8d  8c 8f 8e 89 88 8b 8a 95  |................|
00000010  94 97 96 91 90 93 92 9d  9c 9f ef                 |...........|
0000001b
$ hexdump -C file3.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b

エクセルでプログレスバーを表示する

エクセルのマクロ(VBA)で処理の進捗状況を表示する。

プログレスバーのフォーム作成

フォームの追加

f:id:segmentation-fault:20170303233616p:plain


コントロールボックスにプログレスバーを追加

f:id:segmentation-fault:20170303233642p:plain

f:id:segmentation-fault:20170303233749p:plain

f:id:segmentation-fault:20170303233801p:plain


ラベル、ボタン、バーを追加してそれっぽく作成

f:id:segmentation-fault:20170303233846p:plain

ソースコード作成

UserFormに中断ボタン実行を判定するフラグを追加する。

UserForm

'中断ボタン実行フラグ
Public IsCancel As Boolean

Private Sub CommandButton1_Click()
  '中断ボタン実行でフラグをオン
  IsCancel = True

End Sub

Private Sub Label1_Click()

End Sub


Private Sub ProgressBar1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)


End Sub

Private Sub UserForm_Click()

End Sub

Moduleにプログレスバー表示処理を追加

Main Module

'Sleepを使うための定義
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If


Sub ProgressBar()
  
  Const MaxCount As Long = 100
  
  UserForm2.Show P_bar
  UserForm2.ProgressBar1.Min = 1
  UserForm2.ProgressBar1.Max = MaxCount
  
  UserForm2.IsCancel = False
  
  Dim index As Long
  Dim progress As Long
  For index = 1 To MaxCount
  
    Sleep (100)
    
    progress = CInt((index / MaxCount) * 100)
    UserForm2.Label1.Caption = index & "%完了"
    UserForm2.ProgressBar1.Value = index
  
    If UserForm2.IsCancel = True Then
      End
    End If
  
    DoEvents
    
  Next
  
  Unload UserForm2

End Sub

実行結果

f:id:segmentation-fault:20170303234347p:plain