You have already answered almost all of your own question; there are only two things missing.
Firstly, the relationship between file name/line number and program counter is encoded in .debug_line, not .debug_info.
Secondly, the variables are not children of foo(): each is a child of a lexical block. The relevant portion of the program structure will look like
DW_TAG_compile_unit
DW_TAG_subprogram
DW_TAG_lexical_block
DW_TAG_variable
DW_TAG_lexical_block
DW_TAG_variable
The lexical block should be associated with an address range but this might be encoded using DW_AT_ranges instead of DW_AT_low_pc/DW_AT_high_pc; if that's the case then you'll need to interpret .debug_ranges.
To illustrate the case in hand I compiled the following with cc -g (gcc 4.8.5 on Oracle Linux)...
1 #include <stdlib.h>
2
3 struct A { int a; };
4 struct B { int b; };
5
6 void foo()
7 {
8 {
9 struct A *b;
10 }
11
12 {
13 struct B *b;
14 b = malloc(sizeof (struct B));
15 }
16 }
...and used 'readelf -w' to decode the DWARF. Line 14 appears here in the line number table:
[0x00000032] Special opcode 124: advance Address by 8 to 0x8 and Line by 7 to 14
meaning that we're interested in address 0x8. The DIE hierarchy includes
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1><96>: Abbrev Number: 6 (DW_TAG_subprogram)
<9d> DW_AT_low_pc : 0x0
<a5> DW_AT_high_pc : 0x18
<2><b3>: Abbrev Number: 7 (DW_TAG_lexical_block)
<b4> DW_AT_low_pc : 0x8
<bc> DW_AT_high_pc : 0xe
<3><c4>: Abbrev Number: 8 (DW_TAG_variable)
<c5> DW_AT_name : b
<c7> DW_AT_decl_file : 1
<c8> DW_AT_decl_line : 13
<c9> DW_AT_type : <0xd2>
The DIE at 0xb3 does not contain any further lexical blocks so it represents the tightest scope at address 0x8. At this point, hence, the name "b" must refer to the DIE's child at 0xc4. This variable's type is given by
<1><d2>: Abbrev Number: 9 (DW_TAG_pointer_type)
<d3> DW_AT_byte_size : 8
<d4> DW_AT_type : <0x81>
<1><81>: Abbrev Number: 4 (DW_TAG_structure_type)
<82> DW_AT_name : B
<84> DW_AT_byte_size : 4
<2><8b>: Abbrev Number: 5 (DW_TAG_member)
<8c> DW_AT_name : b
<90> DW_AT_type : <0x34>
<94> DW_AT_data_member_location: 0
<1><34>: Abbrev Number: 3 (DW_TAG_base_type)
<35> DW_AT_byte_size : 4
<36> DW_AT_encoding : 5 (signed)
<37> DW_AT_name : int
EDIT:
In your own answer you've given a counter-example for mplayer in which there are lexical blocks without corresponding address ranges. Such DWARF does not conform to the standard: ยง3.4 of DWARF 2 states that a lexical block entry has DW_AT_low_pc and DW_AT_high_pc attributes and makes no suggestion that these are optional. A likely candidate for this bug, assuming you're using gcc, is "DWARF debug info for inlined lexical blocks missing range". The default mplayer configuration includes -O2 optimisation, which turns on inlining; you will see this reflected in the parent DW_TAG_subprogram for draw_vertices(), from which the example code is taken. A workaround for the bug is to add -fno-inline to the compiler options; this does not seem to suppress all inlining so you may wish to disable optimisation altogether.