NAKAMURA Minoru の日記 (2008年7月)

先月の日記(2008年06月) 今月の日記(2008年07月)
2002 | 10 | 11 | 12
2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2012 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2013 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2014 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2015 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2016 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2017 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
ホームページ | 最新のコメント50
インデックス: 食べ歩き | Java | プログラム | UNIX | 画像
最新の日記へのリンク | この日記ページをはてなアンテナに追加 この日記ページをはてなブックマークに追加
はてな ダイアリー アンテナ ブックマーク ブログ
Twitter | mixi | Facebook | Google+
slideshare | github | Qiita



7/29 (火)

[CPU] Itanium2 プロセッサのエラッタ?

前提

最近のアーキテクチャには CPU が指定のメモリ位置に到着したり、 指定のメモリにアクセスした時にトラップ/フォルトをあげるハード機構が存在する。 ここではまとめてデバッグレジスタ と呼ぶことにする。 デバッグレジスタ機構は、 主にデバッガから利用され、 例えば gdb だと awatch コマンドのために利用されている。

我らが IA-64 アーキテクチャは、 他のアーキテクチャと比べて結構リッチなデバッグレジスタを持っている。 Itanium2 プロセッサの場合、 命令実行を停止させるための Instruction Break Register (IBR)が4組、 指定のメモリアクセスをした時にフォルトを発生させるための Data Break Register (DBR)が4組も存在する (デバッグレジスタの数はアーキテクチャ上は可変数となっている)。 同じ Intel の IA-32 の場合にはデバッグレジスタは命令/データが兼用で4組存在しかない。

さらに面白いのは IA-64 のデバッグレジスタは DBR/IBR は 2 本のレジスタが一組で、 偶数レジスタは「アドレス指定レジスタ」と 奇数レジスタは「マスク指定レジスタ」となっている点だ。 検査アドレスがデバッグレジスタにヒットするとは、 以下が求められる。

  1. 検査アドレスの上位8ビットがアドレス指定レジスタの上位8ビットに一致する。
  2. 検査アドレスの下位56ビットがマスク指定レジスタの下位56ビットで論理積をとったものと、 アドレス指定レジスタの下位56ビットがマスク指定レジスタの下位56ビットをとったものに一致する。
bool match_dbr(uint64_t address, uint64_t dbr_address, uint64_t dbr_mask)
{
    uint64_t mask = (dbr_mask | 0xFF00000000000000UL)

    return (address & mask) == (dbr_address & mask);
}

IA-32 のデバッグレジスタなどの検査するバイト範囲が1,2,4バイトに絞られているのに対して、 IA-64 はマスクを使って自由に合成できる。 そのため2のべき乗の並んだ巨大配列の列要素だけを検査対象にするなどの柔軟な指定が可能だ。

ちなみにマスク指定レジスタのアドレスマスクに使用されない上位8ビットは、 属性情報を指定するのに利用される。

struct dbr_address {
    uint64_t   r       : 1;  // 読み込みでブレークする
    uint64_t   w       : 1;  // 書き込みでブレークする
    uint64_t   ignore  : 2;
    uint64_t   pl      : 4;  // ブレークする特権レベル(PL0〜PL3)をビット指定
    uint64_t   mask    : 56;
};

Itanium2 のデバッグレジスタにはもう一つ美味しい点がある。 少なくともデータブレークの方はブレーク設定を有効にしたままプログラムを走行させても、 DBR の設定にヒットしない限り実行速度が落ちないという点だ。 これは Madison/Montecito で中規模テストプログラムの走行実験を行って、 観測可能な範囲で速度低下ないことを確かめている。 このためブレークレジスタを gdb などのデバッガにデバッグ用に使わせるのではなく、 自分のプログラムの中で利用したくなる (当然、カーネルを書き直すことが前提)。

エラッタ?

DBR の値の変更に対してデバッグレジスタ機構が正しく追従してこない現象を発見。 検査範囲外のメモリアクセスに対してデータデバッグブレークフォルトが発生することがある。

DBR は 0x0007ffff00000000 の1バイトをピンポンでアクセスした場合のみに デバッグフォルトが発生するように仕掛けているのに、 0x0010028000????? という明後日なアドレスでフォルトが発生する。 現在残っている DBR は、どう考えても 0x0010028000????? でブレークしない設定だ。

dbr[0] = 0x0007ffff00000000
dbr[1] = 0x48ffffffffffffff // r=0, w=1, pl3 のみ許可, mask=0x00ffffffffffffff
dbr[2] = 0x0000000000000000
// あと dbr[7] まで 0x0

直前までは 0x0010028000????? にヒットする dbr があったのだが、 それはアドレスを書き潰して srlz.d を発行済み。

一方、 1組目の DBRのマスク指定レジスタを変更して、 「どの特権レベルでもブレークしない」と指定すると、 同じ状態でもデータブレークフォルトが発生しなくなる。

dbr[1] = 0x48ffffffffffffff // r=0, w=1, pl3 のみ許可, mask=0x00ffffffffffffff
        ↓
dbr[1] = 0x40ffffffffffffff // r=0, w=1, どの plでも許可しない, mask=0x00ffffffffffffff

Itanium Processor Specification には、 「IBR を書き直す場合にはいったん PSW.db=0 にしないとダメ」というエラッタが載っているのだが、 これも同種のエラッタなのかしら?

追記:2009/1/19

Itanium2 は PSW.db=1 の時は16バイト境界を越えるメモリアクセスを行なうと 常にデバッグフォルトがあがるという実装らしい。 トホホ。


7/27 (日)

[Linux] SIGSEGV シグナルをエミュレーションできないものかしら?

SIGSEGV シグナルハンドラを利用して プロセス内で独自のメモリ管理を導入しているプログラムは多いと思う。 というか、ここ数年はそういうプログラムしか書いたことがない。

問題はそういうプログラムだとテスト方法が面倒で、 「最初にページにアクセスした時」とか、 「ページが回収されて mumap された時」とかの状況を作り辛い。 そこでSIGSEGV シグナルハンドラのテストのために、 プログラムの中で SIGSEGV シグナルを意図的に生成できないものかと考える。 ぶっちゃけ 任意のsi_codesi_addr を持った SIGSEGV シグナルをテスト生成 できないだろうか?

raise(3) は SIGSEGV シグナルであることしか指定できない。 sigqueue(2) を利用すると si_code は SI_QUEUE になる。 si_addr の方は、 siginfo_t 構造体の中で si_addr と si_int/si_ptr が偶然同じ位置を占める アーキテクチャ以外は指定できないため、 実質的に利用不可能だ。

#include <stdio.h>
#include <stdint.h>
#include <signal.h>

void handler(int signu, siginfo_t * info, void * data)
{
    printf("si_code = %d si_addr = %p\n", info->si_code, info->si_addr);
    exit(0);
}

int main(int argc, char** argv)
{
    struct sigaction act;
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = handler;
    sigemptyset(&act.sa_mask);

    if (sigaction(SIGSEGV, &act, NULL)) {
        perror("sigaction"), exit(1);
    }

#if 1
    raise(SIGSEGV);
#else
    sigval_t value;
    value.sival_ptr = (void*)(uintptr_t)0x0123456789ABCDEFUL;
    if (sigqueue(getpid(), SIGSEGV, value)) {
        perror("sigqueue"), exit(1);
    }
#endif

    return 0;
}

実際、si_code や si_addr がデタラメな値になる。 ダメみたい。

si_code = -1 si_addr = 0x1f500003d52

7/26 (金)

[MyWeb] 自サイトの DNS キャッシュ汚染の対策

世の中を賑わせている DNS キャッシュ汚染問題のチェックをしてみる。

ソースポートのランダム性に関しては POOR のようだ。 ソースポートのランダム性に関しては DNS サーバの bind 任せだから、 今のところ named.conf で設定を変更することはできないようだ。

> nslookup -q=txt porttest.dns-oarc.net ns.nminoru.jp
Server:		ns.nminoru.jp
Address:	219.117.195.5#53

Non-authoritative answer:
porttest.dns-oarc.net	canonical name = z.y.x.w.v.u.t.s.r.q.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.pt.dns-oarc.net.
z.y.x.w.v.u.t.s.r.q.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.pt.dns-oarc.net	text = "219.117.195.5 is POOR: 26 queries in 3.3 seconds from 26 ports with std dev 105.58"

Authoritative answers can be found from:
z.y.x.w.v.u.t.s.r.q.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.pt.dns-oarc.net	nameserver = ns.z.y.x.w.v.u.t.s.r.q.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.pt.dns-oarc.net.

とりあえず自宅のネットワークは外部/内部で別の DNS サーバを使っていて、 外部公開用の DNSサーバも recursive query を受け付けていない。 当面はよしとしよう。


7/24 (木)

[時事] 岩手県沿岸地震

岩手県沿岸部に00:26分頃にマグニチュード6.8の地震が発生。
徹夜中、誰もいない会社のビルがグラグラと揺れる。


7/4 (木)

[Prog] g++ で offsetof が警告に

g++ で offsetof をクラスに対して適用すると警告が表示される。

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

class T {
private:
    int _field;

public:
    static size_t getFieldOffset();
};

size_t T::getFieldOffset() { return offsetof(T, _field);}
offsetof.cpp: In static member function 'static size_t T::getFieldOffset()':
offsetof.cpp:15: warning: invalid access to non-static data member 'T::_field' of NULL object
offsetof.cpp:15: warning: (perhaps the 'offsetof' macro was used incorrectly)

そういう時は -Wno-invalid-offsetof をつけよう。

トラックバック   [Trackback URL: http://www.nminoru.jp/cgi-bin/tb.cgi/2008-07-04]
[モデラート - C#とゲーム開発と雑記] [C++][cygwin][UNIX&Linuxコマンド・シェルスクリプト]g++でoffsetofを使うと警告 2008-11-30 (Sun) 03:24:24
出典 NAKAMURA Minoru の日記 -- g++ で offsetof が警告に メンバ変数のオフセットを取得するマクロを使うとinvalid access to non-static data member とかいう警告がでます。 コンストラクタのあるクラスや構造体ででるっぽいです。 stddef.hのoffsetofマクロだけじゃな

先月の日記(2008年06月) 今月の日記(2008年07月)
2002 | 10 | 11 | 12
2003 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2004 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2005 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2006 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2007 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2008 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2009 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2010 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2011 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2012 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2013 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2014 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2015 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2016 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
2017 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
ホームページ | 最新のコメント50
インデックス: 食べ歩き | Java | プログラム | UNIX | 画像
最新の日記へのリンク | この日記ページをはてなアンテナに追加 この日記ページをはてなブックマークに追加
はてな ダイアリー アンテナ ブックマーク ブログ
Twitter | mixi | Facebook | Google+
slideshare | github | Qiita


Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp