How to print details of dns_name_t* when hitting a gdb breakpoint in dns_name_equal

Petr Špaček pspacek at isc.org
Wed Dec 4 20:41:01 UTC 2024


On 04. 12. 24 17:31, Kees Bakker wrote:
> On 03-12-2024 15:56, Petr Špaček wrote:
>> On 03. 12. 24 11:36, Kees Bakker via bind-users wrote:
>>> I have a CentOS FreeIPA setup with with multiple named (bind9 9.16.23)
>>> servers.
>>> On two of my five servers, when I start named it fails a REQUIRE in
>>> dns_name_equal
>>>
>>>      /*
>>>       * Either name1 is absolute and name2 is absolute, or neither is.
>>>       */
>>>      REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
>>>          (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
>>>
>>> My question: if I run gdb and break in "assertion_failed", then "go up",
>>> how can I print name1 and name2 in a meaningful manner,
>>> so that I can figure out what entries are causing this failure?
>>>
>>> Just doing "p *name1" in gdb isn't very helpful for that.
>>
>> Many years ago I wrote
>> https://github.com/pspacek/bind-gdb-pretty-printers
>> to help with this problem. I have no idea if it still works, but it
>> might be worth a try, given the ancient version you are running!
> Thanks
> I got that to work after some refactoring gen_json_dict.py (I'll send
> it to your Github)
> I see that the pretty printers can help displaying dns_name_t variables.
> 
> Unfortunately, I still can't make heads or tails from the name1 and name2
> at the moment of the crash.
> 
> [Switching to Thread 0x7fffef88e640 (LWP 322823)]
> 
> Thread 2.13 "isc-net-0011" hit Breakpoint 1, assertion_failed 
> (file=0x7ffff7dd4ffe "../../../lib/dns/name.c", line=668,
>      type=isc_assertiontype_require, cond=0x7ffff7dd5770 "(name1- 
>  >attributes & 0x00000001) == (name2->attributes & 0x00000001)")
>      at ../../../bin/named/main.c:208
> 208                      const char *cond) {
> (gdb) up
> #1  0x00007ffff7e9a4e0 in isc_assertion_failed 
> (file=file at entry=0x7ffff7dd4ffe "../../../lib/dns/name.c", 
> line=line at entry=668,
>      type=type at entry=isc_assertiontype_require,
>      cond=cond at entry=0x7ffff7dd5770 "(name1->attributes & 0x00000001) == 
> (name2->attributes & 0x00000001)")
>      at ../../../lib/isc/assertions.c:46
> 46              isc_assertion_failed_cb(file, line, type, cond);
> (gdb)
> #2  0x00007ffff7c9fb4a in dns_name_equal (name1=<optimized out>, 
> name2=<optimized out>) at ../../../lib/dns/name.c:668
> 668             REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
> (gdb)
> #3  0x00007ffff7cb4adc in match (name2=0x7fffd8650010, 
> name1=0x7fffd806fca0) at ../../../lib/dns/order.c:96
> 96              return (dns_name_equal(name1, name2));
> (gdb) p *name1
> $10 = {magic = 1145983854, ndata = 0x7fffd8066010 "", length = 0, labels 
> = 0, attributes = 0, offsets = 0x7fffd806fcf8 "",
>    buffer = 0x0, link = {prev = 0x0, next = 0x0}, list = {head = 
> 0x7fffd8073a90, tail = 0x7fffd8073a90}, ht = 0x0}
> (gdb) p *name2
> $11 = {magic = 1145983854, ndata = 0x7fffd8650128 "", length = 1, labels 
> = 1, attributes = 1, offsets = 0x7fffd8650068 "",
>    buffer = 0x7fffd86500e8, link = {prev = 0xffffffffffffffff, next = 
> 0xffffffffffffffff}, list = {head = 0x0, tail = 0x0}, ht = 0x0}

LOL. It seems that it *somehow* got two names:
- name1 = empty relative name (equivalent to @ in a zone file)
- name2 - the root zone name (.)

Obviously comparing relative and absolute name does not make sense so it 
crashes on assert. The assert works as intended ;-)


Now more seriously - you will need to track down source of the two names 
and find out how they got generated.

>>> BTW My work around is to keep restarting named until it no longer fails
>>> on that REQUIRE. 

It sounds like you are able to reproduce it fairly easily, right?

If that's the case I would recommend running `named` under RR debugger.

In case you are not familiar with it have a look at
https://rr-project.org/ - it is an _awesome_ debugger
Once you get `rr record` functional on your system (which might require 
a bit of fiddling, but definitely worth it!) ... go and modify command 
to run BIND from:
   named -c ...
to something like:
   rr record named -n1 -g -c ...

Then try long enough until it crashes.

If you manage to crash it under RR you basically won already. It allows 
you to step back and forth in the _recording_ until you find the two 
sources of names - which should shed light on the root cause.
`(gdb) watch -l` and
`(gdb) reverse-continue`
might be of use.

Good luck!

P.S. I'm eager to hear more about this journey, but perhaps e-mail me 
privately? I guess the rest of bind-users might not want to hear all the 
gory details.

-- 
Petr Špaček
Internet Systems Consortium


More information about the bind-users mailing list