[lldb-dev] [RFC] Segmented Address Space Support in LLDB

Jonas Devlieghere via lldb-dev lldb-dev at lists.llvm.org
Tue Nov 10 13:01:06 PST 2020

> On Nov 10, 2020, at 12:58 PM, Zdenek Prikryl <prikryl at codasip.com> wrote:
> Hi all,
> Just for the record, we have successfully implemented the wrapping of addr_t into a class to support multiple address spaces. The info about address space is stored in the ELF file, so we get the info from ELF parser and then pass it to the rest of the system. CLI/MI interface has been extended as well, so user can select with address space he wants for memory printing. Similarly, we patched expression evaluation, disassembler, etc.

That's really interesting, I'm excited to hear that this is feasible and has been done before. Is this code available publicly and/or is this something you'd be willing to upstream (with our help)? 

> If the address wrap is part of the upstream version, it will be awesome :-)...
> Best regards.
> On 10/20/20 9:30 PM, Ted Woodward via lldb-dev wrote:
>> I agree with Pavel about the larger picture - we need to know the driver behind address spaces before we can discuss a workable solution.
>> I've dealt with 2 use cases - Harvard architecture cores, and low level hardware debugging.
>> A Harvard architecture core has separate instruction and data memories. These often use the same addresses, so to distinguish between them you need address spaces. The Motorola DSP56300 had 1 program and 2 data memories, called p, x and y. p:100, x:100 and y:100 were all separate memories, so "address 100" isn't enough to get what the user needed to see.
>> For low level hardware debugging (often using JTAG), many devices let you access memories in ways like "virtual using the TLB", or "virtual == physical, through the core", or "physical, through the SoC, not cached". Memory spaces, done right, can give the user the flexibility to pick how to view memory.
>> Are these the use cases you were envisioning, Jonas?
>>> -----Original Message-----
>>> From: lldb-dev <lldb-dev-bounces at lists.llvm.org> On Behalf Of Pavel Labath
>>> via lldb-dev
>>> Sent: Tuesday, October 20, 2020 12:51 PM
>>> To: Jonas Devlieghere <jonas at devlieghere.com>; LLDB <lldb-
>>> dev at lists.llvm.org>
>>> Subject: [EXT] Re: [lldb-dev] [RFC] Segmented Address Space Support in
>>> LLDB
>>> There's a lot of things that are unclear to me about this proposal. The
>>> mechanics of representing an segmented address are one thing, but I I think
>>> that the really interesting part will be the interaction with the rest of lldb. Like
>>> - What's going to be the source of this address space information? Is it going
>>> to be statically baked into lldb (a function of the target architecture?), or
>>> dynamically retrieved from the target or platform we're debugging? How
>>> would that work?
>>> - How is this going to interact with Object/SymbolFile classes? Are you
>>> expecting to use existing object and symbol formats for address space
>>> information, or some custom ones? AFAIK, none of the existing formats
>>> actually support encoding address space information (though that hasn't
>>> stopped people from trying).
>>> Without understanding the bigger picture it's hard for me to say whether the
>>> proposed large scale refactoring is a good idea. Nonetheless, I am doubtful of
>>> the viability of that approach. Some of my reasons for that are:
>>> - not all addr_ts represent an actual address -- sometimes that is a difference
>>> between two addresses, which still uses addr_t, as that's guaranteed to fit.
>>> - relatedly to that, there is a difference (I'd expect) between the operations
>>> supported by the two types. addr_t supports all integral operations (though I
>>> hope we don't use all of them), but I wouldn't expect to be able to do the
>>> same with a SegmentedAddress. For one, I'd expect it wouldn't be possible
>>> to add two SegmentedAddresses together (which is possible for addr_t).
>>> OTOH, adding a SegmentedAddress and an addr_t would probably be fine?
>>> Would subtracting two SegmentedAddresses should result in an addr_t? But
>>> only if they have matching address spaces (and assert otherwise)?
>>> - I'd also be worried about over-generalizing specialized code which can
>>> afford to work with plain addresses, and where the added address space
>>> would be a nuisance (or a source of bugs). E.g. ELF has no notion of address
>>> space, so I don't think I'd find it helpful to replace all plain integer calculations
>>> in elf parsing code with something more complex.
>>> (I'm aware that some people are using elf to encode address space
>>> information, but this is a pretty nonstandard extension, and it'd take more
>>> than type substitution to support anything like that.)
>>> - large scale refactorings are very much not the norm in llvm
>>> On 19/10/2020 23:56, Jonas Devlieghere via lldb-dev wrote:
>>>> We want to support segmented address spaces in LLDB. Currently, all of
>>>> LLDB’s external API, command line interface, and internals assume that
>>>> an address in memory can be addressed unambiguously as an addr_t (aka
>>>> uint64_t). To support a segmented address space we’d need to extend
>>>> addr_t with a discriminator (an aspace_t) to uniquely identify a
>>>> location in memory. This RFC outlines what would need to change and
>>>> how we propose to do that.
>>>> ### Addresses in LLDB
>>>> Currently, LLDB has two ways of representing an address:
>>>>   - Address object. Mostly represents addresses as Section+offset for
>>>> a binary image loaded in the Target. An Address in this form can
>>>> persist across executions, e.g. an address breakpoint in a binary
>>>> image that loads at a different address every execution. An Address
>>>> object can represent memory not mapped to a binary image. Heap, stack,
>>>> jitted items, will all be represented as the uint64_t load address of
>>>> the object, and cannot persist across multiple executions. You must
>>>> have the Target object available to get the current load address of an
>>>> Address object in the current process run. Some parts of lldb do not
>>>> have a Target available to them, so they require that the Address can
>>>> be devolved to an addr_t (aka uint64_t) and passed in.
>>>>   - The addr_t (aka uint64_t) type. Primarily used when receiving
>>>> input (e.g. from a user on the command line) or when interacting with
>>>> the inferior (reading/writing memory) for addresses that need not
>>>> persist across runs. Also used when reading DWARF and in our symbol
>>>> tables to represent file offset addresses, where the size of an
>>>> Address object would be objectionable.
>>>> ## Proposal
>>>> ### Address + ProcessAddress
>>>>   - The Address object gains a segment discriminator member variable.
>>>> Everything that creates an Address will need to provide this segment
>>>> discriminator.
>>>>   - A ProcessAddress object which is a uint64_t and a segment
>>>> discriminator as a replacement for addr_t. ProcessAddress objects
>>>> would not persist across multiple executions. Similar to how you can
>>>> create an addr_t from an Address+Target today, you can create a
>>>> ProcessAddress given an Address+Target. When we pass around addr_ts
>>>> today, they would be replaced with ProcessAddress, with the exception
>>>> of symbol tables where the added space would be significant, and we do
>>>> not believe we need segment discriminators today.
>>> I'm strongly in favor of the first approach. The reason for that is that we have
>>> a lot of code that can only reasonable deal with one kind of an address, and
>>> I'd like to be able to express that in the type system. In fact, I think we could
>>> have more distinct types even now, but adding address spaces makes that
>>> even more important.
>>>> ### Address Only
>>>> Extend the lldb_private::Address class to be the one representation of
>>>> locations; including file based ones valid before running, file
>>>> addresses resolved in a process, and process specific addresses
>>>> (heap/stack/JIT code) that are only valid during a run. That is
>>>> attractive because it would provide a uniform interface to any “where
>>>> is something” question you would ask, either about symbols in files,
>>>> variables in stack frames, etc.
>>>> At present, when we resolve a Section+Offset Address to a “load address”
>>>> we provide a Target to the resolution API.  Providing the Target
>>>> externally makes sense because a Target knows whether the Section is
>>>> present or not and can unambiguously return a load address.    We
>>>> could continue that approach since the Target always holds only one
>>>> process, or extend it to allow passing in a Process when resolving
>>>> non-file backed addresses.  But this would make the conversion from
>>>> addr_t uses to Address uses more difficult, since we will have to push
>>>> the Target or Process into all the API’s that make use of just an
>>>> addr_t.  Using a single Address class seems less attractive when you
>>>> have to provide an external entity to make sense of it at all the use sites.
>>>> We could improve this situation by including a Process (as a weak
>>>> pointer) and fill that in on the boundaries where in the current code
>>>> we go from an Address to a process specific addr_t.  That would make
>>>> the conversion easier, but add complexity.  Since Addresses are
>>>> ubiquitous, you won’t know what any given Address you’ve been handed
>>>> actually contains.  It could even have been resolved for another
>>>> process than the current one.  Making Address usage-dependent in this
>>>> way reduces the attractiveness of the solution.
>>>> ## Approach
>>>> Replacing all the instances of addr_t by hand would be a lot of work.
>>>> Therefore we propose writing a clang-based tool to automate this
>>>> menial task. The tool would update function signatures and replace
>>>> uses of addr_t inside those functions to get the addr_t from the
>>>> ProcessAddress or Address and return the appropriate object for
>>>> functions that currently return an addr_t. The goal of this tool is to
>>>> generate one big NFC patch. This tool needs not be perfect, at some
>>>> point it will be more work to improve the tool than fixing up the remaining
>>> code by hand.
>>>> After this patch LLDB would still not really understand address spaces
>>>> but it will have everything in place to support them.
>>>> Once all the APIs are updated, we can start working on the functional
>>>> changes. This means actually interpreting the aspace_t values and
>>>> making sure they don’t get dropped.
>>>> Finally, when all this work is done and we’re happy with the approach,
>>>> we extend the SB API with overloads for the functions that currently
>>>> take or return addr_t . I want to do this last so we have time to
>>>> iterate before committing to a stable interface.
>>>> ## Testing
>>>> By splitting off the intrusive non-functional changes we are able to
>>>> rely on the existing tests for coverage. Smaller functional changes
>>>> can be tested in isolation, either through a unit test or a small GDB
>>>> remote test. For end-to-end testing we can run the test suite with a
>>>> modified debugserver that spoofs address spaces.
>>>> Thanks,
>>>> Jonas
>>>> _______________________________________________
>>>> lldb-dev mailing list
>>>> lldb-dev at lists.llvm.org
>>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>>> _______________________________________________
>>> lldb-dev mailing list
>>> lldb-dev at lists.llvm.org
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>> _______________________________________________
>> lldb-dev mailing list
>> lldb-dev at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
> -- 
> Zdenek Prikryl
> T +420 541 141 475
> Codasip.com

More information about the lldb-dev mailing list