Aliasy funkcji modelu danych debugera

Aliasy funkcji to unikatowa krótka nazwa, za pomocą której użytkownik debugera może uzyskać dostęp do funkcji zdefiniowanych w rozszerzeniu debugera (niezależnie od tego, czy jest napisany w języku C++, czy w środowisku skryptowym, takim jak JavaScript). Ta krótka nazwa jest skojarzona z obiektem funkcji modelu danych (obiekt, który implementuje element IModelMethod). Ta funkcja przyjmuje dowolną liczbę argumentów i zwraca pojedynczą wartość. Wpływ wywoływania aliasu funkcji i tego, co robi się z tej wartości, zależy od sposobu wywoływania aliasu funkcji i wywoływania debugera hosta w obrębie.

W tym temacie założono, że czytelnik jest zaznajomiony z modelem obiektów debugera i językiem JavaScript. Aby uzyskać informacje o korzystaniu z obiektów debugera w języku JavaScript, zobacz Native Debugger Objects in JavaScript Extensions (Rozszerzenia JavaScript).

Niektóre z przedstawionych tutaj przykładów używają polecenia dx, aby uzyskać więcej informacji na temat pracy z poleceniem dx, zobacz dx (Display Debugger Object Model Expression). Ponadto używany jest linQ, który jest opisany w Using LINQ With the debugger objects.

Używanie aliasu funkcji jako poleceń rozszerzenia

Wszystkie aliasy funkcji utworzone w usłudze WinDbg można wywołać tak, jakby były one rozszerzeniem debugowania ! polecenia "bang". Jeśli funkcja nie przyjmuje żadnych argumentów, po prostu wywołanie !aliasName spowoduje wywołanie funkcji i wyświetlenie wartości wyniku. Jako przykład (utworzony za pomocą rozszerzalności języka JavaScript)

Na przykład ta funkcja udostępnia dwie stałe wartości, pi i e.

function __constants()
{
    return { math_constants : { pi :  3.1415926535 , e :  2.7182818284}, description : "Archimedes' pi and Euler's number e" };
}

function initializeScript()
{
    return [new host.functionAlias(__constants, "constants")];
}

Wyniki wywoływania aliasu funkcji są wyświetlane tutaj.

0:000> !constants
@$constants()                 : [object Object]
    math_constants   : [object Object]
    description      : Archimedes' pi and Euler's number e

Linki DML do złożonych obiektów będą generowane automatycznie. Kliknięcie powyższego math_constants spowoduje wyświetlenie następujących danych wyjściowych.

0:000> dx -r1 @$constants().math_constants
@$constants().math_constants                 : [object Object]
    pi               : 3.141593
    e                : 2.718282

Jeśli funkcja ma argumenty, można je podać po samym poleceniu aliasu funkcji. Należy pamiętać, że wszystko, co następuje po poleceniu aliasu funkcji, jest traktowane jako wyrażenie i jest oceniane jako takie. Ciąg tekstowy nie jest przekazywany bezpośrednio do funkcji. W przypadku pojedynczego wyrażenia argumentu może on pochodzić po samym poleceniu aliasu funkcji. W przypadku wielu argumentów powinny one być nawiasem tak, jakby było to wywołanie funkcji, jak pokazano w następnym przykładzie.

function __oneArgument(x)
{
    return -x;
}

function __twoArguments(x, y)
{
    return x + y;
}

function initializeScript()
{
    return [new host.functionAlias(__oneArgument, "neg"),
            new host.functionAlias(__twoArguments, "add")];
}

Te dwie funkcje można wywołać, jak pokazano tutaj.

0:000> !neg 42
@$neg(42)        : -42

0:000> !add (5, 7)
@$add(5, 7)      : 0xc

Alias funkcji jest używany z ewaluatorem wyrażeń dx

Oprócz rozszerzenia debugowania ! składnia polecenia "bang" na potrzeby wywoływania funkcji aliasu, wszystkie nazwy skojarzone z aliasami funkcji są dostępne bezpośrednio w ewaluatorze wyrażeń dx, gdy prefiksowany przez @$, jak pokazano tutaj.

0:000> dx @$neg(42)
@$neg(42)        : -42

0:000> dx @$add(99, 77)
@$add(99, 77)    : 0xb0

Zagadnienia dotyczące projektowania aliasu funkcji

Alias funkcji nigdy nie powinien być jedynym sposobem uwidocznienia funkcji w zdecydowanej większości rozszerzeń modelu danych. Rozszerzenie modelu danych (czy w języku C++ lub JavaScript) powinno zawierać niemal zawsze dane, które są ujawniane z typem lub inną koncepcją debugera. Elementy skojarzone z procesami powinny znajdować się w obszarze Debugger.Models.Process lub podrzędnej przestrzeni nazw tego obiektu. Alias funkcji może być wygodnym sposobem uzyskiwania (lub przekształcania) danych, które mogą wymagać znacznie dłuższego zapytania.

Na przykład w trybie jądra następujące zapytanie pobiera drzewo urządzeń PnP i spłaszcza je w prostą płaską listę urządzeń:

0: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children),5
@$cursession.Devices.DeviceTree.Flatten(n => n.Children),5                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
    [...]     

Ten kod JavaScript pokazuje, jak można to zaimplementować jako alias funkcji.

function __flatDevices()
{
    return host.currentSession.Devices.DeviceTree.Flatten(n => n.Children);
}

function initializeScript()
{
    return [new host.functionAlias(__flatDevices, "devices")];
}

Alias funkcji można następnie wywołać jako polecenie rozszerzenia debugowania.

0: kd> !devices
@$devices()                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
    [0x5]            : ROOT\spaceport\0000 (spaceport)

    ...

Jedną z zalet korzystania z aliasu funkcji jest to, że można go dodatkowo udoskonalić przy użyciu składni dx. W tym przykładzie dodano klauzulę where, aby wyszukać węzły urządzeń zawierające ciąg "Harddisk".

0: kd> dx @$devices().Where(n => n.InstancePath.Contains("Harddisk"))
@$devices().Where(n => n.InstancePath.Contains("Harddisk"))                
    [0x0]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot1
    [0x1]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot2
    [0x2]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot3
    [0x3]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot4
    [0x4]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot5
    [0x5]            : STORAGE\VolumeSnapshot\HarddiskVolumeSnapshot6

Polecenia LINQ, takie jak poniższe, mogą być używane z aliasami funkcjonalnymi — . Cały. Jakikolwiek. Hrabia. Pierwszy. Spłaszczyć. GroupBy, . Ostatni. OrderBy, . OrderByDescending, . Wybierz i . Gdzie. Te metody są zgodne (jak najbliżej) formularza metody LINQ języka C#. Aby uzyskać więcej informacji, zobacz Using LINQ With the debugger objects.

wyświetlania siatki

Podobnie jak w przypadku innych poleceń dx, możesz kliknąć prawym przyciskiem myszy polecenie po jego wykonaniu i kliknąć polecenie "Wyświetl jako siatkę" lub dodać "-g" do polecenia, aby uzyskać widok siatki wyników. Następnie możesz kliknąć dowolną kolumnę do sortowania, na przykład na instancePath.

0: kd> dx -g @$devices().OrderBy(obj => obj.@"InstancePath")

Zrzut ekranu przedstawiający dane wyjściowe siatki aliasu funkcji debugera z posortowanych wierszy.

Przykład wątków przetwarzania

Obiekty debugera są projektowane w przestrzeni nazw rooted w "Debugger". Procesy, moduły, wątki, stosy, ramki stosu i zmienne lokalne są dostępne do użycia w zapytaniu LINQ.

W tym przykładzie w języku JavaScript pokazano, jak wyświetlić liczbę wątków dla bieżących procesów sesji:

function __Processes()
{
    return host.currentSession.Processes.Select(p => ({Name: p.Name, ThreadCount: p.Threads.Count()}));
}

function initializeScript()
{
    return [new host.functionAlias(__Processes, "Processes")];
}

Spowoduje to wyświetlenie przykładowych danych wyjściowych za pomocą polecenia ! Przetwarza alias funkcji.

0: kd> !Processes
@$Processes()                
    [0x0]            : [object Object]
    [0x4]            : [object Object]
    [0x1b4]          : [object Object]
    [0x248]          : [object Object]
    [0x2c4]          : [object Object]
    [0x340]          : [object Object]
    [0x350]          : [object Object]
    [0x3d4]          : [object Object]
    [0x3e8]          : [object Object]
    [0x4c]           : [object Object]
    [0x214]          : [object Object]
    [0x41c]          : [object Object]
    [0x494]          : [object Object]

...    

W tym przykładzie jest wyświetlanych 5 pierwszych procesów z największą liczbą wątków.

0: kd> dx -r1 @$Processes().OrderByDescending(p =>p.ThreadCount),5
@$Processes().OrderByDescending(p =>p.ThreadCount),5                
    [0x4]            : [object Object]
    [0x180]          : [object Object]
    [0x978]          : [object Object]
    [0xda4]          : [object Object]
    [0x3e8]          : [object Object]
    [...]   

Zobacz też

dx (Display Debugger Object Model Expression)

używanie LINQ z obiektami debugera

obiektów natywnego debugera w natVis

natywnych obiektów debugera w rozszerzeniach Języka JavaScript