Category Archives: Development Tools

WinDbg/SOS trik: Klikatelný výstup (DML)

Práci s  WinDBG/SOS lze zpříjemnit malým trikem. Pokud za název příkazu (většina to podporuje) připojíte přepínač /d, bude výstup klikatelný (spustí příkaz, který odpovídá prozkoumání daného cíle dle jeho typu):

image

Pokud se nám nechce /d za každý příkaz psát, můžeme ho zapnout globálně:

.prefer_dml 1

Vypnout lze samozřejmě nulou.

Oficiálně se to celé jmenuje „Debugger Mark Up Language“ (DML).

ClrMD: Nalezení statických rootů při analýze .NET memory-dumpu

Používáme-li WinDbg a jeho rozšíření SOS.dll (popř. SOSEX nebo PSSCOR4) k analýze memory-dumpu .NET procesů, pak jednou z komplikovanějších úloh je například nalezení statických rootů, tedy statických fieldů, které drží reference na prozkoumávanou instanci.

Že se jedná o zarootování instance ze statického fieldu je zpravidla zřejmé z výstupu !GCRoot, který pak vypadá například nějak takto:

0:000> !GCRoot 0000000acaf3e8f8 
HandleTable:
    0000000f159f19f8 (pinned handle)
    -> 0000000ec87f1be8 System.Object[]
    -> 0000000d11ac08c8 System.Action
    -> 00000010f5df1020 System.Object[]
    -> 0000000acaf3e8f8 System.Action

Found 1 unique roots (run '!GCRoot -all' to see all roots).

.NET si drží hodnoty statických fieldů v systémových object[] polích, nicméně dohledat, který konkrétní statický field je naším rootem, už není tak jednoduché (obvykle skončíme ve WinDbg u s-d nebo s-q prohledávání paměti a hledání další reference, atp.).

ClrMD: Microsoft.Diagnostics.Runtime

Naštěstí existuje a z NuGet se dá snadno nainstalovat .NET knihovna Microsoft.Diagnostics.Runtime (zkráceně ClrMD), která umožňuje inspekci a analýzu memory-dumpu z .NET kódu obdobně jako byste pracovali s SOS ve WinDbg.

…a jednou z věcí, které lze pomocí ClrMD snadno dostat je právě identifikace statického fieldu, který je rootovou referencí na prozkoumávaný objekt:

DataTarget dataTarget = DataTarget.LoadCrashDump(@"D:\path\to\memory-dump.DMP");
ClrRuntime runtime = dataTarget.CreateRuntime(@"D:\path\to\mscordacwks.dll");
ClrHeap heap = runtime.GetHeap();

foreach (ClrRoot root in heap.EnumerateRoots())
{
	if (root.Object == 0x0000000d11ac08c8) // adresa rootu, který chceme prozkoumat
	{
		// jen pro ukázku třeba:
		Console.WriteLine(root.Kind);
		if (root.Kind == GCRootKind.StaticVar)
			Console.WriteLine(root.Name);
	}
}

Pracujeme ideálně paralelně s WinDbg+SOS:

  • do CreateRuntime() dáváme cestu k příslušnému mscordacwks.dll, z WinDbg získáme přes .cordll -ve -u -l
  • adresu prozkoumávaného rootu známe z WinDbg (první po System.Object[], viz výše uvedený příklad z !GCRoot)
  • výše uvedený snippet stačí prsknout do ConsoleApp, do které nareferencujeme ClrMD z NuGet
        • je potřeba nastavit Build / Platform Target na x86 nebo x64, podle toho, z jaké platformy pochází memory-dump

Zkušenosti s přechodu na TFS a agilní techniky – záznam a slides [WUG Praha 1/2015]

Slides z přednášky 15.1.2015 pro Windows User Group Praha (WUG), kde jsme s kolegou Jirkou Kandou povídali i našich zkušenostech z přechodu HAVITu na TFS a agilní techniky (v období 08/2012 až 12/2014):

Z přednášky jsem pořizoval záznam, který najdete na našem HAVIT YouTube Channelu:

Omluvte sníženou kvalitu zvuku záznamu, nahrávali jsme tentokrát na dva různé mikrofony a výsledný záznam je sestřihán ze dvou různých zvukových stop (jedna z mikrofonů navíc nebyl zřejmě úplně ideálně umístěn a chytal nežádoucí ruchy).

.NET Memory Internals 2/2 – Heap, Garbage Collector – záznam, slides a dema [MS Fest Praha 2014]

Slides z mé přednášky 30.11.2014 pro konferenci MS Fest Praha:

Z přednášky jsem pořizoval záznam, který najdete na našem HAVIT YouTube Channelu:

.NET Memory Internals 1/2 – záznam, slides a dema [MS Fest Praha 2014]

Slides z mé přednášky 29.11.2014 pro konferenci MS Fest Praha:

Z přednášky jsem pořizoval záznam, který najdete na našem HAVIT YouTube Channelu:

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel

Mě touto hláškou obšťastnil sign-in dialog ve Visual Studiu v lab Virtual Machine, ale můžete ji potkat i jinde. V mém případě byl důvod v nepřiměřeně se rozcházejícím čase virtuálního stroje a času skutečného (na serverech MSFT).

Stejně tak například bez rozumného času nejde Windows Update.

„Copy Local“ referencí ve Visual Studiu

Copy Local standardně zobrazuje hodnotu True, ale ve skutečnosti to znamená neuvedeno, protože v *.csproj souboru není nic uvedeno. Pokud běží build na stroji, který má assembly uložené v GAC, nebude knihovna zkopírována do složky bin.

2014-10-24_1711

Řešení je jednoduché, stačí hodnotu nastavit na False a zpět na True. Tím dojde k uložení informace do *.csproj souboru a sice v elementu Reference přibyde nový element Private s hodnotou True.

<Reference Include="Havit">
  <HintPath>...</HintPath>
  <Private>True</Private>
</Reference>

MSBuild v rámci TFS Build Service nevytváří Web Deployment Packages

Problém

V projektu máme webovou aplikaci, která má Publish Profile, který má vytvořit Web Deployment balíček. Balíček se úspěšně vytváří jak při spuštění MSBuildu z Visual Studia, tak z příkazové řádky na vývojářském počítači, tak při spuštění z příkazové řádky na počítači s TFS Build Service. Jenže při spuštění z TFS Build Service se balíček nevytvoří.

Proč to nefunguje

Podoba publish profile, který byl vyroben pomocí UI ve Visual Studio 2013 je (plus mínus) takováto:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<DesktopBuildPackageLocation>TfsPublish\BalicekKteryChciVytvorit.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
...
</PropertyGroup>
</Project>

Důvodem, proč se balíček nevytváří je skutečnost, že Visual Studio do publish profilu vytvoří vlastnost DesktopBuildPackageLocation, jenže je očekávána hodnota vlastnosti PackageLocation.

A jak to, že v rámci VS a z příkazové řádky to funguje? Protože PackageLocation se v průběhu načítání C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.targets nastaví podle DestopBuildPackageLocation.

<PackageLocation Condition="'$(PackageLocation)'=='' and !(('$(OutDir)' != '$(OutputPath)') Or ('$(IsDesktopBuild)' == 'False')) ">$(DesktopBuildPackageLocation)</PackageLocation>

Jenže jen za podmínky, kdy IsDesktopBuild není false (druhou podmínku není ukázanou výše třeba řešit). Otázkou je, kde se nastavuje hodnota vlastnosti IsDesktopBuild. Odpověď se skrývá v témže souboru:

<IsDesktopBuild Condition="'$(IsDesktopBuild)'=='' And '$(TeamFoundationServerUrl)' != ''">False</IsDesktopBuild>

A problém je objasněn – TFS Build Service nastavuje hodnotu TeamFoundationServerUrl, čímž se build liší od spuštění z příkazové řádky.

Možnosti řešení

Nastavení vlastnosti PackageLocation bohužel nefunguje v rámci vlastního targetu, neboť to je již pozdě. Z vlastnosti se odvozují další vlastnosti během načítání target souborů.

  1. Natvrdo nastavit hodnotu IsDesktopBuild na True při spouštění MS Buildu. Nenašel jsem žádné jiné použití této vlastnosti, tedy alespoň prozatím jde o bezpečné řešení.
  2. Během studia zmíněného souboru s MSBuild targety jsem našel, že se MSBuild po importu PublishProfile souboru (pubxml) pokouší importovat ještě další targety, pokud existují. Šlo by tedy takový soubor vytvořit a v něm zkopírovat hodnotu z DesktopBuildPackageLocation do PackageLocation.
    Pokud se projekt jmenuje Web a ten obsahuje publish profile v Properties\PublishProfiles\TfsPublish.pubxml, pak se načítají
  • Web\Properties\PublishProfiles\TfsPublish.wpp.targets (viz vlastnost WebPublishProfileCustomizeTargetFile)
  • Web\*.wpp.targets (viz vlastnost WebPublishPipelineCustomizeTargetFile)
  • Web\..\wpp.deploysettings.targets (viz WebPublishPipelineSolutionTargetFile)

Advanced .NET Debugging – záznam, slides a dema [MS Fest Brno 2014]

Slides z mé přednášky 18.10.2014 pro konferenci MS Fest Brno:

Z přednášky jsem pořizoval záznam, který najdete na našem HAVIT YouTube Channelu:

Windows Explorer: Založení/přejmenování souboru s názvem začínajícím tečkou

Pokud potřebujete vytvořit nebo přejmenovat ve Windows Exploreru soubor/složku na jméno, které začíná tečkou (.tfignore, .svn, …), funguje jednoduchý trik – přidejte ještě jednu tečku na konec jména(např. „.tfignore.“). Windows Explorer to překousne a záměru je dosaženo.

…starý trik, ale občas si ho musím připomenout.