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:
- Otwórz menu Debugowanie i wybierz Dołącz do procesu...
- W menu Transport wybierz Android Game Development Extension.
- W menu Kwalifikator wybierz swoje urządzenie z Androidem.
- Wybierz proces gry z listy dostępnych procesów i kliknij Załącz.
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<*>">
<AlternativeType Name="MySimilarVectorType<*>"/>
<!-- 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 < 4 && _size >= 1" Optional="true">_items[0]</Item>
<Item Name="Y" Condition="_size < 4 && _size >= 2" Optional="true">_items[1]</Item>
<Item Name="Z" Condition="_size < 4 && _size >= 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++.