Heim  >  Artikel  >  System-Tutorial  >  Syscall-Systemaufruf-Linux-Kernel-Tracing

Syscall-Systemaufruf-Linux-Kernel-Tracing

WBOY
WBOYnach vorne
2024-02-12 21:21:14397Durchsuche

Im Linux-Benutzerbereich müssen wir häufig Systemaufrufe aufrufen. Nehmen wir Linux Version 2.6.37 als Beispiel, um die Implementierung des Lesesystemaufrufs zu verfolgen. Die Implementierung von Systemaufrufen kann zwischen den Linux-Versionen variieren.

Syscall-Systemaufruf-Linux-Kernel-Tracing

In einigen Anwendungen können wir die folgende Definition sehen:

scssCopy code
#define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))

Eigentlich wird die Systemfunktion syscall(SYS_read) aufgerufen, also die Funktion sys_read(). In der Linux-Version 2.6.37 wird diese Funktion durch mehrere Makrodefinitionen implementiert.

Linux-Systemaufruf (SCI, Systemaufrufschnittstelle) ist eigentlich ein Prozess der Mehrkanalaggregation und -zerlegung. Der Aggregationspunkt ist der 0x80-Interrupt-Einstiegspunkt (X86-Systemstruktur). Das heißt, alle Systemaufrufe werden vom Benutzerbereich bis zum Interruptpunkt 0x80 aggregiert und gleichzeitig die spezifische Systemaufrufnummer gespeichert. Wenn der 0x80-Interrupt-Handler ausgeführt wird, werden unterschiedliche Systemaufrufe entsprechend der Systemaufrufnummer separat verarbeitet, dh es werden unterschiedliche Kernelfunktionen zur Verarbeitung aufgerufen.

Es gibt zwei Möglichkeiten, Systemaufrufe auszulösen:

(1) int $0×80, dies war die einzige Möglichkeit, in alten Linux-Kernelversionen einen Systemaufruf auszulösen.

(2) Sysenter-Montageanleitung

Im Linux-Kernel können wir die folgenden Makrodefinitionen verwenden, um Systemaufrufe durchzuführen.

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;
}

Die Makrodefinition von SYSCALL_DEFINE3 lautet wie folgt:

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

## bedeutet, die Zeichen im Makro direkt zu ersetzen,
Wenn name = read, dann wird __NR_##name im Makro durch __NR_read ersetzt. NR##Name ist die Systemrufnummer, ## bezieht sich auf zwei Makroerweiterungen. Das heißt, ersetzen Sie „Name“ durch den tatsächlichen Systemaufrufnamen und erweitern Sie dann __NR.... Wenn name == ioctl, ist es __NR_ioctl.

#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...)                \
    static const char *types_##sname[] = {            \
        __SC_STR_TDECL##x(__VA_ARGS__)            \
    };                            \
    static const char *args_##sname[] = {            \
        __SC_STR_ADECL##x(__VA_ARGS__)            \
    };                            \
    SYSCALL_METADATA(sname, x);                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname, ...)                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#endif

Unabhängig davon, ob das Makro CONFIG_FTRACE_SYSCALLS definiert ist oder nicht, wird letztendlich die folgende Makrodefinition ausgeführt:

__SYSCALL_DEFINEx(x, sname, VA_ARGS)

#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS

#define SYSCALL_DEFINE(name) static inline 
long SYSC_##name

#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));        \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));    \
    asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))        \
    {                                \
        __SC_TEST##x(__VA_ARGS__);                \
        return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));    \
    }                                \
    SYSCALL_ALIAS(sys##name, SyS##name);                \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))

#else /*
 CONFIG_HAVE_SYSCALL_WRAPPERS */

#define SYSCALL_DEFINE(name) asmlinkage 
long sys_##name
#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

#endif /*
 CONFIG_HAVE_SYSCALL_WRAPPERS */

Die folgende Art von Makrodefinition wird schließlich aufgerufen:

asmlinkage long sys##name(__SC_DECL##x(VA_ARGS))
Das ist die Systemfunktion sys_read(), die wir zuvor erwähnt haben.
asmlinkage weist den Compiler an, nur die Argumente der Funktion aus dem Stapel zu extrahieren. Alle Systemaufrufe erfordern dieses Qualifikationsmerkmal! Dies ähnelt der Makrodefinition, die in unserem vorherigen Artikel Quagga erwähnt wurde.

Das heißt, der folgende Code in der Makrodefinition:

struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;

Code-Analyse:

  • fget_light(): Rufen Sie gemäß dem von fd angegebenen Index das entsprechende Dateiobjekt aus dem aktuellen Prozessdeskriptor ab (siehe Abbildung 3).
  • Wenn das angegebene Dateiobjekt nicht gefunden wird, wird ein Fehler zurückgegeben
  • Wenn das angegebene Dateiobjekt gefunden wird:
  • Rufen Sie die Funktion file_pos_read() auf, um die aktuelle Position der Datei zu erhalten, die dieses Mal gelesen und geschrieben wird.
  • Rufen Sie vfs_read() auf, um einen Dateilesevorgang durchzuführen. Diese Funktion ruft letztendlich die Funktion auf, auf die file->f_op.read() zeigt. Der Code lautet wie folgt:

if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);

  • Rufen Sie file_pos_write() auf, um die aktuelle Lese- und Schreibposition der Datei zu aktualisieren.
  • Rufen Sie fput_light() auf, um den Referenzzähler der Datei zu aktualisieren.
  • Abschließend wird die Anzahl der Bytes der gelesenen Daten zurückgegeben.

An diesem Punkt ist die Verarbeitung durch die virtuelle Dateisystemschicht abgeschlossen und die Kontrolle wird an die ext2-Dateisystemschicht übergeben.

Das obige ist der detaillierte Inhalt vonSyscall-Systemaufruf-Linux-Kernel-Tracing. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen