Debuger

Podczas używania rozszerzenia Android Game Development Debuggeruj projekt za pomocą narzędzia Visual Studio Debugger (LLDB).

Uruchamianie debugera

Zanim uruchomisz debuger, musisz mieć możliwość skompilowania, wdrożenia i uruchomienia gry na Androidzie. Więcej informacji znajdziesz w sekcji Uruchamianie przykładu.

Gdy upewnisz się, że możesz uruchomić grę bez debugera, użyj go, naciskając F5 lub wybierając pozycję Rozpocznij debugowanie w menu Debugowanie. Podczas podłączania debugera do gry powinno się wyświetlić okno.

Uruchomienie debugera zajmuje od 10 sekund do 1 minuty lub dłużej, w zależności od rozmiaru aplikacji i liczby symboli, które muszą zostać załadowane przy uruchomieniu. Podłączenie do nowego urządzenia po raz pierwszy trwa dłużej, ponieważ debuger musi pobrać z urządzenia niektóre biblioteki Androida na hosta. Jeśli pierwsze próby na nowym urządzeniu trwają dłużej niż 1 minutę, rozważ anulowanie sesji debugowania i jej ponowne uruchomienie.

Jeśli uruchomisz debuger w ten sposób, gra uruchamia się w trybie Oczekiwanie na debugera i nie wykonuje żadnego kodu gry, dopóki debuger się nie połączy. Dzięki temu możesz też debugować sekcję inicjowania gry.

Więcej informacji o konkretnych funkcjach debugera Visual Studio znajdziesz w dokumentacji Visual Studio.

Dołączanie do procesu

Jeśli chcesz debugować grę, która jest już uruchomiona na urządzeniu fizycznym lub wirtualnym, możesz dołączyć do procesu debugera z poziomu Visual Studio.

W Visual Studio sprawdź, czy rozwiązanie na Androida jest otwarte oraz:

  1. Otwórz menu Debugowanie i wybierz Dołącz do procesu...
  2. W menu Transport wybierz Android Game Development Extension.
  3. W menu Kwalifikator wybierz swoje urządzenie z Androidem.
  4. Wybierz proces gry z listy dostępnych procesów i kliknij Załącz.

Dołącz do procesu

Wykonywanie poleceń powłoki LLDB.

Gdy sesja debugowania jest aktywna, do uruchamiania poleceń LLDB.Shell użyj okna poleceń Visual Studio.

Format polecenia:

LLDB.Shell [command]

Przykład:

>LLDB.Shell expr myIntVariable = 9
Status:  Success
Output Message:
(int) $2 = 9

Wizualizacja danych

Specyfikacje formatu

Za pomocą specyfikatorów formatu możesz zmienić format wyświetlania wartości w oknach Autos, Locals, Watch i zmiennych DataTip.

Specyfikacje formatu znajdują się na końcu wyrażeń. Zaczynają się od przecinka, po którym następuje krótki ciąg znaków. Na przykład specyfikator ,x w wyrażeniu _myInt,x sformatuje myInt jako małą wartość szesnastkową.

Specyfikatorów formatu można używać bezpośrednio w oknie Watch lub w oknach Autos, Locals i DataTip – wystarczy dodać je do wyrażeń Natvis. Więcej informacji znajdziesz w artykule Natvis.

Lista specyfikatorów pomocy

Nazwa formatu Specyfikatory Opis
Wartość logiczna mld pokaż tę wartość jako wartość logiczną prawda/fałsz, używając zwyczajowej reguły, że 0 to fałsz, a wszystkie pozostałe wartości to prawda.
plik binarny B pokaż to jako sekwencję bitów
binarny, bez początku 0b bb pokaż to jako sekwencję bitów bez prefiksu 0b
B Y pokaż bajty, ale spróbuj też wyświetlić je jako znaki ASCII
np. (int *) c.sp.x = 50 f8 bf 5f ff 7f 00 00 P.._....
bajty z ASCII T pokaż bajty, ale spróbuj też wyświetlić je jako znaki ASCII
np. (int *) c.sp.x = 50 f8 bf 5f ff 7f 00 00 P.._....
znak C pokaż bajty jako znaki ASCII
np. (int *) c.sp.x = P\xf8\xbf_\xff\x7f\0\0
znak do wydrukowania C pokaż bajty jako możliwe do wydrukowania znaki ASCII
np. (int *) c.sp.x = P.._....
liczba zmiennoprzecinkowa F interpretuj tę wartość jako część rzeczywistą i urojoną zespolonej liczby zmiennoprzecinkowej
np. (int *) c.sp.x = 2.76658e+19 + 4.59163e-41i
separator dziesiętny d, i pokaż tę wartość jako liczbę całkowitą ze znakiem (nie przeprowadza rzutowania, a jedynie pokazuje bajty w postaci liczby całkowitej ze znakiem)
wyliczenie E,pl wyświetli to jako wyliczenie, drukując nazwę wartości (jeśli jest dostępna) lub wartość całkowitą, w przeciwnym razie
np. (enum enumType) val_type = eValue2
szesnastkowy – małe litery x, h pokaż to w notacji szesnastkowej z małymi literami (nie umożliwia to rzutowania, tylko przedstawia bajty jako wartości szesnastkowe)
szesnastkowy – wielkie litery X, H pokaż to w notacji szesnastkowej wielkimi literami (nie umożliwia to rzutowania, tylko przedstawia bajty jako wartości szesnastkowe)
szesnastkowy – małe litery, bez początkowego 0x xb, hb pokaż to w zapisie szesnastkowym z małymi literami bez prefiksu 0x (nie powoduje to rzutowania, a jedynie pokazuje bajty jako wartości szesnastkowe)
szesnastkowy – duże litery, bez początkowego 0x Xb, Hb pokaż to w notacji szesnastkowej wielkie litery bez prefiksu 0x (nie powoduje to rzutowania, tylko pokazuje bajty jako wartości szesnastkowe)
liczba zmiennoprzecinkowa F pokaż to jako liczbę zmiennoprzecinkową (nie przeprowadza rzutowania, tylko interpretuje bajty jako wartość zmiennoprzecinkową IEEE754)
ósemkowy O pokaż to w notacji ósemkowej
Typ systemu operacyjnego O pokaż jako typ systemu MacOS
np. (float) x = '\n\x1f\xd7\n'
string – C-string s pokaż to jako ciąg tekstowy z końcówką 0
np. „Witaj świecie”
string - C-string, bez cudzysłowów SB pokaż ten ciąg znaków C z końcówką 0 bez cudzysłowu
np. witaj świecie
ciąg znaków – UTF-8 S8 pokaż ten ciąg znaków UTF-8 z końcówką 0
np. u8"hello world ☕"
ciąg znaków – UTF-8, bez cudzysłowów S8B pokaż to jako ciąg UTF-8 z końcówką 0 bez cudzysłowu
np. hello world ☕
ciąg znaków – UTF-16 nd. pokaż ten ciąg znaków UTF-16 z końcówką 0
np. u"hello world ☕"
ciąg znaków – UTF-16, bez cudzysłowów zast. pokaż to jako ciąg znaków UTF-16 z końcówką 0 bez cudzysłowu
np. hello world ☕
ciąg znaków – UTF-32 S32 pokaż ten ciąg znaków UTF-32 z końcówką 0
np. „Witaj świecie ☕”
string - UTF-32, bez cudzysłowów S32B pokaż to jako ciąg UTF-32 z końcówką 0 bez cudzysłowu
np. hello world ☕
kod unicode16 U wyświetlaj jako znaki UTF-16
np. (zmiennoprzecinkowy) x = 0xd70a 0x411f
kod Unicode32 U32 wyświetlaj jako znaki UTF-32
np. (zmiennoprzecinkowy) x = 0x411fd70a
liczba dziesiętna bez znaku U pokaż tę wartość jako nieoznaczoną liczbę całkowitą (nie umożliwia to rzutowania, a jedynie pokazuje bajty jako nieoznaczoną liczbę całkowitą)
wskaźnik P pokaż to jako wskaźnik natywny (chyba że to rzeczywiście jest wskaźnik, wynikowy adres będzie prawdopodobnie nieprawidłowy)
zespolona liczba całkowita I interpretuj tę wartość jako rzeczywistą i urojoną część zespolonej liczby całkowitej
np. wskaźnik (int *) = 1048960 + 1i
tablica znaków a pokaż to jako tablica znaków
np. (znak) *c.sp.z = {X}
Nieprzetworzony ! format RAW z pominięciem wszelkich dostosowań widoków typów danych

Natvis

Platforma Natvis pozwala dostosować sposób, w jaki Visual Studio wyświetla typy natywne w oknach zmiennych debugera. Możesz np. dostosować wyświetlanie za pomocą Natvisa do okien Zegarek, Locals i Wskazówki dotyczące danych.

Funkcja Natvis jest domyślnie włączona, ale można ją wyłączyć w Visual Studio, ustawiając flagę Narzędzia > Opcje > Rozszerzenie tworzenia gier na Androida > Natvis na Wyłączono.

Wczytuję pliki Natvis

Visual Studio wczytuje pliki Natvis z 3 wymienionych poniżej lokalizacji i odświeża je za każdym razem, gdy uruchamiasz sesję debugowania. Pliki muszą być zgodne ze schematem Visual Studio 2017 Natvis.

  • Pliki .natvis, które są częścią wczytanego projektu lub elementu rozwiązania najwyższego poziomu.
  • Katalog specyficzny dla użytkownika (%USERPROFILE%\Documents\Visual Studio 2017\Visualizers)
  • Katalog systemowy (%VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers)
Ponownie ładuję pliki Natvis

Załaduj ponownie pliki Natvis podczas sesji debugowania, oceniając .natvisreload w oknie poleceń lub w oknie odtwarzania.

Przykładowy plik Natvis

Ten przykładowy plik Natvis zawiera wszystkie tagi i atrybuty, które są obecnie obsługiwane.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <Type Name="demo::Vector&lt;*&gt;">
    <AlternativeType Name="MySimilarVectorType&lt;*&gt;"/>

    <!-- Included to show the <SmartPointer> feature is supported. -->
    <SmartPointer Optional="true" Usage="Minimal">ptr</SmartPointer>

    <!-- Included to show the <DisplayString> feature is supported. -->
    <DisplayString Condition="_size == 0" Optional="true">()</DisplayString>
    <DisplayString Condition="_size == 1">(x={_items[0]})</DisplayString>
    <DisplayString Condition="_size == 2">(x={_items[0]}, y={_items[1]})</DisplayString>
    <DisplayString Condition="_size == 3">(x={_items[0]}, y={_items[1]}, z={_items[2]})</DisplayString>
    <DisplayString>[Size={_size,x}] (x={_items[0]}, y={_items[1]}, z={_items[2]}, ...)</DisplayString>

    <!-- Included to show the <StringView> feature is supported. -->
    <StringView Condition="true" Optional="true">_stringViewText</StringView>

    <Expand HideRawView="false">
      <!-- Included to show the <Item> feature is supported. -->
      <Item Name="X" Condition="_size &lt; 4 &amp;&amp; _size &gt;= 1" Optional="true">_items[0]</Item>
      <Item Name="Y" Condition="_size &lt; 4 &amp;&amp; _size &gt;= 2" Optional="true">_items[1]</Item>
      <Item Name="Z" Condition="_size &lt; 4 &amp;&amp; _size &gt;= 3" Optional="true">_items[2]</Item>

      <!-- Included to show the <ArrayItems> feature is supported. -->
      <ArrayItems Condition="_size >= 4" Optional="true">
        <Size Condition="true" Optional="true">_size</Size>
        <ValuePointer Condition="true">_items</ValuePointer>
      </ArrayItems>

      <!-- Included to show the <IndexListItems> feature is supported. -->
      <IndexListItems Condition="true" Optional="true">
        <Size Condition="true" Optional="true">_listSize</Size>
        <ValueNode Condition="true">_list[%i]</ValueNode>
      </IndexListItems>

      <!-- Included to show the <LinkedListItems> feature is supported. -->
      <LinkedListItems Condition="true" Optional="true">
        <Size Optional="true">_listSize</Size>
        <HeadPointer>_head</HeadPointer>
        <NextPointer>_next</NextPointer>
        <ValueNode>_value</ValueNode>
      </LinkedListItems>

      <!-- Included to show the <ExpandedItem> feature is supported. -->
      <ExpandedItem Condition="true" Optional="true">_childVar</ExpandedItem>

      <!-- Included to show the <Synthetic> feature is supported. -->
      <Synthetic Name="[Size]" Condition="true" Optional="true">
        <DisplayString>_size</DisplayString>
        <Expand HideRawView="true">
          <!-- Any supported <Expand> sub-tags. -->
        </Expand>
      </Synthetic>

      <!-- Included to show the <TreeItems> feature is supported. -->
      <TreeItems Condition="true" Optional="true">
        <Size>_treeSize</Size>
        <HeadPointer>_head</HeadPointer>
        <LeftPointer>_left</LeftPointer>
        <RightPointer>_right</RightPointer>
        <ValueNode>_value</ValueNode>
      </TreeItems>

      <!-- Included to show format specifiers are supported. -->
      <Item Name="[Hex Dump at {_index,x}]">myInt[_index],x</Item>
    </Expand>
  </Type>
</AutoVisualizer>

Tworzenie plików Natvis

Visual Studio umożliwia tworzenie własnych plików Natvis. Więcej informacji o dostosowywaniu okien zmiennych debugera znajdziesz w artykule o MSDN.

Debugowanie plików Natvis

W niektórych przypadkach błędy są prezentowane jako Wartość zmiennej (np. w oknach Automatycznie, Oglądaj itd.). Przykład: <error: use of undeclared identifier 'missingVar'>

Więcej informacji o błędzie znajdziesz, otwierając plik GoogleAndroid.log na pasku narzędzi rozszerzenia gier na Androida.

Znane ograniczenia

  • Jeśli Twojego tagu lub atrybutu nie ma w przykładowym pliku powyżej, nie są one obecnie obsługiwane. Visual Studio ignoruje nieobsługiwane tagi i atrybuty, więc możesz je pozostawić w dotychczasowym pliku Natvis, a plik będzie działał, o ile będzie korzystał z naszego schematu.

  • Atrybut Usage, choć wymagany przez schemat, nie jest obsługiwany w przypadku elementu <SmartPointer>. Jednak LLDB nie ogranicza dostępu do operatorów zdefiniowanych w C++, więc dowolny wymagany operator można zdefiniować w C++.