Showing posts with label Free Software. Show all posts
Showing posts with label Free Software. Show all posts

Jun 21, 2016

Para o infinito e além: consultas ainda mais poderosas sob metadados NET com drivers parta LINQPad e Mono.Cecil

No post anterior mostrei como usar o LINQPad para executar consultas em metadados .NET usando .NET Reflection, técnica que, apesar de muito útil, possui algumas limitações:
  • Zero integração com LINQPad, exigindo que o assembly seja carregado manualmente (ainda pior é fato de termos que digitar o caminho completo do assembly),
  • Como o .Net Reflection não expõe o corpo (instruções) de métodos, não é possível por exemplo, encontrar todos os métodos que executam algum outro método específico ou que acessem uma propriedade, etc.
Felizmente o LINQPad nos permite desenvolver / utilizar custom drivers que se integram muito mais naturalmente com o mesmo. No meu caso eu escrevi um que usa o Mono.Cecil (ao invés de .Net Reflection) para expor algumas fontes pré-definidas para consultas:
  • Types : Uma lista com todos os tipos (independentemente do tipo ser público ou não e/ou ser uma inner class) definidos no módulo principal do assembly.
  • PublicTypes: Uma lista composta por todos os tipos definidos publicamente.
Também introduzi as seguintes extensões (extension methods):
  • AsString(): Método que estende MethodBody retornando as instruções que compõe o corpo do método na forma de uma string.
  • Calls(method): Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) caso o método passado como parâmetro seja executado pelo corpo do método estendido.
  • References(type)Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) se o tipo passado como parâmetro for referenciado pelas instruções do corpo do método estendido.
  • Property(name): Método que estende TypeDefinition retornando a propriedade especificada pelo parâmetro (caso o tipo possua uma propriedade com o mesmo nome) ou null.
  • Event(name): Método que estende TypeDefinition retornando o evento que possua o nome igual ao passado como parâmetro ou null caso o tipo em questão não possua um evento com este nome.
  • Field(name): Método que estende TypeDefinition retornando o campo que possua o nome igual ao especificado no parâmetro ou null caso o tipo em questão não possua um campo com este nome.
Você pode ver um exemplo da utilização de tais métodos na imagem abaixo:


Para usar este Custom Driver você pode baixar o arquivo Cecil.LINQPad.Driver.lpx e instalar o mesmo no LINQPad clicando na opção Add connection,  depois em "View more drivers...", "Browse" e finalmente selecionando o arquivo que você acabou de baixar (Cecil.LINQPad.Driver.lpx)

É claro que você também pode baixar o source do mesmo do GitHub e compilar / instalar ;)


Uma vez instalado, o mesmo aparecerá na lista de opções de drivers disponíveis:



Pressione o botão Next e, a seguir selecione o assembly que você deseja fazer consultas. Lembre-se de, após abrir o assembly, clicar no dropdown "Connection" para selecionar a conexão que o LINQPad deve usar para rodar as consultas, ou seja, qual assembly deve ser usado como fonte nas consultas. No exemplo abaixo o assembly Boo.Lang.Parser.dll será usado:

Pronto. Agora você já pode rodar suas consultas LINQ!

Have fun!

Aug 15, 2015

Invalid offsets in IL instructions after modifying assembly with Mono.Cecil

Hi

Since 2008 I've been using Mono.Cecil, an amazing piece of software, that exposes .Net assemblies contents in a relatively easy and intuitive way so one can inspect and/or change the assembly's contents. 

Unfortunately, in order to use Mono.Cecil effectively, you need a fair amount of knowledge about how MS IL works and Mono.Cecil documentation is kind of sparse (to say the least).

Some time ago I was using it to change some assembly IL and to my surprise after applying the changes peverify complained that some IL instructions had invalid offsets

After some head scratching I've figured out that the issue was that the target of a (short) branch instruction have crossed the threshold that would require it to be  a normal branch (i.e, one that could use 32 bits offsets instead of 8 bits of the short version).

So now the issue was that I'd be forced to scan every single IL instruction in the method body and check/fix the target offset of branches; fortunately, Mono.Cecil has  two methods: MethodBody.SimplifyMacros() and  MethodBody.OptimizeMacros() that can be used to achieve my goal. 

Basically before start doing changes to the method body's IL, you call SimplifyMacros() and when you've finished with your changes on that method body you call OptimizeMacros() and Cecil will take care of adjusting branches accordingly. Nice!


Thanks everybody that helped to develop Mono.Cecil! It's really a handy library! :)

(Leia este post em português)

Instruções com offsets IL inválidos após modificar assembly com Mono.Cecil

Desde 2008 venho usando a biblioteca (muito boa diga-se de passagem) Mono.Cecil que permite você tanto ler quanto modificar o conteúdo de assemblies .Net de uma forma relativamente simples (depois que você compreende como utilizá-la, pois infelizmente,  usar tal biblioteca de forma efetiva exige um bom conhecimento sobre como o MS IL funciona e a documentação do Mono.Cecil deixa a desejar).

Algum tempo atras, um dos testes de um dos meus aplicativos (que usa esta biblioteca) começou a falhar; para ser mais preciso peverify começou a reportar algumas instruções com offsets inválidos

Após investigar por algum tempo concluí que o problema se encontrava no offset (operando) usado em alguma instruções de desvio (branch), as quais estavam ultrapassando o limite de um byte (-127 / 128) (isto ocorria devido a dois motivos: i) o código IL usava a forma (short) branch, ou seja, a instrução de desvio utilizada aceitava um único byte como offset e ii) meu aplicativo adicionava instruções entre a instrução de desvio e o alvo do desvio efetivamente exigindo um offset maior que 128).

Munido desta nova informação, tudo que tinha que fazer agora era verificar instrução por instrução (é claro, apenas as de desvio) se o operando da mesma estava dentro da faixa válida (-127 a 128) e corrigir quaisquer uma que não esteja. É claro que eu queria evitar isto a qualquer custo, pois este processo adicionaria mais código (e possíveis bugs) a meu aplicativo. 

Felizmente, Mono.Cecil possui dois método (MethodBody.SimplifyMacros() e  MethodBody.OptimizeMacros()) que, quando usados, se encubem em garantir que os operandos (offset) das instruções de desvio estão dentro das faixas válidas e caso não estejam, trocam a instrução para uma instrução de desvio que suporte o offset em questão (neste  case uma que use 4 bytes).

Basicamente, antes de iniciar qualquer modificação nas instruções (IL) de um método, você executa o método SimplifyMacros() e quando finalizar suas modificações você executa OptimizeMacros() e Mono.Cecil se incumbirá em ajustar as instruções de desvio (se necessário).


Desenvolvedores do Mono.Cecil: meu muito obrigado! :)

Have fun

(Read this post in english)

Jul 24, 2012

Arduwhat ?

Hi
Since I was 5 ~ 8 years old I was interested in mechanics, electronics and how things worked in general - my mother has some interesting histories about me disassembling all sort of devices (and usually not being able to put them together again); one in particular in which I got a saw as a "gift" (I was only 6 or 7 and someone gave me a real saw, not a toy, plastic one!) and went to put it into good use sawing some furniture :).

Even though having a high interest in electronics I ended up in the computer software field (just to make it clear: I do enjoy being involved in such fast changing, challenging industry :) and since then I've been having lots of fun (and some frustrations also).
As anyone involved with IT knows, keeping up to date with such a fast changing field requires a lot of effort and over time I put my electronics pretensions to rest (after all there are enough fun stuff in the computer world to play with to keep me busy for a long time...).
But about one year ago this started to change as I started to play with some basic (really basic) electronics stuff again (just for fun) and I stumbled on a small but very interesting piece of hardware: a small board with a microcontroller and a lot of software support with some nice characteristics (at least from my point of view ;) :
  • Open Source Software / Hardware
  • Inexpensive (will not cost you an arm and a leg :)
  • Simple to work with, at least not as complex as the other options I had seem before (no complex, expensive tools required)
  • Easily integrated with the "external" world (through sensors/actuators).
  • Extensible (shields, breakout boards and virtually anything you want)
  • Well supported
  • Large community
which perfectly describes this nice board called "Arduino" (since the name Arduino is trademarked most probably you'll  find compatible devices under some generic brand named with a "duino" suffix).
At this point you may be wondering what can be accomplished with such beautiful piece of hardware... well, I guess it is fair to say that you can find an Arduino C/C++ library for virtually anything you can come up (of course this is not completely true, but it is not too far from the truth). IMO, the important  question is not "is it possible to connect X to Arduino" but instead "how hard is to connect X to Arduino" and based on the list bellow (which I wrote based on information I found) I conclude that, excluding more exotic hardware, it does pretty well job on this topic (note that almost all items in the list bellow requires extra hardware): 
  • Sensors
    • Temperature, Pressure, Gas, Light, Distance, Color, Humidity, Accelerometers, etc.
  • Communications
    • Bluetooth, TCP/IP, UDP/IP, Serial, GPRS, Infrared, etc.
  • Storage
    • EEPROM, SD cards
  • Actuators/Output
    • Step Motors, Servos, DC Motors, LCDs, etc
As you can see it is quite flexible, and more importantly, all of the hardware above have at least one Arduino library ready to be used.

This post is not intended to be an Arduino introduction / course / tutorial. Instead it is meant to be only a teaser so if you want to learn more, you can find lots of information in the internet. Personally there are some sites I highly recommend you to give a visit:

Also, if you want to buy Arduino related hardware you can go to your favorite search engine and search for it and I am sure you'll be able to find lots of stores that sell them. But if you don't want to search, bellow you can find a list of sites in which you can buy Arduino parts (ps: I have no affiliation with any of them :).


Finally, some electronics interesting tools:


Well, that's it. Now let me get back to play with my just arrived Arduino!

In the next post I hope to shed some light about my current projects related to Arduino (both soft and hardware).

Hope you found this post interesting.

May 9, 2012

Free (open source) RAM disk for Windows (x86 / x64)

Hi


Have you ever had the need to perform some I/O intensive operation on a relative small set of files? I do, usually when I need to compile some application.

In order to speed up this operation I've recurred to the so called "RAM Disks", applications that takes part of your computer's main memory and pretends that it is an actual disk. As you can imagine read/write/etc (I/O) operations against this virtual disk are much faster than operations against your actual hard disks (be it a traditional magnetic HD or a shine new SSD).

In the past 3 years I've used at least 3 different solutions and was happy with none. My main complain is that most of them were not capable (or it was really clumsy/hard to accomplish) of creating RAM disks dynamically, i.e, one is required to create it at OS start up time. Since my needs are dynamic (I may need more disk space at some points in time during the day) it is really hard to come up with a disk size that work for me: choose a to big disk and I am wasting precious RAM space; create a disk that's to small and I may find myself facing "out of disk space" errors (then cleaning up some junk and restarting my build tasks).

Fortunately some time ago I stumbled upon a RAM disk implementation that allows me to mount and unmount disks dynamically! Since then my work flow has been much more smooth ;) The not so good side is that it is not very easy for the "not computer savvy" user.

Bottom line is: if you need a stable and flexible (but maybe not so easy to start with) RAM disk solution you can't go wrong with this one.







Jan 26, 2012

Interfaces in IL

After a long period of silence, today I've something interesting (IMHO) (and the time to, of course :)) to post about.

Last night I was reading a book about MS IL (intermediate language) when suddenly I stumbled with an intriguing paragraph about interfaces. The "intriguing" part motivated me to write a sample application to test whenever that would be valid in C# or not.
Given the following NUnit test, how can you define a type "IAmAnInterface" so it can pass ?
 
using System;
using NUnit.Framework;

namespace Testing
{
 
 [TestFixture]
 public class BlobPost_Interface
 {
  [Test]
  public void Test()
  {
   var type = typeof(IAmAnInterface);
   Assert.That(type.IsInterface, Is.True);

   var field = type.GetField("fld");
   Console.WriteLine("    Field: {0}", field);
   Assert.That(field, Is.Not.Null);

   field.SetValue(null, 10);

   Assert.That(field.GetValue(null), Is.EqualTo(10));
  }
 }
}

Just in case you missed it, the crux here, is that the test expects IAmAnInterface to be an interface and (and here lies the issue) to define a (static) field! 

How come? An interface with fields?

Well, it happens that the C# specification (and the compiler also!) disallows such constructs, but they are actually valid in IL (as described in Common Language Infrastructure ,session 8.9.4)!

So, in order to get this to work I simply created an assembly in IL (actually I disassembled an assembly written in C# and changed it) that looks like:
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         
  .ver 4:0:0:0
}
.assembly TestString
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module TestString.dll
// MVID: {64C46A76-194E-4608-A835-B41B179AF4FA}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x004D0000


// =============== CLASS MEMBERS DECLARATION ===================

.class interface public abstract auto ansi IAmAnInterface
{
  .method public hidebysig newslot specialname abstract virtual 
          instance int32  get_value() cil managed
  {
  } // end of method IAmAnInterface::get_value
  
  .field public static int32 fld

} // end of class IAmAnInterface


// =============================================================

and referenced it in my C# test application inside VS2010 which happily showed the field in IntelliSense but gave an error when I tried to compile the code (so I resorted to reflection, and it worked) (see picture below):
What do you think?

Best

Adriano

Jun 19, 2009

Hexadecimal Control Viewer DotNet

Hi!

Some time ago I started developing a .Net application that requires a control to display hexadecimal values; considering that I could not find a suitable one (and also, that I do suffer for the NIH syndrome) I decided to write one myself.

After some time developing the application I lost interest (since I moved jobs and the main goal of the application was to make my previous job easier) and now it is kind of abandoned but I think that the hexadecimal control may be handy for some developers.

Here is a list of this control's main features:
  • Find
  • Print / Print Preview
  • Ranges: It's possible to specify that some byte ranges should be displayed with a specific color for instance
  • Selection
  • Cut/Past
Since the application is released under an open source license anyone can grab the sources, or, if you are interested I can add you as a developer on source forge!

Best

Adriano

Nov 5, 2008

Are you a C# developer?

If so, you should go and grab a copy (for free) of CodeRush Xpress for Visual Studio!

(I already own a copy of another addin, but I'll give it a try anyway :)

Adriano