syscall.c int fetchstr(uint addr, char **pp)

トップページ
jupiteroak.hatenablog.com


syscall.c
https://github.com/mit-pdos/xv6-public/blob/master/syscall.c#L31

int fetchstr(uint addr, char **pp)
{
  char *s, *ep;
  struct proc *curproc = myproc();

  if(addr >= curproc->sz)
    return -1;
  *pp = (char*)addr;
  ep = (char*)curproc->sz;
  for(s = *pp; s < ep; s++){
    if(*s == 0)
      return s - *pp;
  }
  return -1;
}

fetchstr関数は、プロセスのユーザ空間においてアドレスaddが指定するメモリ領域に格納されたヌル終端文字列を、アドレスppが指定するポインタが参照できるようにします。

引数 uint addr
ヌル終端文字列が格納されたメモリ領域を指定するアドレス。

引数 char **pp
ヌル終端文字列を参照するポインタを指定するアドレスです。

戻り値 (char *)(s - *pp) または -1
アドレスaddrが指定するメモリ領域にヌル終端文字列が格納されていた場合は、ヌル終端文字列のサイズ(ヌル文字を除く)が戻り値となります。
アドレスaddrやアドレスaddrが指定するメモリ領域に格納されている値が不正だった場合は、-1が戻り値となります。

処理の内容

現在実行中のプロセスに対応しているプロセスディスクリプタを取得する

struct proc *curproc = myproc();

myproc関数を呼び出して、現在この関数を実行中のプロセスに対応しているプロセスディスクリプタを取得します。

アドレスaddrが不正な値ではないことを確認する

if(addr >= curproc->sz)
    return -1;

addr >= curproc->szが真となる場合→アドレスaddrがプロセスのカーネル空間に入ってしまっている場合は、-1を戻り値として処理を終了します。
プロセスのユーザー空間のサイズがszの時、プロセスのユーザー空間の終端アドレスはsz-1となるので、カーネル空間の先頭アドレスはszとなります。

アドレスppが指定するポインタp*がヌル終端文字列のデータを参照できるようにする

 *pp = (char*)addr;

char型へのポインタのポインタであるppに間接参照演算子を用いることで、ppが指定するポインタp*にアドレスaddrを格納しています。
これにより、アドレスaddが指定するメモリ領域に格納されたヌル終端文字列を、アドレスppが指定するポインタが参照できるようになります。

ヌル終端文字列であることを確認する

ep = (char*)curproc->sz;
  for(s = *pp; s < ep; s++){
    if(*s == 0)
      return s - *pp;
  }

ドレスaddが指定するメモリ領域に格納された文字列がヌル終端文字列であることを確かめるために、文字列の先頭アドレス *pp(addr)から
プロセスのユーザー空間の終端アドレスsz-1までの範囲を走査して、ヌル文字を探します。
ヌル文字が見つかった場合→*s == 0が真となる場合は、ヌル文字が配置しているアドレス値から文字列の先頭アドレス値を引くことで文字列データのサイズ(ヌル文字を除く)を算出し、その値を戻り値としてリターンします。

ヌル終端文字列の長さがユーザ空間を越えている場合は処理を終了する

return -1;

for文のループ処理を全て終えた場合→ユーザ空間内でヌル文字が見つからなかった場合→ヌル終端文字列の長さがユーザ空間を越えている場合は、-1を戻り値として処理を終了します。