Articles Menu
Login
|
| Graphic cards history | | Posted by bleader -- Wednesday 22nd of August 2007 16:45:42 PM | Introduction
As the Bioshock demo has been released for PC, I was wondering if it would run on my old card (radeon 9700pro)... of course not. I then started thinking that maybe it was time to invest in a new card, there a pretty nice card at accessible prices at this time. And then I wondered how old was this card... I found that the 9x00 series was released in 2002... 5 years. This card was gently given to me by wOrst (thanks my little pouet), my last bought card was a 8500 and I searched: 2001. From various things I was wondering I wandered along wikipedia and thought it would be fun to make a little history of 3D cards.
Note: I've found everything here in wikipedia, it may contains mistakes. Additionally it's not order by release date inside a year as it's somewhat hard to get a precise date (announcement, consumer release, availability)
"Back in my time...", said grandpa
Back in the ol' days, there wasn't 3D card except for some pros, and then the 3D games spawned out of nowhere, but the cpu back then had real hard time copping with the work load that kind of games where putting on them. Mostly Quake and Tomb Raider have marked my memory... and then 3dfx came with the voodoo add-on card, the glide and patches for the games were released and that's how everything started for the 3D card and the game market.
History
1996:
- 3dfx launch their add-on card voodoo
- power vr and rendition do the same later on
- matrox, ati and s3 launch 2d/3d cards, with minor acceleration
1997:
- voodoo rush, 3dfx 2d/3d card
1998:
- voodoo2 2nd generation 3dfx card (add-on card)
- riva tnt
- ati rage 128
- matrox g200
- banshee, voodoo2 2d/3d card
- voodoo3 2d/3d cards (3rd generation)
1999:
- riva tnt2 (3rd generation)
- matrox g400 (3rd)
- geforce 256, addition of transform & ligthning (4th generation)
2000:
- voodoo4 et 5 (4th)
- ati radeon to compete with geforce (7x00 series, 4th generation)
- g450 (4th)og
- geforce2 (5th)
2001:
- geforce3 (6th)
- g550 (?)
- radeon 8x00 (6th)
2002:
- geforce4 (7th)
- radeon 9x00 (7th)
- geforce FX (8th)
2004:
- geforce6 (9th)
- radeon x800 (9th)
2005:
- geforce7 (10th)
- radeon x1x00 (10th)
2006:
- geforce8 (11th)
- radeon HD2x00 (11th)
2007:
- (to come: geforce 9 12th)
Conclusion
We can see that the 1998 was somewhat "the" year with lots of products and the T&L coming to the geforce256 incredibly boosting performances in games (quake3 anyone? :p).
I also can see that I have a 4 generation late card, maybe it's actually really time to change... We'll see.
| | -- 0 comments -- |
| Xorg and ICC profiles | | Posted by bleader -- Tuesday 08th of May 2007 00:37:32 AM | EDIT: After some time using it, I realized that overlay isn't affected by this, therefore mplayer -xv/gl/xvidix won't get color correction... that's a negative point.
Also using -vo x11 will discard the profile, loading a fullscreen opengl application (who says quake3 ?) will give the same result.
In addition most of the probes in the link I give are really old, and I'm not sure of the quality of any of them :/
One thing that linux and unixes lack the most is a full color profile support. It's not that disturbing for most people, but working on photos or some graphics may be quite innacurate if your monitor is not calibrated.
Happilly, there is now a way to load ICC profile under X:
xcalib
As explained in the README file:
"load 'vcgt'-tag of ICC profiles to X-server like MS-Windows or MacOS do it to calibrate your display."
It works under linux, exist in FreeBSD ports, I didn't find it in NetBSD pkgsrc, and don't know about OpenBSD ports.
It works with most of X drivers, and there is also a target for ati binary drivers in the Makefile. Everything was made with multiple display in mind, except for fglrx that doesn't works exactly the same way.
I therefore made a little patch adding the '-x' or '-controller' option to the command line letting you choose
which driver to use in case you're un dual-head with two drivers.
Get it here if needed.
The main drawback in calibration is that most color probes are not supported under linux. If you don't already own one you may want to have a look at argyllcms, there are valuable information about supported probes.
Once you got your ICC profile, there not much to do
xcalib -d :0 profile.icc
will probably do the trick. On my fglrx I use
xcalib -x 0 left.icc
xcalib -x 1 right.icc
To have this automatically applied simply add thoses commands to your ~/.xinitrc and `voila !`
| | -- 0 comments -- |
| Qube 2 PSU connector | | Posted by bleader -- Friday 16th of February 2007 22:11:38 PM | I recently got my own qube 2, but without power supply, as the vendor have probably lost it. So I started searching a way to replace it, at first just for some tests. I used an old AT alimentation, but I wasn't sure what was the scheme of the connector... I only found it on a forum no schema or so, just a text, that's already very helpful, but you can quickly miss it if you're getting through pages and pages searching for it :)
So here is a picture of the back of my qube with colored pins of the connector:

Hope that will help people, you can also have a look here if you still have the old psu at hand, that may be faster than what I did.
So here we go.
I got two nails, cut them, and placed them in the qube connector. I then took a cd, cut little part about the size of the connector, pressed on top of the nails to get where I needed to make the holes, make two holes large enough for the nails.

After this a stuck the nails with the cd part in a clamp and glued everything together

Some soldering on the choosen power cord (yeah I know soldering on nails...), some coating, and here we go.

As I wanted it to work quickly, I didn't wait to buy a new power supply supporting 12v/3.3A and had the other side of the chord plugged to a molex in my main computer, and it work like a charm. Still beware of old psu like my AT psu, the 12v was a bit low and the 5v generated inside the cube was way too low, thus the 120Go hard drive wasn't working correctly. Maybe a second part later about installing NetBSD on it :)

<3
| | -- 0 comments -- |
| Checkinstall | | Posted by bleader -- Sunday 26th of November 2006 13:47:36 PM | Recently, as I was wondering wether to choose ubuntu or slackware, I was searching for the better way to keep a slackware up to date. I like to download sofware and compile them by myself, but the matter is to upgrade/remove them later. Searching for this matter I found CheckInstall.
Even if I didn't decide to switch to gentoo, this finding was usefull today.
I was planning on installing nzbget, and found out it wasn't in any of the repository my sources.list contains.
download sources, ./configure && make
and instead of make install :
checkinstall -D --install make install
It will run the `make install command` in a temporary dir, get the output files and what was done, and create a .deb package from it, with the --install flag it will install the package automatically.
This way I installed my software, got a .deb package I can redistribute, and my manually compiled software is easy to remove if I need to !
I really think this is great.
Even more interesting, -D create a .deb package, but -R will create a RPM, and -S will create a slackware tarball.
It can handle package maintainer mail address, license, translation in file system to have install done somewhere else, and a lot more.
links
>> CheckInstall
>> InstallWatch
>> nzbget 0.2.3-i386 for ubuntu edgy | | -- 0 comments -- |
| DWARF 2 Debugging Information | | Posted by bleader -- Monday 12th of June 2006 08:27:15 AM | DWARF2 debugging information format
Summary- Basics
- Data Structures
- Data Types
- Need more information?
- Appendix
Introduction :
In this article I'll try to explain a bit how to use the DWARF 2 to get debugging information. Nothing in this article is given for sure, I'll do my best just to enable people to get some more information if they want to use this format. Those of you who have read the official documentation will understand why I won't say that I'm sure I got it right. The format is a binary format, with a very few fixed size data, and the documentation is not really easy to understand.
I'll only talk about it in ELF binary generated from C/C++ code by for example gcc. The DWARF 2 is written and made to be really portable to any language, unfortunately for you if you're searching for help about something else I won't be able to help you.
What you will need to understand is mainly the organisation of the data. When you got it, it's not that hard, but at first sight, it may be a little frightening.
You should have at disposal a compiler able to generate DWARF 2 debugging information (like gcc), readelf, an hexadecimal editor of your choice (hexedit is pretty cool, except his help is bind on my "launch urxvt" binding :).
You can have a look at the --debug-dump option in readelf's manpage, that may be a great help.
Remember that gcc under *BSD seems to be generating stabs information if you don't force it to dwarf with the '-gdwarf-2' option. Under linux -g will generate DWARF2 information.
A little knowledge about the organisation of ELF binaries may be a good help even if you may be able to get the main point without it.
For sources, you can have a look at readelf (can be found in binutils), or the libdwarf, coming along with a dwarf-dump program. I don't really found it usefull as the code is pretty unbereable to me, but it's still one of the rare programs reading DWARF 2 information. Finally you can have a look at the gdb sources, but it's a little big and not always easy to follow. Hope that you'll find something to help you out with this little list.
Basic principles :
All information in DWARF 2 are stored in binary, except for strings of course.
That means that compared to stabs, you won't have to do parsing, the real hard part of DWARF 2 is to understand how it works, not to parse a strange text format (people who tried to read stabs information know what I mean :)
When a binary is compiled with DWARF 2 debugging information, those information are stored in sections of the ELF binary. The two main sections you'll need are:
- .debug_info
- .debug_abbrev
I may refer to those as abbrev table, info table, info, abbrev, I'll try to not screw up too much with the names :)
Those two sections are extremly close to each other (in term of use, not especially in memory space), and are both needed to get DWARF 2 information.
As soon as the binary get a little bigger, or there are multiple files compiled (which is almost always the case), you'll get another section named :
- .debug_str
This one will only contain null terminated strings, they will be used to lighten the content of the info section, and to avoid redundant information. We will see how this is done further in this document.
In thoses sections you will be able to find some basic information like:
- name of the compiled file
- name of the compiler
- functions, return type and parameters
- types
- variables
More information are available in the DWARF 2 format, like line numbers, functions addresses and much more, but you will need to use other sections:
- .debug_lines
- .debug_aranges
- .debug_pubnames
- .debug_frame
For now this document will focus on the information in info abbrev and str sections, somewhat the basics.
Getting sections :
As I've said before, info et abbrev are used together to get the information. You will have to find the address of the right section in the binary file.
I'll explain how I made it in our project where I used DWARF 2 information. Once again this is not the only way or even the best way to do this, I'm just telling my own experience in hope that it could be usefull to someone.
What I did was like this :
- mapping binary file
- reading ELF information
- stocking a linked list of section headers
- finding sections headers for DWARF 2
- for each sections header:
|--> get offset
|--> add it to mappeed binary address to have where it start
|--> store this address
|--> store section size
For each sections I kept :
- base address
- current address
- size
This was made really easy to do as emp made a library for this project which was helping out do all the ELF work.
As you will see, you can't just read and that's ok, to read DWARF 2 information you will alway be reading forward in the sections, and unless you keep a giant list of what you've read and in which order, you won't be able to go back.
As it's all in binary format, any mistake will be a pain in the ass to debug, you will have to print lots of information and compare them with the binary file in an hexadecimal editor, or have a look at the values that readelf may show you.
At the beginning it is probably a good idea to follow step by step what you read with the binary opened in an hexadecimal editor.
You'd better get familiar with the ELF section, offsets found with readelf so that you may find back the right addresses quickly.
Having a fixed binary that you won't recompile, and make tests on it is a pretty good idea, you will soon know the addresses you need in the binary and won't have to search for it. But be warned : try on other binaries too, maybe mistakes can slips in your code, and won't show up when testing on your main test binary (yep, it happened to me :/).
Organization :
In this section I'll try to explain how the data are organized in the sections used by the DWARF 2 format. As I haven't talk about the types yet this will probably be a bit abstractive of some explanations. But as types contain refecences in sections, you will need to understand the data's organization before.
As I've already told earlier, info and abbrev are used in bundle, that is to say you will need to understand both, and how they are linked together.
Unfortunatelly it's pretty complicated just to explain each section, that's why I won't try to explain both at the same time.
If you've followed the beginning of this documentation, you already know how to get the sections addresses. Here is the main organization of the info section:

There is no main header, you'll directly find a header that will refer to the first Compilation Unit (I'll call them CU from now on).
What is a CU ? It's a part of the DWARF information that will only refer to one "object" or in most cases, one compiled file. Most of the time you will find in a CU those kind of information :
- file name
- path where it was compiled
- compiler name
- types defined in included headers
- basics types used in this files (only those used)
- functions and their return type
- parameters name and type
That's all that come to my mind at the moment, but that is not an exhaustive list.
As you've seen in Fig-1 the info section is a concatened list of bundles header-CU. What this header looks like anyway ? Here it is:
- CU length : 32bits
- DWARF version : 16bits
- abbrev offset : 32bits
- pointer size : 8bits
That is a total of 11 bytes. This is the only fixed size thing you'll have in DWARF 2 as far as I know :).
Warning
The first thing you'll think of is probably making a nice structure and then point it to the address. There are two fallback to this:
Problem :
If you're not on x86 you will surely have alignement problems. That goes for the whole DWARF 2. As sizes or not fixed, nothing will be aligned, on x86 you can point and read everywhere on your mapped binary, but as soon as you switch to sparc or ia64, that won't be nice.
Solution :
The best method is probably to memcpy as this is dependant of the system and is hopefully done to avoid bus error and alignement problems.
That goes for the whole DWARF 2, you'll have to read data that will most of the time won't be aligned. It is probably a good idea to always memcpy the data and work on the copy.
Problem :
Compiler packs structures by default. That is to say if you made a structure like int, short, int, char for this case, it won't use 11 bytes, but 16. Pointing or copying the data from the start of .debug_info to your structure won't do the trick as it will write in the padding left by the compiler.
Solution :
There is a "#pragma pack" directive that may be used to do this.
The best way to learn about it is probably to search for it on the web.
By the way here is the first google result about it at the time of this writing.
Let's get back to the CU header.
- CU length : 32bits
- DWARF version : 16bits
- abbrev offset : 32bits
- pointer size : 8bits
The Length will let you know how long will the CU be without the 11 bytes of the header.
In our case the DWARF version should always be 2, but it may soon be common to find version 3. I think there may be some common thing between version 2 and 3, but I don't have checked it yet.
The abbrev offset will let you know where to find the corresponding entry in the .debug_abbrev table. Just add this offset to the base address of the abbrev section (you got it as we explain earlier, don't you ?)
Finally the pointer size will let you know the size of a pointer on the target architecture.
The most interesting information here is the abbrev offset, of course don't loose the others they will come handy later.
The least significant information here is probably the DWARF version, but when you know which version you are currently using that may make a good error check.
You should now have the address where you have to read for the abbrev of the current CU:
mapped_binary_base + .debug_abbrev_offset + CU_abbrev_offset
After this header you will find the CU entry, found on the CU by itself.

The Index is written in LEB128 format, unsigned, aka ULEB128. To get more information you should refer to the Data Types paragraph.
This index will allow you to find the right part in the .debug_abbrev corresponding CU entry.
Let's have a look at the abbrev section:

Each CU entry in the abbrev section will look the way it's shown on the right of Fig-2
The first thing you should read in both section, info and abbrev, is the index, here in ULEB128 too.
If those two index (in .debug_info and .debug_abbrev) don't correspond there is a big chance that you made a mistake while reading previous information.
Note: That won't happen in the later explanations as I read abbrev and find the corresponding entry by searching by index.
Then comes another ULEB128, the Tag, this will tell what will be representing the coming information in this entry, they correspond to the DW_TAG_* that you can find in the official documentation or in the headers files with thoses defines.
Then comes a one byte flag telling you wheter it will have child or not.
In DWARF 2, information create a tree, but as it is in binary format, you'll have to represent yourself this tree, the only information is that child flag telling you wheter it's a leaf or not of the tree.
The tree organisation may be somthing like that:
-function
|--> type
|--> parameter
|-----> type
|--> parameter
|-----> type
The first entry will tell you that from now on will have a function information, with the Child flag set to 1.
The second will have the Child flag set to 0, and will be the return type of the function.
The third will have the Child flag set to 1 and will give you the parameter name.
The fourth will have the Child flag set to 0 and will give the type of the parameter.
And so on...
In fact things that are part of a tree always refer to their parents.
After this flag will always be a pair of ULEB128: Attr and Form.
The first one, Attr will give you information about what you are about to read, the name, the value, and lots more possibilities. They are the DW_AT_* in the DWARF 2 defines.
The second one will be telling the FORM, that will be usefull to be able to know how long your next read in the current CU will be. They of course are the DW_FORM_* in the DWARF 2 defines.
The end of a section will be a pair of ULEB128 both set to 0.
That's it for the explanations of the organization, the best thing to do is probably to play around and code some program that will read those information.
Let's try to have a look at how I was reading DWARF 2 information in my program.
First I was getting the .debug_* section from the mapped binary, .debug_info first, getting the offset, the size and setting a pointer to the beginning, the one that will move in this section. Next the same thing was done for .debug_abbrev, and the same for .debug_str if available (most binary will have one if it was compiled with more than one file, that is used to prevent storage of redundant information).
From here everything will be done in loop, while we are done.
If I recall well, to know if I was done I was checking that my moving pointer was in bounds (between base and base + size of the .debug_info section), and that my current deepness wasn't 0.
I was counting how deep I was in the tree using the child flag, when you find the flag set to 1 you increase the deepness in the tree. Decreasing is a bit more disapointing, you need to find an index that is 0, the child flag set to 0 only indicate that you are reading a leaf. They may be several leaf following each other.. As far as I've understand the official documentation that doesn't seem quite clear, but that's the way I've done it and it was working well.
The first step of the loop is to read the CU header getting the important information and store them if needed. I was storing everything with a lots of linked list, that may be somewhat overkill but it probably depends on what you plan to do with thoses information. That's up to you.
You now have the abbrev offset for the corresponding CU.
From this offset I then read all the entry of this abbrev section, and store all information in a linked list: index, tag, child flag, and a linked list of attr/form pair.
Then, read a ULEB128 from the .debug_info section to find the index of the current entry.
Now I have a function that find the right abbrev entry from the index stored in the previous step.
Next step is to have a look at the TAG and the Child flag to find out what we are going to read in .debug_info, and where we are in the tree.
Now while we don't find a couple attr/form set to 0/0 we keep on reading.
The form part telling how long we will have to read at the current position in info. For more information about this refer to the data types section of this document.
The attr will tell what is the part you are going to read, that mostly tell you if your program need this information and let you choose what you will want to do with it. This part is dependent of your needs, but what you must really do well here, is move your pointer to the right position depending of the form you've read. As I've already told, any mistake here will be hard to find out until you get really used to this kind of mistake and know the binary you're testing like the palm of your hand.
When you find the pair 0/0 that is to say the current entry for this CU is finished, restart reading index and so on until you find a 0 index.
At this point you've successfully read a complete CU, you can now loop and restart reading from CU header, and CU data
3. Data types
Let's start getting familliar with the different types of data that are used in DWARF 2.
All types are refered to, using their defines as they are found in the official documentation. You may also found most of the defines in the header I used in my project.
Note: I may have lighten this header by removing unused sections, if you seem to miss something have a look at the headers of the libdwarf.
Here are the main types you will find in DWARF 2:
- LEBs
Either LEB128 or ULEB128 (signed, unsigned respectively), are undefined length data. They are used pretty often in DWARF 2. You have to decode them to get their length and their value. The official documentation have some pseudo code on how to decode LEBs, I've copied this pseudo code to Appendix
Most of the time they are used in other types rather than directly.
- References:
DW_FORM_/ref1/ref2/ref4/ref8/ref_udata
There are lots of references in DWARF 2 format. They are pretty useful to avoid redundant information. This type is referencing an offset from the beginning of the current CU.
Their names let you know which size they are in the CU (in bytes).
For exemple when you find a DW_FORM_ref2 in the abbrev section, you know that the value to be read in the current CU is 2 bytes long.
DW_FORM_ref_udata is a ULEB128.
- Blocks:
DW_FORM_blockX
X may be 1 2 4 8 or inexistant, once again this will let you know the length to be read in the current CU. If it is only a DW_FORM_block it is a ULEB128.
What will be read at this point will be a size, this size will tell you how many bytes you have to read after this entry, that's the "block" of data.
For exemple let's say you found a DW_FORM_block1, you read one byte at the current position in the info section. If you read 0x0A there is 10 bytes of data following 0A, the next entry for this CU will be 10 bytes after the current position.
- Datas:
DW_FORM_dataX
Those are just uninterpreted data, on the length corresponding to the name
1/2/4/8 are for the size in bytes.
udata and sdata are for ULEB128 and LEB128 respectively.
- Flag:
Simple flag on one byte.
- Addr:
An address, coded on the size of a pointer on the target architecture, you should have found this size in the CU Header.
- String and strp:
They are both null terminated strings.
DW_FORM_string are directly found in the info section, at the current position.
DW_FORM_strp are 4 bytes coded offsets telling where to find the string in the .debug_str section.
That's all I plan to explain on this document, mainly because I haven't coded the other parts. This section will be a little overview of what and how you should probably get the other information.
You can for example get the line number and the function adresses.
The DWARF 2 use it's own pseudo calling convention, so in fact you will have to decode the execution of the program using this system.
Let's say you know in which file you are, and at which program counter you start. You should have found both by reading the beginning information, after this you have to see how the program will run in this calling convention.
Each step you'll do you should find of how many lines you have progress, and the same goes for the position of the PC.
Unfortunately I don't remember the how this is done, and I don't have enough motivation for searching about it, maybe in a future update of this document, or in the next part... I would like to be able to complete this document with a second part about the other information that I you can get using DWARF 2.
I'll se if I have time, motivation and if anybody read this firt part and ask for the second :)
This is only a copy/paste of the pseudo code given in the official documentation, it's up to you how you implement those.
Keep in mind you'll need to read the value and know the length read to go keep reading at the rigth place.
Decode unsigned LEB128 number:
result = 0;
shift = 0;
while(true)
{
byte = next byte in input;
result |= (low order 7 bits of byte << shift);
if (high order bit of byte == 0)
break;
shift += 7;
}
Decode signed LEB128 number:
result = 0;
shift = 0;
size = no. of bits in signed integer;
while(true)
{
byte = next byte in input;
result |= (low order 7 bits of byte << shift);
shift += 7;
/* sign bit of byte is 2nd high order bit (0x40) */
if (high order bit of byte == 0)
break;
}
if ((shift < size) && (sign bit of byte is set))
/* sign extend */
result |= - (1 << shift);
--- EOF ---
Here come the end of my first real article, trying to explain something useful, sorry for all the english errors I may have left, and forgive me if it's not clear enough... At least I tried :p
| | -- 39 comments -- |
|