1

Ubuntu 12.04 (64 ビット) で chroot された Debian Etch (32 ビット) をセットアップしました。errno は EINVAL に設定されています。これは、man ページによると、「指定された clk_id はこのシステムではサポートされていません」という意味です。

3 つのクロックはすべて、chroot された Debian の外でも、64 ビット chroot された Debian etch でも正常に動作します。

誰かが私にこれが当てはまる理由とそれを修正する方法を説明できますか?

とても有難い。

4

1 に答える 1

1

原因はまだわかりませんが、コメント欄に収まりきらないアイデアがあります。

まず、C++ ではなく C としてコンパイルし、libpthread にリンクしないことで、テスト プログラムをより単純にすることができます。-lrtを取得するのに十分なはずですclock_gettime。また、それをコンパイルすると-static、動的リンカのスタートアップがそこにないため、トレースが容易になる可能性があります。

静的リンクは、clock_gettime の動作を変更することさえあります。バグを回避できるかどうかを調べるだけでも価値があります。

もう 1 つ見たいのは、この vdso バイパス テスト プログラムの出力です。

#define _GNU_SOURCE
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(void)
{
    struct timespec ts;
    if(syscall(SYS_clock_gettime, CLOCK_PROCESS_CPUTIME_ID, &ts)) {
        perror("clock_gettime");
        return 1;
    }
    printf("CLOCK_PROCESS_CPUTIME_ID: %lu.%09ld\n",
           (unsigned long)ts.tv_sec, ts.tv_nsec);
    return 0;
}

の有無にかかわらず-static、失敗した場合は追加しstraceます。

更新 (実際には、これをスキップします。2 番目の更新に進みます)

さらにいくつかの簡単なテストのアイデア:

  1. -m32gcc コマンドに追加して、Ubuntu ホスト システムで 32 ビット テスト プログラムをコンパイルして実行します。カーネルの 32 ビット互換モードがエラーの原因である可能性があります。その場合、32 ビット バージョンは、リンク先の libc に関係なく失敗します。
  2. Debian でコンパイルした非静的テスト プログラムを Ubuntu ホスト システムにコピーし、そこで実行してみてください。動作の変更は、原因として libc を指します。

次に、難しいものの時間です。逆アセンブルされたコードを見て、おそらく gdb でそれをシングルステップ実行します。あなた自身でそれを行う代わりに、あなたが実行しているコードのコピーを入手したいと思います. 静的にコンパイルされた失敗したテスト プログラムを、入手できる場所にアップロードしてください。また、カーネルが提供する 32 ビット vdso のコピーも興味深いかもしれません。vdso を抽出するには、次のプログラム (32 ビット chroot でコンパイル) を実行して、というファイルを作成し、vdso.dumpそれもアップロードします。

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

static int getvseg(const char *which, const char *outfn)
{
  FILE *maps, *outfile;
  char buf[1024];
  void *start, *end;
  size_t sz;
  void *copy;
  int ret;
  char search[strlen(which)+4];

  maps = fopen("/proc/self/maps", "r");
  if(!maps) {
    perror("/proc/self/maps");
    return 1;
  }
  outfile = fopen(outfn, "w");
  if(!outfile) {
    perror(outfn);
    fclose(maps);
    return 1;
  }

  sprintf(search, "[%s]\n", which);
  while(fgets(buf, sizeof buf, maps)) {
    if(strlen(buf)<strlen(search) ||
       strcmp(buf+strlen(buf)-strlen(search),search))
      continue;
    if(sscanf(buf, "%p-%p", &start, &end)!=2) {
      fprintf(stderr, "weird line in /proc/self/maps: %s", buf);
      continue;
    }
    sz = (char *)end - (char *)start;
    /* copy because I got an EFAULT trying to write directly from vsyscall */
    copy = malloc(sz);
    if(!copy) {
      perror("malloc");
      goto fail;
    }
    memcpy(copy, start, sz);
    if(fwrite(copy, 1, sz, outfile)!=sz) {
      if(ferror(outfile))
        perror(outfn);
      else
        fprintf(stderr, "%s: short write", outfn);
      free(copy);
      goto fail;
    }
    free(copy);
    goto success;
  }
  fprintf(stderr, "%s not found\n", which);

fail:
  ret = 1;
  goto out;
success:
  ret = 0;
out:
  fclose(maps);
  fclose(outfile);
  return ret;
}

int main(void)
{
  int ret = 1;
  if(!getvseg("vdso", "vdso.dump")) {
    printf("vdso dumped to vdso.dump\n");
    ret = 0;
  }
  if(!getvseg("vsyscall", "vsyscall.dump")) {
    printf("vsyscall dumped to vsyscall.dump\n");
    ret = 0;
  }
  return ret;
}

更新 2

etch libc をダウンロードしてこれを再現しました。それは間違いなくglibcの愚かさが原因です。clock_gettime の単純な syscall ラッパーの代わりに、「事前承認されていないクロック ID は使用できません」というプリプロセッサ スパゲッティの大きな塊があります。古い glibc では動作しません。これは、私が聞きたくない質問に私たちを導きます: どうして古いバージョンの Debian を使おうとしているのですか?

于 2012-08-23T21:31:47.400 に答える